Skip to content

Conversation

@jdx
Copy link
Owner

@jdx jdx commented Feb 11, 2026

Summary

  • Move gen-release-notes.sh to a mise file task
  • Script writes parsed title/notes to an output directory instead of stdout for better CI log visibility
  • Claude's stdout/stderr flows through naturally instead of being suppressed
  • Add continue-on-error so failures don't block releases

Test plan

  • Trigger a release and verify the editorialize step logs are visible
  • If Claude produces bad output, the release still succeeds

🤖 Generated with Claude Code


Note

Medium Risk
Touches the GitHub release/publish pipeline; misconfiguration could degrade release-note generation or titles, though it still falls back to CHANGELOG.md.

Overview
Release note generation is refactored to be file-based and driven by mise. The publish-cli workflow now runs mise run gen-release-notes into a temp output directory, reads the generated title to optionally augment the GitHub release title, and uses the generated notes file for gh release create.

The release-notes generator is converted into a mise task. tasks/gen-release-notes now takes version, output_dir, and optional prev_version via mise #USAGE args and writes parsed results to $output_dir/title and $output_dir/notes instead of emitting them on stdout.

Written by Cursor Bugbot for commit c956a35. This will update automatically on new commits. Configure here.

Copilot AI review requested due to automatic review settings February 11, 2026 16:49
@gemini-code-assist
Copy link

Summary of Changes

Hello @jdx, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the robustness and user experience of the release notes generation process. By refactoring the script into a mise task, redirecting its output to files, and improving error visibility, the editorialization step becomes less prone to blocking releases and provides clearer feedback during CI runs. Additionally, documentation for handling variadic arguments in Bash was improved.

Highlights

  • Release Notes Script Refactoring: The gen-release-notes.sh script was moved to tasks/gen-release-notes and converted into a mise task, improving its integration and argument handling.
  • Output Redirection for Release Notes: The script now writes the generated release title and body to separate files within a specified output directory, rather than printing to standard output, which enhances CI log clarity.
  • Improved Error Visibility: The handling of Claude Code's standard error output was simplified, allowing it to flow naturally, which aids in debugging potential issues.
  • New Documentation for Variadic Arguments: Added a section to the arg.md documentation explaining how to correctly handle variadic arguments containing spaces when using them in Bash scripts.
Changelog
  • docs/spec/reference/arg.md
    • Added a new section "Using Variadic Args in Bash" with examples.
    • Provided guidance on converting shell-escaped variadic arguments into bash arrays.
    • Demonstrated how to use these arrays in loops and with commands.
  • scripts/gen-release-notes.sh
    • Renamed scripts/gen-release-notes.sh to tasks/gen-release-notes.
    • Converted the script into a mise task by adding MISE and USAGE directives.
    • Updated argument parsing to use usage_ variables instead of positional parameters.
    • Modified the script to create an output directory and write the generated title and notes to title and notes files within it.
    • Removed explicit stderr_file handling, allowing Claude's stderr to pass through directly.
    • Adjusted echo statements to print to stdout instead of stderr for general messages.
