Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -153,14 +153,14 @@ jobs:
run: |
# Analyze current HEAD (strip line:col for stable diff across line shifts)
# Filter "go: downloading ..." lines to avoid false diffs from module cache state
go run golang.org/x/tools/cmd/deadcode@v0.31.0 ./... 2>&1 | \
go run golang.org/x/tools/cmd/deadcode@v0.31.0 -test ./... 2>&1 | \
grep -v '^go: ' | \
sed 's/:[0-9][0-9]*:[0-9][0-9]*:/:/' | sort > /tmp/dc-head.txt

# Analyze base branch via worktree
git worktree add -q /tmp/dc-base "origin/${{ github.base_ref }}"
(cd /tmp/dc-base && python3 scripts/fetch_meta.py && \
go run golang.org/x/tools/cmd/deadcode@v0.31.0 ./... 2>&1 | \
go run golang.org/x/tools/cmd/deadcode@v0.31.0 -test ./... 2>&1 | \
grep -v '^go: ' | \
sed 's/:[0-9][0-9]*:[0-9][0-9]*:/:/' | sort > /tmp/dc-base.txt) || {
echo "::warning::Failed to analyze base branch — skipping incremental dead code check"
Expand Down Expand Up @@ -209,6 +209,7 @@ jobs:
env:
TEST_BOT1_APP_ID: ${{ secrets.TEST_BOT1_APP_ID }}
TEST_BOT1_APP_SECRET: ${{ secrets.TEST_BOT1_APP_SECRET }}
TEST_USER_ACCESS_TOKEN: ${{ secrets.TEST_USER_ACCESS_TOKEN }}
steps:
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
Expand All @@ -229,6 +230,8 @@ jobs:
- name: Run CLI E2E tests
env:
LARK_CLI_BIN: ${{ github.workspace }}/lark-cli
LARKSUITE_CLI_APP_ID: ${{ env.TEST_BOT1_APP_ID }}
LARKSUITE_CLI_USER_ACCESS_TOKEN: ${{ env.TEST_USER_ACCESS_TOKEN }}
run: |
packages=$(go list ./tests/cli_e2e/... | grep -v '^github.com/larksuite/cli/tests/cli_e2e$' | grep -v '/demo$')
if [ -z "$packages" ]; then
Expand Down
6 changes: 3 additions & 3 deletions tests/cli_e2e/base/base_basic_workflow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func TestBase_BasicWorkflow(t *testing.T) {
baseName := "lark-cli-e2e-base-basic-" + clie2e.GenerateSuffix()
baseToken := createBaseWithRetry(t, ctx, baseName)

t.Run("get base", func(t *testing.T) {
t.Run("get base as bot", func(t *testing.T) {
result, err := clie2e.RunCmd(ctx, clie2e.Request{
Args: []string{"base", "+base-get", "--base-token", baseToken},
DefaultAs: "bot",
Expand All @@ -49,7 +49,7 @@ func TestBase_BasicWorkflow(t *testing.T) {
`{"name":"Main","type":"grid"}`,
)

t.Run("get table", func(t *testing.T) {
t.Run("get table as bot", func(t *testing.T) {
result, err := clie2e.RunCmd(ctx, clie2e.Request{
Args: []string{"base", "+table-get", "--base-token", baseToken, "--table-id", tableID},
DefaultAs: "bot",
Expand All @@ -61,7 +61,7 @@ func TestBase_BasicWorkflow(t *testing.T) {
assert.Equal(t, tableName, gjson.Get(result.Stdout, "data.table.name").String())
})

t.Run("list tables and find created table", func(t *testing.T) {
t.Run("list tables and find created table as bot", func(t *testing.T) {
result, err := clie2e.RunCmd(ctx, clie2e.Request{
Args: []string{"base", "+table-list", "--base-token", baseToken},
DefaultAs: "bot",
Expand Down
6 changes: 3 additions & 3 deletions tests/cli_e2e/base/base_role_workflow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func TestBase_RoleWorkflow(t *testing.T) {
}
})

t.Run("list", func(t *testing.T) {
t.Run("list as bot", func(t *testing.T) {
result, err := clie2e.RunCmd(ctx, clie2e.Request{
Args: []string{"base", "+role-list", "--base-token", baseToken},
DefaultAs: "bot",
Expand Down Expand Up @@ -81,7 +81,7 @@ func TestBase_RoleWorkflow(t *testing.T) {
require.NotEmpty(t, roleID, "stdout:\n%s", result.Stdout)
})

t.Run("get", func(t *testing.T) {
t.Run("get role as bot", func(t *testing.T) {
require.NotEmpty(t, roleID, "role ID should be resolved before get")

result, err := clie2e.RunCmd(ctx, clie2e.Request{
Expand All @@ -98,7 +98,7 @@ func TestBase_RoleWorkflow(t *testing.T) {
assert.Equal(t, roleID, gjson.Get(rolePayload, "role_id").String())
})

t.Run("update", func(t *testing.T) {
t.Run("update role as bot", func(t *testing.T) {
require.NotEmpty(t, roleID, "role ID should be resolved before update")

updatedRoleName := roleName + " Updated"
Expand Down
91 changes: 91 additions & 0 deletions tests/cli_e2e/base/coverage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Base CLI E2E Coverage

## Metrics
- Denominator: 73 leaf commands
- Covered: 10
- Coverage: 13.7%

## Summary
- TestBase_BasicWorkflow: proves `+base-create`, `+base-get`, `+table-create`, `+table-get`, and `+table-list`; key `t.Run(...)` proof points are `get base as bot`, `get table as bot`, and `list tables and find created table as bot`.
- TestBase_RoleWorkflow: proves `+advperm-enable`, `+role-create`, `+role-list`, `+role-get`, and `+role-update`; key `t.Run(...)` proof points are `list as bot`, `get as bot`, and `update as bot`.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
- Cleanup note: `+table-delete` and `+role-delete` only run in cleanup and are intentionally left uncovered.
- Blocked area: dashboard, field, form, record, 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 |
| --- | --- | --- | --- | --- | --- |
Comment thread
coderabbitai[bot] marked this conversation as resolved.
| ✕ | 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 +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-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 | | none | field workflows not covered |
| ✕ | 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-get | shortcut | | none | form workflows not covered |
| ✕ | base +form-list | shortcut | | none | form workflows not covered |
| ✕ | base +form-questions-create | shortcut | | none | form workflows not 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 | | none | form workflows not covered |
| ✕ | base +form-update | shortcut | | none | form workflows not covered |
| ✕ | base +record-batch-create | shortcut | | none | record workflows not covered |
| ✕ | base +record-batch-update | shortcut | | none | record workflows not covered |
| ✕ | base +record-delete | shortcut | | none | record workflows not covered |
| ✕ | base +record-get | shortcut | | none | record workflows not covered |
| ✕ | 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-upload-attachment | shortcut | | none | record workflows not covered |
| ✕ | 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`; optional `--fields`; optional `--view` | helper asserts table id |
| ✕ | 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 +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 |
6 changes: 3 additions & 3 deletions tests/cli_e2e/calendar/calendar_create_event_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func TestCalendar_CreateEvent(t *testing.T) {
var eventID string
calendarID := getPrimaryCalendarID(t, ctx)

t.Run("create event with shortcut", func(t *testing.T) {
t.Run("create event with shortcut as bot", func(t *testing.T) {
result, err := clie2e.RunCmd(ctx, clie2e.Request{
Args: []string{"calendar", "+create",
"--summary", eventSummary,
Expand All @@ -50,7 +50,7 @@ func TestCalendar_CreateEvent(t *testing.T) {
require.NotEmpty(t, eventID)
})

t.Run("verify event created", func(t *testing.T) {
t.Run("verify event created as bot", func(t *testing.T) {
require.NotEmpty(t, eventID)
result, err := clie2e.RunCmd(ctx, clie2e.Request{
Args: []string{"calendar", "events", "get"},
Expand All @@ -69,7 +69,7 @@ func TestCalendar_CreateEvent(t *testing.T) {
assert.Equal(t, unixSecondsRFC3339(endAt), gjson.Get(result.Stdout, "data.event.end_time.timestamp").String())
})

t.Run("delete event", func(t *testing.T) {
t.Run("delete event as bot", func(t *testing.T) {
require.NotEmpty(t, eventID)
result, err := clie2e.RunCmd(ctx, clie2e.Request{
Args: []string{"calendar", "events", "delete"},
Expand Down
16 changes: 8 additions & 8 deletions tests/cli_e2e/calendar/calendar_manage_calendar_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func TestCalendar_ManageCalendar(t *testing.T) {

var createdCalendarID string

t.Run("list calendars", func(t *testing.T) {
t.Run("list calendars as bot", func(t *testing.T) {
result, err := clie2e.RunCmd(ctx, clie2e.Request{
Args: []string{"calendar", "calendars", "list"},
DefaultAs: "bot",
Expand All @@ -37,12 +37,12 @@ func TestCalendar_ManageCalendar(t *testing.T) {
require.NotEmpty(t, gjson.Get(result.Stdout, "data.calendar_list").Array(), "stdout:\n%s", result.Stdout)
})

t.Run("get primary calendar", func(t *testing.T) {
t.Run("get primary calendar as bot", func(t *testing.T) {
primaryCalendarID := getPrimaryCalendarID(t, ctx)
require.NotEmpty(t, primaryCalendarID)
})

t.Run("create calendar", func(t *testing.T) {
t.Run("create calendar as bot", func(t *testing.T) {
result, err := clie2e.RunCmd(ctx, clie2e.Request{
Args: []string{"calendar", "calendars", "create"},
DefaultAs: "bot",
Expand All @@ -59,7 +59,7 @@ func TestCalendar_ManageCalendar(t *testing.T) {
require.NotEmpty(t, createdCalendarID)
})

t.Run("get created calendar", func(t *testing.T) {
t.Run("get created calendar as bot", func(t *testing.T) {
require.NotEmpty(t, createdCalendarID)
result, err := clie2e.RunCmd(ctx, clie2e.Request{
Args: []string{"calendar", "calendars", "get"},
Expand All @@ -76,7 +76,7 @@ func TestCalendar_ManageCalendar(t *testing.T) {
assert.Equal(t, calendarDescription, gjson.Get(result.Stdout, "data.description").String())
})

t.Run("find created calendar in list", func(t *testing.T) {
t.Run("find created calendar in list as bot", func(t *testing.T) {
require.NotEmpty(t, createdCalendarID)
result, err := clie2e.RunCmd(ctx, clie2e.Request{
Args: []string{"calendar", "calendars", "list"},
Expand All @@ -88,7 +88,7 @@ func TestCalendar_ManageCalendar(t *testing.T) {
require.True(t, gjson.Get(result.Stdout, `data.calendar_list.#(calendar_id=="`+createdCalendarID+`")`).Exists(), "stdout:\n%s", result.Stdout)
})

t.Run("update calendar", func(t *testing.T) {
t.Run("update calendar as bot", func(t *testing.T) {
require.NotEmpty(t, createdCalendarID)
result, err := clie2e.RunCmd(ctx, clie2e.Request{
Args: []string{"calendar", "calendars", "patch"},
Expand All @@ -105,7 +105,7 @@ func TestCalendar_ManageCalendar(t *testing.T) {
result.AssertStdoutStatus(t, 0)
})

t.Run("verify updated calendar", func(t *testing.T) {
t.Run("verify updated calendar as bot", func(t *testing.T) {
require.NotEmpty(t, createdCalendarID)
result, err := clie2e.RunCmd(ctx, clie2e.Request{
Args: []string{"calendar", "calendars", "get"},
Expand All @@ -120,7 +120,7 @@ func TestCalendar_ManageCalendar(t *testing.T) {
assert.Equal(t, updatedCalendarSummary, gjson.Get(result.Stdout, "data.summary").String())
})

t.Run("delete calendar", func(t *testing.T) {
t.Run("delete calendar as bot", func(t *testing.T) {
require.NotEmpty(t, createdCalendarID)
result, err := clie2e.RunCmd(ctx, clie2e.Request{
Args: []string{"calendar", "calendars", "delete"},
Expand Down
Loading
Loading