Skip to content

refactor(output)!: emitter follow-ups from PR #1899 (strict Format, pretty scan, jq safety, pagination merge)#1998

Open
sang-neo03 wants to merge 9 commits into
mainfrom
refactor/output-emitter-followups
Open

refactor(output)!: emitter follow-ups from PR #1899 (strict Format, pretty scan, jq safety, pagination merge)#1998
sang-neo03 wants to merge 9 commits into
mainfrom
refactor/output-emitter-followups

Conversation

@sang-neo03

@sang-neo03 sang-neo03 commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

Summary

Follow-ups from the PR #1899 (output Emitter convergence) owner review, each establishing one verifiable invariant. Scope kept to items ①, ②, ④ and the pagination-merge half of ⑤; items ③ (poisoned-stream state machine) and the notice-ownership half of ④ are deliberately deferred.

Changes

  • refactor(output)! — strict typed Format (⚠️ breaking). An unknown --format (e.g. a typo like --format tabel) is now a typed ValidationError with a non-zero exit code instead of a stderr warning + JSON fallback. Format gains FormatPretty; ParseFormatStrict rejects unknown values at the api/service/shortcut boundaries (before the dry-run branch); EmitOptions.Format / StreamOptions.Format are the typed output.Format (no more .String() round-trip); the raw api/service commands reject --format pretty on the emit path while keeping the dry-run preview; ValidateJqFlags classifies the format case-insensitively so --format JSON --jq no longer mis-rejects. Shortcuts that declare their own format flag (markdown/data) keep their enum.
  • refactor(output) — scan pretty-rendered output. The pretty path scanned the structured data argument but rendered via an opaque closure, so a renderer printing content absent from data could bypass content-safety in block mode. Pretty output is now rendered into a buffer, the safety scan runs on the actual rendered text, and stdout receives exactly what was scanned.
  • refactor(output) — always warn on stderr when jq may drop a content-safety alert. Whether the stderr fallback warning was written used to depend on a caller-set JQSafetyWarning flag, so api/service warned but shortcut commands silently lost the alert when --jq filtered it out. The flag is removed; the Emitter always warns when jq is applied and an alert exists.
  • refactor(output) — unify api/service pagination into client.PaginateToOutput. apiPaginate and servicePaginate were near-identical; merged into one shared function, with checkErr and markErr injected. Pure refactor, byte-identical output and error semantics.

Test Plan

  • Unit tests pass — go test -count=1 ./internal/output/ ./cmd/api/ ./cmd/service/ ./shortcuts/common/ ./shortcuts/base/ ./shortcuts/mail/ ./shortcuts/calendar/ ./shortcuts/contact/ ./internal/client/ all green.
  • Full go test -count=1 ./... green except the tests/cli_e2e/* packages, which fail identically on clean main for environmental reasons (require a built binary / live env), unrelated to this change.
  • Added acceptance tests: unknown-format rejection (unit + api/service command level), jq case-insensitivity, pretty block/warn/off rendered-text scanning, jq-drops-alert stderr warning, and the pagination byte-for-byte oracle tests continue to pass.
  • Manual local verification confirms the lark-cli <domain> <command> flow works as expected

Related Issues

Summary by CodeRabbit

  • New Features
    • Added pretty output format support, including plain-text dry-run previews.
  • Bug Fixes
    • --format validation now fails fast with typed validation errors (no silent fallback to JSON).
    • --format pretty is rejected for normal emit, but supported for dry-run previews.
    • Improved --jq/--format compatibility and consistent JQ safety alert warning behavior.
    • Pagination and output emission now consistently use the unified pagination-to-output path for streaming/envelope handling.
  • Tests
    • Expanded/updated CLI, service, pagination, emitter, and shortcut tests for strict --format handling and pretty behavior.

…gal combos

An unknown --format now fails with a typed ValidationError instead of printing a
stderr warning and silently degrading to JSON, and unfulfillable combinations are
rejected at the flag boundary rather than dropped silently.

- Add FormatPretty to the Format enum and ParseFormatStrict, which returns a
  typed validation error (param --format) for any unrecognized format.
- EmitOptions.Format / StreamOptions.Format / Emitter.streamFormat are now the
  typed output.Format; the upstream .String() -> ParseFormat round-trip and the
  Emitter's internal unknown-format fallback (printLegacyDataJSON) are removed.
- Strict parsing runs at the api, service, and shortcut boundaries, before the
  dry-run branch so both dry-run and emit reject an unknown format. The strict
  contract applies only to the framework-injected --format; a shortcut that
  declares its own format flag (base +record-* markdown|json, mail +watch
  json|data) keeps its own enum, validated by validateEnumFlags.
- The raw api/service commands reject --format pretty on the emit path (no
  response pretty renderer) while preserving the dry-run plain-text preview;
  the check runs before confirmation and client init.
- ValidateJqFlags classifies the format via ParseFormat so --jq's JSON-only
  check is case-insensitive and single-sourced: --format JSON --jq no longer
  mis-rejects, while any non-JSON value (including a shortcut's markdown/data)
  still conflicts with --jq.

BREAKING CHANGE: an unknown --format value (e.g. a typo like `--format tabel`)
is now a typed validation error with a non-zero exit code instead of a stderr
warning plus JSON output. Scripts that relied on the unknown-format JSON
fallback must pass a valid format (json, ndjson, table, csv, or pretty).
The pretty path scanned the structured `data` argument but rendered via an
opaque closure, so a renderer that printed content absent from `data` could
bypass content-safety in block mode. Render pretty output into a buffer, run
the safety scan on the actual rendered text, and only copy to stdout when it
passes — the bytes that reach stdout are now exactly what was scanned. Applies
to both Success's pretty path and StreamPage's pretty branch; json/table/csv/
ndjson are unchanged (they render from the scanned data directly).
…fety alert

When --jq is applied, the jq expression can filter the _content_safety_alert
field out of stdout, hiding the warning. Whether a stderr fallback warning was
written used to depend on a caller-set EmitOptions.JQSafetyWarning flag, so the
raw api/service paths warned but shortcut commands did not — the safety alert
was silently lost. Remove the flag and always write the stderr warning when jq
is applied and an alert exists.
…Output

apiPaginate and servicePaginate were near-identical; merge them into one shared
client.PaginateToOutput. The two call-site differences are injected: checkErr
(both pass APIClient.CheckResponse) and markErr (cmd/api passes errs.MarkRaw,
cmd/service passes nil). markErr wraps only the PaginateAll / StreamPages /
checkErr errors — never the WriteSuccessEnvelope return — preserving both
commands' exact stdout/stderr bytes and error semantics. Pure refactor.
@sang-neo03
sang-neo03 requested a review from liangshuo-1 as a code owner July 22, 2026 07:16
@github-actions github-actions Bot added domain/calendar PR touches the calendar domain size/XL Architecture-level or global-impact change labels Jul 22, 2026
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 88e5b770-4699-4d86-a1ec-bfd67195f9be

📥 Commits

Reviewing files that changed from the base of the PR and between d668d75 and 8b30b07.

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

📝 Walkthrough

Walkthrough

The CLI now strictly validates output formats, adds typed pretty support, centralizes paginated output in client.PaginateToOutput, and updates emitters and shortcuts to use typed formats. Pretty rendering and content-safety behavior receive expanded coverage.

Changes

Format contracts and emission

Layer / File(s) Summary
Typed format and emitter contracts
internal/output/format_type.go, internal/output/emitter.go, internal/output/jq.go, internal/client/response.go, internal/output/envelope_success.go
Formats use typed values, pretty is supported, strict parsing returns validation errors, and legacy unknown-format fallback is removed.
Emission safety and compatibility validation
internal/output/*_test.go, internal/output/testdata/*
Tests cover typed formats, pretty rendering, jq warnings, content-safety scanning, and updated golden output.

Centralized pagination

Layer / File(s) Summary
Shared pagination emission
internal/client/paginate_emit.go, cmd/api/api_paginate_test.go, cmd/service/service_paginate_test.go
PaginateToOutput handles aggregation, streaming, jq processing, fallback behavior, and error marking; API and service pagination tests use it directly.
API and service format flow
cmd/api/api.go, cmd/service/service.go, cmd/api/api_test.go, cmd/service/service_test.go
Unknown formats are rejected, pretty remains available for dry-run previews, and raw pretty emission is rejected.

Shortcut integration

Layer / File(s) Summary
Shortcut format validation
shortcuts/common/runner.go, shortcuts/common/runner_jq_test.go, shortcuts/calendar/calendar_test.go
Shortcut output helpers use typed formats, and undeclared format flags are validated and canonicalized before execution.

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

Sequence Diagram(s)

sequenceDiagram
  participant APIServiceCommand
  participant PaginateToOutput
  participant APIClient
  participant Emitter
  APIServiceCommand->>PaginateToOutput: provide format and pagination options
  PaginateToOutput->>APIClient: request pages
  APIClient-->>PaginateToOutput: return page data
  PaginateToOutput->>Emitter: emit streamed or aggregated output
  Emitter-->>APIServiceCommand: write output or return error
Loading

Possibly related PRs

  • larksuite/cli#211: Related pagination and jq output routing in shared client helpers.
  • larksuite/cli#1489: Related removal of local API/service pagination helpers and centralized emission.
  • larksuite/cli#1899: Related emitter, typed format, and pagination output refactoring.

Suggested labels: feature

Suggested reviewers: liangshuo-1

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.75% 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 is specific and clearly reflects the main breaking output-format, safety, and pagination refactor.
Description check ✅ Passed The description follows the template with Summary, Changes, Test Plan, and Related Issues sections, and includes relevant verification details.
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.
✨ 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 refactor/output-emitter-followups

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@da5b75290715d28277453c0c23bbc53138cf59ee

🧩 Skill update

npx skills add larksuite/cli#refactor/output-emitter-followups -y -g

@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: 1

🧹 Nitpick comments (1)
cmd/api/api.go (1)

261-268: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the shared pretty-rejection contract into one helper. cmd/api/api.go and cmd/service/service.go each hardcode the identical FormatPretty rejection (same subtype, message, and param) for their raw emit paths. A single shared helper keeps the two raw commands' "pretty is shortcut-only" contract from silently drifting apart.

  • cmd/api/api.go#L261-L268: replace the inline check with a call to a shared helper (e.g. output.RejectPretty(format)).
  • cmd/service/service.go#L415-L423: replace the inline check with the same shared helper call.
♻️ Proposed shared helper
// in internal/output (e.g. format_type.go)

// RejectPretty returns a typed validation error if f is FormatPretty. Raw
// api/service commands have no pretty renderer for responses and must reject
// it before client init rather than silently falling back.
func RejectPretty(f Format) error {
	if f != FormatPretty {
		return nil
	}
	return errs.NewValidationError(errs.SubtypeInvalidArgument,
		"--format pretty is not supported here (use json, ndjson, table, or csv)").
		WithParam("--format")
}
-	if format == output.FormatPretty {
-		return errs.NewValidationError(errs.SubtypeInvalidArgument,
-			"--format pretty is not supported here (use json, ndjson, table, or csv)").
-			WithParam("--format")
-	}
+	if err := output.RejectPretty(format); err != nil {
+		return err
+	}
🤖 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 `@cmd/api/api.go` around lines 261 - 268, Extract the identical FormatPretty
validation into a shared output.RejectPretty helper that returns nil for other
formats and preserves the existing typed error, message, and parameter. Replace
the inline checks in cmd/api/api.go lines 261-268 and cmd/service/service.go
lines 415-423 with calls to this helper.
🤖 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 `@cmd/api/api_test.go`:
- Around line 124-184: Add test isolation for the cmd/api tests by setting
LARKSUITE_CLI_CONFIG_DIR to a per-test temporary directory via t.Setenv near the
setup in TestApiCmd_UnknownFormat_Rejected, TestApiCmd_Pretty_RejectedOnEmit,
and TestApiCmd_Pretty_PreservedOnDryRun, or establish equivalent package-wide
isolation with TestMain. Ensure cmdutil.TestFactory cannot access the
developer’s real configuration.

---

Nitpick comments:
In `@cmd/api/api.go`:
- Around line 261-268: Extract the identical FormatPretty validation into a
shared output.RejectPretty helper that returns nil for other formats and
preserves the existing typed error, message, and parameter. Replace the inline
checks in cmd/api/api.go lines 261-268 and cmd/service/service.go lines 415-423
with calls to this helper.
🪄 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: e4f75c0e-b4fe-48d1-ba65-a4c77d9df2f6

📥 Commits

Reviewing files that changed from the base of the PR and between bb246b5 and ed60f31.

📒 Files selected for processing (19)
  • cmd/api/api.go
  • cmd/api/api_paginate_test.go
  • cmd/api/api_test.go
  • cmd/service/service.go
  • cmd/service/service_paginate_test.go
  • cmd/service/service_test.go
  • internal/client/paginate_emit.go
  • internal/client/response.go
  • internal/output/emitter.go
  • internal/output/emitter_contract_test.go
  • internal/output/emitter_legacy_compat_test.go
  • internal/output/envelope_success.go
  • internal/output/format_type.go
  • internal/output/format_type_test.go
  • internal/output/jq.go
  • internal/output/jq_test.go
  • internal/output/testdata/runtime_context_legacy.golden.json
  • shortcuts/calendar/calendar_test.go
  • shortcuts/common/runner.go

Comment thread cmd/api/api_test.go
Comment on lines +124 to +184
func TestApiCmd_UnknownFormat_Rejected(t *testing.T) {
for _, extra := range [][]string{nil, {"--dry-run"}} {
name := "emit"
if len(extra) > 0 {
name = "dry-run"
}
t.Run(name, func(t *testing.T) {
f, stdout, _, _ := cmdutil.TestFactory(t, &core.CliConfig{
AppID: "test-app", AppSecret: "test-secret", Brand: core.BrandFeishu,
})
cmd := newTestApiCmd(f, nil)
cmd.SetArgs(append([]string{"GET", "/open-apis/test", "--as", "bot", "--format", "bogus"}, extra...))
err := cmd.Execute()
if err == nil {
t.Fatal("expected a validation error for unknown --format")
}
requireProblem(t, err, errs.CategoryValidation, errs.SubtypeInvalidArgument, 0)
if !strings.Contains(err.Error(), "unknown output format") {
t.Errorf("error = %v, want unknown-format message", err)
}
if stdout.String() != "" {
t.Errorf("unknown --format must not write stdout, got:\n%s", stdout.String())
}
})
}
}

// pretty is shortcut-only: the raw api command rejects it on the emit path
// (before client init) but keeps the dry-run plain-text preview.
func TestApiCmd_Pretty_RejectedOnEmit(t *testing.T) {
f, stdout, _, _ := cmdutil.TestFactory(t, &core.CliConfig{
AppID: "test-app", AppSecret: "test-secret", Brand: core.BrandFeishu,
})
cmd := newTestApiCmd(f, nil)
cmd.SetArgs([]string{"GET", "/open-apis/test", "--as", "bot", "--format", "pretty"})
err := cmd.Execute()
if err == nil {
t.Fatal("expected a validation error for --format pretty on the emit path")
}
requireProblem(t, err, errs.CategoryValidation, errs.SubtypeInvalidArgument, 0)
if !strings.Contains(err.Error(), "pretty") {
t.Errorf("error = %v, want pretty-not-supported message", err)
}
if stdout.String() != "" {
t.Errorf("rejected --format pretty must not write stdout, got:\n%s", stdout.String())
}
}

func TestApiCmd_Pretty_PreservedOnDryRun(t *testing.T) {
f, stdout, _, _ := cmdutil.TestFactory(t, &core.CliConfig{
AppID: "test-app", AppSecret: "test-secret", Brand: core.BrandFeishu,
})
cmd := newTestApiCmd(f, nil)
cmd.SetArgs([]string{"GET", "/open-apis/test", "--as", "bot", "--format", "pretty", "--dry-run"})
if err := cmd.Execute(); err != nil {
t.Fatalf("dry-run --format pretty must be accepted, got: %v", err)
}
if !strings.Contains(stdout.String(), "# dry-run: request not sent") {
t.Fatalf("dry-run --format pretty lost its plain-text preview, stdout:\n%s", stdout.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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check whether cmdutil.TestFactory already isolates LARKSUITE_CLI_CONFIG_DIR via t.TempDir()/t.Setenv.
fd -t f 'testfactory|factory_test|testing' internal/cmdutil -a | xargs -r rg -nP -C4 'func TestFactory' 
rg -nP -C4 'LARKSUITE_CLI_CONFIG_DIR|t\.TempDir\(\)|t\.Setenv' internal/cmdutil

Repository: larksuite/cli

Length of output: 18769


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the cmd/api tests and the test factory/config resolution path.
ast-grep outline cmd/api/api_test.go --view expanded
printf '\n--- internal/cmdutil/testing.go ---\n'
cat -n internal/cmdutil/testing.go | sed -n '1,220p'
printf '\n--- internal/cmdutil/factory.go ---\n'
cat -n internal/cmdutil/factory.go | sed -n '1,260p'
printf '\n--- cmd/api test helpers and setup references ---\n'
rg -n --hidden 'LARKSUITE_CLI_CONFIG_DIR|TestFactory\(|newTestApiCmd|TestMain|os\.Setenv|t\.Setenv' cmd/api internal/cmdutil cmd -g '*_test.go' -g '*.go'

Repository: larksuite/cli

Length of output: 50369


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- cmd/api/api_test.go (top) ---'
cat -n cmd/api/api_test.go | sed -n '1,40p'

printf '\n%s\n' '--- cmd/api TestMain files ---'
fd -a 'testmain_test.go' cmd/api cmd | xargs -r -I{} sh -c 'printf "\n### %s ###\n" "{}"; cat -n "{}" | sed -n "1,120p"'

printf '\n%s\n' '--- package declarations in cmd/api ---'
rg -n '^package ' cmd/api -g '*.go'

Repository: larksuite/cli

Length of output: 7281


Isolate the cmd/api tests from host config
cmd/api has no package-level TestMain, and cmdutil.TestFactory doesn’t set LARKSUITE_CLI_CONFIG_DIR. Add t.Setenv("LARKSUITE_CLI_CONFIG_DIR", t.TempDir()) here, or a package-level TestMain, so these tests can’t read or write a developer’s real config.

🤖 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 `@cmd/api/api_test.go` around lines 124 - 184, Add test isolation for the
cmd/api tests by setting LARKSUITE_CLI_CONFIG_DIR to a per-test temporary
directory via t.Setenv near the setup in TestApiCmd_UnknownFormat_Rejected,
TestApiCmd_Pretty_RejectedOnEmit, and TestApiCmd_Pretty_PreservedOnDryRun, or
establish equivalent package-wide isolation with TestMain. Ensure
cmdutil.TestFactory cannot access the developer’s real configuration.

Source: Path instructions

…ormat

Address code-review findings on the emitter follow-ups:

- Large pretty output is scanned in overlapping 64 KiB windows instead of one
  string, so content past the safety scanner's 128 KiB per-string cap is no
  longer skipped — this was a content-safety bypass reintroduced by the
  buffer-then-scan change.
- Feed the canonical Format.String() into the dry-run path (api/service/
  shortcut) so a mixed-case --format Pretty still renders the plain-text
  preview instead of falling through to the JSON envelope.
- The raw api/service unknown-format error lists only json/ndjson/table/csv,
  not the shortcut-only pretty, so it no longer suggests a value those commands
  reject.

@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: 1

Caution

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

⚠️ Outside diff range comments (1)
cmd/service/service_test.go (1)

830-836: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert the validation parameter, not only the message.

This test does not verify that the typed error contains Param == "--format", so removing WithParam("--format") would still pass. Add an errors.As assertion for *errs.ValidationError.

As per coding guidelines, command error-path tests must assert typed metadata including param. Based on learnings, errs.ProblemOf exposes no Param; use errors.As with *errs.ValidationError for this field. The production path in cmd/service/service.go attaches this parameter.

🤖 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 `@cmd/service/service_test.go` around lines 830 - 836, Enhance the validation
error test around requireProblem to extract the typed error with errors.As into
*errs.ValidationError and assert its Param equals "--format". Keep the existing
category, subtype, and message assertions, while verifying the
production-attached parameter metadata directly.

Sources: Coding guidelines, Learnings

🧹 Nitpick comments (1)
shortcuts/common/runner_jq_test.go (1)

355-356: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use the standard isolated factory for executable shortcut tests.

Both new tests execute runShortcut but construct a manual cmdutil.Factory. Use cmdutil.TestFactory(t, config) and the repository’s required configuration isolation pattern so these tests do not diverge from the standard runtime setup.

As per coding guidelines, test factories must use cmdutil.TestFactory(t, config) and isolate LARKSUITE_CLI_CONFIG_DIR. Based on learnings, direct factory construction is appropriate only for mount-only tests; these tests execute runShortcut.

Also applies to: 380-381

🤖 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/common/runner_jq_test.go` around lines 355 - 356, Replace the
manual factory setup in both tests around newTestFactory and newTestShortcutCmd
with cmdutil.TestFactory(t, config), applying the repository’s standard
LARKSUITE_CLI_CONFIG_DIR isolation pattern. Keep the runShortcut execution
unchanged and use direct factory construction only for mount-only tests.

Sources: Coding guidelines, Learnings

🤖 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/common/runner_jq_test.go`:
- Around line 385-392: Update the unknown-format test around runShortcut to
inspect the typed validation problem via errs.ProblemOf and assert
errs.CategoryValidation and errs.SubtypeInvalidArgument, while retaining
errors.As to extract Param from *errs.ValidationError. Preserve the existing
--format and “pretty” message assertions, using ParseFormatStrict’s defined
typed values.

---

Outside diff comments:
In `@cmd/service/service_test.go`:
- Around line 830-836: Enhance the validation error test around requireProblem
to extract the typed error with errors.As into *errs.ValidationError and assert
its Param equals "--format". Keep the existing category, subtype, and message
assertions, while verifying the production-attached parameter metadata directly.

---

Nitpick comments:
In `@shortcuts/common/runner_jq_test.go`:
- Around line 355-356: Replace the manual factory setup in both tests around
newTestFactory and newTestShortcutCmd with cmdutil.TestFactory(t, config),
applying the repository’s standard LARKSUITE_CLI_CONFIG_DIR isolation pattern.
Keep the runShortcut execution unchanged and use direct factory construction
only for mount-only tests.
🪄 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: 6da1fc11-4279-4390-8a71-ea25549c0584

📥 Commits

Reviewing files that changed from the base of the PR and between ed60f31 and 0a61b41.

📒 Files selected for processing (8)
  • cmd/api/api.go
  • cmd/api/api_test.go
  • cmd/service/service.go
  • cmd/service/service_test.go
  • internal/output/emitter.go
  • internal/output/emitter_contract_test.go
  • shortcuts/common/runner.go
  • shortcuts/common/runner_jq_test.go
🚧 Files skipped from review as they are similar to previous changes (6)
  • shortcuts/common/runner.go
  • cmd/service/service.go
  • cmd/api/api.go
  • cmd/api/api_test.go
  • internal/output/emitter_contract_test.go
  • internal/output/emitter.go

Comment on lines +385 to +392
err := runShortcut(cmd, f, s, false)
if err == nil {
t.Fatal("expected a validation error for unknown --format")
}
assertValidationParam(t, err, "--format")
if !strings.Contains(strings.ToLower(err.Error()), "pretty") {
t.Fatalf("shortcut unknown-format error = %v, want pretty in allowed choices", err)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert the complete typed validation problem.

The visible assertions check the parameter and message text, but do not assert errs.CategoryValidation and errs.SubtypeInvalidArgument. Add those checks through errs.ProblemOf; retain errors.As for Param.

As per coding guidelines, command error-path tests must verify category, subtype, and parameter. Based on learnings, Param must be read from *errs.ValidationError, not errs.ProblemOf. The ParseFormatStrict contract in internal/output/format_type.go defines the expected typed values.

🤖 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/common/runner_jq_test.go` around lines 385 - 392, Update the
unknown-format test around runShortcut to inspect the typed validation problem
via errs.ProblemOf and assert errs.CategoryValidation and
errs.SubtypeInvalidArgument, while retaining errors.As to extract Param from
*errs.ValidationError. Preserve the existing --format and “pretty” message
assertions, using ParseFormatStrict’s defined typed values.

Sources: Coding guidelines, Learnings

Further review fixes:
- Normalize the framework-injected --format to its canonical lowercase and
  write it back to the runtime context and the cobra flag, so shortcuts that
  branch on the exact value (e.g. Format == "pretty") behave correctly for
  mixed-case input like --format Pretty, which previously slipped past those
  checks and produced empty output.
- Size the pretty rendered-text scan window to the content-safety scanner's
  native 128 KiB per-string capacity (was 64 KiB) so the windowing is no more
  restrictive than scanning the raw value; keep the 4 KiB overlap for matches
  crossing a window boundary.

@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: 1

🤖 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/common/runner_jq_test.go`:
- Around line 385-386: Update the execution-path test around newTestShortcutCmd
to use cmdutil.TestFactory(t, config) instead of newTestFactory(). Isolate
LARKSUITE_CLI_CONFIG_DIR with t.Setenv and t.TempDir() before creating the
command, while preserving the existing shortcut execution assertions.
🪄 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: 3530ff2f-fe48-4e13-8d0c-0258fbbb2a3b

📥 Commits

Reviewing files that changed from the base of the PR and between 0a61b41 and d668d75.

📒 Files selected for processing (4)
  • internal/output/emitter.go
  • internal/output/emitter_contract_test.go
  • shortcuts/common/runner.go
  • shortcuts/common/runner_jq_test.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • shortcuts/common/runner.go
  • internal/output/emitter_contract_test.go
  • internal/output/emitter.go

Comment on lines +385 to +386
f := newTestFactory()
cmd := newTestShortcutCmd(s, f)

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 | 🟠 Major | ⚡ Quick win

Use the repository test factory for this execution-path test.

runShortcut reaches configuration/auth setup and executes the shortcut, so this is not a mount-only test. Replace newTestFactory() with cmdutil.TestFactory(t, config) and isolate LARKSUITE_CLI_CONFIG_DIR with t.Setenv(..., t.TempDir()).

As per coding guidelines, *_test.go fixtures must use cmdutil.TestFactory(t, config) and isolate configuration state; the shortcut test learning limits raw factories to mount-only tests.

🤖 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/common/runner_jq_test.go` around lines 385 - 386, Update the
execution-path test around newTestShortcutCmd to use cmdutil.TestFactory(t,
config) instead of newTestFactory(). Isolate LARKSUITE_CLI_CONFIG_DIR with
t.Setenv and t.TempDir() before creating the command, while preserving the
existing shortcut execution assertions.

Sources: Coding guidelines, Learnings

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

Labels

domain/calendar PR touches the calendar domain size/XL Architecture-level or global-impact change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant