Skip to content

fix(docs): validate --selection-by-title format early#256

Merged
fangshuyu-768 merged 4 commits intolarksuite:mainfrom
wwenrr:fix/issue-93-selection-by-title-validation
Apr 21, 2026
Merged

fix(docs): validate --selection-by-title format early#256
fangshuyu-768 merged 4 commits intolarksuite:mainfrom
wwenrr:fix/issue-93-selection-by-title-validation

Conversation

@wwenrr
Copy link
Copy Markdown
Contributor

@wwenrr wwenrr commented Apr 3, 2026

Summary

  • add early validation for docs +update --selection-by-title so invalid plain-text inputs are rejected before sending MCP requests
  • require markdown heading syntax (e.g. ## Section) for --selection-by-title
  • add explicit error messages that guide users to the expected format

Why

Issue #93 reports that users pass plain titles (like 第二章) and receive opaque MCP validation failures. This change fails fast in CLI with actionable guidance, reducing trial-and-error and noisy server calls.

Thinking path

  • Considered implementing server-side title parsing changes, but that requires MCP-side updates and longer review cycle.
  • Chose a CLI-side guard as a small, isolated fix suitable for quick contribution scope.
  • Added tests around the validator to lock behavior and keep error guidance stable.

Changes

  • shortcuts/doc/docs_update.go
    • call validateSelectionByTitle during flag validation
    • new helper validates:
      • empty title => pass
      • heading-style title (#, ##, etc.) => pass
      • multi-line title => fail with single-line guidance
      • plain text title => fail with heading-prefix guidance
  • shortcuts/doc/docs_update_test.go
    • add TestValidateSelectionByTitle for pass/fail cases

Verification

Executed in Docker (host has no Go toolchain):

docker run --rm -v /tmp/larksuite-cli:/src -w /src golang:1.24 bash -lc "export PATH=/usr/local/go/bin:$PATH; go test ./shortcuts/doc -run 'TestValidateSelectionByTitle|TestIsWhiteboardCreateMarkdown|TestNormalizeDocsUpdateResult'"

Result: ok github.com/larksuite/cli/shortcuts/doc

Also ran broad suite check:

docker run --rm -v /tmp/larksuite-cli:/src -w /src golang:1.24 bash -lc "export PATH=/usr/local/go/bin:$PATH; go test ./..."

Observed unrelated pre-existing failures in internal/registry and e2e integration tests requiring external binaries/env; changed package tests pass.

Closes #93

Summary by CodeRabbit

  • Bug Fixes

    • Strengthened validation for the --selection-by-title option: trims surrounding whitespace, rejects newline characters, allows empty values, accepts headings starting with “#”, and enforces a markdown heading prefix with clearer user-facing errors.
  • Tests

    • Added unit and integration tests covering title validation (valid/invalid inputs, multi-line rejection, error messages, flag precedence, mutual-exclusion) and normalization behavior for board-token inputs.

@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Apr 3, 2026

CLA assistant check
All committers have signed the CLA.

@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 Apr 3, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 3, 2026

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

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b8b3974e-fb0e-4430-a246-bb0008478ad5

📥 Commits

Reviewing files that changed from the base of the PR and between 4bfe54c and 66d3688.

📒 Files selected for processing (1)
  • shortcuts/doc/docs_update_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • shortcuts/doc/docs_update_test.go

📝 Walkthrough

Walkthrough

DocsUpdate.Validate now invokes a new validateSelectionByTitle helper to validate the --selection-by-title flag. The helper trims whitespace, allows empty values, rejects inputs containing \n or \r, accepts values that start with #, and otherwise returns a flag error requiring a markdown heading prefix.

Changes

Cohort / File(s) Summary
Selection-by-title validation
shortcuts/doc/docs_update.go
Added validateSelectionByTitle(title string) error (trims whitespace, permits empty, rejects multiline \n/\r, accepts titles starting with #, otherwise returns common.FlagErrorf asking for a markdown heading). Integrated this check into DocsUpdate.Validate for --selection-by-title.
Validation & utilities tests
shortcuts/doc/docs_update_test.go
Added TestNormalizeBoardTokens and TestValidateSelectionByTitle, plus TestDocsUpdateValidate integration-style test and containsAll helper. Tests cover normalizeBoardTokens behavior, selection-by-title acceptance/rejection cases, and Validate flag precedence/interaction. Updated imports for testing.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇📜 I trim the whitespace, banning newlines' fray,
A leading # lets headings stay.
Empty is welcome, plain text must hide,
I hop through flags with carrot-fluffy pride. 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% 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
Title check ✅ Passed The title clearly and concisely summarizes the primary change: adding early validation for the --selection-by-title flag format.
Description check ✅ Passed The description includes all required sections: Summary, Changes, and Verification with specific test commands. It exceeds minimal requirements with 'Why' and 'Thinking path' context.
Linked Issues check ✅ Passed The PR addresses issue #93 by implementing CLI-side validation for --selection-by-title that rejects invalid formats (plain text, multiline) with helpful error messages before MCP calls.
Out of Scope Changes check ✅ Passed All changes are scoped to the --selection-by-title validation feature: validation logic in docs_update.go and comprehensive test coverage in docs_update_test.go.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 and usage tips.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 3, 2026

Greptile Summary

This PR adds early client-side validation for the --selection-by-title flag in docs update, rejecting plain-text titles and multi-line inputs before any MCP request is made, with actionable error messages pointing users to the correct markdown-heading syntax.

Key changes:

  • shortcuts/doc/docs_update.go: New validateSelectionByTitle helper called during flag validation. Multi-line check (\n/\r) is evaluated before the #-prefix check, so inputs like "## A\n## B" are correctly rejected. Empty titles pass through (flag is optional).
  • shortcuts/doc/docs_update_test.go: TestValidateSelectionByTitle covers empty, single-heading-pass, plain-text-fail, multi-line-heading-fail, and multi-line-plain-fail cases — including the "## 第二章\n## 第三章" case that was flagged as missing in a prior review.
  • Both issues raised in previous review threads (check ordering and missing test) have been resolved in the current HEAD.

Confidence Score: 5/5

Safe to merge — logic is correct, tests are comprehensive, and both prior review concerns have been resolved.

No P0 or P1 findings remain. The two issues flagged in previous review threads (multi-line check ordering and the missing multi-line-heading test case) are both addressed in the current HEAD. The validation logic is simple and well-covered by tests.

No files require special attention.

Important Files Changed

Filename Overview
shortcuts/doc/docs_update.go Adds validateSelectionByTitle helper and wires it into flag validation; multi-line check correctly precedes the #-prefix check, addressing the ordering concern raised in prior review threads.
shortcuts/doc/docs_update_test.go Adds TestValidateSelectionByTitle covering empty, single-heading, plain-text, multi-line heading (`## A

B`), and multi-line plain-text cases; the previously-missing multi-line heading test is now present. |

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["validateSelectionByTitle(title)"] --> B{title == ""}
    B -- yes --> C[return nil ✓]
    B -- no --> D["trimmed = TrimSpace(title)"]
    D --> E{"contains \n or \r?"}
    E -- yes --> F["error: must be a single heading line"]
    E -- no --> G{"HasPrefix(trimmed, '#')"}
    G -- yes --> H[return nil ✓]
    G -- no --> I["error: must include markdown heading prefix '#'"]
Loading

Reviews (2): Last reviewed commit: "fix(docs): reject multiline selection-by..." | Re-trigger Greptile

Comment thread shortcuts/doc/docs_update.go
Comment thread shortcuts/doc/docs_update_test.go
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@shortcuts/doc/docs_update.go`:
- Around line 168-173: The current logic returns early for any trimmed string
starting with "#" (trimmed variable) before checking for newlines, allowing
multiline headings like "## Section\nNext" to pass; change the order or add a
newline check before the prefix acceptance so strings containing "\n" or "\r"
trigger common.FlagErrorf("--selection-by-title must be a single heading line
(for example: '## Section')") even if they start with "#". Ensure the multiline
guard (strings.Contains(trimmed, "\n") || strings.Contains(trimmed, "\r")) runs
prior to the if strings.HasPrefix(trimmed, "#") return nil branch.
🪄 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: 93550292-bb6d-47a0-9c95-a404218a42e1

📥 Commits

Reviewing files that changed from the base of the PR and between 0c77c95 and 73559f8.

📒 Files selected for processing (2)
  • shortcuts/doc/docs_update.go
  • shortcuts/doc/docs_update_test.go

Comment thread shortcuts/doc/docs_update.go Outdated
@wwenrr
Copy link
Copy Markdown
Contributor Author

wwenrr commented Apr 3, 2026

Addressed review feedback ✅

I fixed the validation-order bug in validateSelectionByTitle:

  • now checks multiline (\n/\r) before heading-prefix check
  • so inputs like "## A\n## B" are rejected correctly

Added test coverage:

  • multi-line heading still fails case in TestValidateSelectionByTitle

Verification:

docker run --rm -v /tmp/larksuite-cli:/src -w /src golang:1.24 bash -lc "export PATH=/usr/local/go/bin:$PATH; go test ./shortcuts/doc -run 'TestValidateSelectionByTitle|TestIsWhiteboardCreateMarkdown|TestNormalizeDocsUpdateResult'"

Result: pass (ok github.com/larksuite/cli/shortcuts/doc)

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
shortcuts/doc/docs_update_test.go (1)

88-92: Consider adding edge case tests for robustness.

The current tests cover the main scenarios well. For additional confidence, consider adding tests for:

  • Single # heading: "# Title"
  • Leading/trailing whitespace: " ## Section "
  • Windows line endings: "## A\r\n## B"
📝 Additional test cases
 	t.Run("heading style title passes", func(t *testing.T) {
 		if err := validateSelectionByTitle("## 第二章"); err != nil {
 			t.Fatalf("expected nil error, got %v", err)
 		}
 	})
+
+	t.Run("single # heading passes", func(t *testing.T) {
+		if err := validateSelectionByTitle("# Title"); err != nil {
+			t.Fatalf("expected nil error, got %v", err)
+		}
+	})
+
+	t.Run("heading with surrounding whitespace passes", func(t *testing.T) {
+		if err := validateSelectionByTitle("  ## Section  "); err != nil {
+			t.Fatalf("expected nil error, got %v", err)
+		}
+	})
+
+	t.Run("windows line endings fail", func(t *testing.T) {
+		err := validateSelectionByTitle("## A\r\n## B")
+		if err == nil {
+			t.Fatalf("expected validation error")
+		}
+	})
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@shortcuts/doc/docs_update_test.go` around lines 88 - 92, Add edge-case
table-driven tests for validateSelectionByTitle: include t.Run cases for
single-level heading "# Title", headings with leading/trailing whitespace like "
## Section  ", and Windows CRLF input "## A\r\n## B" to ensure trimming and CRLF
handling; locate the existing test block that contains t.Run("heading style
title passes", func(t *testing.T) { ... }) and add these additional t.Run
subtests asserting nil error (or expected behavior) for each input.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@shortcuts/doc/docs_update_test.go`:
- Around line 88-92: Add edge-case table-driven tests for
validateSelectionByTitle: include t.Run cases for single-level heading "#
Title", headings with leading/trailing whitespace like "  ## Section  ", and
Windows CRLF input "## A\r\n## B" to ensure trimming and CRLF handling; locate
the existing test block that contains t.Run("heading style title passes", func(t
*testing.T) { ... }) and add these additional t.Run subtests asserting nil error
(or expected behavior) for each input.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 09644839-3178-4aa3-9e60-4717982abd83

📥 Commits

Reviewing files that changed from the base of the PR and between 73559f8 and e50a006.

📒 Files selected for processing (2)
  • shortcuts/doc/docs_update.go
  • shortcuts/doc/docs_update_test.go

fangshuyu-768
fangshuyu-768 previously approved these changes Apr 16, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 16, 2026

🚀 PR Preview Install Guide

🧰 CLI update

npm i -g https://pkg.pr.new/larksuite/cli/@larksuite/cli@66d3688ab6622953e972f44bacb012ccd956a577

🧩 Skill update

npx skills add wwenrr/cli#fix/issue-93-selection-by-title-validation -y -g

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 21, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (main@0c77c95). Learn more about missing BASE report.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #256   +/-   ##
=======================================
  Coverage        ?   61.05%           
=======================================
  Files           ?      400           
  Lines           ?    34130           
  Branches        ?        0           
=======================================
  Hits            ?    20838           
  Misses          ?    11368           
  Partials        ?     1924           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copilot AI review requested due to automatic review settings April 21, 2026 08:32
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

@fangshuyu-768 fangshuyu-768 force-pushed the fix/issue-93-selection-by-title-validation branch from e206d9f to 4bfe54c Compare April 21, 2026 08:54
codecov/patch was at 27.27% because the PR added three lines to the
Validate closure (the `if err := validateSelectionByTitle(selTitle); err
!= nil { return err }` block) but nothing in the test file exercised
that closure — only the helper function was tested directly.

TestDocsUpdateValidate now builds a bare RuntimeContext via
common.TestNewRuntimeContext, sets the relevant flags on a cobra
command, and calls DocsUpdate.Validate(ctx, rt) across five cases:

  1. Heading-style selection-by-title passes — covers the happy path
     through the new call site and the final `return nil`.
  2. Plain-text title is rejected with heading-prefix guidance —
     covers the new error branch.
  3. Multi-line title is rejected as not a single heading line —
     covers the other error branch inside the helper.
  4. Invalid --mode is still rejected first — proves the new check
     doesn't swallow pre-existing validation.
  5. Conflicting --selection-with-ellipsis + --selection-by-title is
     rejected at the mutual-exclusion check — same ordering contract.

Coverage profile confirms the three added production lines
(docs_update.go L65-67) are now hit: condition 3x, error branch 2x,
happy path via the closure's return nil 1x.
@fangshuyu-768 fangshuyu-768 force-pushed the fix/issue-93-selection-by-title-validation branch from 4bfe54c to 66d3688 Compare April 21, 2026 09:55
@fangshuyu-768 fangshuyu-768 merged commit 04e3a28 into larksuite:main Apr 21, 2026
18 checks passed
@liangshuo-1 liangshuo-1 mentioned this pull request Apr 21, 2026
3 tasks
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.

--selection-by-title 无法匹配标题

4 participants