mirror of
https://github.com/larksuite/cli.git
synced 2026-09-14 18:42:53 +08:00
723f884e9b
* feat(base): add BaseApp workspace, page and block shortcuts Implement the CLI layer of the BaseApp CLI/OpenAPI protocol design: 17 new shortcuts covering workspace entities, blank app creation, page CRUD and page block CRUD, plus skill references and dry-run E2E for each. The data_config validator moves to a neutral block_data_config.go with chart logic unchanged; list and richText dispatch are new branches, so dashboard behaviour is untouched. Command spaces stay separate — dashboard commands never take --app-token and app block commands never take --dashboard-id. The one exception is +app-block-get-data, which shares the dashboard endpoint, execute and dry-run hooks and therefore takes --base-token instead of --app-token. This phase ships no +app-block-delete and no page arrange command; both the help text and the skill docs spell out that a block type cannot be changed after creation. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(base): implement app mode shortcuts and list components * feat: support deleting BaseApp via drive delete * fix: 修复 workspace scope * fix: correct BaseApp permission scopes * feat: 新增 moveIn workspace 逻辑 * feat(base): support multi-datasource data_config for BaseApp charts BaseApp page charts follow section 8 图表协议 of the App CLI RPC 协议, which differs from dashboard charts by supporting multiple data sources: base_token is a single top-level value shared by every source, while table_name/series/count_all/group_by/filter move into each data_sources[] element (plus top-level data_source_mode and sort). The per-source value semantics are identical to dashboard charts, so each data_sources[] element reuses normalizeDataConfig / validateChartDataConfig; the wrapper only adds the top-level structure. Dashboard charts keep the flat shape; the list protocol is untouched. - block_data_config.go: add normalizeAppChartDataConfig / validateAppChartDataConfig / validateAppBlockDataConfig - app_block_create/update: route chart blocks to the multi-datasource normalize/validate; refresh tips and examples - reference doc: rewrite the chart section for the multi-datasource shape - unit + e2e tests: migrate chart cases to data_sources; add a multi-datasource combo case Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(base): map BaseApp richText block type to the wire type "text" The rich-text widget's API type is "text" (App CLI RPC 协议 §10), but the CLI exposes the friendlier "richText" alias and was sending it verbatim, so the backend rejected +app-block-create --type richText with "type is invalid". Map richText -> text when building the request body; the user-facing --type richText is unchanged. Add TestAppRichTextTypeMapsToText. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(base): remove internal protocol doc link/reference from skills The BaseApp skill references pointed at an internal Lark doc (deep link with a private token) as the source of truth, which must not ship in this repo. Drop the link and the doc name entirely from the reference markdown and from code comments; describe behavior in neutral terms ("服务端协议 / 服务端返回和校验") instead. No functional change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: create workspace for BaseApp when omitted * fix(base): align BaseApp block protocol * fix: 删掉废弃的 workspace-entity-remove * fix(base): align app get reference response * fix(base): align app shortcuts with API contract * fix(base): refine app mode shortcut contracts * fix: use entity_type for workspace entity filtering * fix: return workspace URLs for base workspace ops * fix(base): enforce unique app block names * fix(base): use chart token for app block data * 明确baseapp边界,不导向到dashboard-arrange * docs(base): clarify app copy is unsupported * docs(base): define unsupported app page operations * fix(base): align app block text type with dashboard AppMode 的文本组件此前对外叫 richText,发送时再映射成 wire 上的 text, 而读取方向没有反向映射:写进去用 richText、读回来是 text,同一个 CLI 表面自相矛盾,回填或幂等复建时会被枚举校验拒掉。 统一成 text,与 Dashboard 文本组件同名同义: - appBlockTypes/isAppBlockType/textBlockTypes 去掉 richText - 删除 appBlockBody 里的 richText → text 发送期映射 - help、枚举、示例、tips 与 baseapp block data_config reference 同步 - 新增回归测试,确保 richText 不再被接受也不再出现在枚举里 richText 不保留别名:+app-* 尚未随已发布版本对外,无存量调用方。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat(base): resolve BaseApp URLs Migrate the net changes from bitable/base_cli!1308 onto the current BaseApp development branch. * fix(base): remove app block list type filter * docs: preserve explicit intent when reusing BaseApp blocks * fix(base): route +app-block-get-data to base_apps endpoint Move the shortcut off the dashboard route and onto the dedicated BaseApp block-data endpoint: - URL: /open-apis/base/v3/base_apps/:app_token/blocks/:block_id/data - base_token is passed as a required query parameter per the new IDL - Refresh --block-id description and tips to list all producers of the chart_token (create/list/get) and note the cht… prefix - Update the dryrun test to expect the new URL Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix: clarify unsupported BaseApp copy paths * fix: front-load BaseApp copy stop rule * fix: surface unsupported PageGroup operations * fix: preserve PageGroup support boundary * docs(base): clarify unsupported app block handling * docs(base): clarify how to read text block content Text blocks have no /data endpoint; calling +app-block-get-data on one returns a generic server 500. Point readers at +app-block-get, whose data_config.text carries the Markdown source. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs: clarify immutable BaseApp block types * docs(base): correct chart date filter format * docs(base): explain inaccessible app pages * docs: require workspace removal lookup * fix(base): return workspace move-in result faithfully * chore(base): adapt BaseApp changes to upstream main * fix(base): align app mode changes with upstream scope * fix(base): address app mode review feedback * test(base): assert app data transport error contract * fix(base): satisfy app mode merge requirements * refactor(base): align app mode filenames * docs: fix BaseApp rename guidance * fix(base): remove unsupported workspace icon * docs(base): clarify app mode concepts and config reuse --------- Co-authored-by: weibiao.x <weibiao.x@bytedance.com> Co-authored-by: zhangbinkai.zbk <zhangbinkai.zbk@bytedance.com> Co-authored-by: yurunjie <yurunjie.xx@bytedance.com> Co-authored-by: Codex <codex@example.com>
13 KiB
13 KiB
Base CLI E2E Coverage
Metrics
- Denominator: 89 leaf commands
- Covered: 30
- Coverage: 33.7%
Summary
- TestBase_BasicWorkflow: proves
+base-create,+base-get,+table-create,+table-get, and+table-list; keyt.Run(...)proof points areget base as bot,get table as bot, andlist tables and find created table as bot. - TestBaseBlockDryRun: proves the five
+base-block-*shortcuts request shapes without touching live data. - TestBaseAppWorkflow: live user workflow in an isolated fixture Workspace covering Workspace entity listing, BaseApp create/get, Page create/list/get/update/delete, text Block create/list/get/update, and App cleanup through Drive delete (
type=bitable). SetLARK_CLI_E2E_BASEAPP_WORKSPACE_TOKENto enable it. - TestBaseFieldCreateDryRunArrayCompat: proves
+field-createdry-run request shape for the internal JSON-array compatibility path. - TestBaseFormQuestionsCreateDryRun: proves
+form-questions-createpreserves its POST body and renders the existing-question guard in command help. - TestBaseFormDetailDryRun / TestBaseFormSubmitDryRun: prove shared-form detail and submission request shapes.
- TestBaseDashboardBlockGetDataDryRun: proves dashboard block data request shapes and identifier handling.
- TestBaseRecordBatchUpdatePerRecordDryRun: proves
+record-batch-updatepreserves the per-recordupdate_recordsrequest shape. - TestBaseRecordBatchUpdatePerRecordWorkflow: creates two records, updates different field types in one request, asserts the minimal response contract, reads both records back, verifies a missing record ID is not prevalidated, and cleans up the temporary Base.
- TestBase_RoleWorkflow: proves
+advperm-enable,+role-create,+role-list,+role-get, and+role-update; keyt.Run(...)proof points arelist as bot,get as bot, andupdate as bot. - TestBaseFormListDryRun_UsesBaseAndTableIdentifiers: proves
+form-listdry-run request shape uses Base and table identifiers in the endpoint. - TestBaseFormQuestionsCreateVisibleRuleDryRun / TestBaseFormQuestionsUpdateVisibleRuleDryRun: prove
+form-questions-create/+form-questions-updatedry-run request shape and that the optionalvisible_ruledisplay condition is transcribed verbatim into the request body. - TestBaseTableCopyDryRun: proves
+table-copyand+table-copy-statusrequest shapes, including the schema-safe default, table-name path escaping, explicit all+wait orchestration, Cobra duration parsing, and the opaque task ID body. - TestBaseTableCopyWorkflow: feature-gated by
LARK_CLI_E2E_BASE_TABLE_COPY_READY=1until the OpenAPI is deployed; creates a source table and record, proves schema-only copy, all no-wait plus status, all wait, record inclusion, and cleanup. - Cleanup note:
+table-deleteand+role-deleteonly run in cleanup and are intentionally left uncovered. - Blocked area: table-copy live integration remains deployment-gated; dashboard, field, most record operations, most form operations, view, and workflow operations still lack deterministic create/read/update workflows in this suite.
Command Table
| Status | Cmd | Type | Testcase | Key parameter shapes | Notes / uncovered reason |
|---|---|---|---|---|---|
| ✕ | base +advperm-disable | shortcut | none | no disable workflow yet | |
| ✓ | base +advperm-enable | shortcut | base_role_workflow_test.go::TestBase_RoleWorkflow | --base-token |
|
| ✕ | base +base-copy | shortcut | none | no copy workflow yet | |
| ✓ | base +base-create | shortcut | base/helpers_test.go::createBaseWithRetry | --name; --time-zone |
helper asserts created base token |
| ✓ | base +base-get | shortcut | base_basic_workflow_test.go::TestBase_BasicWorkflow/get base as bot | --base-token |
|
| ✓ | base +base-block-create | shortcut | base_block_dryrun_test.go::TestBaseBlockDryRun/create | --base-token; --type; --name; --parent-id; dry-run only |
request shape only |
| ✓ | base +base-block-delete | shortcut | base_block_dryrun_test.go::TestBaseBlockDryRun/delete | --base-token; --block-id; dry-run only |
request shape only |
| ✓ | base +base-block-list | shortcut | base_block_dryrun_test.go::TestBaseBlockDryRun/list all,list folder | --base-token; optional --parent-id; optional --type; dry-run only |
request shape only |
| ✓ | base +base-block-move | shortcut | base_block_dryrun_test.go::TestBaseBlockDryRun/move root,move after | --base-token; --block-id; optional --parent-id; --after-id; dry-run only |
request shape only |
| ✓ | base +base-block-rename | shortcut | base_block_dryrun_test.go::TestBaseBlockDryRun/rename | --base-token; --block-id; --name; dry-run only |
request shape only |
| ✕ | base +dashboard-arrange | shortcut | none | dashboard workflows not covered | |
| ✕ | base +dashboard-block-create | shortcut | none | dashboard workflows not covered | |
| ✕ | base +dashboard-block-delete | shortcut | none | dashboard workflows not covered | |
| ✕ | base +dashboard-block-get | shortcut | none | dashboard workflows not covered | |
| ✓ | base +dashboard-block-get-data | shortcut | base_dashboard_block_get_data_dryrun_test.go | --base-token; --dashboard-id; --block-id; dry-run only |
request shape and identifier handling |
| ✕ | base +dashboard-block-list | shortcut | none | dashboard workflows not covered | |
| ✕ | base +dashboard-block-update | shortcut | none | dashboard workflows not covered | |
| ✕ | base +dashboard-create | shortcut | none | dashboard workflows not covered | |
| ✕ | base +dashboard-delete | shortcut | none | dashboard workflows not covered | |
| ✕ | base +dashboard-get | shortcut | none | dashboard workflows not covered | |
| ✕ | base +dashboard-list | shortcut | none | dashboard workflows not covered | |
| ✕ | base +dashboard-update | shortcut | none | dashboard workflows not covered | |
| ✕ | base +data-query | shortcut | none | no data-query assertions yet | |
| ✓ | base +field-create | shortcut | base_field_dryrun_test.go::TestBaseFieldCreateDryRunArrayCompat | --base-token; --table-id; --json; dry-run only |
request shape only |
| ✕ | base +field-delete | shortcut | none | field workflows not covered | |
| ✕ | base +field-get | shortcut | none | field workflows not covered | |
| ✕ | base +field-list | shortcut | none | field workflows not covered | |
| ✕ | base +field-search-options | shortcut | none | field workflows not covered | |
| ✕ | base +field-update | shortcut | none | field workflows not covered | |
| ✕ | base +form-create | shortcut | none | form workflows not covered | |
| ✕ | base +form-delete | shortcut | none | form workflows not covered | |
| ✓ | base +form-detail | shortcut | base_form_detail_dryrun_test.go::TestBaseFormDetailDryRun | --share-token; dry-run only |
shared-form request shape |
| ✕ | base +form-get | shortcut | none | form workflows not covered | |
| ✓ | base +form-list | shortcut | base_form_detail_dryrun_test.go::TestBaseFormListDryRun_UsesBaseAndTableIdentifiers | --base-token; --table-id; dry-run only |
request shape only |
| ✓ | base +form-questions-create | shortcut | TestBaseFormQuestionsCreateVisibleRuleDryRun; base_form_questions_create_dryrun_test.go | questions[].visible_rule; dry-run | request body, visible_rule passthrough, and help guard covered |
| ✕ | base +form-questions-delete | shortcut | none | form workflows not covered | |
| ✕ | base +form-questions-list | shortcut | none | form workflows not covered | |
| ✓ | base +form-questions-update | shortcut | TestBaseFormQuestionsUpdateVisibleRuleDryRun | questions[].visible_rule | dry-run: request shape + visible_rule body passthrough |
| ✓ | base +form-submit | shortcut | base_form_submit_dryrun_test.go::TestBaseFormSubmitDryRun | --share-token; --json; dry-run only |
submission request shape |
| ✕ | base +form-update | shortcut | none | form workflows not covered | |
| ✓ | base +record-batch-create | shortcut | base_record_batch_update_workflow_test.go::TestBaseRecordBatchUpdatePerRecordWorkflow | --base-token; --table-id; --json.create_records |
seeds heterogeneous live workflow records |
| ✓ | base +record-batch-update | shortcut | base_record_batch_update_dryrun_test.go::TestBaseRecordBatchUpdatePerRecordDryRun; base_record_batch_update_workflow_test.go::TestBaseRecordBatchUpdatePerRecordWorkflow | --base-token; --table-id; --json.update_records; dry-run + live |
heterogeneous select/number update with write-back verification |
| ✕ | base +record-delete | shortcut | none | record workflows not covered | |
| ✓ | base +record-get | shortcut | base_record_batch_update_workflow_test.go::TestBaseRecordBatchUpdatePerRecordWorkflow | --record-id; repeated --field-id; --format json |
reads back select and number values after batch update |
| ✕ | base +record-history-list | shortcut | none | record workflows not covered | |
| ✕ | base +record-list | shortcut | none | record workflows not covered | |
| ✕ | base +record-search | shortcut | none | record workflows not covered | |
| ✕ | base +record-share-link-create | shortcut | none | record workflows not covered | |
| ✓ | base +record-upload-attachment | shortcut | base_attachment_dryrun_test.go::TestBase_AttachmentDryRun/upload | dry-run only | request shape only |
| ✓ | base +record-download-attachment | shortcut | base_attachment_dryrun_test.go::TestBase_AttachmentDryRun/download | dry-run only | request shape only |
| ✓ | base +record-remove-attachment | shortcut | base_attachment_dryrun_test.go::TestBase_AttachmentDryRun/remove | dry-run only | request shape only |
| ✕ | base +record-upsert | shortcut | none | record workflows not covered | |
| ✓ | base +role-create | shortcut | base/helpers_test.go::createRole | --base-token; --json |
helper asserts created role id |
| ✕ | base +role-delete | shortcut | none | cleanup only | |
| ✓ | base +role-get | shortcut | base_role_workflow_test.go::TestBase_RoleWorkflow/get as bot | --base-token; --role-id |
|
| ✓ | base +role-list | shortcut | base_role_workflow_test.go::TestBase_RoleWorkflow/list as bot | --base-token |
|
| ✓ | base +role-update | shortcut | base_role_workflow_test.go::TestBase_RoleWorkflow/update as bot | --base-token; --role-id; --json |
|
| ✓ | base +table-create | shortcut | base/helpers_test.go::createTableWithRetry | --base-token; --name; --fields; optional --view |
helper asserts table id |
| ✓ | base +table-copy | shortcut | base_table_copy_dryrun_test.go::TestBaseTableCopyDryRun; base_table_copy_workflow_test.go::TestBaseTableCopyWorkflow | --table-id ID/name; default --range schema; explicit --range all --wait --timeout |
dry-run covered; live workflow is deployment-gated and not yet verified |
| ✓ | base +table-copy-status | shortcut | base_table_copy_dryrun_test.go::TestBaseTableCopyDryRun/status; base_table_copy_workflow_test.go::TestBaseTableCopyWorkflow/all no-wait and status | opaque --task-id |
dry-run covered; live polling is deployment-gated and not yet verified |
| ✕ | base +table-delete | shortcut | none | cleanup only | |
| ✓ | base +table-get | shortcut | base_basic_workflow_test.go::TestBase_BasicWorkflow/get table as bot | --base-token; --table-id |
|
| ✓ | base +table-list | shortcut | base_basic_workflow_test.go::TestBase_BasicWorkflow/list tables and find created table as bot | --base-token |
|
| ✕ | base +table-update | shortcut | none | no rename workflow yet | |
| ✕ | base +title-resolve | shortcut | none | resolver workflow not covered | |
| ✕ | base +url-resolve | shortcut | none | resolver workflow not covered | |
| ✕ | base +view-create | shortcut | none | view workflows not covered | |
| ✕ | base +view-delete | shortcut | none | view workflows not covered | |
| ✕ | base +view-get | shortcut | none | view workflows not covered | |
| ✕ | base +view-get-card | shortcut | none | view workflows not covered | |
| ✕ | base +view-get-filter | shortcut | none | view workflows not covered | |
| ✕ | base +view-get-group | shortcut | none | view workflows not covered | |
| ✕ | base +view-get-sort | shortcut | none | view workflows not covered | |
| ✕ | base +view-get-timebar | shortcut | none | view workflows not covered | |
| ✕ | base +view-get-visible-fields | shortcut | none | view workflows not covered | |
| ✕ | base +view-list | shortcut | none | view workflows not covered | |
| ✕ | base +view-rename | shortcut | none | view workflows not covered | |
| ✕ | base +view-set-card | shortcut | none | view workflows not covered | |
| ✕ | base +view-set-filter | shortcut | none | view workflows not covered | |
| ✕ | base +view-set-group | shortcut | none | view workflows not covered | |
| ✕ | base +view-set-sort | shortcut | none | view workflows not covered | |
| ✕ | base +view-set-timebar | shortcut | none | view workflows not covered | |
| ✕ | base +view-set-visible-fields | shortcut | none | view workflows not covered | |
| ✕ | base +workflow-create | shortcut | none | workflow CRUD not covered | |
| ✕ | base +workflow-disable | shortcut | none | workflow CRUD not covered | |
| ✕ | base +workflow-enable | shortcut | none | workflow CRUD not covered | |
| ✕ | base +workflow-get | shortcut | none | workflow CRUD not covered | |
| ✕ | base +workflow-list | shortcut | none | workflow CRUD not covered | |
| ✕ | base +workflow-update | shortcut | none | workflow CRUD not covered |