Ignored Files
  • Ignored by pattern: .github/workflows/** (1)
    • .github/workflows/publish-cli.yml
Activity
  • The author provided a summary of changes in the PR description.
  • A test plan was outlined to verify the editorialization step logs and ensure releases succeed even with bad Claude output.
  • The PR was generated with Claude Code.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Makes the “editorialized release notes” generation non-blocking and more CI-log friendly by moving it into a mise task, persisting outputs to files, and letting Claude output flow through normally.

Changes:

  • Convert gen-release-notes into a mise task with structured USAGE args and file outputs.
  • Update release workflow to use the mise task output files for title/notes.
  • Make the release step non-blocking via continue-on-error.

Reviewed changes

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

File Description
tasks/gen-release-notes Implements mise task interface and writes generated title/notes to an output directory.
docs/spec/reference/arg.md Documents how variadic args are exposed and how to consume them in bash.
.github/workflows/publish-cli.yml Switches release-note generation to the mise task and marks the step non-blocking.

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

run: npm install -g @anthropic-ai/claude-code
- name: Create draft release
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
continue-on-error: true
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

continue-on-error: true is applied to the entire 'Create draft release' step, so any failure in that step (including failures unrelated to LLM editorialization, e.g., actually creating the draft release) will be ignored and the workflow can appear successful. To make only the editorialization non-blocking, remove step-level continue-on-error and instead make the LLM sub-command non-fatal (e.g., handle the failure within the script/if-block, which you already do) while keeping the overall release creation failing on real errors.

Suggested change
continue-on-error: true

Copilot uses AI. Check for mistakes.
# First line is pithy title, rest is body
PITHY_TITLE="$(head -n1 /tmp/release-notes-full.txt)"
# Only concatenate if we got a real title (not just the version fallback)
OUTPUT_DIR=$(mktemp -d)
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

mktemp -d creates a temporary directory that is never cleaned up. While runners are ephemeral, this is still easy to clean up and reduces clutter when iterating/debugging. Add a trap to rm -rf \"$OUTPUT_DIR\" (or explicitly remove it after copying the files).

Suggested change
OUTPUT_DIR=$(mktemp -d)
OUTPUT_DIR=$(mktemp -d)
trap 'rm -rf "$OUTPUT_DIR"' EXIT

Copilot uses AI. Check for mistakes.
Comment on lines 22 to 23
echo "Error: No changes found for release"
exit 1
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

Error messages are no longer written to stderr, and echo is used for file writes. For CLI/task tooling, it’s better to keep errors on stderr (so logs/consumers can distinguish failures cleanly) and prefer printf over echo for writing arbitrary content (to avoid edge cases like content equal to -n, escape handling differences, etc.).

Copilot uses AI. Check for mistakes.
Comment on lines 66 to 67
echo "Error: Claude CLI failed"
exit 1
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

Error messages are no longer written to stderr, and echo is used for file writes. For CLI/task tooling, it’s better to keep errors on stderr (so logs/consumers can distinguish failures cleanly) and prefer printf over echo for writing arbitrary content (to avoid edge cases like content equal to -n, escape handling differences, etc.).

Copilot uses AI. Check for mistakes.
Comment on lines 72 to 73
echo "Error: Claude returned empty output"
exit 1
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

Error messages are no longer written to stderr, and echo is used for file writes. For CLI/task tooling, it’s better to keep errors on stderr (so logs/consumers can distinguish failures cleanly) and prefer printf over echo for writing arbitrary content (to avoid edge cases like content equal to -n, escape handling differences, etc.).

Copilot uses AI. Check for mistakes.
Comment on lines +91 to +92
echo "$title" >"$output_dir/title"
echo "$body" >"$output_dir/notes"
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

Error messages are no longer written to stderr, and echo is used for file writes. For CLI/task tooling, it’s better to keep errors on stderr (so logs/consumers can distinguish failures cleanly) and prefer printf over echo for writing arbitrary content (to avoid edge cases like content equal to -n, escape handling differences, etc.).

Copilot uses AI. Check for mistakes.
# Given: usage_files="arg1 'arg with space' arg3"

# Convert to bash array:
eval "files=($usage_files)"
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

The docs recommend using eval to turn usage_<name> into an array. eval can execute arbitrary code if the variable content is attacker-controlled or accidentally contains unexpected shell fragments. If usage_files is guaranteed to be generated by a trusted tool, please document that assumption explicitly and add a warning; otherwise, consider documenting a safer serialization/transport format (e.g., newline/NUL-delimited output or JSON) that can be parsed without eval.

Copilot uses AI. Check for mistakes.
Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request refactors the release notes generation script to be a non-blocking mise task, improving its integration into the CI/CD pipeline. The changes are generally good, especially writing output to files for better log visibility and simplifying stderr handling for the claude command.

I have a few suggestions to further improve the changes:

  • In docs/spec/reference/arg.md, I recommend adding a security note regarding the use of eval to educate users on its safe usage in this context.
  • In the tasks/gen-release-notes script, I've pointed out that all informational and error messages should be redirected to stderr to follow shell scripting best practices.
  • I've also suggested a more efficient way to parse the output from the claude command in the same script, using shell built-ins to avoid unnecessary process forking.

# Given: usage_files="arg1 'arg with space' arg3"

# Convert to bash array:
eval "files=($usage_files)"

Choose a reason for hiding this comment

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

medium

Using eval can be risky and should be handled with care. While it's necessary here to correctly parse the shell-escaped arguments, it would be beneficial to add a security note to the documentation. This note should explain why eval is safe in this specific context (i.e., usage generates a properly escaped string) and warn developers against using eval with untrusted input in general.

For example, you could add a note below the code block:

Security Note: The eval command can execute arbitrary code and should be used with caution. In this example, it is safe because the usage_<name> variable is generated by usage which properly shell-escapes all arguments. Avoid using eval with unescaped or untrusted user input.

Comment on lines 54 to 57
echo "Generating release notes with Claude..." >&2
echo "Version: $version" >&2
echo "Previous version: ${prev_version:-none}" >&2
echo "Changelog length: ${#changelog} chars" >&2

Choose a reason for hiding this comment

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

medium

It's a best practice in shell scripting to write progress, informational, and error messages to stderr, reserving stdout for the script's primary data output. The previous version of this script followed this practice. Even though this script now writes its main output to files, adhering to this convention improves consistency and makes the script's behavior more predictable for users and other tools. All echo statements used for logging in this script should redirect to stderr (>&2). This applies to other logging lines as well (e.g., lines 22, 66, 72, 76, 85, 93).

echo "Generating release notes with Claude..." >&2
echo "Version: $version" >&2
echo "Previous version: ${prev_version:-none}" >&2
echo "Changelog length: ${#changelog} chars" >&2

Comment on lines 80 to 88
first_line=$(echo "$output" | head -n1)
if [[ $first_line == "# "* ]]; then
title="${first_line#\# }"
body=$(echo "$output" | tail -n +2)
else
echo "Warning: First line not a title, using version" >&2
title="$version"
body="$output"
fi

Choose a reason for hiding this comment

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

medium

This block can be made more efficient by using shell built-ins instead of forking external commands like echo, head, and tail. This avoids creating subshells and processing the $output variable multiple times. The suggested change uses read to get the first line and parameter expansion to get the rest of the body, which is much faster. It also redirects the warning message to stderr, which is a best practice for logging.

read -r first_line <<< "$output"
if [[ $first_line == "# "* ]]; then
	title="${first_line#\# }"
	body="${output#*$'\n'}"
else
	echo "Warning: First line not a title, using version" >&2
	title="$version"
	body="$output"
fi

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is ON, but a Cloud Agent failed to start.

jdx and others added 4 commits February 11, 2026 11:07
Clarifies that readarray/mapfile are alternatives in bash 4.0+, but
macOS ships with bash 3.2 by default which doesn't include them.
The eval pattern works with all bash versions.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
readarray/mapfile don't understand shell quoting, so they wouldn't
work with the current format regardless of bash version.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Move gen-release-notes.sh to a mise file task
- Script writes parsed title/notes to an output directory instead of
  stdout for better CI log visibility
- Claude stdout/stderr flows through naturally instead of being suppressed
- Add continue-on-error so failures do not block releases

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The in-step fallback logic already handles LLM failures. Having
continue-on-error on the step that also runs gh release create would
swallow real release creation failures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@jdx jdx force-pushed the fix/release-notes-non-blocking branch from 16cff24 to c956a35 Compare February 11, 2026 18:57
@codecov
Copy link

codecov bot commented Feb 11, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 69.58%. Comparing base (ee4533e) to head (c956a35).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #490   +/-   ##
=======================================
  Coverage   69.58%   69.58%           
=======================================
  Files          47       47           
  Lines        6789     6789           
  Branches     6789     6789           
=======================================
  Hits         4724     4724           
  Misses       1299     1299           
  Partials      766      766           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@jdx jdx merged commit 43e0e06 into main Feb 12, 2026
9 checks passed
@jdx jdx deleted the fix/release-notes-non-blocking branch February 12, 2026 00:53
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.

1 participant