Skip to content

Fix action summary for structured output#485

Open
GautamBytes wants to merge 3 commits into
Gitlawb:mainfrom
GautamBytes:fix/action-stream-json-summary
Open

Fix action summary for structured output#485
GautamBytes wants to merge 3 commits into
Gitlawb:mainfrom
GautamBytes:fix/action-stream-json-summary

Conversation

@GautamBytes

@GautamBytes GautamBytes commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Fixes #483. The action now reads final/error events for structured output instead of tailing run metadata.

Summary by CodeRabbit

  • New Features

    • Improved one-line summary generation using a structured-output-aware approach, with safer fallback when structured parsing isn’t possible.
    • The action now provides an ACTION_PATH environment variable during runtime.
    • Added a command-line summary helper to generate summaries directly from output files.
  • Bug Fixes

    • Correctly prefers the most relevant structured event (including later error events) instead of relying on the last captured non-empty line.
  • Tests

    • Expanded test coverage for JSON/streamed/text modes, malformed structured input, truncation/normalization, and both CLI invocation styles.

Copilot AI review requested due to automatic review settings July 4, 2026 12:37

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.

Pull request overview

This PR fixes the GitHub Action summary output for structured formats (stream-json / json) by extracting the assistant’s terminal content (final/error) instead of emitting trailing lifecycle metadata (run_end / done), addressing issue #483.

Changes:

  • Add scripts/action-summary.mjs to compute a best-effort, single-line, 280-char summary from captured output (structured-aware parsing).
  • Add a Node test suite validating summary extraction behavior across formats and CLI invocation.
  • Update action.yml to call the new summarizer script rather than tailing the output file.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
scripts/action-summary.test.mjs Adds unit tests and a CLI integration test for summary extraction across output formats.
scripts/action-summary.mjs Implements structured-output parsing to return final/error text instead of lifecycle JSON.
action.yml Switches action output summarization to the new Node summarizer script and wires in github.action_path.

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

Comment thread scripts/action-summary.mjs Outdated
Comment thread scripts/action-summary.mjs Outdated
Comment thread scripts/action-summary.test.mjs
@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d070830d-395a-4912-8336-4e49c86ea1cd

📥 Commits

Reviewing files that changed from the base of the PR and between 25030f4 and 57dcd94.

📒 Files selected for processing (1)
  • action.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • action.yml

Walkthrough

Adds a Node-based summary extractor for ZERO output, updates the GitHub Action to call it, and expands tests for structured output ordering, fallback behavior, truncation, and CLI invocation.

Changes

Action summary extraction fix

Layer / File(s) Summary
summarizeOutput implementation and CLI entrypoint
scripts/action-summary.mjs
New module exporting summarizeOutput(format, contents), which parses newline-delimited JSON events or falls back to last-line extraction, truncates the result, and supports direct CLI execution reading a file path argument.
Wire action.yml to use new summary script
action.yml
Adds ACTION_PATH environment variable to the Run ZERO step and replaces grep/tail-based summary extraction with a node invocation of scripts/action-summary.mjs using ZERO_INPUT_OUTPUT_FORMAT and output_file.
Unit and CLI tests for summarizeOutput
scripts/action-summary.test.mjs
Test suite covering stream-json and json event ordering, text and unknown-format fallback, malformed input handling, truncation to 280 characters, and CLI integration tests for absolute and relative invocation.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant RunZeroStep as action.yml Run ZERO step
  participant Node
  participant ActionSummary as action-summary.mjs

  RunZeroStep->>Node: node scripts/action-summary.mjs output_file
  Node->>ActionSummary: read output_file, call summarizeOutput(format, contents)
  ActionSummary->>ActionSummary: parse NDJSON events for final/error event
  ActionSummary-->>Node: return truncated one-line summary
  Node-->>RunZeroStep: write summary to stdout
Loading

Related issues: #483

Suggested labels: bug, github-actions

Suggested reviewers: none identified

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: fixing summary handling for structured output.
Linked Issues check ✅ Passed The changes address #483 by extracting final assistant text for stream-json/json summaries and preserving best-effort fallback behavior.
Out of Scope Changes check ✅ Passed The PR stays focused on summary extraction logic and tests, with no clear unrelated code changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

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

Caution

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

⚠️ Outside diff range comments (1)
action.yml (1)

246-260: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Guard the summary command from failing the step action.yml:253set -e is active here, so a non-zero node exit will abort before GITHUB_OUTPUT is written and before exit "${code}" runs, replacing the real ZERO status with the summary helper’s failure. Wrap this call in set +e/set -e (or equivalent) and fall back to an empty summary.

🤖 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 `@action.yml` around lines 246 - 260, The summary generation in the
`action.yml` step can terminate the whole script because `set -e` is enabled,
which prevents writing to `GITHUB_OUTPUT` and exiting with the intended `code`.
Update the `summary="$(node ...)"` section in the step that writes `exit-code`,
`output-file`, and `summary` so the `action-summary.mjs` call is run with error
handling disabled temporarily (or equivalent), then restore `set -e` and use an
empty summary fallback if the helper fails.
🧹 Nitpick comments (1)
action.yml (1)

253-253: 🧹 Nitpick | 🔵 Trivial

New hard dependency on node being present on the runner.

Previously the summary extraction used only bash/grep/tail. This now requires a node binary on PATH. GitHub-hosted runners ship Node, but self-hosted runners (which this composite action doesn't otherwise preclude) may not have it installed — combined with the set -e issue above, a missing node would fail the whole step. Consider documenting this new requirement (e.g., README/action description) or guarding with a command -v node check.

🤖 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 `@action.yml` at line 253, The summary extraction step in action.yml now
hard-depends on the node binary via action-summary.mjs, so update the composite
action to handle missing Node on self-hosted runners by adding a command -v node
guard or an equivalent fallback before invoking node in the summary assignment,
and also document this requirement in the action description or README so users
know node must be available on PATH.
🤖 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.

Outside diff comments:
In `@action.yml`:
- Around line 246-260: The summary generation in the `action.yml` step can
terminate the whole script because `set -e` is enabled, which prevents writing
to `GITHUB_OUTPUT` and exiting with the intended `code`. Update the
`summary="$(node ...)"` section in the step that writes `exit-code`,
`output-file`, and `summary` so the `action-summary.mjs` call is run with error
handling disabled temporarily (or equivalent), then restore `set -e` and use an
empty summary fallback if the helper fails.

---

Nitpick comments:
In `@action.yml`:
- Line 253: The summary extraction step in action.yml now hard-depends on the
node binary via action-summary.mjs, so update the composite action to handle
missing Node on self-hosted runners by adding a command -v node guard or an
equivalent fallback before invoking node in the summary assignment, and also
document this requirement in the action description or README so users know node
must be available on PATH.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f35b5206-2f0c-45a2-a9ee-1a562801b4fe

📥 Commits

Reviewing files that changed from the base of the PR and between 949ee43 and f391cec.

📒 Files selected for processing (3)
  • action.yml
  • scripts/action-summary.mjs
  • scripts/action-summary.test.mjs

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

🧹 Nitpick comments (1)
scripts/action-summary.test.mjs (1)

101-148: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicate CLI spawn/assert scaffolding across absolute- and relative-path tests.

The relative-path test (124-148) repeats the mkdtemp/write/spawnSync/assert/cleanup boilerplate from the absolute-path test (101-123), differing only in the script path argument and cwd. Extracting a small helper (e.g., runCli(scriptArg, { cwd })) would reduce duplication without losing clarity.

♻️ Suggested helper extraction
+function runCli(scriptArg, expectedSummary, { cwd } = {}) {
+  const dir = mkdtempSync(join(tmpdir(), 'zero-action-summary-'));
+  try {
+    const outputFile = join(dir, 'zero-output.jsonl');
+    writeFileSync(
+      outputFile,
+      jsonl([
+        { type: 'final', text: expectedSummary },
+        { type: 'run_end', status: 'success', exitCode: 0 },
+      ]),
+    );
+    const result = spawnSync(process.execPath, [scriptArg, 'stream-json', outputFile], {
+      cwd,
+      encoding: 'utf8',
+    });
+    assert.equal(result.status, 0);
+    assert.equal(result.stderr, '');
+    assert.equal(result.stdout, `${expectedSummary}\n`);
+  } finally {
+    rmSync(dir, { recursive: true, force: true });
+  }
+}
🤖 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 `@scripts/action-summary.test.mjs` around lines 101 - 148, The two CLI tests
duplicate the same mkdtempSync/writeFileSync/spawnSync/assert/cleanup flow in
action-summary.test.mjs; extract that repeated setup into a small helper (for
example, around scriptPath, spawnSync, and the shared assertions) and call it
from both the absolute-path and relative-path tests. Keep the helper flexible
for the only differences: the script argument passed to process.execPath and the
optional cwd for the relative-path case.
🤖 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.

Nitpick comments:
In `@scripts/action-summary.test.mjs`:
- Around line 101-148: The two CLI tests duplicate the same
mkdtempSync/writeFileSync/spawnSync/assert/cleanup flow in
action-summary.test.mjs; extract that repeated setup into a small helper (for
example, around scriptPath, spawnSync, and the shared assertions) and call it
from both the absolute-path and relative-path tests. Keep the helper flexible
for the only differences: the script argument passed to process.execPath and the
optional cwd for the relative-path case.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: cd01c752-558e-4074-8b01-92acf5328d4b

📥 Commits

Reviewing files that changed from the base of the PR and between f391cec and 25030f4.

📒 Files selected for processing (2)
  • scripts/action-summary.mjs
  • scripts/action-summary.test.mjs
🚧 Files skipped from review as they are similar to previous changes (1)
  • scripts/action-summary.mjs

@Vasanthdev2004 Vasanthdev2004 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Core fix is right — reading the final/error events instead of tailing metadata matches the event schema, and the tests cover the #483 case well.

One thing to fix first: the new summary line in action.yml runs under set -e without the || true the old grep/tail line had. If node exits non-zero — module not found, or no node on a self-hosted runner — the summary="$(node ...)" assignment aborts the step before it writes the output and before exit "${code}", so the step reports the helper's failure instead of Zero's real exit code. It won't fire on GitHub-hosted runners where node's always there, but it's a real drop in defensiveness. Append || true (or wrap the call in set +e/set -e). CodeRabbit flagged the same one.

Fix that and it's good to go.

@GautamBytes

Copy link
Copy Markdown
Contributor Author

done @Vasanthdev2004

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@kevincodex1 kevincodex1 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.

LGTM

@kevincodex1

Copy link
Copy Markdown
Contributor

please have a look again @Vasanthdev2004

@Vasanthdev2004 Vasanthdev2004 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-reviewing — my one blocker is fixed. The summary line has the || true now, so a node failure (missing module, no node on a self-hosted runner) degrades to an empty summary instead of aborting the step under set -euo pipefail, and ACTION_PATH is wired so the script actually resolves.

The core fix is right and I checked it holds: summarizeStructured walks the stream-json events and takes the last final event's text (or an error event's message) rather than tailing the last line — which was the run_end lifecycle metadata #483 was showing. Non-structured output keeps the old last-line behavior, both paths stay bounded at 280, and it falls back to the last non-empty line if no final/error event is present. The dedicated action-summary.test.mjs covers it, and CI is green including the action.yml validation.

Marked #483 issue-approved — real bug, clean fix.

Good to merge — kevin's already signed off too.

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.

GitHub Action summary returns run_end/done JSON instead of final answer

5 participants