fix(api): support stdin and quoted JSON inputs on Windows#367
fix(api): support stdin and quoted JSON inputs on Windows#367liangshuo-1 merged 2 commits intomainfrom
Conversation
…indows (#64) Windows PowerShell 5.x mangles JSON double-quotes when passing arguments to native executables, causing --params and --data to fail with "invalid JSON format". This commit adds two mitigations at the framework level: - stdin piping: `echo '{"k":"v"}' | lark-cli --params -` bypasses shell argument parsing entirely and works on all platforms/shells. - single-quote stripping: cmd.exe passes literal single quotes which are now transparently removed before JSON parsing. Implementation: - New `cmdutil.ResolveInput(raw, stdin)` handles `-` (stdin), strip surrounding `'...'`, and plain passthrough. - `ParseJSONMap` and `ParseOptionalBody` now accept an `io.Reader` and delegate to `ResolveInput` before JSON unmarshalling. - `cmd/api` and `cmd/service` pass `IOStreams.In` and guard against simultaneous stdin usage by --params and --data. - Empty stdin is rejected with a clear error message. Closes #64 Change-Id: If21e735d0aed5c6a2d6674c1e6c898186fca3aba
Change-Id: I4e00bf1c6b6f3259f503e3414cae10fa4b34ba75
📝 WalkthroughWalkthroughAdded stdin support ( Changes
Sequence Diagram(s)sequenceDiagram
participant User as User/Shell
participant CLI as CLI Handler
participant ResolveInput as ResolveInput()
participant Stdin as Stdin Reader
participant ParseFunc as ParseJSONMap/<br/>ParseOptionalBody
User->>CLI: --params - --data input.json
CLI->>ResolveInput: ResolveInput("--params", "-", stdin)
ResolveInput->>Stdin: Read all bytes
Stdin-->>ResolveInput: Content
ResolveInput->>ResolveInput: Trim whitespace
ResolveInput-->>CLI: Resolved string
CLI->>ResolveInput: ResolveInput("--data", "input.json", stdin)
ResolveInput->>ResolveInput: Strip single quotes (if present)
ResolveInput-->>CLI: Resolved string
CLI->>ParseFunc: Parse resolved inputs
ParseFunc-->>CLI: Validated objects
CLI-->>User: Request ready
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Greptile SummaryThis PR adds Windows-safe stdin ( Confidence Score: 5/5Safe to merge; only P2 findings remain — both are edge-case behavior nuances, not blocking defects. The core stdin/single-quote logic is correct and well-tested. The two flagged issues are: (1) silent body-drop for GET+--data in the raw api command (unusual use-case, low real-world impact), and (2) a confusing error for the unlikely '-' input. Neither breaks the primary user paths described in the PR. internal/cmdutil/json.go (ParseOptionalBody method gate) and internal/cmdutil/resolve.go (single-quote then stdin ordering)
|
| Filename | Overview |
|---|---|
| internal/cmdutil/resolve.go | New ResolveInput helper correctly handles stdin (-), single-quote stripping, and empty/nil inputs; well-tested edge cases. |
| internal/cmdutil/json.go | ParseJSONMap and ParseOptionalBody correctly delegate to ResolveInput; ParseOptionalBody restricts body parsing to POST/PUT/PATCH/DELETE — behavior change vs. old api.go which allowed any method to carry a body. |
| cmd/api/api.go | Removes local parseJsonOpt and delegates to cmdutil helpers; double-stdin guard is correct, but ParseOptionalBody now silently ignores --data for GET/HEAD/etc., which the original code did not. |
| cmd/service/service.go | Service command correctly adopts shared helpers; --data flag is only registered for POST/PUT/PATCH/DELETE so the method-gate in ParseOptionalBody is redundant but harmless here. |
| tests/cli_e2e/core.go | Adds Stdin field to Request struct and wires it to cmd.Stdin; defaultAsInitOnce shared state is best-effort and intentional per comment. |
| tests/cli_e2e/stdin_regression_test.go | Comprehensive E2E regression tests covering stdin success, empty stdin, double-stdin conflict, and single-quoted JSON for both api and service commands. |
| internal/cmdutil/resolve_test.go | Good unit coverage for ResolveInput including nil stdin, read errors, whitespace-only input, and Windows shell scenarios. |
| internal/cmdutil/json_test.go | Covers ParseOptionalBody and ParseJSONMap including stdin and single-quote flows. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["--params / --data flag value"] --> B{value == '-'?}
B -- yes --> C{both params AND data == '-'?}
C -- yes --> D["ErrValidation: cannot both read from stdin"]
C -- no --> E["io.ReadAll(stdin)"]
E --> F{empty after TrimSpace?}
F -- yes --> G["ErrValidation: stdin is empty"]
F -- no --> H["resolved string"]
B -- no --> I{surrounded by single quotes?}
I -- yes --> J["strip outer quotes → raw inner string"]
I -- no --> K["use as-is"]
J --> H
K --> H
H --> L{caller context}
L -- ParseJSONMap --> M["json.Unmarshal → map[string]any"]
L -- ParseOptionalBody --> N{httpMethod in POST/PUT/PATCH/DELETE?}
N -- no --> O["return nil (body ignored)"]
N -- yes --> P["json.Unmarshal → interface{}"]
Reviews (1): Last reviewed commit: "test: add stdin e2e regression coverage" | Re-trigger Greptile
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@internal/cmdutil/json.go`:
- Around line 46-50: json.Unmarshal into map[string]any allows JSON "null" and
leaves result == nil, which currently returns success; update the code that
parses params (the block with variable result map[string]any and the
json.Unmarshal call) to explicitly reject non-object JSON by checking if result
== nil after Unmarshal and returning output.ErrValidation("%s invalid format,
expected JSON object", label) when it is nil (and still return result, nil only
when result is non-nil).
In `@tests/cli_e2e/stdin_regression_test.go`:
- Around line 198-203: The setDryRunConfigEnv helper currently sets app
ID/secret/brand but does not isolate CLI config state; update setDryRunConfigEnv
to also set the config directory to a unique temp location by calling
t.Setenv("LARKSUITE_CLI_CONFIG_DIR", t.TempDir()) so tests use an isolated
config/cache directory; modify the function named setDryRunConfigEnv to add that
single t.Setenv call alongside the existing LARKSUITE_CLI_* env setups.
🪄 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: 2cd5bc38-9703-46f2-b05c-2849de0ede03
📒 Files selected for processing (11)
cmd/api/api.gocmd/api/api_test.gocmd/service/service.gocmd/service/service_test.gointernal/cmdutil/json.gointernal/cmdutil/json_test.gointernal/cmdutil/resolve.gointernal/cmdutil/resolve_test.gotests/cli_e2e/core.gotests/cli_e2e/core_test.gotests/cli_e2e/stdin_regression_test.go
🚀 PR Preview Install Guide🧰 CLI updatenpm i -g https://pkg.pr.new/larksuite/cli/@larksuite/cli@7de0af641c341d3abad567e99c1ff897d3f81690🧩 Skill updatenpx skills add larksuite/cli#fix/params-stdin-resolve -y -g |
Summary
This PR adds Windows-safe stdin and single-quoted JSON handling for
--paramsand--data, then locks the behavior down with real end-to-end regression coverage.Changes
-) and surrounding single-quote support forapiand generated service commands when parsing--paramsand--datainternal/cmdutil/resolve_test.goso the branch stays lint-cleanTest Plan
make unit-testgo test -count=1 ./tests/...go mod tidy(no changes)go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.1.6 run --new-from-rev=origin/mainapi/servicewith stdin success, empty stdin, double-stdin conflict, and single-quoted JSON inputsRelated Issues
--paramsJSON parsing fails forim messages read_users(and other non-empty params calls) #64Summary by CodeRabbit
New Features
--paramsand--dataflags using-as a sentinel value, enabling piped JSON data input to CLI commands.Bug Fixes
--params -and--data -are specified.Documentation
--paramsand--dataflags to document stdin support.