Skip to content

fix(release): make release notes editorialization non-blocking#8116

Merged
jdx merged 5 commits intomainfrom
fix/release-notes-non-blocking
Feb 12, 2026
Merged

fix(release): make release notes editorialization non-blocking#8116
jdx merged 5 commits intomainfrom
fix/release-notes-non-blocking

Conversation

@jdx
Copy link
Owner

@jdx jdx commented Feb 11, 2026

Summary

  • 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

Low Risk
Release automation-only changes with a straightforward fallback path; main risk is malformed parsing/output causing slightly degraded release notes rather than a failed release.

Overview
Draft release creation is updated to treat LLM-generated release notes as best-effort: it now runs gen-release-notes into a temp output directory, uses the generated title/notes files when successful, and falls back to git cliff notes (with a warning) when it fails.

The gen-release-notes task is refactored to accept <version> <output_dir> [prev_version], emit more useful logs, parse Claude output into separate title/body files, and documentation is updated accordingly; the workflow also switches to printf when appending the Aqua section to avoid shell quoting issues.

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

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

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 significantly enhances the reliability of both the release process and the Conda backend. It ensures that release note generation is non-blocking and provides clearer output, while also introducing critical fixes for Conda package installations on Linux. These fixes include automatically correcting hardcoded build prefixes in text files and refining the handling of RPATHs and dynamic linkers for ELF binaries, thereby improving the overall stability and compatibility of Conda-managed tools.

Highlights

  • Release Notes Generation Improvement: The release note generation script has been updated to be more robust and non-blocking. It now writes parsed titles and notes to a specified output directory, and Claude's stdout/stderr flows naturally, preventing release failures due to editorialization issues.
  • Conda Backend Prefix Fixing: A new mechanism was introduced to automatically fix hardcoded Conda build prefixes in text files (like shell scripts) within installed packages, ensuring correct execution in the target environment.
  • Enhanced Linux Library Path Handling: The Linux library path fixing logic for Conda packages was significantly refactored. It now dynamically discovers all relevant library directories, builds more comprehensive RPATHs, and correctly adjusts ELF interpreter paths for executables.
  • Expanded Conda Tool Support: Conda backend support was added for ffmpeg, ghc, and vim tools, along with corresponding test commands in their registry configurations.
  • Improved Test Tool Debugging: The test_tool now logs command output when a test exits with code 127, providing better diagnostic information for dynamic linker or missing library errors.
Changelog
  • registry/ffmpeg.toml
    • Added 'conda' as a backend option.
    • Included a 'test' command for verification.
  • registry/ghc.toml
    • Added 'conda' as a backend option.
    • Included a 'test' command for verification.
  • registry/vim.toml
    • Added 'conda' as a backend option.
    • Included a 'test' command for verification.
  • src/backend/conda.rs
    • Integrated a new function call to fix hardcoded Conda build prefixes in text files.
    • Revised the list of packages to skip during dependency resolution, re-including python, ruby, perl, and r-base.
  • src/backend/conda_common.rs
    • Introduced new functions (fix_text_prefixes, find_conda_prefix, extract_placeholder_prefix) to identify and replace hardcoded Conda build paths within installed packages.
  • src/backend/conda_linux.rs
    • Refactored library path fixing on Linux to dynamically discover library directories.
    • Improved RPATH generation to include all relevant library paths.
    • Added functionality to fix ELF interpreter paths for executables, falling back to system linkers if necessary.
    • Defined known dynamic linker names and system linker search paths.
  • src/cli/test_tool.rs
    • Implemented logging of command output when a test command exits with code 127, aiding in debugging dynamic linker or missing library errors.
  • xtasks/gen-release-notes
    • Modified the script to accept arguments via MISE usage directives.
    • Updated the script to write generated release notes and title to a specified output directory instead of stdout.
    • Removed stderr redirection for Claude CLI calls, allowing natural flow of Claude's output.
    • Added mkdir -p for the output directory.
Ignored Files
  • Ignored by pattern: .github/workflows/** (1)
    • .github/workflows/release.yml
Activity
  • No specific activity (comments, reviews, progress updates) has been recorded for this pull request yet.
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

@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 contains two main sets of changes. The first, reflected in the PR title, modifies the gen-release-notes script to be non-blocking in CI by writing output to files. The second, larger set of changes significantly improves the conda backend by adding support for fixing hardcoded prefixes in text files and robustly handling library paths (RPATH and interpreter) on Linux. These are excellent improvements that will make conda-installed tools much more reliable.

My review focuses on suggesting a small improvement to the shell script's error handling. The Rust code changes for the conda backend are well-implemented and a great addition.


if [[ -z $changelog ]]; then
echo "Error: No changes found for release" >&2
echo "Error: No changes found for release"
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

It's a good practice to redirect error messages to stderr in shell scripts. This separates diagnostic output from normal output and is the standard convention. While this might be for CI log visibility, using stderr is more idiomatic.

echo "Error: No changes found for release" >&2

else
echo "(no stderr output from Claude CLI)" >&2
fi
echo "Error: Claude CLI failed"
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

For consistency and standard shell scripting practice, error messages should be redirected to stderr.

echo "Error: Claude CLI failed" >&2

if [[ -z $output ]]; then
echo "Error: Claude returned empty output" >&2
cat "$stderr_file" >&2
echo "Error: Claude returned empty output"
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This error message should also be redirected to stderr for consistency.

echo "Error: Claude returned empty output" >&2

body=$(echo "$output" | tail -n +3)

if [[ -z $body ]]; then
echo "Error: Empty body after parsing"
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

Please redirect this error message to stderr as well to follow standard error handling conventions in shell scripts.

echo "Error: Empty body after parsing" >&2

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

This PR aims to make the “editorialize release notes” step non-blocking and improve CI log visibility by writing parsed release-note artifacts to a directory instead of stdout.

Changes:

  • Update gen-release-notes to write title and notes files into an output directory and stop suppressing Claude CLI output.
  • Make the GitHub Release creation step continue-on-error and update it to read generated title/notes files.
  • Enhance conda-based installs on Linux by improving RPATH/interpreter handling and adding text-prefix rewrites; update some registry entries to prefer conda backends + add tests.

Reviewed changes

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

Show a summary per file
File Description
xtasks/gen-release-notes Writes parsed title/notes to an output dir and changes logging/Claude output handling.
.github/workflows/release.yml Uses output dir artifacts for release notes and makes the release step non-blocking.
src/backend/conda_linux.rs Expands Linux patchelf handling (RPATH + interpreter) and library directory discovery.
src/backend/conda_common.rs Adds logic to rewrite conda placeholder prefixes in extracted text files.
src/backend/conda.rs Invokes text-prefix rewriting and tweaks skip-package policy docs/behavior.
src/cli/test_tool.rs Improves diagnostics when a command exits 127 by logging captured output.
registry/vim.toml Prefers conda backend and adds a simple runtime test.
registry/ghc.toml Prefers conda backend ordering.
registry/ffmpeg.toml Prefers conda backend and adds a simple runtime test.

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

Comment on lines +96 to +102
title=$(echo "$output" | head -1)
body=$(echo "$output" | tail -n +3)

if [[ -z $body ]]; then
echo "Error: Empty body after parsing"
exit 1
fi
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 parsing assumes Claude output is exactly: first line title, second line blank, body from line 3 (tail -n +3). If Claude returns no blank line, line 2 will be dropped and body may be empty even when valid content exists. Consider splitting on the first blank line when present, otherwise treat everything after the first line as the body (with optional trimming of a single leading blank line).

Copilot uses AI. Check for mistakes.

if [[ -z $changelog ]]; then
echo "Error: No changes found for release" >&2
echo "Error: No changes found for release"
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.

These error messages were previously written to stderr; now they go to stdout, which can make it harder for CI tooling/users to distinguish failures from normal output (especially since you also print raw Claude output). Recommend sending errors to stderr (e.g., >&2) while keeping the raw Claude output printing behavior unchanged.

Copilot uses AI. Check for mistakes.
else
echo "(no stderr output from Claude CLI)" >&2
fi
echo "Error: Claude CLI failed"
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.

These error messages were previously written to stderr; now they go to stdout, which can make it harder for CI tooling/users to distinguish failures from normal output (especially since you also print raw Claude output). Recommend sending errors to stderr (e.g., >&2) while keeping the raw Claude output printing behavior unchanged.

Copilot uses AI. Check for mistakes.
if [[ -z $output ]]; then
echo "Error: Claude returned empty output" >&2
cat "$stderr_file" >&2
echo "Error: Claude returned empty output"
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.

These error messages were previously written to stderr; now they go to stdout, which can make it harder for CI tooling/users to distinguish failures from normal output (especially since you also print raw Claude output). Recommend sending errors to stderr (e.g., >&2) while keeping the raw Claude output printing behavior unchanged.

Copilot uses AI. Check for mistakes.
Comment on lines +96 to +97
title=$(echo "$output" | head -1)
body=$(echo "$output" | tail -n +3)
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.

Using echo to pipe arbitrary LLM output is brittle (some echo implementations treat leading -n/-e as options, and escape handling varies). Prefer printf '%s\n' \"$output\" (or equivalent) to ensure the content is passed through exactly as received.

Copilot uses AI. Check for mistakes.
Comment on lines +328 to +337
if: startsWith(github.event.ref, 'refs/tags/v')
continue-on-error: true
run: |
VERSION="$(./scripts/get-version.sh)"
PREV_VERSION="$(git describe --tags --abbrev=0 --match 'v[0-9]*' "$VERSION^" 2>/dev/null || echo "")"
# Generate rich release notes using LLM (first line is title, rest is body)
mise run gen-release-notes "$VERSION" "$PREV_VERSION" >/tmp/release-full.txt
RELEASE_TITLE="$VERSION: $(head -1 /tmp/release-full.txt)"
tail -n +3 /tmp/release-full.txt >/tmp/release-notes.txt
# Generate rich release notes using LLM
OUTPUT_DIR=$(mktemp -d)
mise run gen-release-notes "$VERSION" "$OUTPUT_DIR" "$PREV_VERSION"
RELEASE_TITLE="$VERSION: $(cat "$OUTPUT_DIR/title")"
cp "$OUTPUT_DIR/notes" /tmp/release-notes.txt
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.

Setting continue-on-error: true on the entire 'Create Draft GitHub Release' step makes any failure in the step non-blocking (including failures unrelated to editorialization or even the actual release creation). If the intent is only to make the LLM editorialization non-blocking, consider isolating the editorialization into its own step with continue-on-error, or handling just the mise run gen-release-notes ... failure in-shell and falling back to non-editorialized notes.

Copilot uses AI. Check for mistakes.
RELEASE_TITLE="$VERSION: $(head -1 /tmp/release-full.txt)"
tail -n +3 /tmp/release-full.txt >/tmp/release-notes.txt
# Generate rich release notes using LLM
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 directory that isn't cleaned up. While runners are ephemeral, it’s still good hygiene to trap a cleanup (rm -rf \"$OUTPUT_DIR\") in the step to avoid clutter and reduce the chance of leaking sensitive artifacts if the environment is re-used.

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 +259 to +263
if let Ok(stdout) = String::from_utf8(res.stdout.clone()) {
let stdout = stdout.trim();
if !stdout.is_empty() {
info!("command output:\n{stdout}");
}
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.

This clones res.stdout just to decode it, which can be unnecessarily expensive for large outputs. Consider decoding without cloning (e.g., with String::from_utf8_lossy(&res.stdout)) and logging the trimmed view.

Suggested change
if let Ok(stdout) = String::from_utf8(res.stdout.clone()) {
let stdout = stdout.trim();
if !stdout.is_empty() {
info!("command output:\n{stdout}");
}
let stdout = String::from_utf8_lossy(&res.stdout);
let stdout = stdout.trim();
if !stdout.is_empty() {
info!("command output:\n{stdout}");

Copilot uses AI. Check for mistakes.
Comment on lines +112 to +122
// Walk backward to find start of the absolute path
let before = &content[..idx];
let pos = before
.rfind(|c: char| !c.is_alphanumeric() && !matches!(c, '/' | '_' | '-' | '.' | '+'))?;
// Skip past the delimiter character (handles multi-byte UTF-8 correctly)
let start = pos + before[pos..].chars().next()?.len_utf8();

// Validate it starts with /
if !content[start..].starts_with('/') {
return None;
}
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.

rfind(...)? returns None if the placeholder path begins at the start of the content (i.e., there is no preceding delimiter). In that case, a valid prefix won't be detected and no replacements will occur. Consider handling the 'no delimiter found' case by treating start as 0 when before itself starts with /.

Copilot uses AI. Check for mistakes.
Comment on lines +110 to +127
// Add all discovered lib directories as $ORIGIN-relative paths
for lib_dir in lib_dirs {
if let Ok(rel_path) = lib_dir.strip_prefix(install_dir) {
let Some(rel) = rel_path.to_str() else {
continue; // Skip non-UTF8 paths
};
if let Some(parent) = path.parent()
&& let Ok(from_parent) = parent.strip_prefix(install_dir)
{
let depth = from_parent.components().count();
let up = "../".repeat(depth);
let entry = format!("$ORIGIN/{}{}", up, rel);
if !entries.contains(&entry) {
entries.push(entry);
}
}
}
}
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.

entries.contains(&entry) inside the loop makes dedup O(n²) in the number of discovered library directories. For installs with many .so directories, this can become a noticeable bottleneck. Consider tracking seen entries with a HashSet<String> (or IndexSet) while preserving order in entries.

Copilot uses AI. Check for mistakes.
jdx and others added 2 commits February 11, 2026 11:07
- 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 536dff7 to ca9097b Compare February 11, 2026 18:57
@github-actions
Copy link

github-actions bot commented Feb 11, 2026

Hyperfine Performance

mise x -- echo

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.9 x -- echo 22.2 ± 0.4 21.0 25.0 1.00
mise x -- echo 22.9 ± 0.5 21.8 25.5 1.03 ± 0.03

mise env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.9 env 22.0 ± 0.7 20.9 27.9 1.00
mise env 22.5 ± 0.5 21.6 25.7 1.02 ± 0.04

mise hook-env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.9 hook-env 22.0 ± 0.4 21.2 24.8 1.00
mise hook-env 22.8 ± 0.5 21.9 25.7 1.04 ± 0.03

mise ls

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.9 ls 20.3 ± 0.4 19.3 22.6 1.01 ± 0.03
mise ls 20.2 ± 0.3 19.6 22.4 1.00

xtasks/test/perf

Command mise-2026.2.9 mise Variance
install (cached) 120ms 122ms -1%
ls (cached) 73ms 75ms -2%
bin-paths (cached) 77ms 77ms +0%
task-ls (cached) 535ms ⚠️ 798ms -32%

⚠️ Warning: task-ls cached performance variance is -32%

The workflow expects gen-release-notes to accept an output_dir arg
and write title/notes files there. Update the script to match,
using mise task arg syntax.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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 2 potential issues.

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

autofix-ci bot and others added 2 commits February 11, 2026 20:24
- Add >&2 to missing error message in gen-release-notes
- Use printf instead of echo for LLM output to avoid -n/-e interpretation
- Make gen-release-notes non-blocking: fall back to git-cliff on failure
- Add trap cleanup for mktemp directory

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@jdx jdx enabled auto-merge (squash) February 12, 2026 01:07
@jdx jdx disabled auto-merge February 12, 2026 01:07
@jdx jdx enabled auto-merge (squash) February 12, 2026 01:08
@jdx jdx merged commit f314b26 into main Feb 12, 2026
35 checks passed
@jdx jdx deleted the fix/release-notes-non-blocking branch February 12, 2026 01:20
lucasew pushed a commit to lucasew/CONTRIB-mise that referenced this pull request Feb 18, 2026
)

## Summary
- 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](https://claude.com/claude-code)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Release automation-only changes with a straightforward fallback path;
main risk is malformed parsing/output causing slightly degraded release
notes rather than a failed release.
> 
> **Overview**
> Draft release creation is updated to treat LLM-generated release notes
as **best-effort**: it now runs `gen-release-notes` into a temp output
directory, uses the generated `title`/`notes` files when successful, and
*falls back to `git cliff`* notes (with a warning) when it fails.
> 
> The `gen-release-notes` task is refactored to accept `<version>
<output_dir> [prev_version]`, emit more useful logs, parse Claude output
into separate title/body files, and documentation is updated
accordingly; the workflow also switches to `printf` when appending the
Aqua section to avoid shell quoting issues.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
0440455. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
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.

2 participants