feat(sheets): add --range flag to +append for targeting specific tabs (#641)

Previously +append always used hardcoded "A1" range, limiting appends
to the first sheet. Add optional --range flag (default: "A1") to allow
appending to any sheet tab using A1 notation.
This commit is contained in:
Simon
2026-04-01 02:51:15 +08:00
committed by GitHub
parent 705fb0ecac
commit a3768d0e82
3 changed files with 67 additions and 5 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"@googleworkspace/cli": minor
---
Add `--range` flag to `sheets +append` for targeting specific sheet tabs
@@ -51,14 +51,22 @@ impl Helper for SheetsHelper {
.help("JSON array of rows, e.g. '[[\"a\",\"b\"],[\"c\",\"d\"]]'")
.value_name("JSON"),
)
.arg(
Arg::new("range")
.long("range")
.help("Target range in A1 notation (e.g. 'Sheet2!A1'). Defaults to 'A1' (first sheet)")
.value_name("RANGE"),
)
.after_help(
r#"EXAMPLES:
gws sheets +append --spreadsheet ID --values 'Alice,100,true'
gws sheets +append --spreadsheet ID --json-values '[["a","b"],["c","d"]]'
gws sheets +append --spreadsheet ID --range "Sheet2!A1" --values 'Alice,100'
TIPS:
Use --values for simple single-row appends.
Use --json-values for bulk multi-row inserts."#,
Use --json-values for bulk multi-row inserts.
Use --range to target a specific sheet tab (default: A1, i.e. first sheet)."#,
),
);
@@ -212,11 +220,9 @@ fn build_append_request(
GwsError::Discovery("Method 'spreadsheets.values.append' not found".to_string())
})?;
let range = "A1";
let params = json!({
"spreadsheetId": config.spreadsheet_id,
"range": range,
"range": config.range,
"valueInputOption": "USER_ENTERED"
});
@@ -262,6 +268,8 @@ fn build_read_request(
pub struct AppendConfig {
/// The ID of the spreadsheet to append to.
pub spreadsheet_id: String,
/// Target range in A1 notation (e.g. "Sheet2!A1"). Defaults to "A1".
pub range: String,
/// The rows to append, where each inner Vec represents one row.
pub values: Vec<Vec<String>>,
}
@@ -289,8 +297,14 @@ pub fn parse_append_args(matches: &ArgMatches) -> AppendConfig {
Vec::new()
};
let range = matches
.get_one::<String>("range")
.cloned()
.unwrap_or_else(|| "A1".to_string());
AppendConfig {
spreadsheet_id: matches.get_one::<String>("spreadsheet").unwrap().clone(),
range,
values,
}
}
@@ -353,7 +367,8 @@ mod tests {
let cmd = Command::new("test")
.arg(Arg::new("spreadsheet").long("spreadsheet"))
.arg(Arg::new("values").long("values"))
.arg(Arg::new("json-values").long("json-values"));
.arg(Arg::new("json-values").long("json-values"))
.arg(Arg::new("range").long("range"));
cmd.try_get_matches_from(args).unwrap()
}
@@ -369,17 +384,32 @@ mod tests {
let doc = make_mock_doc();
let config = AppendConfig {
spreadsheet_id: "123".to_string(),
range: "A1".to_string(),
values: vec![vec!["a".to_string(), "b".to_string(), "c".to_string()]],
};
let (params, body, scopes) = build_append_request(&config, &doc).unwrap();
assert!(params.contains("123"));
assert!(params.contains("USER_ENTERED"));
assert!(params.contains("A1"));
assert!(body.contains("a"));
assert!(body.contains("b"));
assert_eq!(scopes[0], "https://scope");
}
#[test]
fn test_build_append_request_with_range() {
let doc = make_mock_doc();
let config = AppendConfig {
spreadsheet_id: "123".to_string(),
range: "Sheet2!A1".to_string(),
values: vec![vec!["x".to_string()]],
};
let (params, _body, _scopes) = build_append_request(&config, &doc).unwrap();
let parsed: serde_json::Value = serde_json::from_str(&params).unwrap();
assert_eq!(parsed["range"], "Sheet2!A1");
}
#[test]
fn test_build_read_request() {
let doc = make_mock_doc();
@@ -399,9 +429,32 @@ mod tests {
let matches = make_matches_append(&["test", "--spreadsheet", "123", "--values", "a,b,c"]);
let config = parse_append_args(&matches);
assert_eq!(config.spreadsheet_id, "123");
assert_eq!(config.range, "A1");
assert_eq!(config.values, vec![vec!["a", "b", "c"]]);
}
#[test]
fn test_parse_append_args_with_range() {
let matches = make_matches_append(&[
"test",
"--spreadsheet",
"123",
"--range",
"Sheet2!A1",
"--values",
"a,b",
]);
let config = parse_append_args(&matches);
assert_eq!(config.range, "Sheet2!A1");
}
#[test]
fn test_parse_append_args_default_range() {
let matches = make_matches_append(&["test", "--spreadsheet", "123", "--values", "a"]);
let config = parse_append_args(&matches);
assert_eq!(config.range, "A1");
}
#[test]
fn test_parse_append_args_json_single_row() {
let matches = make_matches_append(&[
@@ -436,6 +489,7 @@ mod tests {
let doc = make_mock_doc();
let config = AppendConfig {
spreadsheet_id: "123".to_string(),
range: "A1".to_string(),
values: vec![
vec!["Alice".to_string(), "100".to_string()],
vec!["Bob".to_string(), "200".to_string()],
+3
View File
@@ -30,18 +30,21 @@ gws sheets +append --spreadsheet <ID>
| `--spreadsheet` | ✓ | — | Spreadsheet ID |
| `--values` | — | — | Comma-separated values (simple strings) |
| `--json-values` | — | — | JSON array of rows, e.g. '[["a","b"],["c","d"]]' |
| `--range` | — | `A1` | Target range in A1 notation (e.g. 'Sheet2!A1') to select a specific tab |
## Examples
```bash
gws sheets +append --spreadsheet ID --values 'Alice,100,true'
gws sheets +append --spreadsheet ID --json-values '[["a","b"],["c","d"]]'
gws sheets +append --spreadsheet ID --range "Sheet2!A1" --values 'Alice,100'
```
## Tips
- Use --values for simple single-row appends.
- Use --json-values for bulk multi-row inserts.
- Use --range to append to a specific sheet tab (default: A1, i.e. first sheet).
> [!CAUTION]
> This is a **write** command — confirm with the user before executing.