From 0524692bed5a465303b0e974d3396277b103b6f9 Mon Sep 17 00:00:00 2001 From: 1-Bort-1 Date: Fri, 11 Sep 2026 21:21:48 +0200 Subject: [PATCH] Stop the changelog version scan at the first `## ` header `bin/release` read the changelog version with an awk scan whose `exit` sat inside the `if` that matched a `v[0-9]` field, so a top header carrying no version fell through to the next `## ` header and returned the previous release instead. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01PnzAXASD57wVcJf4W7YX3Z --- bin/release | 2 +- test/bin/test_release.jl | 70 ++++++++++++++++++++++++++++++++++++++++ test/runtests.jl | 2 ++ 3 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 test/bin/test_release.jl diff --git a/bin/release b/bin/release index 2da31dc4..9406c289 100755 --- a/bin/release +++ b/bin/release @@ -53,7 +53,7 @@ if [[ -z "$_version" ]]; then exit 1 fi -_changelog_version=$(awk '/^## / {for (i = 1; i <= NF; i++) if ($i ~ /^v[0-9]/) {print $i; exit}}' CHANGELOG.md) +_changelog_version=$(awk '/^## / {for (i = 1; i <= NF; i++) if ($i ~ /^v[0-9]/) print $i; exit}' CHANGELOG.md) if [[ "$_changelog_version" != "v$_version" ]]; then echo "Version mismatch: Project.toml is $_version but CHANGELOG top is" \ "$_changelog_version (expected v$_version)." >&2 diff --git a/test/bin/test_release.jl b/test/bin/test_release.jl new file mode 100644 index 00000000..dff1cd69 --- /dev/null +++ b/test/bin/test_release.jl @@ -0,0 +1,70 @@ +using Test + +""" + dry_run_release(top_header, older_header) -> (exit_code, stderr_text) + +Run `bin/release --dry-run` against a throwaway repository at version 5.0.0 +whose `CHANGELOG.md` holds a section under each of the two headers, with a stub +`gh` on `PATH` so nothing reaches GitHub. +""" +function dry_run_release(top_header, older_header) + root = mktempdir() + repo = mkpath(joinpath(root, "repo")) + write(joinpath(repo, "Project.toml"), """ + name = "Fixture" + version = "5.0.0" + """) + write(joinpath(repo, "CHANGELOG.md"), """ + # Changelog + + $top_header + + ### Added + + - the newer note + + $older_header + + ### Fixed + + - the older note + """) + run(`git -C $repo init --quiet`) + run(`git -C $repo add --all`) + run(`git -C $repo -c user.email=fixture@example.com -c user.name=Fixture + commit --quiet -m "fixture"`) + + stub = mkpath(joinpath(root, "stub")) + gh_stub = joinpath(stub, "gh") + write(gh_stub, """ + #!/bin/bash + case "\$1" in + repo) echo "OpenSourceAWE/Fixture" ;; + esac + """) + chmod(gh_stub, 0o755) + + script = normpath(joinpath(@__DIR__, "..", "..", "bin", "release")) + stderr_file = joinpath(root, "stderr.txt") + env = copy(ENV) + env["PATH"] = stub * ":" * ENV["PATH"] + command = setenv(`bash $script --dry-run`, env; dir=repo) + process = run(pipeline(ignorestatus(command); stdout=devnull, stderr=stderr_file)) + return process.exitcode, read(stderr_file, String) +end + +@testset "bin/release" begin + @testset "release refuses an unversioned top section above the last release" begin + exit_code, stderr_text = + dry_run_release("## Unreleased", "## Fixture v5.0.0 2026-09-07") + @test exit_code != 0 + @test occursin("Version mismatch", stderr_text) + end + + @testset "release accepts a top section naming the package version" begin + exit_code, stderr_text = + dry_run_release("## Fixture v5.0.0 2026-09-07", "## Fixture v4.3.1 2026-08-01") + @test exit_code == 0 + @test isempty(stderr_text) + end +end diff --git a/test/runtests.jl b/test/runtests.jl index 08f8763c..ee518668 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -65,6 +65,8 @@ function include_selected_tests() should_run_test("airfoil_aero/test_live_polar.jl") && include("airfoil_aero/test_live_polar.jl") should_run_test("obj_adapter/test_obj_adapter.jl") && include("obj_adapter/test_obj_adapter.jl") should_run_test("surfplan/test_surfplan.jl") && include("surfplan/test_surfplan.jl") + # bin/release is a bash script, so only the unix runners can run it. + Sys.isunix() && should_run_test("bin/test_release.jl") && include("bin/test_release.jl") should_run_test("Aqua.jl") && include("Aqua.jl") end