From a58e5f701a8ec0e5d3a0f5b9321ed9de19ae6017 Mon Sep 17 00:00:00 2001 From: Richard Schneeman Date: Thu, 18 Jun 2026 15:01:03 -0500 Subject: [PATCH 1/7] Drop the "Add a changelog item" link from changelog output The changelog binaries printed an internal "Add a changelog item: https://devcenter.heroku.com/admin/changelog_items/new" line as the first line of their output. When a maintainer copies the generated changelog to paste into the devcenter form, that instructional URL can get accidentally copied and posted to the public interface. --- jruby_executable/src/bin/jruby_changelog.rs | 3 --- ruby_executable/src/bin/ruby_changelog.rs | 11 ----------- 2 files changed, 14 deletions(-) diff --git a/jruby_executable/src/bin/jruby_changelog.rs b/jruby_executable/src/bin/jruby_changelog.rs index 6586505..52b838c 100644 --- a/jruby_executable/src/bin/jruby_changelog.rs +++ b/jruby_executable/src/bin/jruby_changelog.rs @@ -16,9 +16,6 @@ fn jruby_changelog(args: &Args) -> Result<(), Box> { let stdlib_version = jruby_build_properties(version)?.ruby_stdlib_version()?; - println!("Add a changelog item: https://devcenter.heroku.com/admin/changelog_items/new"); - println!(); - let changelog = formatdoc! {" ## JRuby version {version} is now available diff --git a/ruby_executable/src/bin/ruby_changelog.rs b/ruby_executable/src/bin/ruby_changelog.rs index ff7c71c..78b8256 100644 --- a/ruby_executable/src/bin/ruby_changelog.rs +++ b/ruby_executable/src/bin/ruby_changelog.rs @@ -17,13 +17,6 @@ where { let Args { version } = args; - writeln!( - io, - "Add a changelog item: https://devcenter.heroku.com/admin/changelog_items/new" - )?; - - writeln!(io)?; - let gemfile_format = version.bundler_format(); let changelog = formatdoc! {" @@ -81,8 +74,6 @@ mod test { let output = ruby_changelog(&args, &mut io).unwrap(); let actual = String::from_utf8_lossy(output); let expected = formatdoc! {" - Add a changelog item: https://devcenter.heroku.com/admin/changelog_items/new - ## Ruby version 3.3.2 is now available [Ruby v3.3.2](/articles/ruby-support#ruby-versions) is now available on Heroku. To run \ @@ -106,8 +97,6 @@ mod test { let output = ruby_changelog(&args, &mut io).unwrap(); let actual = String::from_utf8_lossy(output); let expected = formatdoc! {" - Add a changelog item: https://devcenter.heroku.com/admin/changelog_items/new - ## Ruby version 3.1.0-rc1 is now available [Ruby v3.1.0-rc1](/articles/ruby-support#ruby-versions) is now available on Heroku. To run \ From 97f4c2ab48133ddd8f39baab60d3b1b04c5a1417 Mon Sep 17 00:00:00 2001 From: Richard Schneeman Date: Thu, 18 Jun 2026 15:01:16 -0500 Subject: [PATCH 2/7] Remove cargo build output from changelog Build in its own step so compile/download output doesn't pollute the changelog step. --- .github/workflows/build_jruby.yml | 2 ++ .github/workflows/build_ruby.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.github/workflows/build_jruby.yml b/.github/workflows/build_jruby.yml index ecfa35e..e0d96c9 100644 --- a/.github/workflows/build_jruby.yml +++ b/.github/workflows/build_jruby.yml @@ -41,6 +41,8 @@ jobs: run: rustup update - name: Rust Cache uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 + - name: Cargo build + run: cargo build --locked - name: Output CHANGELOG run: cargo run --locked --bin jruby_changelog -- --version "${{inputs.jruby_version}}" | tee "$GITHUB_STEP_SUMMARY" diff --git a/.github/workflows/build_ruby.yml b/.github/workflows/build_ruby.yml index 93d576c..26bbcce 100644 --- a/.github/workflows/build_ruby.yml +++ b/.github/workflows/build_ruby.yml @@ -41,6 +41,8 @@ jobs: run: rustup update - name: Rust Cache uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 + - name: Cargo build + run: cargo build --locked - name: Output CHANGELOG run: cargo run --locked --bin ruby_changelog -- --version "${{inputs.ruby_version}}" | tee "$GITHUB_STEP_SUMMARY" From d866050f76cb6e14bb761caa6a5000e330f317c0 Mon Sep 17 00:00:00 2001 From: Richard Schneeman Date: Thu, 18 Jun 2026 15:51:08 -0500 Subject: [PATCH 3/7] Push raw markdown to summary Problem: The output of the changelog entry on the summary is intended to be a copy/pasteable entry, however github summaries use markdown for styling so the contents are rendered instead of raw. To fix it we have to escape the contents by wrapping the changelog in a four-backtick fence. This is needed because the changelog already uses three backticks in the output: ```ruby Per https://github.github.com/gfm/#fenced-code-blocks > The content of the code block consists of all subsequent lines, until a closing code fence of the same type as the code block began with (backticks or tildes), and with at least as many backticks or tildes as the opening code fence. --- .github/workflows/build_jruby.yml | 8 +++++++- .github/workflows/build_ruby.yml | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_jruby.yml b/.github/workflows/build_jruby.yml index e0d96c9..ddb918b 100644 --- a/.github/workflows/build_jruby.yml +++ b/.github/workflows/build_jruby.yml @@ -44,7 +44,13 @@ jobs: - name: Cargo build run: cargo build --locked - name: Output CHANGELOG - run: cargo run --locked --bin jruby_changelog -- --version "${{inputs.jruby_version}}" | tee "$GITHUB_STEP_SUMMARY" + run: | + set -euo pipefail + { + echo '````' + cargo run --locked --bin jruby_changelog -- --version "${{inputs.jruby_version}}" + echo '````' + } | tee -a "$GITHUB_STEP_SUMMARY" build-and-upload: runs-on: pub-hk-ubuntu-24.04-xlarge diff --git a/.github/workflows/build_ruby.yml b/.github/workflows/build_ruby.yml index 26bbcce..b5c75bc 100644 --- a/.github/workflows/build_ruby.yml +++ b/.github/workflows/build_ruby.yml @@ -44,7 +44,13 @@ jobs: - name: Cargo build run: cargo build --locked - name: Output CHANGELOG - run: cargo run --locked --bin ruby_changelog -- --version "${{inputs.ruby_version}}" | tee "$GITHUB_STEP_SUMMARY" + run: | + set -euo pipefail + { + echo '````' + cargo run --locked --bin ruby_changelog -- --version "${{inputs.ruby_version}}" + echo '````' + } | tee -a "$GITHUB_STEP_SUMMARY" build-and-upload: runs-on: ${{ matrix.arch == 'arm64' && 'pub-hk-ubuntu-24.04-arm-xlarge' || 'pub-hk-ubuntu-24.04-xlarge' }} From 2a372d99e1038f24e1bc233e505d5ca161960d0a Mon Sep 17 00:00:00 2001 From: Richard Schneeman Date: Thu, 18 Jun 2026 16:15:21 -0500 Subject: [PATCH 4/7] Use stdout for jruby changelog THe ruby one already printed to stdout. --- jruby_executable/src/bin/jruby_changelog.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/jruby_executable/src/bin/jruby_changelog.rs b/jruby_executable/src/bin/jruby_changelog.rs index 52b838c..bae89bd 100644 --- a/jruby_executable/src/bin/jruby_changelog.rs +++ b/jruby_executable/src/bin/jruby_changelog.rs @@ -1,4 +1,4 @@ -use std::error::Error; +use std::{error::Error, io::Write}; use bullet_stream::global::print; use clap::Parser; @@ -11,7 +11,10 @@ struct Args { version: JRubyVersion, } -fn jruby_changelog(args: &Args) -> Result<(), Box> { +fn jruby_changelog(args: &Args, mut io: W) -> Result> +where + W: Write, +{ let Args { version } = args; let stdlib_version = jruby_build_properties(version)?.ruby_stdlib_version()?; @@ -29,14 +32,14 @@ fn jruby_changelog(args: &Args) -> Result<(), Box> { The JRuby release notes can be found on the [JRuby website](https://www.jruby.org/news). "}; - print::plain(changelog); + writeln!(io, "{changelog}")?; - Ok(()) + Ok(io) } fn main() { let args = Args::parse(); - if let Err(error) = jruby_changelog(&args) { + if let Err(error) = jruby_changelog(&args, std::io::stdout()) { print::error(formatdoc! {" ❌ Command failed ❌ From f9e68f268e779ef9a60827bded5122ce2e6cdafd Mon Sep 17 00:00:00 2001 From: Richard Schneeman Date: Fri, 19 Jun 2026 21:01:29 -0500 Subject: [PATCH 5/7] Add jruby_changelog test coverage parity Extract a pure render_jruby_changelog helper so the changelog output format can be unit tested without a network fetch, and add a regular_release test mirroring ruby_changelog. Adds pretty_assertions as a dev-dependency. --- Cargo.lock | 1 + jruby_executable/Cargo.toml | 3 ++ jruby_executable/src/bin/jruby_changelog.rs | 40 ++++++++++++++++++++- 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index e276c7b..cb8d6c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1088,6 +1088,7 @@ dependencies = [ "java-properties", "lazy_static", "libherokubuildpack", + "pretty_assertions", "regex", "reqwest", "serde", diff --git a/jruby_executable/Cargo.toml b/jruby_executable/Cargo.toml index 98d918c..dfbe9f2 100644 --- a/jruby_executable/Cargo.toml +++ b/jruby_executable/Cargo.toml @@ -38,3 +38,6 @@ tar = { workspace = true } tempfile = { workspace = true } thiserror = { workspace = true } winnow = { workspace = true } + +[dev-dependencies] +pretty_assertions = { workspace = true } diff --git a/jruby_executable/src/bin/jruby_changelog.rs b/jruby_executable/src/bin/jruby_changelog.rs index bae89bd..cdfcb88 100644 --- a/jruby_executable/src/bin/jruby_changelog.rs +++ b/jruby_executable/src/bin/jruby_changelog.rs @@ -11,7 +11,7 @@ struct Args { version: JRubyVersion, } -fn jruby_changelog(args: &Args, mut io: W) -> Result> +fn jruby_changelog(args: &Args, io: W) -> Result> where W: Write, { @@ -19,6 +19,17 @@ where let stdlib_version = jruby_build_properties(version)?.ruby_stdlib_version()?; + render_jruby_changelog(version, &stdlib_version, io) +} + +fn render_jruby_changelog( + version: &str, + stdlib_version: &str, + mut io: W, +) -> Result> +where + W: Write, +{ let changelog = formatdoc! {" ## JRuby version {version} is now available @@ -49,3 +60,30 @@ fn main() { std::process::exit(1); } } + +#[cfg(test)] +mod test { + use super::*; + use pretty_assertions::assert_eq; + + #[test] + fn regular_release() { + let mut io = Vec::new(); + + let output = render_jruby_changelog("9.4.7.0", "3.1.4", &mut io).unwrap(); + let actual = String::from_utf8_lossy(output); + let expected = formatdoc! {" + ## JRuby version 9.4.7.0 is now available + + [JRuby v9.4.7.0](/articles/ruby-support-reference#supported-jruby-versions) is now available on Heroku. To run + your app using this version of Ruby, add the following `ruby` directive to your Gemfile: + + ```ruby + ruby \"3.1.4\", engine: \"jruby\", engine_version: \"9.4.7.0\" + ``` + + The JRuby release notes can be found on the [JRuby website](https://www.jruby.org/news). + "}; + assert_eq!(expected.trim(), actual.trim()); + } +} From 133a6bca8574f016f9413f631c4f1686cd88f0ef Mon Sep 17 00:00:00 2001 From: Richard Schneeman Date: Fri, 19 Jun 2026 21:03:14 -0500 Subject: [PATCH 6/7] Document why changelog output uses a 4-backtick fence --- .github/workflows/build_jruby.yml | 1 + .github/workflows/build_ruby.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/build_jruby.yml b/.github/workflows/build_jruby.yml index ddb918b..f573de8 100644 --- a/.github/workflows/build_jruby.yml +++ b/.github/workflows/build_jruby.yml @@ -47,6 +47,7 @@ jobs: run: | set -euo pipefail { + # 4 backticks so the inner ```ruby fences in the changelog render literally echo '````' cargo run --locked --bin jruby_changelog -- --version "${{inputs.jruby_version}}" echo '````' diff --git a/.github/workflows/build_ruby.yml b/.github/workflows/build_ruby.yml index b5c75bc..938095d 100644 --- a/.github/workflows/build_ruby.yml +++ b/.github/workflows/build_ruby.yml @@ -47,6 +47,7 @@ jobs: run: | set -euo pipefail { + # 4 backticks so the inner ```ruby fences in the changelog render literally echo '````' cargo run --locked --bin ruby_changelog -- --version "${{inputs.ruby_version}}" echo '````' From d1a9ff5609fb8af9d7e000dd2683ed7103e1d89b Mon Sep 17 00:00:00 2001 From: Richard Schneeman Date: Fri, 19 Jun 2026 21:47:26 -0500 Subject: [PATCH 7/7] Fix compiling after merge ``` Compiling ruby_executable v0.0.0 (/home/runner/work/docker-heroku-ruby-builder/docker-heroku-ruby-builder/ruby_executable) Compiling jruby_executable v0.0.0 (/home/runner/work/docker-heroku-ruby-builder/docker-heroku-ruby-builder/jruby_executable) error[E0308]: mismatched types --> jruby_executable/src/bin/jruby_changelog.rs:22:28 | 22 | render_jruby_changelog(version, &stdlib_version, io) | ---------------------- ^^^^^^^ expected `&str`, found `&JRubyVersion` | | | arguments to this function are incorrect | = note: expected reference `&str` found reference `&JRubyVersion` note: function defined here --> jruby_executable/src/bin/jruby_changelog.rs:25:4 | 25 | fn render_jruby_changelog( | ^^^^^^^^^^^^^^^^^^^^^^ 26 | version: &str, | ------------- For more information about this error, try `rustc --explain E0308`. error: could not compile `jruby_executable` (bin "jruby_changelog") due to 1 previous error warning: build failed, waiting for other jobs to finish... ``` --- jruby_executable/src/bin/jruby_changelog.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/jruby_executable/src/bin/jruby_changelog.rs b/jruby_executable/src/bin/jruby_changelog.rs index cdfcb88..33f104a 100644 --- a/jruby_executable/src/bin/jruby_changelog.rs +++ b/jruby_executable/src/bin/jruby_changelog.rs @@ -23,7 +23,7 @@ where } fn render_jruby_changelog( - version: &str, + version: &JRubyVersion, stdlib_version: &str, mut io: W, ) -> Result> @@ -70,7 +70,9 @@ mod test { fn regular_release() { let mut io = Vec::new(); - let output = render_jruby_changelog("9.4.7.0", "3.1.4", &mut io).unwrap(); + let output = + render_jruby_changelog(&JRubyVersion::parse("9.4.7.0").unwrap(), "3.1.4", &mut io) + .unwrap(); let actual = String::from_utf8_lossy(output); let expected = formatdoc! {" ## JRuby version 9.4.7.0 is now available