Skip to content

feat(workflows): opt-in output_format: json exposes parsed shell stdout as output.data#2963

Open
doquanghuy wants to merge 2 commits into
github:mainfrom
doquanghuy:feat/2962-shell-output-format-json
Open

feat(workflows): opt-in output_format: json exposes parsed shell stdout as output.data#2963
doquanghuy wants to merge 2 commits into
github:mainfrom
doquanghuy:feat/2962-shell-output-format-json

Conversation

@doquanghuy

Copy link
Copy Markdown
Contributor

Description

Reference implementation for #2962 — for discussion, direction welcome.

Adds an opt-in output_format: json to shell steps: when declared, stdout is parsed and exposed under output.data (the raw stdout/stderr/exit_code keys are unchanged, so there is no merge/clobber ambiguity), letting later steps consume typed values — e.g. a fan-out's items: "{{ steps.emit.output.data.items }}". A parse failure fails the step with a clear error (declaring the format is a contract; silence would hide wiring bugs). Without the key, behavior is byte-identical — fully backward-compatible. validate() rejects unknown formats.

The issue lists output_file: and a declared named-outputs: schema as alternatives — happy to rework toward either if you prefer that direction.

Coordination: aware of #2443 touching the same file; this diff is isolated to the structured-output addition and I'm happy to rebase in whichever order suits.

Testing

  • Ran existing tests with uv sync && uv run pytest — full suite 3729 passed
  • Four new tests in TestShellStep: data exposed on valid JSON; invalid stdout fails the step; no-flag backcompat (no data key); validate rejects unknown formats — the three behavior tests are red against current main, green with the change (verified both directions)
  • uvx ruff check src/ — clean
  • Tested locally with uv run specify --help
  • Tested with a sample project (covered by the step-level tests)

AI Disclosure

  • I did not use AI assistance for this contribution
  • I did use AI assistance (describe below)

Code, tests, and this description were authored with AI assistance (Claude); verified by running the repo's test suite and ruff locally in both red and green directions.

…ut as output.data

No step that runs external code could hand a typed value to a later
step, so e.g. a fan-out could never consume a runtime-computed
collection. With output_format: json declared, stdout is parsed and
exposed under output.data (raw keys unchanged); a parse failure fails
the step with a clear error. Without the key, behavior is unchanged.

Reference implementation for the proposal in github#2962.

Addresses github#2962
@doquanghuy doquanghuy requested a review from mnriem as a code owner June 12, 2026 17:36
@doquanghuy

Copy link
Copy Markdown
Contributor Author

@mnriem when you have a moment, would appreciate your thoughts on the direction here — the issue lists the alternatives considered, and I'm happy to rework toward whichever shape fits Spec Kit best.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Not ready to approve

The newly added tests use shell echo quoting that is not portable to Windows cmd.exe, which will likely break the existing Windows CI matrix.

Pull request overview

Adds an opt-in structured output mode for shell workflow steps, enabling later steps to consume typed data derived from shell stdout while preserving the existing raw stdout/stderr/exit_code outputs for backward compatibility.

Changes:

  • Add output_format: json handling to ShellStep.execute() to parse stdout and expose it as output.data, failing the step on JSON parse errors.
  • Extend ShellStep.validate() to reject unknown output_format values.
  • Add unit tests covering JSON parsing success/failure, backward compatibility (no data key without the flag), and validation behavior.
File summaries
File Description
src/specify_cli/workflows/steps/shell/init.py Implements output_format: json parsing into output.data and validates allowed formats.
tests/test_workflows.py Adds TestShellStep coverage for JSON structured output and validation.

Copilot's findings

  • Files reviewed: 2/2 changed files
  • Comments generated: 3

Note

Your feedback helps us improve the quality of this feature.
Please use 👍 or 👎 to tell us whether this assessment is correct.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/test_workflows.py
Comment on lines +948 to +954
step = ShellStep()
ctx = StepContext(project_root=str(tmp_path))
config = {
"id": "emit",
"run": "echo '{\"items\": [1, 2]}'",
"output_format": "json",
}
Comment thread tests/test_workflows.py
Comment on lines +964 to +970
step = ShellStep()
ctx = StepContext(project_root=str(tmp_path))
config = {
"id": "emit",
"run": "echo not-json",
"output_format": "json",
}
Comment thread tests/test_workflows.py
Comment on lines +979 to +982
step = ShellStep()
ctx = StepContext(project_root=str(tmp_path))
config = {"id": "emit", "run": "echo '{\"items\": []}'"}
result = step.execute(config, ctx)
@mnriem

mnriem commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

Please address Copilot feedback. Please make sure to include negative and positive tests

doquanghuy added a commit to doquanghuy/spec-kit that referenced this pull request Jun 17, 2026
…ormat tests

Address review (github#2963): replace non-portable echo '{...}' (Windows cmd.exe keeps the single quotes, breaking JSON) with the established '"{py}" "{script}"' pattern using sys.executable + a temp script, so the output_format tests pass on the Windows CI matrix. Also make the validate test's run inert (exit 0).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@doquanghuy

Copy link
Copy Markdown
Contributor Author

@mnriem Thanks for the review — addressed the Copilot feedback:

  • The output_format tests now emit JSON via sys.executable + a temp script (the established '"{py}" "{script}"' pattern used elsewhere in the suite) instead of echo '{...}', so they're portable to the Windows cmd.exe CI matrix.

Full suite green; ruff check src/ clean. Ready for another look.

doquanghuy added a commit to doquanghuy/spec-kit that referenced this pull request Jun 17, 2026
…ormat tests

Address review (github#2963): replace non-portable echo '{...}' (Windows cmd.exe keeps the single quotes, breaking JSON) with the established '"{py}" "{script}"' pattern using sys.executable + a temp script, so the output_format tests pass on the Windows CI matrix. Also make the validate test's run inert (exit 0).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@doquanghuy doquanghuy force-pushed the feat/2962-shell-output-format-json branch from 1634fe9 to 4f666b9 Compare June 17, 2026 02:25
…ormat tests

Address review (github#2963): replace non-portable echo '{...}' (Windows cmd.exe keeps the single quotes, breaking JSON) with the established '"{py}" "{script}"' pattern using sys.executable + a temp script, so the output_format tests pass on the Windows CI matrix. Also make the validate test's run inert (exit 0).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@doquanghuy doquanghuy force-pushed the feat/2962-shell-output-format-json branch from 4f666b9 to 7416ae5 Compare June 17, 2026 02:29
@doquanghuy

Copy link
Copy Markdown
Contributor Author

@mnriem on the positive/negative coverage you asked for — it's in TestShellStep:

  • Positive: test_output_format_json_exposes_data — valid JSON stdout is parsed and surfaced as output.data (raw stdout/exit_code still present).
  • Negative (parse): test_output_format_json_invalid_stdout_fails — non-JSON stdout fails the step with an output_format: json error.
  • Negative (validation): test_validate_rejects_unknown_output_format — a non-json output_format is rejected at validate time.
  • Back-compat: test_no_output_format_keeps_raw_output_only — no output_format ⇒ no data key.

All four emit any JSON via sys.executable now (cross-platform). Happy to add more cases if you'd like a specific one covered.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants