Skip to content

e2e: harden CLI E2E retry, cleanup, and domain selection#1709

Merged
liangshuo-1 merged 2 commits into
larksuite:mainfrom
yxzhaao:e2e-retryable-default
Jul 7, 2026
Merged

e2e: harden CLI E2E retry, cleanup, and domain selection#1709
liangshuo-1 merged 2 commits into
larksuite:mainfrom
yxzhaao:e2e-retryable-default

Conversation

@yxzhaao

@yxzhaao yxzhaao commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Summary

  • make CLI E2E RunCmd retry structured service failures when error.retryable=true, while keeping explicit RunCmdWithRetry for custom predicates or retry budgets
  • harden Drive and Wiki teardown verification with shared wait helpers, 30s/3s delete-visibility polling, cleanup warnings for accepted Drive deletes, and transient Wiki verify retries
  • scope dry-run/live CLI E2E jobs by changed business domains using shared scripts/domain-map.json; pr-labels reads the same map for label domains
  • keep dry-run harness coverage by running the root tests/cli_e2e package unfiltered, then domain packages with DryRun|Regression
  • pass dynamic E2E domain outputs through job env before shell use, fail open to full E2E when mapped domains drift, and skip make build when E2E mode is skip
  • decouple the strict-mode user-vs-bot unit test from drifting live API metadata by using a fixed test service catalog

Validation

  • make script-test
  • node --test scripts/e2e_domains.test.js
  • bash scripts/ci-workflow.test.sh
  • GITHUB_TOKEN=$(gh auth token) node scripts/pr-labels/test.js
  • go test ./tests/cli_e2e ./tests/cli_e2e/drive ./tests/cli_e2e/wiki -run 'TestRunCmd|TestRunCmdWithRetry|TestWaitForCondition|TestDeleteDriveResourceAndVerify|TestWikiVerifyTransientResult' -count=1\n- go test ./cmd -run 'TestIntegration_StrictModeUser_ProfileOverride_ServiceBotOnlyMethodReturnsEnvelope' -count=1 -v\n- go test ./cmd -run 'TestIntegration_StrictMode' -count=1\n- go test ./cmd/... -count=1

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR adds shared CLI E2E domain resolution for CI and PR labels, updates CLI E2E execution to retry structured errors and classify cleanup warnings, and adjusts docs fetch coverage and tests to use the v1 compatibility flag.

Changes

CLI E2E domain routing

Layer / File(s) Summary
Domain map data and helpers
scripts/domain-map.json, scripts/domain-map.js
The shared domain map JSON and utility module define path mappings, fallback and skip rules, and exported path-to-domain helpers.
E2E domain resolution script and tests
scripts/e2e_domains.js, scripts/e2e_domains.test.js
The new E2E domain resolver computes mode, reason, domains, and package lists from changed files, emits those values for GitHub Actions, and is covered by path-mapping tests.
CI workflow and workflow checks
.github/workflows/ci.yml, Makefile, scripts/ci-workflow.test.sh, scripts/pr-labels/index.js
The CI workflow resolves E2E domains before dry-run and live runs, branches execution on the resolved mode, and the workflow test script and Node test target are updated to assert the new control flow. The PR labeling script now derives business domains from the shared mapping.

CLI retry and cleanup warnings

Layer / File(s) Summary
Retry defaults and error parsing
tests/cli_e2e/core.go
Core CLI helpers add shared retry defaults, route RunCmd through retry handling, detect retryable JSON errors, treat cleanup warnings as non-fatal, and refactor cleanup suppression parsing through shared JSON extraction.
Retry behavior tests
tests/cli_e2e/core_test.go
The core E2E tests add fast retry settings, fake CLI retryable and non-retryable commands, retry assertions for RunCmd, and a RunCmdWithRetry case with explicit retry options.
Drive delete cleanup warning
tests/cli_e2e/drive/helpers.go, tests/cli_e2e/drive/helpers_test.go
The Drive helper switches delete execution to RunCmd, polls visibility with a shared timeout configuration, and returns a cleanup warning when the resource still appears after an accepted delete. The Drive helper tests add a fake CLI script and subtests that cover cleanup-warning and fatal delete paths while temporarily overriding the visibility polling timeout.
Wiki transient verification handling
tests/cli_e2e/wiki/helpers_test.go
The wiki delete polling loop records transient verification errors, wraps them with a dedicated error type, and classifies transient invalid_response results from HTTP 429 and 500-series failures.

Docs fetch compatibility

Layer / File(s) Summary
Docs fetch dry-run behavior
tests/cli_e2e/docs/coverage.md, tests/cli_e2e/docs/docs_fetch_dryrun_test.go
The docs fetch E2E test package name and CLI argument are updated, and the coverage note records the v1 compatibility flag behavior.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • larksuite/cli#148: Both PRs modify the PR labeling system; this PR replaces local business-domain lookup with the shared domain map.
  • larksuite/cli#236: Both PRs touch the tests/cli_e2e harness, including command execution and result handling.
  • larksuite/cli#528: Both PRs change CLI E2E cleanup handling and CleanupTimeout-related behavior in the same framework area.

Suggested labels: feature, domain/ccm

Suggested reviewers: liangshuo-1, fangshuyu-768, caojie0621

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.44% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: hardening CLI E2E retry, cleanup, and domain-selection logic.
Description check ✅ Passed The description covers the main summary and validation, but it omits the template's explicit Changes and Related Issues sections.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@CLAassistant

CLAassistant commented Jul 1, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@github-actions github-actions Bot added the size/S Low-risk docs, CI, test, or chore only changes label Jul 1, 2026
@yxzhaao
yxzhaao marked this pull request as ready for review July 1, 2026 13:51

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
tests/cli_e2e/core_test.go (1)

383-394: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

useFastDefaultRetry mutates package-level globals — not parallel-safe.

Overwriting defaultRetryInitialDelay / defaultRetryMaxDelay and restoring via t.Cleanup works only because these tests run serially. If any test in this package is later marked t.Parallel(), this becomes a data race under -race. Consider documenting the serial-only assumption here (or gating retry timing through injected RetryOptions) to prevent a future footgun.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/cli_e2e/core_test.go` around lines 383 - 394, The helper
useFastDefaultRetry mutates package-level retry globals, so it is not safe if
tests in this package ever run in parallel. Update the helper to avoid
shared-state overrides where possible, ideally by threading retry timing through
injected RetryOptions or similar test-scoped configuration; if that refactor is
too large, add an explicit comment near useFastDefaultRetry noting the
serial-only assumption so future t.Parallel() usage does not introduce a race.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/cli_e2e/core_test.go`:
- Around line 383-394: The helper useFastDefaultRetry mutates package-level
retry globals, so it is not safe if tests in this package ever run in parallel.
Update the helper to avoid shared-state overrides where possible, ideally by
threading retry timing through injected RetryOptions or similar test-scoped
configuration; if that refactor is too large, add an explicit comment near
useFastDefaultRetry noting the serial-only assumption so future t.Parallel()
usage does not introduce a race.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fca14ddb-be9b-4e39-b7ab-93d8c8e0f309

📥 Commits

Reviewing files that changed from the base of the PR and between a6797ac and 7658240.

📒 Files selected for processing (2)
  • tests/cli_e2e/core.go
  • tests/cli_e2e/core_test.go

@yxzhaao
yxzhaao force-pushed the e2e-retryable-default branch from d732802 to 7658240 Compare July 6, 2026 08:28
@yxzhaao
yxzhaao force-pushed the e2e-retryable-default branch from 7658240 to 44d58ae Compare July 6, 2026 09:20
@yxzhaao yxzhaao changed the title Retry E2E retryable service errors by default Harden CLI E2E retry, cleanup, and domain selection Jul 6, 2026
@github-actions github-actions Bot added size/L Large or sensitive change across domains or core paths and removed size/S Low-risk docs, CI, test, or chore only changes labels Jul 6, 2026
@yxzhaao
yxzhaao force-pushed the e2e-retryable-default branch 3 times, most recently from e98e947 to 2f3407b Compare July 6, 2026 09:28

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
scripts/e2e_domains.js (1)

37-44: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Repeated go list subprocess spawns without memoization.

domainExists shells out to go list on every call, and classifyPath/addDomain can call it multiple times for the same domain across several changed files in the same PR. Caching results in a Map would avoid redundant subprocess spawns.

⚡ Memoize domainExists
+const domainExistsCache = new Map();
+
 function domainExists(domain) {
+  if (domainExistsCache.has(domain)) return domainExistsCache.get(domain);
+  let exists;
   try {
     execFileSync("go", ["list", `./tests/cli_e2e/${domain}`], { stdio: "ignore" });
-    return true;
+    exists = true;
   } catch {
-    return false;
+    exists = false;
   }
+  domainExistsCache.set(domain, exists);
+  return exists;
 }

