gogcli 实战:用gog sheets datasource update更新 BigQuery Connected Sheets 数据源
【免费下载链接】gogcliGoogle Workspace in your terminal.项目地址: https://gitcode.com/GitHub_Trending/gogcl/gogcli
本文深入讲解 gogcli 中gog sheets datasource update命令的完整用法与底层实现。该命令用于对一个已存在的 BigQuery Connected Sheets 数据源执行部分更新(Partial Update),可替换查询 SQL、原生表定位信息或计费执行项目,且只改动你明确指定的字段。读完本文,你将掌握该命令的全部参数含义、字段掩码生成规则、安全性保护机制(预检验证、dry-run、readonly、禁止自动重试),以及通过源码与测试验证的实际调用链,能够安全地在生产环境中修改 Connected Sheets 数据源。
命令概览与定位
gog sheets datasource update隶属于gog sheets datasource命令组(管理 Connected Sheets 数据源与提取表),与add、delete、list、describe、refresh、table并列。从 sheets_datasource.go 的源码结构看,update子命令的定义为:
Update one BigQuery Connected Sheets data source
其完整用法(含别名)为:
gog sheets (sheet) datasource (data-source,data-sources,connected-sheets) update <spreadsheetId> <dataSourceId> [flags]- 父命令
gog sheets datasource支持sheet、data-source、data-sources、connected-sheets等多组别名; - 命令本身接收两个必填位置参数:
spreadsheetId(电子表格 ID,兼容传入完整 URL,内部会通过normalizeGoogleID提取 ID)与dataSourceId(数据源 ID); - 在源码 sheets_datasource_update.go 中,这两个参数分别声明为
arg:""的SpreadsheetID与DataSourceID,两者都会先做strings.TrimSpace并校验非空。
该命令是典型的“小步修改”型操作:它不会重建数据源,而是通过 Google Sheets API 的BatchUpdateSpreadsheetRequest提交一条UpdateDataSource请求,并携带精确的字段掩码(field mask),只覆盖你显式传入的字段。
可更新的三大类内容
update 命令支持三类更新目标,对应五个核心参数。结合源码 partialBigQuerySpec 的实现,这三类内容为:
1. 替换计费执行项目(Billing Project)
gog sheets datasource update <spreadsheetId> <dataSourceId> --billing-project <new-project>- 对应参数:
--billing-project; - 生成的字段掩码路径:
spec.bigQuery.projectId; - 含义:将 BigQuery 执行/计费项目切换为另一个已启用 BigQuery 计费的 Google Cloud 项目。
2. 替换查询 SQL(Query Source)
gog sheets datasource update <spreadsheetId> <dataSourceId> --query 'SELECT ...'- 对应参数:
--query; - 生成的字段掩码路径:
spec.bigQuery.querySpec.rawQuery; - 含义:为查询类型的 BigQuery 数据源替换原始 SQL;
- 前提约束(源码
validateConnectedSheetsUpdateTarget,见下节):目标数据源必须是查询模式,否则报错cannot apply SQL to non-query BigQuery data source。
3. 替换原生表定位信息(Native Table)
gog sheets datasource update <spreadsheetId> <dataSourceId> \ --table-project <owner-project> --dataset <dataset> --table <table>- 对应参数:
--table-project、--dataset、--table(三者均为可选项,可单独或组合使用); - 生成的字段掩码路径依次为:
spec.bigQuery.tableSpec.tableProjectId、spec.bigQuery.tableSpec.datasetId、spec.bigQuery.tableSpec.tableId; - 含义:将原生表数据源指向新的 BigQuery 表;
- 前提约束:目标数据源必须是原生表模式,否则报错
cannot apply table fields to non-table BigQuery data source。
部分更新与字段掩码原理
与add(整体创建)不同,update的核心设计是只改动显式指定的字段。这一点在源码 partialBigQuerySpec 中有清晰体现:
- 通过
flagProvided(kctx, "...")判断用户是否真正传入了某个 flag; - 只有被传入的 flag 才会写入
sheets.BigQueryDataSourceSpec; - 同时把对应的 API 字段路径追加到
fields切片; - 最终
fields以逗号拼接,作为UpdateDataSourceRequest.Fields(field mask)提交。
字段掩码与参数的映射关系如下表:
| 参数 | 掩码路径(field mask) |
|---|---|
--billing-project | spec.bigQuery.projectId |
--query | spec.bigQuery.querySpec.rawQuery |
--table-project | spec.bigQuery.tableSpec.tableProjectId |
--dataset | spec.bigQuery.tableSpec.datasetId |
--table | spec.bigQuery.tableSpec.tableId |
这一点被测试 TestSheetsDataSourceUpdateUsesExactFieldMasks 严格锁定。例如:
- 仅传
--query时,断言掩码恰为spec.bigQuery.querySpec.rawQuery,且ProjectId、TableSpec必须为空; - 仅传
--billing-project时,断言掩码恰为spec.bigQuery.projectId,QuerySpec、TableSpec不得被改动; - 传入
--table next --table-project owner --dataset data时,掩码必须保持固定顺序spec.bigQuery.tableSpec.tableProjectId,spec.bigQuery.tableSpec.datasetId,spec.bigQuery.tableSpec.tableId; - 传入
--billing-project payer --table next时,测试断言“未提供的字段必须保持不动”(unsupplied fields must remain untouched)。
也就是说:省略的字段在 API 侧不会被覆盖,这是“部分更新”语义的保证,也是与add命令最本质的区别。
互斥与歧义输入的处理
partialBigQuerySpec同时执行严格的输入约束,测试 TestSheetsDataSourceUpdateRejectsInvalidInputsBeforeAuth 覆盖了全部场景:
--query与表相关 flag(--table-project/--dataset/--table)互斥,同时传入报错--query and table flags are mutually exclusive;- 五个更新参数一个都不传时报错
nothing to update: pass --billing-project, --query, --table-project, --dataset, or --table; - 任何参数传空白值都会报对应的
--xxx cannot be empty; --project被显式拒绝:由于全局--project是--select/--pick的别名(用于 JSON 输出字段选择),与 BigQuery 计费项目毫无关系,命令会拦截它并提示--project selects output fields; use --billing-project to change the BigQuery execution project。这一拦截在Run中通过扫描kctx.Args完成(sheets_datasource_update.go),避免用户误把输出选择参数当作计费项目传入。
预检:提交前的目标验证
在真正发起写请求之前,命令会调用 validateConnectedSheetsUpdateTarget 做一次只读预检:
- 调用
svc.Spreadsheets.Get(spreadsheetID),且只请求最小字段集dataSources(dataSourceId,spec(bigQuery(querySpec,tableSpec))),避免拉取整份电子表格; - 遍历返回的
DataSources,确认dataSourceId存在于该电子表格的 Connected Sheets 数据源中,否则报错data source %s was not found in Connected Sheets; - 校验数据源确实由 BigQuery 支撑(
source.Spec.BigQuery != nil),否则报错data source %s is not backed by BigQuery(例如 Looker 数据源会被拒绝); - 校验更新模式与现有模式匹配:SQL 只能用于查询源,表字段只能用于表源。
测试 TestSheetsDataSourceUpdateRejectsWrongProviderOrSourceMode 覆盖了四类危险场景:数据源缺失(was not found)、Looker 源(not backed by BigQuery)、对表源传 SQL(non-query)、对查询源传表字段(non-table),并且断言这些场景下写请求次数必须为 0——预检失败时绝不触碰写 API。
另外,预检阶段的 GET 请求掩码也经过测试断言(dataSources(dataSourceId,spec(bigQuery(querySpec,tableSpec)))),确保这类前置查询保持轻量。
提交、执行状态与错误处理
通过预检后,命令调用 submitConnectedSheetsWrite 提交BatchUpdateSpreadsheetRequest,请求体为:
{ "requests": [{ "updateDataSource": { "dataSource": { "dataSourceId": "<dataSourceId>", "spec": { "bigQuery": { "...": "..." } } }, "fields": "<comma-separated field mask>" } }] }提交环节的关键行为(均有测试佐证):
- 不自动重试计费型变更:写请求以
googleapi.WithoutRetries(ctx)执行(sheets_datasource_write.go)。测试 TestSheetsDataSourceUpdateDoesNotRetryBillableMutation 模拟服务端返回 503,断言写请求只尝试一次——因为 update 会立刻触发一次异步、可能产生 BigQuery 费用的执行,盲目重试可能造成重复扣费。 - 响应缺失时的保守处理:若 Google 未返回
UpdateDataSource应答,命令不会自动重试,而是报错提示provider may have updated data source %s without returning a result; inspect it before retrying,并要求你先检查数据源状态(sheets_datasource_update.go)。 - 应答 ID 一致性校验:若返回的数据源 ID 与请求的目标不一致,报错
provider returned unexpected data source ...(sheets_datasource_update.go)。 - 执行状态处理:Google 的
DataExecutionStatus会异步推进。若返回状态为FAILED,命令在输出结构化 JSON 的同时以非零退出码结束(通过 connectedSheetsExecutionError 组装update Connected Sheets data source: <code>: <message>错误)。测试 TestSheetsDataSourceUpdateProviderFailureRetainsWrappedJSON 验证了失败场景下 JSON 输出依然完整保留dataSourceId等结构化信息。
输出格式:文本与 JSON
- 默认(文本)模式:执行状态非
FAILED时输出一行Updated Connected Sheets data source <dataSourceId>; - JSON 模式(
--json/-j/--machine):输出包含spreadsheetId、dataSourceId、fields(本次实际使用的字段掩码),若响应带有执行状态则追加dataExecutionStatus(包含state、lastRefreshTime、errorCode、errorMessage等)。该结构适合脚本消费;配合--select/--results-only可进一步裁剪输出。
与list刻意不打印 SQL 不同,update 的成功 JSON 只报告改动掩码而不回显查询 SQL,避免敏感查询文本落入日志或脚本输出;测试同样断言输出中绝不包含 provider 回显的 SQL 字符串(private_query不得泄漏,见 sheets_datasource_update_test.go)。
安全机制:dry-run、readonly 与权限要求
dry-run 离线预览
--dry-run(别名--dryrun、--noop、--preview)在不发起任何认证、网络请求与写操作的前提下输出将要执行的动作。对 update 命令而言,预览信息包括(见 sheets_datasource_update.go):
spreadsheet_id、data_source_id、fields(字段掩码);starts_execution: true与may_incur_bigquery_charges: true(提示这是一次计费型异步执行);- 若指定了计费项目则输出
billing_project; - 若指定了 SQL 则只输出
query_bytes(查询字节数)而绝不回显 SQL 本体。
测试 TestSheetsDataSourceUpdateDryRunProtectsSQL 验证了 dry-run 输出包含sheets.datasource.update、字段掩码、query_bytes、may_incur_bigquery_charges,同时断言输出中不含 SQL 内容。
readonly 前置拦截
--readonly会在认证与 writer 创建之前就拒绝本命令。prepareConnectedSheetsWrite(sheets_datasource_write.go)首先检查googleapi.ReadOnly(ctx) || flags.ReadOnly,命中即返回googleapi.ErrReadOnly。测试 TestSheetsDataSourceUpdateReadOnlyRejectsBeforeAuth 通过注入一个“必须不被调用”的 writer 工厂,断言 readonly 模式下工厂调用次数为 0——即连 OAuth 流程都不会启动。这也意味着 update 不能被--readonly绕过。
OAuth 权限与 scope 提示
Google 的 Connected Sheets 文档要求 BigQuery 相关响应/操作在 Sheets 授权之外,额外携带https://www.googleapis.com/auth/bigquery.readonlyscope。update 属于写操作,还需要可写的 Sheets 授权。若提交时返回 scope 不足错误,命令会给出可操作的重新认证提示(sheets_datasource_write.go):
gog auth add you@example.com \ --services sheets \ --extra-scopes https://www.googleapis.com/auth/bigquery.readonly \ --force-consent若账号还覆盖其他服务,应保留其原有的--services选择及任何--drive-scope、--gmail-scope配置,而不是收窄为sheets。Looker 数据源则复用账号已有的 Looker 链接。更完整的数据源授权流程可参考 Connected Sheets 使用指南。
完整命令行示例
以下示例贯穿「预览 → 更新 → 验证」的完整工作流(替换其中的尖括号占位符):
1. 离线预览一次 SQL 替换(不触发网络与费用)
gog --account you@example.com sheets datasource update <spreadsheetId> <dataSourceId> \ --query 'SELECT region, SUM(sales) FROM dataset.orders GROUP BY region' --dry-run --json2. 实际替换查询 SQL
gog --account you@example.com sheets datasource update <spreadsheetId> <dataSourceId> \ --query 'SELECT region, SUM(sales) FROM dataset.orders GROUP BY region' --json3. 仅切换计费执行项目
gog --account you@example.com sheets datasource update <spreadsheetId> <dataSourceId> \ --billing-project new-billing-project --json4. 将原生表数据源指向新表(可只改其中一个字段)
gog --account you@example.com sheets datasource update <spreadsheetId> <dataSourceId> \ --table-project analytics-prod --dataset reporting --table daily_sales_v2 --json5. 更新后轮询执行状态
gog --readonly --account you@example.com sheets datasource describe \ <spreadsheetId> <dataSourceId> --jsondescribe会返回DataExecutionStatus(state为RUNNING/SUCCEEDED/FAILED),待其变为SUCCEEDED后数据即生效;若为FAILED,输出中的errorCode/errorMessage可用于排查。
Flags 完整参考
以下为gog sheets datasource update的完整全局 flag 表(来自命令自动生成的 schema 文档,见 gog-sheets-datasource-update.md):
| Flag | Type | Default | Help |
|---|---|---|---|
--access-token | string | Use provided access token directly (bypasses stored refresh tokens; token expires in ~1h) | |
-a--account--acct | string | Account email, alias, or auto for authenticated Google API commands | |
--billing-project | string | New billing-enabled BigQuery execution project | |
--client | string | OAuth client name (selects stored credentials + token bucket) | |
--color | string | auto | Color output: auto|always|never |
--dataset | string | Replacement dataset for an existing native table | |
--disable-commands | string | Comma-separated list of disabled commands; dot paths allowed | |
-n--dry-run--dryrun--noop--preview | bool | Do not make changes; print intended actions and exit successfully | |
--enable-commands | string | Comma-separated list of enabled command prefixes; dot paths allowed (restricts CLI) | |
--enable-commands-exact | string | Comma-separated list of exact enabled commands; dot paths allowed and parent commands do not enable children | |
-y--force--assume-yes--yes | bool | Skip confirmations for destructive commands | |
--gmail-no-send | bool | false | Block Gmail send operations (agent safety) |
-h--help | kong.helpFlag | Show context-sensitive help. | |
--home | string | Override gogcli config/data/state/cache root (equivalent to GOG_HOME) | |
-j--json--machine | bool | false | Output JSON to stdout (best for scripting) |
--no-input--non-interactive--noninteractive | bool | Never prompt; fail instead (useful for CI) | |
-p--plain--tsv | bool | false | Output stable, parseable text to stdout (TSV; no colors) |
--query | string | Replacement SQL for an existing query source | |
--quota-project | string | Google Cloud project to bill for API usage (sent as X-Goog-User-Project; some APIs require it with --access-token or ADC) | |
--readonly | bool | false | Block mutating API requests at runtime; auth add also requests read-only OAuth scopes |
--results-only | bool | In JSON mode, emit only the primary result (drops envelope fields like nextPageToken) | |
--select--pick--project | string | In JSON mode, select comma-separated fields (best-effort; supports dot paths). Desire path: use --fields for most commands. | |
--table | string | Replacement native table ID | |
--table-project | string | Replacement project owning an existing native table | |
-v--verbose | bool | Enable verbose logging | |
--version | kong.VersionFlag | Print version and exit | |
--wrap-untrusted | bool | false | In JSON/raw output, wrap fetched text fields in external untrusted-content markers |
需要注意:表中--select/--pick/--project是一组输出字段选择别名,与 update 的--billing-project毫无关系;误传--project会被命令主动拒绝。--billing-project、--query、--table-project、--dataset、--table才是本命令的业务参数。
相关资源
- 命令文档:gog sheets datasource update(自动生成的 schema 文档)
- 父命令:gog sheets datasource
- 命令索引
- Connected Sheets 使用指南(授权、增删改查、提取表的完整流程)
- 源码实现:sheets_datasource_update.go、sheets_datasource_write.go、sheets_datasource.go
- 测试用例:sheets_datasource_update_test.go
总而言之,gog sheets datasource update是一把“手术刀”而非“大锤”:精确的字段掩码、提交前的模式校验、dry-run 离线预览、readonly 前置拦截、以及计费型写请求的禁止自动重试,共同保证了它在大数据源上做小改动时既安全又可审计。将它配合sheets datasource list/describe使用,即可完整地完成 Connected Sheets 数据源的查看、修改与状态验证闭环。
【免费下载链接】gogcliGoogle Workspace in your terminal.项目地址: https://gitcode.com/GitHub_Trending/gogcl/gogcli
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考