feat: implement deterministic exit codes and structured machine outpu…#173
feat: implement deterministic exit codes and structured machine outpu…#173KhushviB wants to merge 28 commits into
Conversation
…t (A1) - Add --output json/ndjson/table and --quiet flags - Implement deterministic exit codes (0: success, 1: generic, 2: bad args, 3: auth, 4: not found, 5: throttled) - Emit structured JSON errors on stderr during machine modes - Automatically disable ANSI colors and suppress informational output in machine modes
There was a problem hiding this comment.
Pull request overview
Implements a first-cut “machine output contract” for the Cosmos DB Shell by introducing global --output/--quiet flags, adding NDJSON output support, and mapping error conditions to deterministic exit codes intended for CI/CD and automation consumption.
Changes:
- Adds root CLI flags
--output/-oand--quiet/-q, and forcesNoColors+ quiet behavior for machine modes. - Introduces
OutputFormat.Ndjsonplus NDJSON formatting support for JSON-like command results. - Adds exit-code plumbing via
CommandState.ExitCode,ParserErrorCommandState.ExitCode = 2, andErrorCommandState.ExitCodemapping for Cosmos SDK failures and argument errors.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| CosmosDBShell/Program.cs | Adds root options, machine-mode detection, defaulting to NDJSON in non-interactive runs, and maps parse/connect failures to deterministic exit codes. |
| CosmosDBShell/lang/en.ftl | Adds help strings for --output and --quiet. |
| CosmosDBShell/Azure.Data.Cosmos.Shell.Core/ShellInterpreter.cs | Implements Quiet suppression for ShellInterpreter.Write* and emits structured JSON errors to stderr in machine modes. |
| CosmosDBShell/Azure.Data.Cosmos.Shell.Core/ParserErrorCommandState.cs | Sets parser-error command states to exit code 2. |
| CosmosDBShell/Azure.Data.Cosmos.Shell.Core/OutputFormat.cs | Adds Ndjson output format enum value. |
| CosmosDBShell/Azure.Data.Cosmos.Shell.Core/ErrorCommandState.cs | Adds exit-code mapping based on exception type / Cosmos status codes. |
| CosmosDBShell/Azure.Data.Cosmos.Shell.Core/CommandState.cs | Adds ExitCode and NDJSON formatting logic; extends SetFormat to accept ndjson. |
Comments suppressed due to low confidence (1)
CosmosDBShell/Azure.Data.Cosmos.Shell.Core/CommandState.cs:70
- For an invalid format string,
SetFormatcurrently throwsShellException, which maps to exit code 1 viaErrorCommandState. Since an invalid--outputvalue is a bad-arguments case, throwing anArgumentExceptionhere will allow it to deterministically map to exit code 2.
{
throw new ShellException(MessageService.GetString("error-invalid_output_format", new Dictionary<string, object> { { "format", outputFormat } }));
}
- Handle root System.CommandLine parser errors via JSON serialization to STDERR in machine modes - Propagate COSMOSDB_SHELL_FORMAT automatically to command formatters - Ignore case on JSON/NDJSON format checks - Bypass interactive RBAC prompts in quiet/machine modes - Prevent trailing blank lines in JSON serialization output - Add integration tests for deterministic machine exit codes - Update CLI argument tables in README
|
Can you fix/comment/close the copilot issues - otherwise we can't merge. |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
CosmosDBShell/Program.cs:165
- When
--output json|ndjsonor--quietis used, this early--otelvalidation error still writes plain text to STDOUT (andShellInterpreter.WriteLinecan't honoro.Quietyet becauseShellInterpreter.Instance.Optionsis assigned later). This breaks the machine-output contract by contaminating STDOUT; emit the structured error JSON to STDERR in machine mode.
Environment.ExitCode = 2;
ShellInterpreter.WriteLine(MessageService.GetArgsString(
"otel-error-invalid-endpoint", "endpoint", o.OtlpEndpoint));
return;
}
|
I really appreciate all input but copilot is the endboss that needs to be defeated for PRs beeing mergeable :(. |
…cation scoping - Normalize the accepted --output token to lowercase in parseArgument so o.Output is always a canonical lowercase value (json, ndjson, table, csv). Previously the raw user-supplied casing was stored, making any plain equality check case-sensitive. - Hoist connectionMode and currentLocation declarations above the isQuiet guard in PrintConnectionInfoAsync so they are in scope for the JSON result dictionary regardless of quiet mode. The previous placement caused CS0841 build errors when isQuiet was true. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Only redirect stdin in RunShellAsync when stdinScript is provided. This keeps no-stdin invocations from being misclassified as machine mode via Console.IsInputRedirected and preserves expected root parser behavior. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
- Gate connect RBAC guidance behind interactive mode so quiet/machine runs do not emit interactive stdout text. - In ShellInterpreter.PrintState, treat OperationCanceledException like other machine-mode failures by emitting structured JSON to stderr instead of a warning on stdout. - Reuse a shared inMachineMode condition in the catch block. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
When --output json or --output ndjson is selected, route AnsiConsole output through TextWriter.Null using a dedicated AnsiConsoleSettings instance. This prevents accidental AnsiConsole writes from commands from polluting machine-readable stdout, while command-state output still uses Console.Out. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
- Apply startup machine-mode handling to quiet mode as well as json/ndjson. - Route startup MCP errors through structured stderr output in machine mode instead of unconditional AnsiConsole stdout writes. - Keep interactive behavior unchanged for non-machine runs. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
- Treat startup machine mode consistently for quiet/json/ndjson and suppress startup informational stdout (clear-history/theme warnings). - Route startup machine-mode errors through structured stderr JSON and return exit code 2 for invalid --mcp port argument. - In PrintState, bypass AnsiConsole markup rendering in machine mode so JSON/ text outputs always go through Console.Out. - Expand process integration coverage for implicit -c ndjson output, machine- mode clear-history behavior, and invalid --mcp port behavior. - Clarify README machine-mode wording to avoid over-promising stdout guarantees. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
@mkrueger FInally defeated the endboss 🙌🏻 |
Description (#155 )
This PR implements the deterministic machine output contract (Wave 1, P0) required for the Agentic & Automation Roadmap. It ensures that the Cosmos DB Shell can be safely consumed by downstream CI/CD pipelines, automation tools, and agentic wrappers without output corruption or ambiguous failure states.
Key Changes
--outputand--quietFlags:--output json,ndjson,table, andcsv.--quiet(-q) flag that suppresses all standard informational output (banners, connection logs, etc.).0: Success1: Generic error2: Bad arguments / Parser errors3: Auth / Connection failure4: Not found5: Throttled / RU budget exceeded--output json|ndjsonor--quietare detected, the shell now implicitly disables ANSI color code injections (ColorSystem = NoColors) to prevent STDOUT corruption.--output json|ndjsonis specified, it inherently behaves as--quietto guarantee that no interactive text logs interleave with the JSON objects.stderr:ExitCodeand emitted as a structured JSON object ({"status": "error", "error": "..."}) toSTDERRwhen in machine modes.Validation / Acceptance Criteria Met
-cand-fruns produce parseable NDJSON implicitly.%ERRORLEVEL%/$LASTEXITCODE.