Also applies to: 68-115

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/e2e_domains.js` around lines 37 - 44, The domain existence check is
spawning repeated go list subprocesses for the same domain; memoize the result
in domainExists so classifyPath and addDomain can reuse it across multiple
files. Add a Map-based cache keyed by domain inside the e2e_domains.js flow, and
have domainExists consult the cache before calling execFileSync, then store both
success and failure results for later calls.
scripts/domain-map.js (1)

14-17: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Prefix matching is order-dependent on domain-map.json.

findPathMapping returns the first prefix match via .find(), so correctness silently depends on domain-map.json listing more specific prefixes before more general ones (e.g. shortcuts/doc/ before shortcuts/). Since that JSON file isn't in this diff, I can't confirm the ordering is safe, and any future entry added out of order will silently mis-route domains.

♻️ Make matching order-independent
 function findPathMapping(filePath) {
   const normalized = normalizeRepoPath(filePath);
-  return (domainMap.pathMappings || []).find((entry) => normalized.startsWith(entry.prefix));
+  return (domainMap.pathMappings || [])
+    .slice()
+    .sort((a, b) => b.prefix.length - a.prefix.length)
+    .find((entry) => normalized.startsWith(entry.prefix));
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/domain-map.js` around lines 14 - 17, The prefix lookup in
findPathMapping is order-dependent because it returns the first match from
domainMap.pathMappings, so make the selection order-independent by choosing the
most specific matching entry instead of relying on JSON ordering. Update
findPathMapping to evaluate all matching prefixes and pick the best match based
on prefix length or specificity, using normalizeRepoPath and the existing
entry.prefix values, so future additions to domainMap.pathMappings cannot
silently mis-route domains.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@scripts/domain-map.js`:
- Around line 14-17: The prefix lookup in findPathMapping is order-dependent
because it returns the first match from domainMap.pathMappings, so make the
selection order-independent by choosing the most specific matching entry instead
of relying on JSON ordering. Update findPathMapping to evaluate all matching
prefixes and pick the best match based on prefix length or specificity, using
normalizeRepoPath and the existing entry.prefix values, so future additions to
domainMap.pathMappings cannot silently mis-route domains.

In `@scripts/e2e_domains.js`:
- Around line 37-44: The domain existence check is spawning repeated go list
subprocesses for the same domain; memoize the result in domainExists so
classifyPath and addDomain can reuse it across multiple files. Add a Map-based
cache keyed by domain inside the e2e_domains.js flow, and have domainExists
consult the cache before calling execFileSync, then store both success and
failure results for later calls.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5d120e07-e1ef-41e4-9fdf-c278af74d49a

📥 Commits

Reviewing files that changed from the base of the PR and between d732802 and 44d58ae.

📒 Files selected for processing (12)
  • .github/workflows/ci.yml
  • Makefile
  • scripts/ci-workflow.test.sh
  • scripts/domain-map.js
  • scripts/domain-map.json
  • scripts/e2e_domains.js
  • scripts/e2e_domains.test.js
  • scripts/pr-labels/index.js
  • tests/cli_e2e/core.go
  • tests/cli_e2e/core_test.go
  • tests/cli_e2e/drive/helpers.go
  • tests/cli_e2e/drive/helpers_test.go
💤 Files with no reviewable changes (4)
  • tests/cli_e2e/drive/helpers_test.go
  • tests/cli_e2e/drive/helpers.go
  • tests/cli_e2e/core_test.go
  • tests/cli_e2e/core.go
✅ Files skipped from review due to trivial changes (1)
  • scripts/domain-map.json

@yxzhaao
yxzhaao force-pushed the e2e-retryable-default branch 2 times, most recently from f420058 to 3045b22 Compare July 6, 2026 09:37

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
scripts/e2e_domains.js (2)

37-44: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Cache domainExists results to avoid redundant subprocess spawns.

domainExists runs a synchronous go list subprocess per call with no memoization; for PRs touching many files across the same domain(s), this results in repeated identical subprocess invocations.

⚡ Proposed fix
+const domainExistsCache = new Map();
+
 function domainExists(domain) {
+  if (domainExistsCache.has(domain)) return domainExistsCache.get(domain);
+  let exists;
   try {
     execFileSync("go", ["list", `./tests/cli_e2e/${domain}`], { stdio: "ignore" });
-    return true;
+    exists = true;
   } catch {
-    return false;
+    exists = false;
   }
+  domainExistsCache.set(domain, exists);
+  return exists;
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/e2e_domains.js` around lines 37 - 44, The domainExists helper
currently spawns the same synchronous go list subprocess repeatedly with no
reuse. Add memoization inside domainExists in scripts/e2e_domains.js so repeated
checks for the same domain return a cached result instead of re-running
execFileSync, keeping the try/catch behavior but avoiding duplicate subprocess
calls.

