Skip to content

fix(ci): start release notes from a tag that exists - #333

Merged
EtienneLescot merged 2 commits into
mainfrom
fix/release-notes-start-tag
Aug 10, 2026
Merged

fix(ci): start release notes from a tag that exists#333
EtienneLescot merged 2 commits into
mainfrom
fix/release-notes-start-tag

Conversation

@EtienneLescot

@EtienneLescot EtienneLescot commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

v1.9.4-rc.1 built all four platforms, uploaded every artifact, then died publishing:

NOTES_START_TAG: v1.9.3
fatal: ambiguous argument 'v1.9.3..v1.9.4-rc.1': unknown revision

build.yml:727 derives the notes range from the previous release's name and never checks that the tag exists. 1.9.3 only ever shipped as rc.1, so v1.9.3 is a name for nothing.

The rc walk-down just below it handles a skipped RC. Nothing handled a skipped stable — and that loop does not execute at all for an rc.1 (for n = RC_NUMBER - 1; n >= 1 with RC_NUMBER=1).

Why this is worse than lost release notes

publish-msstore declares needs: publish-release. So the same missing tag takes the Microsoft Store deployment down with it on a stable promotion — the one place where discovering this is expensive. Promoting 1.9.4 would have failed identically.

The fix

Verify the computed tag, and when it is absent fall back to the nearest tag reachable from the release commit's parent — which is what "since the last release" meant to begin with. For the tag that failed:

$ git describe --tags --abbrev=0 v1.9.4-rc.1^
v1.9.2
$ git rev-list --count v1.9.2..v1.9.4-rc.1
25

A sensible range rather than a crash. If no tag is reachable at all — a first release — the root commit keeps the range valid instead of handing git an empty left-hand side.

Needs cherry-picking onto release/v1.9.4 before rc.2 is cut, since that branch is frozen at the commit before this one.

Summary by CodeRabbit

  • Bug Fixes
    • Improved release-note generation when the expected previous release tag is unavailable.
    • Added fallback handling to select the nearest valid release range, preventing invalid or incomplete release notes.
    • Release candidates now include the full available release history when no prior tag exists.
    • Stable releases now use the platform’s default history selection when no previous tag is available.

The notes range was built from the previous release's *name*, never from a check
that it exists. 1.9.3 shipped only as rc.1, so v1.9.4-rc.1 asked git for
v1.9.3..v1.9.4-rc.1 and the publish step died on `unknown revision` -- after all
four platforms had already built and uploaded their artifacts.

The existing rc walk-down covers a skipped RC. Nothing covered a skipped stable,
and that loop does not run at all for an rc.1 (`for n = 0; n >= 1`).

This is not only about release notes: publish-msstore has `needs:
publish-release`, so the same missing tag would have taken the Store deployment
down with it on a stable promotion, which is the one place that failure is
expensive to discover.

Falls back to the nearest tag reachable from the release commit's parent, which
is what "since the last release" meant to begin with -- v1.9.2 for the tag that
failed, a 25-commit range. If no tag is reachable at all, the root commit keeps
the range valid rather than handing git an empty left-hand side.
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d179b0ac-1896-4990-91fb-884fc20e68c3

📥 Commits

Reviewing files that changed from the base of the PR and between 55a225d and 2918c4a.

📒 Files selected for processing (1)
  • .github/workflows/build.yml

📝 Walkthrough

Walkthrough

The build workflow validates the computed previous-release tag. Missing tags use a reachable fallback when available. RC notes and stable release creation handle the absence of a previous tag without creating an invalid range.

Changes

Release note generation

Layer / File(s) Summary
Resolve release-note start tag
.github/workflows/build.yml
The workflow validates NOTES_START_TAG and selects the nearest reachable parent tag when the computed tag is unavailable.
Generate notes with optional start tag
.github/workflows/build.yml
RC notes use the full release history when no previous tag exists. Stable release creation omits --notes-start-tag in that case.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: claude, psychosomat, siddharthvaddem

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains the bug and fix, but it omits most required template sections, including change type, release impact, platform impact, and testing. Use the repository template and complete the missing sections, including the change type, release impact, desktop impact, related issue status, and testing details.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the CI fix for using an existing tag when generating release notes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/release-notes-start-tag

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
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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

Inline comments:
In @.github/workflows/build.yml:
- Around line 762-763: Update the release-notes setup around FALLBACK and
NOTES_START_TAG to track whether a previous tag exists instead of using the root
commit SHA as a notes-start tag. Omit --notes-start-tag for the first stable
release, while retaining the root SHA only for RC git log range calculations.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: cc899fb5-8862-47e0-a860-506c5ee2654f

📥 Commits

Reviewing files that changed from the base of the PR and between e032894 and 55a225d.

📒 Files selected for processing (1)
  • .github/workflows/build.yml

Comment thread .github/workflows/build.yml Outdated
Comment on lines +762 to +763
FALLBACK="$(git describe --tags --abbrev=0 "${TAG}^" 2>/dev/null || true)"
NOTES_START_TAG="${FALLBACK:-$(git rev-list --max-parents=0 HEAD | tail -1)}"

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

ROOT_COMMIT="$(git rev-list --max-parents=0 HEAD | tail -n 1)"

if git show-ref --verify --quiet "refs/tags/${ROOT_COMMIT}"; then
  echo "::error::The root commit is already tagged; use an untagged test repository."
  exit 1
fi

rg -n -C 2 -- '--notes-start-tag "\$NOTES_START_TAG"' .github/workflows/build.yml

if [[ -z "${GH_TOKEN:-}" || -z "${GITHUB_REPOSITORY:-}" || -z "${RELEASE_TAG:-}" ]]; then
  echo "Set GH_TOKEN, GITHUB_REPOSITORY, and RELEASE_TAG to test the API request."
  exit 0
fi

gh api --method POST \
  "/repos/${GITHUB_REPOSITORY}/releases/generate-notes" \
  -f "tag_name=${RELEASE_TAG}" \
  -f "previous_tag_name=${ROOT_COMMIT}" \
  --jq '.body' >/dev/null

Repository: getopenscreen/openscreen

Length of output: 548


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- workflow context ---'
sed -n '735,850p' .github/workflows/build.yml

printf '%s\n' '--- tags ---'
git tag --sort=creatordate | tail -n 30

printf '%s\n' '--- relevant identifiers ---'
rg -n -C 3 'NOTES_START_TAG|FALLBACK|NOTES_ARGS|generate-notes|release create|RC|stable' .github/workflows/build.yml

Repository: getopenscreen/openscreen

Length of output: 18090


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

# Read-only verifier for the fallback contract and the two release-note paths.
set +e
current_tag="$(git describe --tags --abbrev=0 HEAD 2>/dev/null)"
describe_status=$?
set -e

root_commit="$(git rev-list --max-parents=0 HEAD | tail -n 1)"
printf 'root_commit=%s\n' "$root_commit"
printf 'describe_head_status=%s value=%s\n' "$describe_status" "${current_tag:-<none>}"

if [[ -n "$current_tag" ]]; then
  set +e
  previous_tag="$(git describe --tags --abbrev=0 "${current_tag}^" 2>/dev/null)"
  previous_status=$?
  set -e
else
  previous_tag=''
  previous_status=128
fi

printf 'fallback_status=%s value=%s\n' "$previous_status" "${previous_tag:-<none>}"
if [[ -n "$previous_tag" ]]; then
  notes_start_tag="$previous_tag"
  notes_start_tag_is_tag=true
else
  notes_start_tag="$root_commit"
  notes_start_tag_is_tag=false
fi

printf 'notes_start_tag=%s\n' "$notes_start_tag"
printf 'notes_start_tag_is_tag=%s\n' "$notes_start_tag_is_tag"

if [[ "$notes_start_tag_is_tag" == true ]]; then
  printf 'stable_notes_args=--generate-notes --notes-start-tag %s\n' "$notes_start_tag"
else
  printf 'stable_notes_args=--generate-notes\n'
fi
printf 'rc_range=%s..HEAD\n' "$notes_start_tag"

Repository: getopenscreen/openscreen

Length of output: 463


🌐 Web query:

GitHub REST API generate release notes previous_tag_name tag name commit SHA behavior gh release create --notes-start-tag

💡 Result:

The GitHub Release Notes API and the GitHub CLI (gh) provide mechanisms to automatically generate release notes, specifically allowing you to define the range of changes by specifying a starting point. GitHub REST API (Generate Release Notes Endpoint) The endpoint POST /repos/{owner}/{repo}/releases/generate-notes is designed to generate release notes without saving them [1][2]. - previous_tag_name: This body parameter allows you to manually specify the starting tag for the range of changes [1][2]. If provided, the API generates notes for the changes between this tag and the tag_name specified [1]. - tag_name: This required body parameter is the tag name for the new release [1][2]. - target_commitish: This specifies the commit SHA or branch for the tag [1][2]. If the tag does not yet exist, this is required to define where the tag should be placed [1][2]. GitHub CLI (gh release create) The GitHub CLI command gh release create uses the Generate Release Notes API when the --generate-notes flag is passed [3][4]. - --notes-start-tag: This flag allows you to specify the starting tag for the generated release notes, which corresponds to the previous_tag_name parameter in the underlying REST API [5]. - Behavior Note: When using --notes-start-tag, it is often necessary to explicitly include the --generate-notes flag to ensure the CLI uses the Release Notes API to produce the body content rather than reverting to interactive mode or other defaults [6]. - Distinction: --notes-start-tag (used with --generate-notes) should not be confused with --notes-from-tag. The latter fetches notes from the git tag annotation or the commit message associated with the tag, rather than invoking the Release Notes API to summarize changes and contributors [7][4]. In summary, the REST API uses previous_tag_name to define the range, and the CLI exposes this via the --notes-start-tag flag, which should be used in conjunction with --generate-notes to produce automated summary content [1][5].

Citations:


Do not pass the root commit SHA as --notes-start-tag.

When no prior tag exists, NOTES_START_TAG contains the root commit SHA. The stable-release path always passes this value to GitHub's tag-based release-notes API. Track whether the value is a tag, and omit --notes-start-tag for the first stable release. Use the root SHA only for RC git log ranges.

🤖 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 @.github/workflows/build.yml around lines 762 - 763, Update the release-notes
setup around FALLBACK and NOTES_START_TAG to track whether a previous tag exists
instead of using the root commit SHA as a notes-start tag. Omit
--notes-start-tag for the first stable release, while retaining the root SHA
only for RC git log range calculations.

The fallback filled NOTES_START_TAG with the root commit's SHA so the range
would always be valid. That is right for the RC path, which feeds it to
`git log`, and wrong for the stable path, which feeds it to `gh release create
--notes-start-tag` -- the API's previous_tag_name, which takes a tag NAME. A SHA
there is an invalid argument, not a lenient fallback, so the one case the
fallback existed for would still have failed.

It now stays empty when no tag is reachable, and each consumer handles that:
the RC notes walk the whole history and drop the "since <tag>" wording rather
than printing a blank where a tag should be, and the stable path omits the flag
so GitHub picks its own previous release -- which is the correct answer when
there is not one.

Unreachable on this repo today (v1.9.2 is right there), so this is about the
next fork or a fresh repository rather than about 1.9.4.
@EtienneLescot
EtienneLescot merged commit be6e883 into main Aug 10, 2026
15 of 16 checks passed
@EtienneLescot
EtienneLescot deleted the fix/release-notes-start-tag branch August 10, 2026 21:06
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