Skip to content

fix: normalize document write inputs#2003

Closed
fangshuyu-768 wants to merge 3 commits into
mainfrom
codex/fix-docs-write-preflight
Closed

fix: normalize document write inputs#2003
fangshuyu-768 wants to merge 3 commits into
mainfrom
codex/fix-docs-write-preflight

Conversation

@fangshuyu-768

@fangshuyu-768 fangshuyu-768 commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

Summary

Normalize or reject deterministic warning-producing Docs write inputs while preserving existing command semantics. The CLI keeps the established --title-wins contract, removes redundant XML title elements locally, and rejects inputs that cannot be executed unambiguously.

Changes

  • Remove top-level XML <title> elements when --title is supplied, then prepend the escaped flag value so existing --title-wins behavior remains compatible without duplicate-title warnings.
  • Reject multiline XML str_replace patterns; safe idempotent replacements remain allowed and are handled by the existing service contract.
  • Trim whitespace and reject empty or duplicate IDs in comma-separated block_delete requests.
  • Add normalization/validation unit tests and real-binary dry-run E2E coverage.

Test Plan

  • go test ./shortcuts/doc
  • Current-branch binary: LARK_CLI_BIN=... go test ./tests/cli_e2e/docs
  • make fmt-check
  • go vet ./...
  • go mod tidy produces no changes
  • golangci-lint ... --new-from-rev=origin/main reports 0 issues
  • Full make unit-test completes cleanly in this local environment; unrelated tests that create temporary Git repositories intermittently fail during t.TempDir cleanup with .git: directory not empty

Related Issues

Summary by CodeRabbit

  • Bug Fixes
    • Improved v2 document creation/update validation, including stronger XML-mode checks.
    • Ensured XML top-level <title> elements from --content are removed so the CLI --title takes precedence.
    • Rejected multiline str_replace patterns when --doc-format=xml.
    • Strengthened block_delete handling by rejecting missing/empty and duplicate --block-id values, and normalizing whitespace in batch IDs.
  • Documentation
    • Updated help text to clarify --title, --pattern, and --block-id behavior in XML vs Markdown modes.
  • Tests
    • Added unit and end-to-end coverage for XML title normalization and safer dry-run input validation.

@github-actions github-actions Bot added domain/ccm PR touches the ccm domain size/M Single-domain feat or fix with limited business impact labels Jul 22, 2026
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR normalizes XML titles during document creation by giving the CLI title precedence, strengthens v2 update validation for multiline XML patterns and invalid block IDs, and adds unit, contract, and CLI dry-run coverage.

Changes

Document v2 input handling

Layer / File(s) Summary
Create XML title normalization
shortcuts/doc/docs_create_v2.go, shortcuts/doc/docs_create_test.go, tests/cli_e2e/docs/docs_update_dryrun_test.go
XML create content removes top-level <title> elements before prepending the escaped CLI title; nested and malformed content remains covered by tests.
Update input validation
shortcuts/doc/docs_update_v2.go, shortcuts/doc/doc_errors_test.go
XML str_replace patterns reject line breaks, while block_delete rejects empty and duplicate IDs and normalizes whitespace. Flag descriptions and contract cases are updated.
Dry-run coverage
tests/cli_e2e/docs/docs_update_dryrun_test.go
Dry-run tests verify XML title replacement, normalized block IDs, exit code 2, and validation messages for unsafe inputs.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant stripTopLevelXMLTitles
  participant CreateRequest
  CLI->>stripTopLevelXMLTitles: XML content and CLI title
  stripTopLevelXMLTitles->>CLI: Content without top-level title elements
  CLI->>CreateRequest: Escaped CLI title plus normalized content
Loading

Possibly related PRs

Suggested labels: feature

Suggested reviewers: sunpeiyang996

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 is concise and accurately summarizes the main change: normalizing document write inputs.
Description check ✅ Passed The description matches the template with Summary, Changes, Test Plan, and Related Issues sections and is sufficiently detailed.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/fix-docs-write-preflight

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.

@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown

🚀 PR Preview Install Guide

🧰 CLI update

npm i -g https://pkg.pr.new/larksuite/cli/@larksuite/cli@15263efe3045463181fa2f197fc4d263b43fb6ff

🧩 Skill update

npx skills add larksuite/cli#codex/fix-docs-write-preflight -y -g

@fangshuyu-768 fangshuyu-768 changed the title fix: validate unsafe docs write inputs fix: normalize document write inputs Jul 22, 2026

@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

🤖 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 `@shortcuts/doc/docs_create_v2.go`:
- Around line 170-177: The title-stripping reconstruction in
shortcuts/doc/docs_create_v2.go#L170-L177 must return the built string without
strings.TrimSpace, preserving surrounding whitespace exactly; update
shortcuts/doc/docs_create_test.go#L34-L36 to expect "\n<p>body</p>\n" after
removing both title elements, and add an adjacent-text case if needed to verify
whitespace preservation.

In `@tests/cli_e2e/docs/docs_update_dryrun_test.go`:
- Around line 229-249: Isolate configuration in both dry-run tests,
TestDocs_CreateTitleDryRunNormalizesXMLTitle and the adjacent test covering
lines 251-284, by setting LARKSUITE_CLI_CONFIG_DIR to a unique t.TempDir() value
alongside the existing fake credential environment setup. Ensure each test uses
its own temporary configuration directory.
🪄 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: 7880facd-d2da-4317-971c-6eb8c3400b31