165-180: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

GITHUB_OUTPUT entries aren't newline-safe.

reason/path-derived values are written as single-line key=value entries; a changed-file path containing an embedded newline would corrupt the GITHUB_OUTPUT file and could misparse subsequent keys. Since this data ultimately originates from PR-controlled filenames (same root cause as the injection risk in ci.yml), consider using the key<<EOF heredoc delimiter form for multi-line-safe output.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/e2e_domains.js` around lines 165 - 180, The emit() helper writes
GITHUB_OUTPUT entries as single-line key=value pairs, which is unsafe for
reason/path-derived data that may contain embedded newlines. Update emit() to
write multi-line-safe GitHub Actions outputs using the key<<EOF heredoc form
when appending to process.env.GITHUB_OUTPUT, while keeping the console output
unchanged. Use the existing emit() function and the resolved values map to
locate the output-writing logic.
.github/workflows/ci.yml (1)

277-278: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Consider gating the build step on mode != 'skip' too.

Domain resolution now runs before make build, but the build still executes unconditionally even when mode resolves to skip — wasting CI time on docs-only PRs that this feature is meant to optimize for.

Also applies to: 323-326

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 277 - 278, The CI workflow still runs
the Build lark-cli step unconditionally even when the resolved mode is skip, so
update the affected build steps in the workflow to respect the same mode check
used by the domain resolution logic. Add the mode != 'skip' gate around the
Build lark-cli job step (and the other referenced build block) so make build
only runs when the workflow is not skipping, using the existing mode variable
and nearby conditional patterns in the workflow.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ci.yml:
- Around line 337-350: The live CLI E2E workflow step is still interpolating
`${{ steps.e2e_domains.outputs.* }}` directly inside the shell script, which
creates the same injection risk as the dry-run job while real credentials are
available. Update the `Live CLI E2E` run block to follow the same env-var
mitigation pattern used elsewhere: pass `mode`, `reason`, and `live_packages`
from `steps.e2e_domains.outputs` into `env:` and reference only those shell
variables in the script, keeping `gotestsum` and the surrounding `if`/`echo`
logic intact.
- Around line 285-297: The CI step is interpolating untrusted e2e domain outputs
directly inside the shell script, which creates a script-injection risk. Update
the workflow job that runs the dry-run CLI E2E command to pass
steps.e2e_domains.outputs.mode, reason, and dry_packages through env instead of
embedding them in run:, then reference those values as shell variables in the
script. Keep the existing logic in the same run block, but ensure all references
to those outputs are read from the environment rather than from direct GitHub
expression expansion.

---

Nitpick comments:
In @.github/workflows/ci.yml:
- Around line 277-278: The CI workflow still runs the Build lark-cli step
unconditionally even when the resolved mode is skip, so update the affected
build steps in the workflow to respect the same mode check used by the domain
resolution logic. Add the mode != 'skip' gate around the Build lark-cli job step
(and the other referenced build block) so make build only runs when the workflow
is not skipping, using the existing mode variable and nearby conditional
patterns in the workflow.

In `@scripts/e2e_domains.js`:
- Around line 37-44: The domainExists helper currently spawns the same
synchronous go list subprocess repeatedly with no reuse. Add memoization inside
domainExists in scripts/e2e_domains.js so repeated checks for the same domain
return a cached result instead of re-running execFileSync, keeping the try/catch
behavior but avoiding duplicate subprocess calls.
- Around line 165-180: The emit() helper writes GITHUB_OUTPUT entries as
single-line key=value pairs, which is unsafe for reason/path-derived data that
may contain embedded newlines. Update emit() to write multi-line-safe GitHub
Actions outputs using the key<<EOF heredoc form when appending to
process.env.GITHUB_OUTPUT, while keeping the console output unchanged. Use the
existing emit() function and the resolved values map to locate the
output-writing logic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 19a0860f-d9a0-424a-8b76-efbcdf045e16

📥 Commits

Reviewing files that changed from the base of the PR and between 44d58ae and 2f3407b.

📒 Files selected for processing (14)
  • .github/workflows/ci.yml
  • Makefile
  • scripts/ci-workflow.test.sh
  • scripts/domain-map.js
  • scripts/domain-map.json
  • scripts/e2e_domains.js
  • scripts/e2e_domains.test.js
  • scripts/pr-labels/index.js
  • tests/cli_e2e/core.go
  • tests/cli_e2e/core_test.go
  • tests/cli_e2e/docs/coverage.md
  • tests/cli_e2e/docs/docs_fetch_dryrun_test.go
  • tests/cli_e2e/drive/helpers.go
  • tests/cli_e2e/drive/helpers_test.go
✅ Files skipped from review due to trivial changes (1)
  • tests/cli_e2e/docs/coverage.md
🚧 Files skipped from review as they are similar to previous changes (7)
  • Makefile
  • scripts/pr-labels/index.js
  • scripts/domain-map.json
  • tests/cli_e2e/drive/helpers_test.go
  • scripts/ci-workflow.test.sh
  • tests/cli_e2e/drive/helpers.go
  • tests/cli_e2e/core_test.go

Comment thread .github/workflows/ci.yml Outdated
Comment thread .github/workflows/ci.yml Outdated
@yxzhaao
yxzhaao force-pushed the e2e-retryable-default branch from 3045b22 to 8f71254 Compare July 6, 2026 09:46

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/cli_e2e/wiki/helpers_test.go (1)

341-362: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Stale lastTransientErr can misreport a genuine "still exists" failure as transient.

lastTransientErr is set whenever a transient error occurs but is never cleared on a subsequent successful (non-error) poll. If a transient blip happens early and later polls succeed but simply confirm the node is still present, the eventual timeout message ("kept hitting transient errors") misattributes the failure, obscuring the real cause during CI debugging.

🐛 Proposed fix: reset lastTransientErr on successful checks
 	for {
 		deleted, err := isWikiNodeDeleted(ctx, nodeToken)
 		if err != nil {
 			if isWikiVerifyTransientError(err) {
 				lastTransientErr = err
 			} else {
 				return err
 			}
+		} else {
+			lastTransientErr = nil
 		}
 		if deleted {
 			return nil
 		}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/cli_e2e/wiki/helpers_test.go` around lines 341 - 362, The wiki delete
verification loop in isWikiNodeDeleted can misreport a timeout as transient
because lastTransientErr is never cleared after a successful poll. Update the
polling logic so that any non-error check that confirms the node is still
present resets lastTransientErr before continuing, while keeping genuine
transient failures recorded only until the next successful check. This change
should be made in the helper around isWikiNodeDeleted and the deadline timeout
handling that emits the “kept hitting transient errors” message.
🧹 Nitpick comments (1)
scripts/domain-map.js (1)

18-44: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Prefix matching lacks path-segment boundaries.

findPathMapping, matchesFullFallback, and isSkippablePath all use bare startsWith/endsWith on normalized paths. If any two prefixes in domain-map.json share a common string prefix at a non-segment boundary (e.g. shortcuts/im vs shortcuts/image), a file under the longer directory could be misrouted to the wrong domain. Since prefixes are sorted by string length (not segment count) for specificity, this is a real edge case rather than purely theoretical.

Consider requiring the matched prefix to be followed by / or be an exact match:

🛡️ Proposed fix
 function findPathMapping(filePath) {
   const normalized = normalizeRepoPath(filePath);
-  return pathMappingsBySpecificity.find((entry) => normalized.startsWith(entry.prefix));
+  return pathMappingsBySpecificity.find(
+    (entry) => normalized === entry.prefix || normalized.startsWith(`${entry.prefix}/`)
+  );
 }

Since I don't have visibility into scripts/domain-map.json, please confirm whether any prefixes actually overlap this way.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/domain-map.js` around lines 18 - 44, The path checks in
findPathMapping, matchesFullFallback, and isSkippablePath rely on raw
startsWith/endsWith against normalized paths, which can misclassify paths when
one prefix is only a string prefix of another at a non-segment boundary. Update
the matching logic to require either an exact match or a path-segment boundary
(for example, a trailing slash after the prefix) while keeping the existing
specificity behavior in pathMappingsBySpecificity and the skip/full-fallback
helpers. Also verify whether any entries in domainMap or domain-map.json overlap
this way so the boundary-aware match covers the real cases.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@tests/cli_e2e/wiki/helpers_test.go`:
- Around line 341-362: The wiki delete verification loop in isWikiNodeDeleted
can misreport a timeout as transient because lastTransientErr is never cleared
after a successful poll. Update the polling logic so that any non-error check
that confirms the node is still present resets lastTransientErr before
continuing, while keeping genuine transient failures recorded only until the
next successful check. This change should be made in the helper around
isWikiNodeDeleted and the deadline timeout handling that emits the “kept hitting
transient errors” message.

---

Nitpick comments:
In `@scripts/domain-map.js`:
- Around line 18-44: The path checks in findPathMapping, matchesFullFallback,
and isSkippablePath rely on raw startsWith/endsWith against normalized paths,
which can misclassify paths when one prefix is only a string prefix of another
at a non-segment boundary. Update the matching logic to require either an exact
match or a path-segment boundary (for example, a trailing slash after the
prefix) while keeping the existing specificity behavior in
pathMappingsBySpecificity and the skip/full-fallback helpers. Also verify
whether any entries in domainMap or domain-map.json overlap this way so the
boundary-aware match covers the real cases.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 73269703-d7ba-4822-9aaa-1f859711a91c

📥 Commits

Reviewing files that changed from the base of the PR and between 2f3407b and 3045b22.

📒 Files selected for processing (15)
  • .github/workflows/ci.yml
  • Makefile
  • scripts/ci-workflow.test.sh
  • scripts/domain-map.js
  • scripts/domain-map.json
  • scripts/e2e_domains.js
  • scripts/e2e_domains.test.js
  • scripts/pr-labels/index.js
  • tests/cli_e2e/core.go
  • tests/cli_e2e/core_test.go
  • tests/cli_e2e/docs/coverage.md
  • tests/cli_e2e/docs/docs_fetch_dryrun_test.go
  • tests/cli_e2e/drive/helpers.go
  • tests/cli_e2e/drive/helpers_test.go
  • tests/cli_e2e/wiki/helpers_test.go
✅ Files skipped from review due to trivial changes (2)
  • tests/cli_e2e/docs/coverage.md
  • scripts/domain-map.json
🚧 Files skipped from review as they are similar to previous changes (6)
  • Makefile
  • scripts/ci-workflow.test.sh
  • tests/cli_e2e/docs/docs_fetch_dryrun_test.go
  • tests/cli_e2e/drive/helpers.go
  • scripts/pr-labels/index.js
  • tests/cli_e2e/core.go

@yxzhaao
yxzhaao force-pushed the e2e-retryable-default branch from 8f71254 to 8fb665a Compare July 7, 2026 09:05
@yxzhaao yxzhaao changed the title Harden CLI E2E retry, cleanup, and domain selection e2e: harden CLI E2E retry, cleanup, and domain selection Jul 7, 2026
@yxzhaao
yxzhaao force-pushed the e2e-retryable-default branch from 8fb665a to 6d1c360 Compare July 7, 2026 09:23
liangshuo-1
liangshuo-1 previously approved these changes Jul 7, 2026
@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

PR Quality Summary

CI did not complete successfully. Use the failed check links below to decide whether this PR needs a code change or a rerun.

Failed checks

  • deterministic-gate — failure — details
  • deadcode — failure — details
  • results — failure — details

deterministic-gate

  • public_content_change_id_trailercommit:410425156518:3 — public contribution contains a Change-Id trailer — Action: remove the value from the public contribution and replace it with a non-sensitive placeholder
  • public_content_change_id_trailercommit:6d1c36032440:3 — public contribution contains a Change-Id trailer — Action: remove the value from the public contribution and replace it with a non-sensitive placeholder

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

🚀 PR Preview Install Guide

🧰 CLI update

npm i -g https://pkg.pr.new/larksuite/cli/@larksuite/cli@5f2994ab5064d465d5d3f13591ccad46e0c89fae

🧩 Skill update

npx skills add yxzhaao/cli#e2e-retryable-default -y -g

@liangshuo-1
liangshuo-1 merged commit 6f95c5e into larksuite:main Jul 7, 2026
19 checks passed
This was referenced Jul 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/L Large or sensitive change across domains or core paths

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants