feat: output json integration - #9172
Conversation
…able output Add a --output option to `sam build` that supports "text" (default, unchanged behavior) and "json" (structured output for programmatic consumers). When --output json is specified: - Success output is a JSON object with status, build_dir, template_file, and a resources array listing each built function's logical_id, runtime, and architecture. - Error output is a JSON object with status, error type, message, and the failing resource name when available. - Build progress logs are suppressed from stdout (sent to stderr only) so that stdout contains only valid JSON. This enables CI/CD pipelines, IDE extensions, and AI-assisted developer tools to consume build results programmatically without fragile text parsing.
- Replace sys.exit(1) with raise UserException in error handlers to
preserve telemetry tracking via @track_command decorator
- Wrap both container and in-process build paths in try/except so
resource_name is tagged on BuildError regardless of build mode
- Include layers in JSON success output alongside functions
- Rename field from logical_id to resource_id (accurate for nested stacks)
- Add type field ("function" or "layer") to each resource entry
Move the try/except BuildError from app_builder._build_function (which only covered the ZIP in-process path) to DefaultBuildStrategy's build_single_function_definition and build_single_layer_definition. This ensures resource_name is tagged for ALL build paths: - ZIP functions (in-process and container) - IMAGE functions (Docker builds) - Layer builds Known limitation: BuildInsideContainerError does not inherit from BuildError (it inherits from Exception directly), so it won't get resource_name tagged by this mechanism. Fixing this would require changing the exception hierarchy which is out of scope for this PR. The error type and message are still present in JSON output for this case — only the resource field is missing. Also fixes unit test assertion to expect the new output="text" kwarg.
… types Expand the except clause in DefaultBuildStrategy to also catch UnsupportedRuntimeException, BuildInsideContainerError, and UnsupportedBuilderLibraryVersionError. These exceptions don't inherit from BuildError but can originate from a specific function build (deprecated runtime, Docker pull failure, missing builder in container). Uses dynamic attribute assignment (ex.resource_name = ...) since these classes don't define resource_name in __init__. The consumer in build_context.py already uses getattr(ex, "resource_name", None) which handles both cases safely.
- Apply black formatting to command.py and build_strategy.py - Fix ruff import ordering in build_strategy.py - Add type: ignore comments for mypy union-attr and index errors (dynamic resource_name assignment on non-BuildError exceptions) - Regenerate schema/samcli.json to include the new --output parameter
Add --output json option to sam deploy that emits newline-delimited JSON (NDJSON) streaming output instead of human-formatted tables. Each deploy stage emits structured JSON lines in real-time as CloudFormation events arrive, preventing process timeouts during long-running deployments. Line types emitted: - changeset: one per resource change (action, logical_id, resource_type) - event: streaming CFN stack events during deploy - outputs: stack outputs after completion - result: final status line (SUCCESS/FAILED/NO_CHANGES/CHANGESET_CREATED)
Ensures stdout is pure NDJSON when --output json is used by: - Forcing no_progressbar=True on both PackageContext and DeployContext S3 uploaders, preventing upload progress lines from leaking to stderr - Raising samcli logger to WARNING level to suppress LOG.info messages
…eaming Thread output_mode=self.output_mode through the two describe_stack_events calls in rollback_delete_stack, preventing table-formatted text from leaking into the NDJSON stream during failure/rollback scenarios.
When --output json and --confirm-changeset are both set, emit a structured result line with status CONFIRMATION_REQUIRED and return without executing, instead of silently skipping the confirmation and proceeding with the deploy.
Move the FAILED result line to after rollback_delete_stack finishes, ensuring the result record is always the last line in the NDJSON stream. Previously it was emitted before rollback, causing event records to appear after the terminal result line.
Redirect stdout to /dev/null while manage_stack() runs in JSON mode,
preventing its click.echo calls ("Creating the required resources...",
"Successfully created!") from corrupting the NDJSON stream.
…s JSON
- Raise UsageError when --guided and --output json are combined, since
guided mode requires interactive prompts incompatible with JSON output.
- Emit {"type": "warning", "message": "no authentication", "resource": ...}
instead of silently dropping the auth warning in JSON mode.
- Move --output into a shared @output_option decorator in _utils/options.py so deploy/init can reuse it instead of redeclaring the option - Give --output its own "Output Options" help group rather than filing it under Build Strategy, which is for options that change how the build runs - Extract the JSON/text reporting out of BuildContext.run() into _print_build_success and _print_build_failure - Collect get_resources_to_build() once in run() and reuse it - Always emit the "resource" key in error output (null when the failure is not attributable to a single resource) so the schema is predictable - Hoist the wrapped_from lookup to the top of the except block instead of computing it in both branches - Drop the unused resource_name param from BuildError; build_strategy sets the attribute at runtime for all handled exception types
Cover _print_build_success and _print_build_failure across JSON and text modes: resource list shapes for functions/layers, architecture edge cases, the always-present "resource" error key, error-type passthrough, and the text-banner suppression path. 23 tests following the existing TestBuildContext_<method> convention.
- Rename output helpers to structured_output_option (avoid shadowing list command) - Use OutputOption enum instead of string literals - Emit JSON error for InvalidBuildDirException; soften "always present" comment - Single-line JSON (remove indent=2) - Add resource_name class attribute to all 4 build exception types, drop type: ignore - Add end-to-end run() JSON test; remove 6 redundant helper tests - Use function.architecture (resolves x86_64 default) instead of architectures[0] - Route interactive prompts to stderr (err=True) so stdout stays pure JSON
Move all --output json failure serialization to a single except UserException handler in do_cli, covering every failure path uniformly (missing layer BuildMethod, invalid build dir, pre-processing errors) instead of only the exception types caught inside run(). - Add build_failure_json() helper in build_context as the single source of truth for the failure wire format - do_cli uses the helper and checks OutputOption(output) is OutputOption.json (enum, not raw string literal) - run() only prints the text "Build Failed" banner and re-raises UserException carrying resource_name; no double-emit - Add resource_name class attribute to UserException - Move JSON failure tests to test_command.py (do_cli level); simplify _print_build_failure tests to text-banner only
- Merge two near-identical "stays silent" tests into one parameterized test - Use OutputOption enum instead of raw "text"/"json" strings so the tests match how the real code sets _output (via enum conversion in __init__), removing a latent fragility where raw strings passed only by coincidence
UnsupportedBuilderException (raised for an invalid Metadata.BuildMethod, e.g. a template typo) subclasses plain Exception, so it escaped both run()'s except tuple and do_cli's UserException handler - exiting 1 with empty stdout in --output json. - Add it to run()'s except tuple so it converts to UserException and routes through build_failure_json, matching its sibling UnsupportedRuntimeException - Add it to the DefaultBuildStrategy except tuples so resource_name is attributed - Add resource_name class attribute (Comment aws#5 pattern) - Extend test_must_catch_known_exceptions to cover it
…ilures Failure paths that know exactly which resource failed were reporting "resource": null in --output json: - FunctionNotFound handler had a dead _print_build_failure(print_text_banner=False) no-op and a getattr that FunctionNotFound never carries. Both failure handlers now fall back to self._resource_identifier, so sam build <bad-name> reports that name. - MissingBuildMethodException (raised from _collect_single_buildable_layer, a UserException) was not in run()'s except tuple, so it reached do_cli with no resource attribution. Added it; the layer name now populates via the fallback. Tests: use OutputOption.text (not the raw string) in the two success-path text-mode tests so they actually exercise the enum comparison, and assert resource_name fallback in test_must_catch_known_exceptions.
…comment - Extend the try in _setup_build_dir to cover shutil.rmtree, not just mkdir. An OSError while clearing the build dir (permission denied, file held open on Windows) now surfaces as InvalidBuildDirException -> JSON error, instead of a bare OSError that exits 1 with empty stdout in --output json. - Soften the do_cli handler comment: it covers user-facing failures, not "every failure path"; note that an unexpected internal error (bare Exception) is not serialized. - Add test_rmtree_oserror_is_converted_to_invalid_build_dir.
… param - Change do_cli's except UserException to except Exception so every build-path failure emits a JSON document, including bare-Exception template errors (InvalidLayerReference, RemoteStackLocationNotSupported, MissingCodeUri, InvalidTemplateFile) that are not UserException subclasses. Re-raises unconditionally so @track_command still records telemetry and wraps non-UserException as UnhandledException. - Drop the now-dead print_text_banner parameter from _print_build_failure; no caller passes False since the FunctionNotFound handler stopped calling it. - Add test_json_failure_for_bare_exception; simplify the silence test.
process_env_var and process_image_options ran outside the try, so an InvalidImageException from a malformed --build-image (e.g. --build-image MyFunc=) exited 1 with empty stdout in --output json. Moving both inside the try routes them through the central JSON failure handler.
The three comments claimed do_cli's handler serializes "every error reachable from the build". That is only true for execution failures once do_cli runs. Errors raised during click option processing (invalid flags, or a --hook-name prepare-hook failure re-raised by track_command) occur before do_cli and surface as click's standard usage/stderr output, not JSON. Soften the three comments to state the guarantee covers execution failures and note that invocation errors surface via click's stderr, so consumers treat "exit != 0 with empty stdout" as an invocation error. No behavior change.
…ailures - Add package_type to each function in the JSON success document so Image functions (runtime: null) are distinguishable from Zip, via a new _function_to_json helper. - Restrict the resource_name fallback: InvalidBuildGraphException and UnsupportedBuilderLibraryVersionError are not resource-specific, so they keep resource=None instead of being attributed to whatever resource the user named. - Document that error.resource is a representative id when functions share a build definition (points to get_resource_full_paths for the full set). - Tests: package_type for image functions; per-type resource_name expectations.
The JSON success document reports resources[].resource_id as the resource's full_path (nested-stack-qualified, e.g. ChildStack/MyFn), but the failure fallback reported the raw CLI identifier (MyFn). Consumers could not correlate a failure back to the resource_id they saw on success. Add _resolve_resource_full_path(), which looks the identifier up via the same function/layer providers the success document uses and returns its full_path, falling back to the raw identifier only when lookup fails. Both fallback paths (FunctionNotFound and the general handler) now route through it.
The comment pointed JSON consumers at get_resource_full_paths() as an escape hatch for the full set of collapsed functions, but that method is internal and nothing in the failure document exposes it. Naming one representative is the deliberate contract — error.resource is a single value. Update the comment to say so and stop describing an escape hatch that does not exist for this output.
…on, trim comment - Remove the samcli-logger WARNING override in deploy JSON mode. It defeated --debug and was never needed for stdout purity since log handlers write to stderr. - Reject --confirm-changeset with --output json up front in do_cli. Previously it emitted CONFIRMATION_REQUIRED and exited 0 without deploying, a silent no-op that CI could mistake for success (confirm_changeset is persisted by --guided). Add tests for this and the existing --guided guard. - Trim the oversized do_cli failure-handler comment in build/command.py to the essential rationale.
PackageContext.run() runs before DeployContext and printed the preview-runtime warning to stdout, which would corrupt the deploy JSON lines a consumer parses. Give PackageContext an output mode and send that warning to stderr when output is JSON, keeping stdout pure. Text mode is unchanged. Add a test for the stderr routing (mutation-verified) and update the do_cli PackageContext assertion. Note: a second preview-style warning in language_extensions_packaging.py is a module-level function without output-mode access and only fires on the --language-extensions path; left as a follow-up.
Functions sharing a runtime, CodeUri, and metadata collapse into one build definition, so a single build failure can affect several of them. The failure document reported only the first (error.resource, a string), hiding the others from consumers. Change the attribution to a list end to end: resource_name (Optional[str]) -> resource_names (Optional[List[str]]) on UserException and the five lib build exceptions; the build-strategy tagging now records every function in the definition; build_failure_json emits error.resources (array); and _resolve_resource_full_paths returns a single-element list for the CLI-arg fallback. A corrupt build graph stays resource_names=None. Tests updated, including a two-function case that fails if only the first is reported.
…stderr in JSON
Two review findings on the deploy JSON stream:
- Most deploy failures emitted no terminal result line (e.g. an empty changeset
with the default --fail-on-empty-changeset, an invalid template, or a
packaging error), so a consumer could not tell failure from a truncated
stream. Wrap the package+deploy sequence in do_cli with a broad handler that
emits {type:result,status:FAILED,error} in JSON mode and re-raises, mirroring
build's central failure serialization. Per-step handlers keep their specific
statuses.
- warn_parameter_based_collections printed to stdout during the deploy package
step, corrupting the JSON lines for Fn::ForEach parameter-collection
templates. Thread a to_stderr flag from PackageContext so it routes to stderr
in JSON mode; non-JSON callers are unchanged.
Both mutation-verified.
There was a problem hiding this comment.
Code Review Results
Reviewed: 9101836..c920b9b
Files: 18 of 27 (9 unit-test files skipped per single-pass scope; schema/samcli.json is generated)
Comments: 3
Comments on lines outside the diff:
[samcli/commands/deploy/command.py:348] [BUG] The comment on the new handler states the intent as "Guarantee the JSON-lines stream always ends with a terminal result object," but the try starts after the S3/ECR resolution block, so failures there still produce an entirely empty stdout stream with no result line:
- raise DeployResolveS3AndS3SetError() when both --resolve-s3 and --s3-bucket are given (line 348).
- manage_stack(...) failures inside the redirect_stdout block — e.g. no permission to create/update aws-sam-cli-managed-default. Note the redirect also swallows the underlying progress text, so stdout is empty either way.
- _resolve_image_repositories(...) failures with --resolve-image-repos.
These are ordinary permission/argument errors, not edge cases, and they are exactly the paths the previous round flagged as indistinguishable from a truncated stream. Moving the try to enclose the resolution block (it is already after the guided/confirm_changeset usage checks, which should stay outside as Click usage errors) would make the guarantee actually hold.
The DeployFailedError handler in deploy_context emitted a FAILED result line and then re-raised. With the new terminal-result handler in do_cli, that re-raise produced a SECOND FAILED line, so a JSON consumer saw the failure twice. Remove the now-redundant emit from the handler (do_cli owns the single terminal line); keep the rollback side-effect and the re-raise. Add a regression test asserting the context emits no result line for DeployFailedError, mutation-verified.
…g caller Follow-ups on the deploy JSON contract: - The terminal-result handler opened after the --resolve-s3/--resolve-image-repos block, so a bucket/ECR resolution failure (common in CI) exited non-zero with zero JSON lines. Move do_cli's try above the guided/else block so those failures also emit the terminal FAILED result. Guided/confirm rejections stay above the try, so their behavior is unchanged. - warn_parameter_based_collections had two callers but only the PackageContext one received the to_stderr flag; the child-template export path still wrote to stdout. Route the warning to stderr unconditionally (it is an advisory already recorded via LOG.debug, matching the telemetry and version-check notices) and drop the flag plumbing, fixing both callers. Both mutation-verified.
…dout The @unsupported_command_cdk decorator (on deploy, package, sync, validate) wrote its 'CDK apps are not officially supported' warning to stdout. It runs before do_cli, so sam deploy --output json on a CDK-synthesized template leaked one or two plain-text lines ahead of the JSON stream, breaking a per-line json.loads consumer. Route both advisory lines to stderr (err=True), matching how the other package/preview warnings and SAM's telemetry/version notices already behave. Update the decorator tests to assert the stderr routing.
There was a problem hiding this comment.
Code Review Results
Reviewed: 9101836..210d51a
Files: 18 of 29 (10 unit-test files skipped per single-pass scope; schema/samcli.json is generated)
Comments: 3
All previously raised comments appear addressed in this revision: the blanket handler in do_cli now opens before S3/ECR resolution, the duplicate result line on DeployFailedError is gone, confirm_changeset + --output json is rejected up front, the logger downgrade is removed, and the remaining stdout writers (cdk_support_decorators, warn_parameter_based_collections, _warn_preview_runtime, prompt_experimental, build/utils.prompt) now go to stderr. I traced the deploy path (manage_stack, sync_ecr_stack, PackageContext.run, Template.export, S3Uploader/ECRUploader, Deployer) and found no remaining unconditional stdout writes in JSON mode.
…inator Three review findings on the JSON contract: - build JSON reported build_dir/template_file as cwd-relative (and Windows flipped relative<->absolute on the ValueError fallback). Emit absolute paths in JSON; apply the relpath human-readability transform only in the text banner. - deploy --express SUCCESS was byte-identical to a settled deploy, so a consumer could not tell the stack may still be stabilizing. Add "express" to the SUCCESS payload. - build and deploy emitted incompatible result schemas (build: lowercase status, no type; deploy: uppercase status, type:result). Align on one convention: lowercase status everywhere plus a type discriminator on every document. Add type to build's success and failure documents; lowercase deploy's statuses. Tests updated on both sides to assert the shared shape; new tests for absolute paths, text-mode relpath, and the express flag.
There was a problem hiding this comment.
Code Review Results
Reviewed: 9101836..48bfe7e
Files: 18 of 29 (10 unit-test files skipped per single-pass scope; schema/samcli.json is generated)
Comments: 2
Verified as addressed in this revision: the blanket handler in do_cli now opens before S3/ECR resolution, the duplicate result line on DeployFailedError is gone, --confirm-changeset + --output json is rejected up front, the logger downgrade is removed, build_dir/template_file are now absolute, the express stabilization caveat is carried as an express field, and the remaining stdout writers (_warn_preview_runtime, warn_parameter_based_collections, unsupported_command_cdk, progress bars, manage_stack) are on stderr, suppressed, or discarded in JSON mode.
Two more shared-contract findings:
- deploy's failure result still diverged from build: status "failed" with a
bare-string error vs build's status "failure" with a structured error object.
Align deploy on build's shape - status "failure" and
error: {type: type(ex).__name__, message: str(ex)} - so a consumer handles
both commands with one code path.
- --resolve-s3 --output json discarded the auto-resolved bucket name (its
progress output is redirected to devnull and print_managed_s3_bucket_info is
skipped). Emit it as a {type: info, managed_s3_bucket: ...} stream line so a
CI consumer can learn where its artifacts went.
Both mutation-verified.
There was a problem hiding this comment.
Code Review Results
Reviewed: 9101836..b1fe047
Files: 18 of 29 (10 unit-test files skipped per single-pass scope; schema/samcli.json is generated)
Comments: 2
Verified as addressed in this revision: the blanket handler in do_cli now opens before S3/ECR resolution, the duplicate result line on DeployFailedError is gone, --confirm-changeset + --output json is rejected up front, the logger downgrade is removed, build_dir/template_file are absolute, the express caveat is carried as "express": bool, the resolved --resolve-s3 bucket is surfaced as an info line, and the two commands now share type: "result" with lowercase statuses. The remaining stdout writers on the deploy path (_warn_preview_runtime, warn_parameter_based_collections, unsupported_command_cdk, manage_stack, progress bars) are now either on stderr, redirected, or suppressed — I traced the packaging/build paths (s3_uploader, ecr_uploader, app_builder, companion_stack_manager, version_checker) and found no remaining ungated stdout writes.
Two robustness findings: - The confirmation_required JSON branch in deploy_context was unreachable: do_cli rejects --confirm-changeset with --output json up front, and sync (the only other DeployContext caller) never enables JSON, so confirm_changeset and JSON output cannot co-occur. Delete the branch (and its defense-in-depth test) so the status vocabulary carries no case a consumer can never see, and the real guard's location is not obscured. - The pprint_column_names decorator silently fell through to table output for any output_mode it did not recognize, which would corrupt a JSON stream on a typo. Validate against OutputOption values and raise on anything unexpected. Both mutation-verified.
Reduce test bloat without losing coverage: - Merge the two deploy interactive-flag rejection tests (confirm-changeset, guided) into one, since both assert the same UsageError. - Parameterize the two build architecture-reporting tests (absent -> x86_64, explicit arm64) into one. - Drop the standalone TestWarnParameterBasedCollections stderr test that duplicated coverage now folded into the existing emits_warning test (which gained an err=True assertion). Distinct-path tests (the three build failure paths, the experimental-flag cases) are left separate on purpose - they exercise different branches. Net -29 test lines, all suites green.
Deployer was the only participant that handled output mode as a bare string, comparing the literal "json" in five places while every other module converts once to OutputOption. That divergence was reachable via the public constructor: DeployContext(output=OutputOption.json) gave the context the enum member but left Deployer comparing that member against "json" (always false), so text output would interleave with the JSON stream. Latent today (live callers pass the click-normalized string) but exactly what the enum exists to prevent. Convert at the boundary: __init__ stores OutputOption(output_mode), which raises on an unrecognized value instead of silently degrading to table output; the self.output_mode comparisons use ; the two decorated methods still receive the string via kwargs (.value at the call site) so the shared table_print decorator stays string-based. DeployContext now forwards the enum and no longer keeps a redundant raw self.output. Tests added for default, string normalization, enum passthrough, and invalid-value raise.
There was a problem hiding this comment.
Code Review Results
Reviewed: 9101836..3615a41
Files: 18 of 30 (11 unit-test files skipped per single-pass scope; schema/samcli.json is generated)
Comments: 2
Previously raised items verified as addressed in this revision: the blanket handler in do_cli now opens before S3/ECR resolution, the duplicate result line on DeployFailedError is gone, --confirm-changeset + --output json is rejected up front (and --no-confirm-changeset exists as an override), the logger downgrade is removed, build_dir/template_file are absolute, the express caveat is carried as "express": self.express, the resolved bucket is surfaced as an info line instead of discarded, Deployer normalizes the mode to OutputOption at the boundary, warn_parameter_based_collections and the CDK advisory now go to stderr on all paths, and the terminal result vocabulary/error shape now line up between build and deploy.
Skipping the mount-with-write prompt in JSON mode silently proceeded READ-only, but that is not a viable default for workflows that REQUIRE a writable mount: DOTNET_CLIPACKAGE_CONFIG (must_mount_with_write_in_container=True) writes build artifacts into the source directory. A .NET container build with --output json therefore failed later inside the container with a cryptic permission error and a status:failure document that never mentioned the fix. Factor the must_mount_with_write detection out of prompt_user_to_enable_mount_with_write_if_needed into resource_requiring_mount_with_write. In JSON mode, if a resource requires a writable mount, raise a UserException naming the source dir and instructing --mount-with WRITE; other workflows still use the READ-only default. Text mode keeps the interactive prompt. Tests added, mutation-verified.
There was a problem hiding this comment.
Code Review Results
Reviewed: 9101836..32fdce3
Files: 18 of 30 (11 unit-test files skipped per single-pass scope; schema/samcli.json is generated)
Comments: 1
Previously raised items verified as addressed in this revision: the blanket handler in do_cli now opens before S3/ECR resolution and covers every failure path; the duplicate result line on DeployFailedError is gone; --confirm-changeset + --output json is rejected up front and the unreachable confirmation_required status is removed; the logger downgrade is gone; build_dir/template_file are absolute; the express stabilization caveat is carried as "express": self.express; the resolved bucket is surfaced as an info line instead of being discarded; Deployer and the table decorator now normalize/validate the mode instead of comparing bare strings; warn_parameter_based_collections, _warn_preview_runtime, the CDK notice, and the two interactive prompts all write to stderr; and the mount-with-write skip now fails with an actionable UserException. I also checked the remaining stdout writers reachable from sam deploy/sam build (manage_stack, S3Uploader, ECRUploader, ApplicationBuilder's stream writer, PackageContext.run, version_checker) — all are either gated, redirected, or already stderr-bound.
Text mode always reports the changeset id (MSG_SHOWCASE_CHANGESET), but in JSON mode result["Id"] only reached stdout on the --no-execute-changeset path. On a normal executed deploy the terminal success line carried only stack_name, region, and express, so a consumer could not link to the changeset in the console, re-describe it, or correlate the changeset stream lines with a CFN API call. Add changeset_id to the success result line.
There was a problem hiding this comment.
Code Review Results
Reviewed: 9101836..9aa2d69
Files: 18 of 30 (11 unit-test files skipped per single-pass scope; schema/samcli.json is generated)
Comments: 1
Previously raised items verified as addressed in this revision: the blanket handler in do_cli now opens before S3/ECR resolution and covers every failure path; the duplicate result line on DeployFailedError is gone; --confirm-changeset + --output json is rejected up front and the unreachable confirmation_required status is removed; the samcli logger downgrade is gone; build_dir/template_file are absolute; the express caveat and changeset_id are now in the JSON result; the resolved managed bucket is surfaced as an info line instead of discarded; warn_parameter_based_collections, _warn_preview_runtime, unsupported_command_cdk, prompt_experimental and the mount-with-write prompt all write to stderr now; the mount-with-write case fails with an actionable UserException rather than silently downgrading; Deployer normalizes output_mode to OutputOption at the boundary; table_print validates the mode; and the build/deploy terminal result objects now share type, lowercase status, and the error: {type, message} shape.
Text mode surfaces CloudFormation's DetailedStatus (e.g. CONFIGURATION_COMPLETE, VALIDATION_FAILED) appended to the status; the JSON event line dropped it. A consumer saw several indistinguishable CREATE_IN_PROGRESS events for one resource and, worse, lost VALIDATION_FAILED on failure paths - the case where it matters most. Carry it as its own key (null when CFN omits it) so status stays a clean enum. Adds the first JSON-mode test for describe_stack_events, covering both the present and absent cases; mutation-verified.
reedham-aws
left a comment
There was a problem hiding this comment.
I only reviewed the build part, but that looks pretty good to me from a logic point of view. I do think some of the inline comments are kind of long and hard to read, so maybe that could use some cleanup. Sorry to be nitpicky on the comments, overall, great work! I will review the deploy part later.
Add
--output jsonto sam build and sam deployOverview
--output jsonflag to both sam build and sam deploy.OutputOptionenum.Important clarification on output shape
typefield.Shared result contract (both commands)
type: "result"and a lowercasestatus.status: "failure"witherror: {type, message}.error.resources(the affected resources), which is additive.sam build files
samcli/commands/build/command.py--outputflag and threads it into do_cli.samcli/commands/build/build_context.pysamcli/commands/build/utils.pysamcli/lib/build/build_strategy.pysamcli/lib/build/exceptions.pyandsamcli/lib/build/workflow_config.pyresource_nameslist attribute to the build exception classes.samcli/commands/build/core/options.pysam deploy files
samcli/commands/deploy/command.py--outputflag as build.--guidedand--confirm-changesetwith JSON up front.--resolve-s3in JSON mode.{type: info}line.samcli/commands/deploy/deploy_context.py{type: warning}lines.samcli/lib/deploy/deployer.pysamcli/commands/deploy/core/options.pyShared and support files
samcli/commands/_utils/options.py--outputflag decorator.samcli/commands/_utils/table_print.pysamcli/commands/_utils/cdk_support_decorators.pysamcli/commands/package/package_context.pysamcli/lib/package/language_extensions_packaging.pysamcli/commands/exceptions.pyresource_namesattribute to the base UserException.Testing
make prpasses and coverage stays above the required bar.