📥 Commits

Reviewing files that changed from the base of the PR and between da149e6 and 5b67085.

📒 Files selected for processing (5)
  • shortcuts/doc/doc_errors_test.go
  • shortcuts/doc/docs_create_test.go
  • shortcuts/doc/docs_create_v2.go
  • shortcuts/doc/docs_update_v2.go
  • tests/cli_e2e/docs/docs_update_dryrun_test.go
💤 Files with no reviewable changes (1)
  • shortcuts/doc/doc_errors_test.go

Comment on lines +170 to +177
var result strings.Builder
cursor := int64(0)
for _, item := range ranges {
result.WriteString(content[int(cursor):int(item.start)])
cursor = item.end
}
result.WriteString(content[int(cursor):])
return strings.TrimSpace(result.String())

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Preserve non-title content exactly when stripping titles.

strings.TrimSpace removes bytes outside the matched <title> ranges, including meaningful leading/trailing text-node whitespace. Remove the trim and update the expectation to retain the surrounding newlines; add an adjacent-text case if needed.

  • shortcuts/doc/docs_create_v2.go#L170-L177: return the reconstructed string without strings.TrimSpace.
  • shortcuts/doc/docs_create_test.go#L34-L36: expect "\n<p>body</p>\n" after removing both title elements.

As per coding guidelines, “When transcribing input or transforming requests, preserve values faithfully.”

Proposed fix
- return strings.TrimSpace(result.String())
+ return result.String()
- want: "<p>body</p>",
+ want: "\n<p>body</p>\n",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
var result strings.Builder
cursor := int64(0)
for _, item := range ranges {
result.WriteString(content[int(cursor):int(item.start)])
cursor = item.end
}
result.WriteString(content[int(cursor):])
return strings.TrimSpace(result.String())
var result strings.Builder
cursor := int64(0)
for _, item := range ranges {
result.WriteString(content[int(cursor):int(item.start)])
cursor = item.end
}
result.WriteString(content[int(cursor):])
return result.String()
📍 Affects 2 files
  • shortcuts/doc/docs_create_v2.go#L170-L177 (this comment)
  • shortcuts/doc/docs_create_test.go#L34-L36
🤖 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 `@shortcuts/doc/docs_create_v2.go` around lines 170 - 177, The title-stripping
reconstruction in shortcuts/doc/docs_create_v2.go#L170-L177 must return the
built string without strings.TrimSpace, preserving surrounding whitespace
exactly; update shortcuts/doc/docs_create_test.go#L34-L36 to expect
"\n<p>body</p>\n" after removing both title elements, and add an adjacent-text
case if needed to verify whitespace preservation.

Source: Coding guidelines

Comment on lines +229 to +249
func TestDocs_CreateTitleDryRunNormalizesXMLTitle(t *testing.T) {
t.Setenv("LARKSUITE_CLI_APP_ID", "app")
t.Setenv("LARKSUITE_CLI_APP_SECRET", "secret")
t.Setenv("LARKSUITE_CLI_BRAND", "feishu")

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
t.Cleanup(cancel)

result, err := clie2e.RunCmd(ctx, clie2e.Request{
Args: []string{
"docs", "+create",
"--title", "Flag title",
"--content", "<title>Content title</title><p>body</p>",
"--dry-run",
},
DefaultAs: "bot",
})
require.NoError(t, err)
result.AssertExitCode(t, 0)
require.Equal(t, "<title>Flag title</title>\n<p>body</p>", clie2e.DryRunGet(result.Stdout, "api.0.body.content").String())
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Isolate CLI configuration state in the new dry-run tests.

Both tests set fake credentials but inherit LARKSUITE_CLI_CONFIG_DIR, making results depend on the developer or CI machine’s existing configuration. Add t.Setenv("LARKSUITE_CLI_CONFIG_DIR", t.TempDir()) to each test.

Proposed fix
 func TestDocs_CreateTitleDryRunNormalizesXMLTitle(t *testing.T) {
+	t.Setenv("LARKSUITE_CLI_CONFIG_DIR", t.TempDir())
 	t.Setenv("LARKSUITE_CLI_APP_ID", "app")
 	t.Setenv("LARKSUITE_CLI_APP_SECRET", "secret")
@@
 func TestDocs_DryRunRejectsUnsafeWriteInputs(t *testing.T) {
+	t.Setenv("LARKSUITE_CLI_CONFIG_DIR", t.TempDir())
 	t.Setenv("LARKSUITE_CLI_APP_ID", "app")
 	t.Setenv("LARKSUITE_CLI_APP_SECRET", "secret")

As per coding guidelines, **/*_test.go tests must isolate configuration with LARKSUITE_CLI_CONFIG_DIR and t.TempDir().

Also applies to: 251-284

🤖 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/docs/docs_update_dryrun_test.go` around lines 229 - 249,
Isolate configuration in both dry-run tests,
TestDocs_CreateTitleDryRunNormalizesXMLTitle and the adjacent test covering
lines 251-284, by setting LARKSUITE_CLI_CONFIG_DIR to a unique t.TempDir() value
alongside the existing fake credential environment setup. Ensure each test uses
its own temporary configuration directory.

Source: Coding guidelines

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

domain/ccm PR touches the ccm domain size/M Single-domain feat or fix with limited business impact

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant