-
Notifications
You must be signed in to change notification settings - Fork 0
feat: phase out release-drafter #50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
See cpp-linter/.github#50 for new release workflow See cpp-linter/.github#49 for changes to pre-commit workflow I generated the CHANGELOG doc which summarizes all previous releases.
See cpp-linter/.github#50 for new release workflow See cpp-linter/.github#49 for changes to pre-commit workflow I generated the CHANGELOG doc which summarizes all previous releases.
See cpp-linter/.github#50 for new release workflow See cpp-linter/.github#49 for changes to pre-commit workflow I generated the CHANGELOG doc which summarizes all previous releases.
WalkthroughAdds organization-wide release tooling: a git-cliff changelog configuration, Nu shell release orchestration script, and GitHub Actions workflows for tagging releases, generating unreleased summaries, and labeling PRs. Also updates Dependabot, spell-check words, and VS Code workspace settings. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Suggested reviewers
Pre-merge checks (3 passed)✅ Passed checks (3 passed)
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches🧪 Generate unit tests
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. Comment |
c84f242 to
cf14c37
Compare
1c1fb5b to
8f641fc
Compare
|
Instead of using a nushell script, I guess I could rewrite it as a TS (using deno for simplicity). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
.github/workflows/tag-release.nu (1)
161-176: Handle SSH remotes without double-prefixing; fix SCP vs ssh:// cases.Wrapping any non-HTTPS origin with
ssh://(...)yieldsssh://ssh://...for URLs that already include a scheme and can also mis-handle SCP-style remotes. Branch explicitly.export def find-repo-name [] { $env | get --optional "GITHUB_REPO" | default { let origin = (^git remote get-url origin) | str trim - ( - if (not ($origin | str starts-with "https://")) { - let patched_ssh = $origin | str replace --regex '([^:]):' '$1:/' - $"ssh://($patched_ssh)" - } else { - $origin - } - ) + let normalized = ( + if ($origin | str starts-with "http://") or ($origin | str starts-with "https://") { + $origin + } else if ($origin | str starts-with "ssh://") { + # Ensure host:/path when a bare colon separates host and path + $origin | str replace --regex '^(ssh://[^/]+):(?=[^/])' '${1}:/' + } else { + # SCP-style: git@host:owner/repo(.git) + $"ssh://($origin | str replace --regex '^([^:]+):' '${1}:/')" + } + ) - | url parse + $normalized + | url parse | get path | str trim --left --char "/" | path parse | format pattern "{parent}/{stem}" } }
🧹 Nitpick comments (5)
.github/cliff.toml (3)
34-45: Avoid dropping distinct commits that share the same summary line.
unique(attribute="message")will collapse different commits/PRs with identical first lines. Prefer de-duping by(message, remote.pr_number, id)or just remove theuniqueto list all entries.- {% for commit in commits | unique(attribute="message") %} + {% for commit in commits %}
99-101: Confirm final casing for the “Breaking …” group; keep it consistent with your chosen UX.You previously noted the title should be “Breaking Changes” (uppercase C) for continuity with Release Drafter. Current config uses “Breaking changes”. If you intend the uppercase variant, update these lines so all rules map to exactly the same string to avoid split sections.
- { field = "github.pr_labels", pattern = "breaking", group = "<!-- 0 --> 💥 Breaking changes" }, - { field = "github.pr_labels", pattern = "breaking-change", group = "<!-- 0 --> 💥 Breaking changes" }, + { field = "github.pr_labels", pattern = "breaking", group = "<!-- 0 --> 💥 Breaking Changes" }, + { field = "github.pr_labels", pattern = "breaking-change", group = "<!-- 0 --> 💥 Breaking Changes" }, @@ - { field = "breaking", pattern = true, group = "<!-- 0 --> 💥 Breaking changes" }, + { field = "breaking", pattern = true, group = "<!-- 0 --> 💥 Breaking Changes" },Also applies to: 133-133
140-155: Tighten some message heuristics to reduce false positives.Patterns like
^.*: supportand^.*: fixmatch anywhere after a colon; combined with the case-insensitive variants they can over-capture. Consider anchoring only when intended or removing duplicates where the(?i)^versions already cover them.- { message = "^.*: add", group = "<!-- 1 --> 🚀 New features and improvements" }, + { message = "(?i)^add", group = "<!-- 1 --> 🚀 New features and improvements" }, @@ - { message = "^.*: remove", group = "<!-- 3 --> 🚨 Removed" }, + { message = "(?i)^remove", group = "<!-- 3 --> 🚨 Removed" }, @@ - { message = "^.*: fix", group = "<!-- 4 --> 🐛 Bug fixes" }, + { message = "(?i)^fix", group = "<!-- 4 --> 🐛 Bug fixes" }, @@ - { message = "^.*: security", group = "<!-- 5 --> 🔐 Security" }, + { message = "(?i)^security", group = "<!-- 5 --> 🔐 Security" },.github/workflows/tag-release.nu (2)
34-43: is-on-main breaks on detached HEAD in CI; add a robust fallback.GitHub Actions often checks out a detached HEAD. Use
GITHUB_REF_NAMEwhen present, and fall back togit symbolic-ref --short -q HEAD.-export def is-on-main [] { - let branch = ( - ^git branch - | lines - | where {$in | str starts-with '*'} - | first - | str trim --left --char '*' - | str trim - ) == 'main' - $branch -} +export def is-on-main [] { + let from_env = ($env | get --optional GITHUB_REF_NAME | default null) + if ($from_env | is-not-empty) { $from_env == 'main' } else { + let name = (^git symbolic-ref --short -q HEAD | str trim) + $name == 'main' + } +}
128-146: Rolling tag mover works; consider idempotency on missing remote tag.Logic correctly deletes and repoints the major tag. Optional: guard remote deletion with
--deletesemantics viagit push origin :refs/tags/$major_tagis fine; no change required.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
.github/cliff.toml(1 hunks).github/dependabot.yml(1 hunks).github/labeler.yml(1 hunks).github/release-drafter.yml(0 hunks).github/requirements.txt(1 hunks).github/workflows/labeler.yml(1 hunks).github/workflows/release-drafter.yml(0 hunks).github/workflows/tag-release.nu(1 hunks).github/workflows/tag-release.yml(1 hunks).github/workflows/unreleased-summary.yml(1 hunks).vscode/extensions.json(1 hunks).vscode/settings.json(1 hunks)cspell.config.yml(1 hunks)
💤 Files with no reviewable changes (2)
- .github/workflows/release-drafter.yml
- .github/release-drafter.yml
🚧 Files skipped from review as they are similar to previous changes (9)
- .vscode/settings.json
- .github/requirements.txt
- .github/dependabot.yml
- .vscode/extensions.json
- cspell.config.yml
- .github/labeler.yml
- .github/workflows/labeler.yml
- .github/workflows/tag-release.yml
- .github/workflows/unreleased-summary.yml
🧰 Additional context used
🧠 Learnings (11)
📓 Common learnings
Learnt from: 2bndy5
PR: cpp-linter/.github#50
File: .github/workflows/tag-release.nu:52-59
Timestamp: 2025-09-09T13:44:00.556Z
Learning: In repositories using git-cliff with conventional_commits = true and proper tag handling templates (like cpp-linter/.github's cliff.toml), the command `git-cliff --bumped-version` outputs properly formatted version tags with the "v" prefix (e.g., "v1.11.0"), not bare version numbers without the prefix.
Learnt from: 2bndy5
PR: cpp-linter/.github#50
File: .github/workflows/tag-release.nu:164-191
Timestamp: 2025-09-08T04:22:14.942Z
Learning: In git-cliff workflows, the --tag parameter should be passed even when generating release notes from unreleased changes because the tag being summarized doesn't exist yet when git-cliff runs. The --tag parameter tells git-cliff what version to associate with the unreleased changes, and the actual tag creation happens after git-cliff generates the notes/changelog.
Learnt from: 2bndy5
PR: cpp-linter/.github#50
File: .github/labeler.yml:1-16
Timestamp: 2025-09-09T13:10:30.243Z
Learning: 2bndy5 prefers to indent list items in YAML files for better readability, even when it may differ from common formatting conventions.
📚 Learning: 2025-09-09T13:44:00.556Z
Learnt from: 2bndy5
PR: cpp-linter/.github#50
File: .github/workflows/tag-release.nu:52-59
Timestamp: 2025-09-09T13:44:00.556Z
Learning: In repositories using git-cliff with conventional_commits = true and proper tag handling templates (like cpp-linter/.github's cliff.toml), the command `git-cliff --bumped-version` outputs properly formatted version tags with the "v" prefix (e.g., "v1.11.0"), not bare version numbers without the prefix.
Applied to files:
.github/cliff.toml.github/workflows/tag-release.nu
📚 Learning: 2025-09-08T04:26:49.968Z
Learnt from: 2bndy5
PR: cpp-linter/.github#50
File: .github/cliff.toml:133-133
Timestamp: 2025-09-08T04:26:49.968Z
Learning: In the cpp-linter/.github repository's .github/cliff.toml file, the "Breaking Changes" group title (uppercase C) is intentionally kept consistent with previous release-drafter output format to maintain user experience, even though other group titles use lowercase (e.g., "Breaking changes"). This inconsistency is by design for backward compatibility.
Applied to files:
.github/cliff.toml.github/workflows/tag-release.nu
📚 Learning: 2025-09-09T13:44:00.556Z
Learnt from: 2bndy5
PR: cpp-linter/.github#50
File: .github/workflows/tag-release.nu:52-59
Timestamp: 2025-09-09T13:44:00.556Z
Learning: In the cpp-linter/.github repository, git-cliff --bumped-version outputs version numbers with the "v" prefix (e.g., "v1.11.0") when using the configured .github/cliff.toml, contrary to assumptions about default git-cliff behavior outputting versions without the "v" prefix.
Applied to files:
.github/cliff.toml.github/workflows/tag-release.nu
📚 Learning: 2025-09-08T04:22:14.942Z
Learnt from: 2bndy5
PR: cpp-linter/.github#50
File: .github/workflows/tag-release.nu:164-191
Timestamp: 2025-09-08T04:22:14.942Z
Learning: In git-cliff workflows, the --tag parameter should be passed even when generating release notes from unreleased changes because the tag being summarized doesn't exist yet when git-cliff runs. The --tag parameter tells git-cliff what version to associate with the unreleased changes, and the actual tag creation happens after git-cliff generates the notes/changelog.
Applied to files:
.github/cliff.toml.github/workflows/tag-release.nu
📚 Learning: 2025-09-08T04:20:32.371Z
Learnt from: 2bndy5
PR: cpp-linter/.github#50
File: .github/workflows/tag-release.nu:142-158
Timestamp: 2025-09-08T04:20:32.371Z
Learning: In git-cliff, when the GIT_CLIFF_CONFIG environment variable is set, git-cliff automatically uses it for configuration. There's no need to pass the --config parameter with the same value, as the environment variable takes precedence. Functions that detect GIT_CLIFF_CONFIG should return null/empty when it's present, allowing git-cliff to use the env var directly.
Applied to files:
.github/workflows/tag-release.nu
📚 Learning: 2025-09-08T06:25:14.311Z
Learnt from: 2bndy5
PR: cpp-linter/.github#50
File: .github/workflows/tag-release.nu:123-133
Timestamp: 2025-09-08T06:25:14.311Z
Learning: Nushell's url parse command fails on SSH URLs in the format "githost:path" due to a bug in the underlying url crate (https://github.com/servo/rust-url/issues/599). The parser cannot distinguish between port and path in SSH URLs without the ssh:// scheme. For robust parsing of git remote URLs, use string manipulation for SSH format (githost:path) and url parse only for HTTPS URLs.
Applied to files:
.github/workflows/tag-release.nu
📚 Learning: 2025-09-09T15:59:38.232Z
Learnt from: 2bndy5
PR: cpp-linter/.github#50
File: .github/workflows/tag-release.nu:0-0
Timestamp: 2025-09-09T15:59:38.232Z
Learning: The cpp-linter organization projects use simple "v1.2.3" tag format without scoped prefixes (not "scope/v1.2.3" style), as they don't deploy from monorepos using fancy scoped tags.
Applied to files:
.github/workflows/tag-release.nu
📚 Learning: 2025-09-09T15:59:38.232Z
Learnt from: 2bndy5
PR: cpp-linter/.github#50
File: .github/workflows/tag-release.nu:0-0
Timestamp: 2025-09-09T15:59:38.232Z
Learning: The cpp-linter-rs project is a monorepo that uses its own separate bump-n-release workflow for deploying various packages, rather than using the unified tag-release workflow used by other cpp-linter projects.
Applied to files:
.github/workflows/tag-release.nu
📚 Learning: 2025-09-09T16:23:11.069Z
Learnt from: 2bndy5
PR: cpp-linter/.github#50
File: .github/workflows/tag-release.nu:26-28
Timestamp: 2025-09-09T16:23:11.069Z
Learning: In Nushell, `$in` is a valid variable that refers to the piped input value in pipeline contexts. It's not invalid syntax and can be used safely in expressions like `$env | get --optional CI | default 'false' | (($in == 'true') or ($in == true))`.
Applied to files:
.github/workflows/tag-release.nu
📚 Learning: 2025-09-09T16:23:11.069Z
Learnt from: 2bndy5
PR: cpp-linter/.github#50
File: .github/workflows/tag-release.nu:26-28
Timestamp: 2025-09-09T16:23:11.069Z
Learning: All CI platforms consistently use the string value `'true'` for the `CI` environment variable when it's set, making simple string comparison the most efficient approach for CI detection.
Applied to files:
.github/workflows/tag-release.nu
🔇 Additional comments (5)
.github/cliff.toml (1)
20-33: Nice job wiring FIRST_COMMIT and compare links.Initialization via FIRST_COMMIT and the Unreleased/Released compare ranges look correct and resilient for first release scenarios.
Also applies to: 47-61, 82-96
.github/workflows/tag-release.nu (4)
74-83: Auto-bump path is clean and trims git-cliff output.Parsing with
version parseafterstr trimavoids newline issues; returning viaversion joinguarantees a v-prefixed tag. LGTM.
281-291: Good UX: warning (local) vs error (CI) when GITHUB_TOKEN is missing.This will prevent confusing partial outputs in CI while allowing local dry runs. Nice.
232-236: Pass-through of FIRST_COMMIT and GITHUB_REPO to git-cliff is solid.Ensures correct diff links and avoids brittle remote parsing inside git-cliff.
216-228: Keep passing--tagfor both full and notes paths.This aligns with your workflow where the tag doesn’t exist yet at generation time. No changes needed.
2bndy5
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@shenxianpeng I don't expect you to review all of this. It is a pretty big patch. I've highlighted some of the important points in this review.
| run-cmd git config --global user.name $"($env.GITHUB_ACTOR)" | ||
| run-cmd git config --global user.email $"($env.GITHUB_ACTOR_ID)+($env.GITHUB_ACTOR)@users.noreply.github.com" | ||
| } | ||
| run-cmd git commit -m $"build: bump version to ($ver)" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the title of the commit pushed after updating the CHANGELOG.md file.
We could change this to something else, like maybe:
| run-cmd git commit -m $"build: bump version to ($ver)" | |
| run-cmd git commit -m $"chore: release ($ver)" |
Tip
git-cliff transforms commit titles when adding them to the CHANGELOG.
For example,
chore: release v1.11.0
is displayed as
Release v1.11.0
| def mv-rolling-tag [ | ||
| ver: string # The fully qualified version of the new tag. | ||
| ] { | ||
| let tag = version parse $ver | ||
| let major_tag = $"v($tag | get major)" | ||
| print $"Moving any tags named '($major_tag)'" | ||
| let tags = (^git tag --list) | lines | each {$in | str trim} | ||
| if ($major_tag in $tags) { | ||
| # delete local tag | ||
| run-cmd git tag -d $major_tag | ||
| # delete remote tag | ||
| run-cmd git push origin $":refs/tags/($major_tag)" | ||
|
|
||
| # create new tag | ||
| run-cmd git tag $major_tag | ||
| run-cmd git push origin $major_tag | ||
| print $"Adjusted tag ($major_tag)" | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This command will
- Take the new version (
ver) and extract themajor_tagfrom it (egv2fromv2.16.3) - Get all tags listed in
git tag --list. - If the
major_tagexists, then it is moved to HEAD (both locally and on remote).
So, there's no need to have an extra CI workflow triggered by a published release in cpp-linter-action.
Note
This command is called from main command after pushing the CHANGELOG update (if any) and creating the GitHub release (via gh-cli).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested this workflow on cpp-linter/cpp-linter#156. See CI summary page.
Note
When run on a non-default branch, all commit on the branch are included.
So, only runs on main branch will resemble what the release notes will look like.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The CI summary page looks good. Can we also have the draft release so that once we publish a release, it will also show on the GitHub Release page
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TL;DR What you see in the CI summary page is what will be used as the next release's notes.
To be clear, we won't be keeping a draft release anymore.
This PR is not meant to be an exact drop-in replacement of release-drafter. This PR proposes an alternative to release-drafter. See #47 for why I don't want to keep using release-drafter.
gh release create will create a new tag (if it doesn't exist already) when it creates the release.
We would manually trigger the tag-release workflow (in this repo) using gh-cli or the github.com UI (or using the github mobile app):

This picture is from a similar approach I use for the nRF24 org. There will be no "default branch" option for this org (see OP).
This means that every release of other cpp-linter repos will be triggered from this repo's tag-release workflow.
Old way (release-drafter)
- browsing to the project's releases
- edit a draft release
- click "Publish Release"
New way (tag-release.yml)
- browse to this repo's tag-release CI
- select the CI parameters
- click the "Run Workflow" button
The workflow will update the changelog, push the changes (if any), and publish a release (using release notes from the changelog about the new version).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested this workflow on cpp-linter/cpp-linter#156.
I verified that the title will affect the PR labels.
I had to exclude CHANGELOG.md file from adding the documentation label.
Other exceptions can be added in the .github/labeler.yml config file.
Currently, it is designed to resemble our old release-drafter config about auto-labeling.
| - package-ecosystem: pip | ||
| directory: .github/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just for updating the pinned version of git-cliff. (see .github/requirements.txt)
I’m a bit concerned that adding a separate CHANGELOG.md might make things more complicated. labeler.ymlRight now, the new labeler.yml may not be as good as before since it does not support adding labels based on the PR title. (release-drafter autoleber already supports branch, title, and body unreleased-summary.ymlThis looks similar to a GitHub draft release, but displayed on the summary page. I think using GitHub draft releases directly would be more effective than the information here. tag-release.ymlIt looks good. Currently, we are using git-cliff, which is quite popular right now. release-drafter isn’t dead—it just wasn’t very active before. Any popular project can become less active if the maintainer shifts focus. For now, it’s good that release-drafter has a new owner. From the perspective of simplicity and ease of use, I feel that release-drafter’s configuration is more straightforward and easier to understand. |
| # The rest of this simply adds labels based on the PR title. | ||
| # This isn't really necessary due to how git-cliff parses commits. | ||
| # This can be removed once actions/labeler resolves the feature request: | ||
| # https://github.com/actions/labeler/issues/809 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
release-drafter autoleber already supports branch, title, and body
https://github.com/release-drafter/release-drafter?tab=readme-ov-file#autolabeler
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes but it also requires write permission when it shouldn't need it. This workflow fixes that problem by separating the auto-label behavior (for PR only) from drafting release behavior (for main branch only)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes but it also requires write permission when it shouldn't need it
It needs both write permission to create a GitHub release and add label to PR. release-drafter/release-drafter#1187
contents: write # for release-drafter to create a github release
pull-requests: write # for release-drafter to add label to PRThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It shouldn't create a draft release for PR events. PR events have no bearing on releases until the changes are merged to main branch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The CI summary page looks good. Can we also have the draft release so that once we publish a release, it will also show on the GitHub Release page
ref #47 supports SSH when finding repo name from git remote URL
for bumping git-cliff automatically and group dependabot updates into 1 PR (for each ecosystem)
Some schemas are used where they shouldn't be (.github/workflows/mkdocs.yml). Some schemas are just outdated or incorrect (.github/labeler.yml). Prefer using GitHub Actions ext in VSCode to validate workflows
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
.github/workflows/labeler.yml (1)
58-75: Normalize existing labels before membership checks.
actions/labeler@v6returnsall-labelsas a comma-separated string, so splitting without trimming/normalizing leaves leading whitespace and preserves original casing. If the repo keeps labels likeBugorEnhancement, the case-sensitiveincheck will miss them and we’ll try to addbug/enhancementagain, which makesgh pr editfail with “label does not exist.” Normalizing up front avoids the duplicate add(es) and keeps the step resilient to formatting differences. (github.com)- let labels = $env.ALL_LABELS | split row "," + let labels = ( + $env.ALL_LABELS + | default "" + | split row "," + | each {|it| $it | str trim } + | compact + ) + let labels_lc = ($labels | each {|it| $it | str downcase }) @@ - and not ("bug" in $labels) + and not ("bug" in $labels_lc) @@ - and not ("enhancement" in $labels) + and not ("enhancement" in $labels_lc)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
.github/cliff.toml(1 hunks).github/dependabot.yml(1 hunks).github/labeler.yml(1 hunks).github/requirements.txt(1 hunks).github/workflows/labeler.yml(1 hunks).github/workflows/tag-release.nu(1 hunks).github/workflows/tag-release.yml(1 hunks).github/workflows/unreleased-summary.yml(1 hunks).vscode/extensions.json(1 hunks).vscode/settings.json(1 hunks)cspell.config.yml(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- .vscode/settings.json
🚧 Files skipped from review as they are similar to previous changes (7)
- .vscode/extensions.json
- .github/labeler.yml
- .github/dependabot.yml
- .github/workflows/tag-release.yml
- .github/requirements.txt
- .github/cliff.toml
- cspell.config.yml
🧰 Additional context used
🧠 Learnings (11)
📚 Learning: 2025-09-10T04:11:21.820Z
Learnt from: 2bndy5
PR: cpp-linter/.github#50
File: .github/workflows/labeler.yml:23-33
Timestamp: 2025-09-10T04:11:21.820Z
Learning: In GitHub Actions reusable workflows (workflow_call event), the github context is inherited from the calling workflow, including PR details and event data. Permissions are also inherited from the calling workflow, so actions like actions/labeler can access the necessary context and permissions without explicit token passing if the caller has granted the required permissions.
Applied to files:
.github/workflows/labeler.yml
📚 Learning: 2025-09-08T04:20:32.371Z
Learnt from: 2bndy5
PR: cpp-linter/.github#50
File: .github/workflows/tag-release.nu:142-158
Timestamp: 2025-09-08T04:20:32.371Z
Learning: In git-cliff, when the GIT_CLIFF_CONFIG environment variable is set, git-cliff automatically uses it for configuration. There's no need to pass the --config parameter with the same value, as the environment variable takes precedence. Functions that detect GIT_CLIFF_CONFIG should return null/empty when it's present, allowing git-cliff to use the env var directly.
Applied to files:
.github/workflows/tag-release.nu
📚 Learning: 2025-09-09T13:44:00.565Z
Learnt from: 2bndy5
PR: cpp-linter/.github#50
File: .github/workflows/tag-release.nu:52-59
Timestamp: 2025-09-09T13:44:00.565Z
Learning: In the cpp-linter/.github repository, git-cliff --bumped-version outputs version numbers with the "v" prefix (e.g., "v1.11.0") when using the configured .github/cliff.toml, contrary to assumptions about default git-cliff behavior outputting versions without the "v" prefix.
Applied to files:
.github/workflows/tag-release.nu
📚 Learning: 2025-09-08T04:22:14.942Z
Learnt from: 2bndy5
PR: cpp-linter/.github#50
File: .github/workflows/tag-release.nu:164-191
Timestamp: 2025-09-08T04:22:14.942Z
Learning: In git-cliff workflows, the --tag parameter should be passed even when generating release notes from unreleased changes because the tag being summarized doesn't exist yet when git-cliff runs. The --tag parameter tells git-cliff what version to associate with the unreleased changes, and the actual tag creation happens after git-cliff generates the notes/changelog.
Applied to files:
.github/workflows/tag-release.nu
📚 Learning: 2025-09-09T13:44:00.565Z
Learnt from: 2bndy5
PR: cpp-linter/.github#50
File: .github/workflows/tag-release.nu:52-59
Timestamp: 2025-09-09T13:44:00.565Z
Learning: In repositories using git-cliff with conventional_commits = true and proper tag handling templates (like cpp-linter/.github's cliff.toml), the command `git-cliff --bumped-version` outputs properly formatted version tags with the "v" prefix (e.g., "v1.11.0"), not bare version numbers without the prefix.
Applied to files:
.github/workflows/tag-release.nu
📚 Learning: 2025-09-08T06:25:14.311Z
Learnt from: 2bndy5
PR: cpp-linter/.github#50
File: .github/workflows/tag-release.nu:123-133
Timestamp: 2025-09-08T06:25:14.311Z
Learning: Nushell's url parse command fails on SSH URLs in the format "githost:path" due to a bug in the underlying url crate (https://github.com/servo/rust-url/issues/599). The parser cannot distinguish between port and path in SSH URLs without the ssh:// scheme. For robust parsing of git remote URLs, use string manipulation for SSH format (githost:path) and url parse only for HTTPS URLs.
Applied to files:
.github/workflows/tag-release.nu
📚 Learning: 2025-09-08T04:26:49.968Z
Learnt from: 2bndy5
PR: cpp-linter/.github#50
File: .github/cliff.toml:133-133
Timestamp: 2025-09-08T04:26:49.968Z
Learning: In the cpp-linter/.github repository's .github/cliff.toml file, the "Breaking Changes" group title (uppercase C) is intentionally kept consistent with previous release-drafter output format to maintain user experience, even though other group titles use lowercase (e.g., "Breaking changes"). This inconsistency is by design for backward compatibility.
Applied to files:
.github/workflows/tag-release.nu
📚 Learning: 2025-09-09T15:59:38.273Z
Learnt from: 2bndy5
PR: cpp-linter/.github#50
File: .github/workflows/tag-release.nu:0-0
Timestamp: 2025-09-09T15:59:38.273Z
Learning: The cpp-linter organization projects use simple "v1.2.3" tag format without scoped prefixes (not "scope/v1.2.3" style), as they don't deploy from monorepos using fancy scoped tags.
Applied to files:
.github/workflows/tag-release.nu
📚 Learning: 2025-09-09T15:59:38.273Z
Learnt from: 2bndy5
PR: cpp-linter/.github#50
File: .github/workflows/tag-release.nu:0-0
Timestamp: 2025-09-09T15:59:38.273Z
Learning: The cpp-linter-rs project is a monorepo that uses its own separate bump-n-release workflow for deploying various packages, rather than using the unified tag-release workflow used by other cpp-linter projects.
Applied to files:
.github/workflows/tag-release.nu
📚 Learning: 2025-09-09T16:23:11.088Z
Learnt from: 2bndy5
PR: cpp-linter/.github#50
File: .github/workflows/tag-release.nu:26-28
Timestamp: 2025-09-09T16:23:11.088Z
Learning: In Nushell, `$in` is a valid variable that refers to the piped input value in pipeline contexts. It's not invalid syntax and can be used safely in expressions like `$env | get --optional CI | default 'false' | (($in == 'true') or ($in == true))`.
Applied to files:
.github/workflows/tag-release.nu
📚 Learning: 2025-09-09T16:23:11.088Z
Learnt from: 2bndy5
PR: cpp-linter/.github#50
File: .github/workflows/tag-release.nu:26-28
Timestamp: 2025-09-09T16:23:11.088Z
Learning: All CI platforms consistently use the string value `'true'` for the `CI` environment variable when it's set, making simple string comparison the most efficient approach for CI detection.
Applied to files:
.github/workflows/tag-release.nu
🔇 Additional comments (16)
.github/workflows/unreleased-summary.yml (1)
1-45: LGTM! Workflow structure is well-designed.The unreleased-summary workflow correctly:
- Uses
workflow_callfor reusability across projects- Sets minimal required permissions (contents: read, pull-requests: read)
- Checks out both the project repo (with full history via
fetch-depth: 0) and the org repo for shared configuration- Properly configures uv with caching against the project's
uv.lock- Passes required environment variables (
GITHUB_TOKEN,GITHUB_REPO,GIT_CLIFF_CONFIG,UV_CONSTRAINT) to git-cliff- Outputs the unreleased summary directly to
GITHUB_STEP_SUMMARYfor easy previewThe multiline run command with
>-correctly folds arguments without introducing unwanted newlines..github/workflows/tag-release.nu (15)
4-21: LGTM! Well-designed utility function.The
run-cmdfunction provides good UX by:
- Displaying the full command being executed
- Measuring and reporting elapsed time
- Smartly abbreviating the command name for common tools (git, gh, uvx)
The use of
--wrappedparameter and command spreading is correct.
26-28: LGTM! CI detection is correct.Based on learnings,
$inis valid in Nushell pipeline contexts, and all CI platforms use the string'true'for theCIenvironment variable. The current implementation is both correct and efficient.
30-43: LGTM! Branch detection is implemented correctly.The function properly filters for the current branch (marked with
*), trims whitespace, and compares against'main'. The implementation is clear and correct.
45-65: LGTM! Version parsing utilities are well-designed.The
version parseandversion joinhelper functions correctly:
- Strip the leading "v" prefix before parsing
- Parse into major/minor/patch components with type conversion
- Format back into the standard "v{major}.{minor}.{patch}" pattern
Clean and reusable design.
74-83: LGTM! Auto-bump logic is correct.The auto-bump path properly:
- Passes
--bumped-versionto git-cliff- Includes the cliff config when available
- Trims the output (addressing previous review feedback)
- Parses and re-joins to normalize the version format
Based on learnings, git-cliff with this repo's configuration outputs versions with the "v" prefix, and the trim/parse/join flow ensures consistency.
85-120: LGTM! Manual bump logic handles all cases correctly.The manual bump implementation:
- Falls back to "v0.0.0" when no tags exist (addressing previous feedback about new repos)
- Uses
completeto safely handle git errors- Correctly increments each component (major resets minor/patch; minor resets patch)
- Validates the component parameter with a clear error message
Well thought-out and defensive.
128-146: LGTM! Rolling tag management is correctly implemented.The
mv-rolling-tagfunction:
- Extracts the major version (e.g., "v2" from "v2.16.3")
- Checks if that major tag exists in the repo
- Deletes the local and remote tag
- Recreates and pushes the tag pointing to HEAD
This enables convenient major-version tracking for users who want to stay on the latest v2.x.x release, for example.
152-154: LGTM! First commit detection is straightforward.Using
git rev-list --max-parents=0 HEADcorrectly finds the initial commit, which git-cliff needs for proper diff hyperlink generation.
160-177: LGTM! Repo name detection handles multiple URL formats.Based on learnings, the function correctly:
- Checks for
GITHUB_REPOin the environment first- Falls back to parsing the git remote URL
- Handles SCP-style SSH URLs (git@host:org/repo.git) by converting them to a parseable format
- Uses
url parsefor HTTPS URLs- Extracts the org/repo path correctly
The workaround for Nushell's URL parsing limitation with SCP-style URLs is appropriate.
185-203: LGTM! Config discovery respects environment variable.Based on learnings, when
GIT_CLIFF_CONFIGis set, git-cliff automatically uses it, so returningnullhere is correct—the function doesn't need to pass--configwith the same value. The fallback logic searches plausible locations when the env var is not set.This design allows the workflow to override the config via environment while maintaining a sensible default.
205-206: LGTM! Constants are appropriately defined.
CHANGELOGandRELEASE_NOTESare clearly named and correctly scoped (RELEASE_NOTES is exported for potential use by callers).
209-236: LGTM! Changelog generation is correctly implemented.The
gen-changesfunction:
- Accepts all necessary parameters (version, first commit, repo name, cliff config)
- Passes
--tageven for unreleased changes (correct per learnings—the tag doesn't exist yet)- Conditionally generates either the full CHANGELOG.md or just release notes
- Properly sets
FIRST_COMMITandGITHUB_REPOin the environment for git-cliff (addressing previous feedback)The use of
with-envto pass environment variables without polluting the global scope is a good practice.
264-316: LGTM! Early validation and setup is thorough.The main function correctly:
- Discovers the repo name and first commit
- Blocks execution on the
.githuborg repo to prevent accidental deployment- Checks for
GITHUB_TOKENand warns/errors appropriately based on CI context- Finds the cliff config
- Validates and normalizes the component parameter with helpful messages
- Determines the next version
- Ensures the script only runs on the
mainbranchComprehensive guards prevent common mistakes.
317-330: LGTM! Changelog update and push logic is sound.The script:
- Regenerates the full CHANGELOG.md with
--full- Stages all changes with
git add --all- Checks for actual changes before committing
- Configures git identity in CI using GitHub actor information
- Uses a clear commit message ("build: bump version to vX.Y.Z")
- Pushes changes to remote
The conditional commit ensures no empty commits are created.
332-350: LGTM! Release creation and rolling tag management complete the workflow.The final steps:
- Generate release notes for just the new version (via
gen-changeswithout--full)- Create a GitHub release with the new version tag using gh-cli
- Pass the release notes file, title, and repo correctly
- Move any corresponding major version tags to point at the new release (e.g., move v2 to v2.16.3)
The sequence is correct: changelog update is pushed first, then the release is created (which creates the git tag), then rolling tags are adjusted. This ensures the release points to the commit containing the updated CHANGELOG.
ref #47
This introduces 3 workflows:
labeler.yml
A reusable workflow that employs actions/labeler to auto manage certain labels based on branch name and changed files. It also has a step to add labels based on PR title (using gh-cli). This workflow is designed to be a replacement of the auto-labeler behavior in release-drafter.
The config for actions/labeler resides in this org repo under
.github/labeler.yml.unreleased-summary.yml
A reusable workflow that will summarize unreleased changes in the run's summary (
GITHUB_STEP_SUMMARY).tag-release.yml
A manually-triggered workflow that invokes the tag-release.nu script (primarily designed to be executed in CI).
This tag-release workflow will take 2 inputs:
project(required): The project to deploy. Supported projects can be selected from the drop-down options..github/.github/workflows/tag-release.yml
Lines 11 to 18 in 519a108
component(optional): The version component to bump. Supported values are.github/.github/workflows/tag-release.yml
Lines 28 to 32 in 519a108
autois selected (the default value), the version will be bumped according to the unreleased changes (via git-cliff bump policy in .github/cliff.toml). Observe the step summary from the unreleased-summary.yml workflow because it uses the auto version bump feature.nu .github/workflows/tag-release.nu -hSummary by CodeRabbit
New Features
Chores