Skip to content

feat(ci): add basic release workflows#665

Draft
Molter73 wants to merge 1 commit into
mainfrom
mauro/ci/releaser
Draft

feat(ci): add basic release workflows#665
Molter73 wants to merge 1 commit into
mainfrom
mauro/ci/releaser

Conversation

@Molter73
Copy link
Copy Markdown
Contributor

Description

Since the repository has some pretty strict rules about pushing certain branches, we need to define some basic workflows that will allow us to push them via a robot account. While we are at it, we are also automating some of the additional steps needed for updating and pinning versions

TODO: update release.md

Checklist

  • Patch has a change log entry OR does not need one.
  • Investigated and inspected CI test results
  • Updated documentation accordingly

Automated testing

  • Added unit tests
  • Added integration tests
  • Added regression tests

If any of these don't apply, please comment below.

Testing Performed

TODO(replace-me)
Use this space to explain how you tested your PR, or, if you didn't test it, why you did not do so. (Valid reasons include "CI is sufficient" or "No testable changes")
In addition to reviewing your code, reviewers must also review your testing instructions, and make sure they are sufficient.

For more details, ref the Confluence page about this section.

Since the repository has some pretty strict rules about pushing certain
branches, we need to define some basic workflows that will allow us to
push them via a robot account. While we are at it, we are also
automating some of the additional steps needed for updating and pinning
versions

TODO: update release.md
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 13, 2026

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • Chores
    • Added automated release branch preparation workflow with version validation, Rust toolchain pinning, and changelog management.
    • Added automated release workflow for version tagging and publication.

Walkthrough

This PR adds two new GitHub Actions workflows to automate the release process. The prepare-release.yml workflow validates version inputs and creates release branches with pinned Rust versions and updated changelogs. The release.yml workflow computes patch versions from git tags and creates annotated release tags.

Changes

Release Automation

Layer / File(s) Summary
Prepare release branch workflow
.github/workflows/prepare-release.yml
Workflow accepts version, next-version, and rust-version inputs in <Major>.<minor> format, validates them via regex, creates a release-<version> branch with an internal <version>.x tag, updates constants.mk to pin RUST_VERSION, updates fact/Cargo.toml to <version>.0 on release branch, updates CHANGELOG.md to add a section for the new version, updates fact/Cargo.toml to <next-version>.0-dev on main, and conditionally opens PRs for both sets of changes when not in dry-run mode.
Release tag creation workflow
.github/workflows/release.yml
Workflow accepts a version input, checks out the corresponding release branch with full history, computes a patch number by matching the latest git tag against expected patterns (<VERSION>.x or <VERSION>.<number>), configures git identity using the workflow sender, creates an annotated tag with v<VERSION>.<PATCH>, and conditionally pushes the tag to origin when not in dry-run mode.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive The description follows the template structure but contains incomplete sections: 'TODO: update release.md' and 'TODO(replace-me)' in the Testing Performed section indicate unfinished work before merge. Complete the TODOs: update release.md documentation and replace the Testing Performed section with actual testing details or a valid reason why testing was not performed.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(ci): add basic release workflows' accurately and concisely summarizes the main change—adding GitHub Actions workflows for release automation.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch mauro/ci/releaser

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 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/prepare-release.yml:
- Around line 63-74: Make the tag and branch steps idempotent so rerunning the
workflow doesn't fail: for the tag referenced as "${{ inputs.version }}.x" check
whether the tag already exists (e.g., via git rev-parse --verify) and only
create it if missing instead of unconditionally running git tag; for the branch
"release-${{ inputs.version }}" use git checkout -B "release-${{ inputs.version
}}" to recreate/reset the local branch reliably, fetch remote refs first, and
when pushing use a safe update (git push --force-with-lease origin "release-${{
inputs.version }}" or push the tag only if newly created) so the Push internal
tag and release-${{ inputs.version }} branch step becomes rerunnable without
manual cleanup.
- Around line 123-127: The update-version job currently only depends on
validate-version, so it can run and open the next-version PR even if
prepare-release-branch fails; change its dependencies so update-version also
waits for the prepare-release-branch job to complete successfully (add
prepare-release-branch to the needs list for the update-version job), ensuring
update-version will not advance main before a release branch/tag is created.
- Around line 82-86: The checkout step always tries to fetch ref: release-${{
inputs.version }} which fails in dry-run because that remote branch isn't
pushed; replace the single checkout with two conditional steps: one
actions/checkout@v6 step that includes ref: release-${{ inputs.version }} and
runs only when inputs.dry-run is false, and a second actions/checkout@v6 step
without the ref (default checkout of the workflow commit) that runs when
inputs.dry-run is true; update the step names accordingly so later steps use the
same workspace.

In @.github/workflows/release.yml:
- Around line 51-60: The tag is constructed with undefined variable RELEASE and
PATCH isn't exported to the Push tag step; update the Create release tag step to
build the tag using the defined VERSION and the patch from
steps.patch.outputs.patch (e.g., use "${VERSION}.${{ steps.patch.outputs.patch
}}") and export or set PATCH consistently so the Push tag step pushes the exact
same ref (or change the Push tag step to push "${VERSION}.${{
steps.patch.outputs.patch }}" too); ensure both steps reference the same
variables (replace RELEASE with VERSION and either set env PATCH from
steps.patch.outputs.patch or inline the steps.patch.outputs.patch expression in
both steps) so the tag name is correct and consistent.
- Around line 29-44: Patch selection currently uses git describe --tags
--abbrev=0 which returns the nearest tag from HEAD (variable last_tag in the
"Determine patch version" step); change it to explicitly pick the latest tag
matching the requested series ${VERSION}.* (e.g. replace the last_tag assignment
with a command that lists tags filtered by pattern and sorts by version, such as
using git tag --list "${VERSION}.*" --sort=-v:refname | head -n1), then keep the
existing regex/patch logic but add a guard to fail if no matching tag is found
(empty last_tag) so the patch calculation uses the correct series tag instead of
a nearest unrelated tag.
🪄 Autofix (Beta)

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: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 5db6a745-9ef7-4156-9be2-6df4dd8c93f0

📥 Commits

Reviewing files that changed from the base of the PR and between d8ceac0 and 21762dc.

📒 Files selected for processing (2)
  • .github/workflows/prepare-release.yml
  • .github/workflows/release.yml

Comment on lines +63 to +74
- name: Create internal tag and release-${{ inputs.version }} branch
run: |
git checkout main
git pull --ff-only
git tag "${{ inputs.version }}.x"
git checkout -b "release-${{ inputs.version }}"

- name: Push internal tag and release-${{ inputs.version }} branch
if: ${{ ! inputs.dry-run }}
run: |
git push origin "${{ inputs.version }}.x"
git push --set-upstream origin "release-${{ inputs.version }}"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Make branch/tag creation rerunnable.

These commands unconditionally recreate the internal tag and release branch. If a later job fails after the push, rerunning the workflow stops here and requires manual cleanup before you can recover.

🤖 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/prepare-release.yml around lines 63 - 74, Make the tag and
branch steps idempotent so rerunning the workflow doesn't fail: for the tag
referenced as "${{ inputs.version }}.x" check whether the tag already exists
(e.g., via git rev-parse --verify) and only create it if missing instead of
unconditionally running git tag; for the branch "release-${{ inputs.version }}"
use git checkout -B "release-${{ inputs.version }}" to recreate/reset the local
branch reliably, fetch remote refs first, and when pushing use a safe update
(git push --force-with-lease origin "release-${{ inputs.version }}" or push the
tag only if newly created) so the Push internal tag and release-${{
inputs.version }} branch step becomes rerunnable without manual cleanup.

Comment on lines +82 to +86
- uses: actions/checkout@v6
with:
submodules: false
ref: release-${{ inputs.version }}
token: ${{ secrets.RHACS_BOT_GITHUB_TOKEN }}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Dry runs cannot reach this checkout.

prepare-release-branch only pushes release-${{ inputs.version }} when dry-run is false, but this job always checks that ref out from origin. In dry-run mode the branch does not exist remotely, so the workflow fails before the validation diff is produced.

Possible fix
   pin-rust-version:
     runs-on: ubuntu-24.04
     needs:
     - validate-version
     - prepare-release-branch
     steps:
       - uses: actions/checkout@v6
         with:
           submodules: false
-          ref: release-${{ inputs.version }}
+          ref: main
           token: ${{ secrets.RHACS_BOT_GITHUB_TOKEN }}
+
+      - name: Switch to release branch
+        run: |
+          if [[ "${{ inputs.dry-run }}" == "true" ]]; then
+            git checkout -b "release-${{ inputs.version }}"
+          else
+            git fetch origin "release-${{ inputs.version }}:release-${{ inputs.version }}"
+            git checkout "release-${{ inputs.version }}"
+          fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- uses: actions/checkout@v6
with:
submodules: false
ref: release-${{ inputs.version }}
token: ${{ secrets.RHACS_BOT_GITHUB_TOKEN }}
- uses: actions/checkout@v6
with:
submodules: false
ref: main
token: ${{ secrets.RHACS_BOT_GITHUB_TOKEN }}
- name: Switch to release branch
run: |
if [[ "${{ inputs.dry-run }}" == "true" ]]; then
git checkout -b "release-${{ inputs.version }}"
else
git fetch origin "release-${{ inputs.version }}:release-${{ inputs.version }}"
git checkout "release-${{ inputs.version }}"
fi
🤖 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/prepare-release.yml around lines 82 - 86, The checkout
step always tries to fetch ref: release-${{ inputs.version }} which fails in
dry-run because that remote branch isn't pushed; replace the single checkout
with two conditional steps: one actions/checkout@v6 step that includes ref:
release-${{ inputs.version }} and runs only when inputs.dry-run is false, and a
second actions/checkout@v6 step without the ref (default checkout of the
workflow commit) that runs when inputs.dry-run is true; update the step names
accordingly so later steps use the same workspace.

Comment on lines +123 to +127
update-version:
runs-on: ubuntu-24.04
needs:
- validate-version
steps:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don’t advance main before the release branch exists.

update-version only waits for validation, so it can still open the next-version PR even if prepare-release-branch fails. That leaves main ahead of a release branch/tag that was never cut.

Possible fix
   update-version:
     runs-on: ubuntu-24.04
     needs:
     - validate-version
+    - prepare-release-branch
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
update-version:
runs-on: ubuntu-24.04
needs:
- validate-version
steps:
update-version:
runs-on: ubuntu-24.04
needs:
- validate-version
- prepare-release-branch
steps:
🤖 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/prepare-release.yml around lines 123 - 127, The
update-version job currently only depends on validate-version, so it can run and
open the next-version PR even if prepare-release-branch fails; change its
dependencies so update-version also waits for the prepare-release-branch job to
complete successfully (add prepare-release-branch to the needs list for the
update-version job), ensuring update-version will not advance main before a
release branch/tag is created.

Comment on lines +29 to +44
- name: Determine patch version
id: patch
run: |
last_tag="$(git describe --tags --abbrev=0)"

if [[ "$last_tag" =~ ^"${VERSION}"\.x$ ]]; then
patch=0
elif [[ "$last_tag" =~ ^"${VERSION}"\.([[:digit:]]+)$ ]]; then
patch=$((BASH_REMATCH[1] + 1))
else
echo >&2 "Failed to determine patch version for ${VERSION}"
echo >&2 "Last tag found: $last_tag"
exit 1
fi

echo "patch=$patch" >> "$GITHUB_OUTPUT"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Patch selection is based on the nearest tag, not the requested release series.

git describe --tags --abbrev=0 returns the closest reachable tag from HEAD; it does not limit the result to ${VERSION}.*. A different series tag on the branch makes Line 34/36 fail or increments from the wrong base.

Safer approach
       - name: Determine patch version
         id: patch
         run: |
-          last_tag="$(git describe --tags --abbrev=0)"
+          last_tag="$(
+            {
+              git tag --list "${VERSION}.[0-9]*"
+              git tag --list "${VERSION}.x"
+            } | sort -V | tail -n1
+          )"
+
+          if [[ -z "$last_tag" ]]; then
+            echo >&2 "Failed to determine patch version for ${VERSION}"
+            exit 1
+          fi
 
           if [[ "$last_tag" =~ ^"${VERSION}"\.x$ ]]; then
             patch=0
           elif [[ "$last_tag" =~ ^"${VERSION}"\.([[:digit:]]+)$ ]]; then
             patch=$((BASH_REMATCH[1] + 1))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Determine patch version
id: patch
run: |
last_tag="$(git describe --tags --abbrev=0)"
if [[ "$last_tag" =~ ^"${VERSION}"\.x$ ]]; then
patch=0
elif [[ "$last_tag" =~ ^"${VERSION}"\.([[:digit:]]+)$ ]]; then
patch=$((BASH_REMATCH[1] + 1))
else
echo >&2 "Failed to determine patch version for ${VERSION}"
echo >&2 "Last tag found: $last_tag"
exit 1
fi
echo "patch=$patch" >> "$GITHUB_OUTPUT"
- name: Determine patch version
id: patch
run: |
last_tag="$(
{
git tag --list "${VERSION}.[0-9]*"
git tag --list "${VERSION}.x"
} | sort -V | tail -n1
)"
if [[ -z "$last_tag" ]]; then
echo >&2 "Failed to determine patch version for ${VERSION}"
exit 1
fi
if [[ "$last_tag" =~ ^"${VERSION}"\.x$ ]]; then
patch=0
elif [[ "$last_tag" =~ ^"${VERSION}"\.([[:digit:]]+)$ ]]; then
patch=$((BASH_REMATCH[1] + 1))
else
echo >&2 "Failed to determine patch version for ${VERSION}"
echo >&2 "Last tag found: $last_tag"
exit 1
fi
echo "patch=$patch" >> "$GITHUB_OUTPUT"
🤖 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/release.yml around lines 29 - 44, Patch selection
currently uses git describe --tags --abbrev=0 which returns the nearest tag from
HEAD (variable last_tag in the "Determine patch version" step); change it to
explicitly pick the latest tag matching the requested series ${VERSION}.* (e.g.
replace the last_tag assignment with a command that lists tags filtered by
pattern and sorts by version, such as using git tag --list "${VERSION}.*"
--sort=-v:refname | head -n1), then keep the existing regex/patch logic but add
a guard to fail if no matching tag is found (empty last_tag) so the patch
calculation uses the correct series tag instead of a nearest unrelated tag.

Comment on lines +51 to +60
- name: Create release tag
env:
PATCH: ${{ steps.patch.outputs.patch }}
run: |
git tag -a -m "fact v${VERSION}.${PATCH} release" "${RELEASE}.${PATCH}"

- name: Push tag
if: ${{ ! inputs.dry-run }}
run: |
git push origin "${VERSION}.${PATCH}"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

The tag name is built from variables that are not available here.

Line 55 uses ${RELEASE}, which is never defined, and Line 60 uses ${PATCH} in a different step where that env var does not exist. As written, the workflow creates the wrong tag name and then tries to push a different or nonexistent ref.

Possible fix
       - name: Create release tag
-        env:
-          PATCH: ${{ steps.patch.outputs.patch }}
         run: |
-          git tag -a -m "fact v${VERSION}.${PATCH} release" "${RELEASE}.${PATCH}"
+          git tag -a \
+            -m "fact v${VERSION}.${{ steps.patch.outputs.patch }} release" \
+            "${VERSION}.${{ steps.patch.outputs.patch }}"
 
       - name: Push tag
         if: ${{ ! inputs.dry-run }}
         run: |
-          git push origin "${VERSION}.${PATCH}"
+          git push origin "${VERSION}.${{ steps.patch.outputs.patch }}"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Create release tag
env:
PATCH: ${{ steps.patch.outputs.patch }}
run: |
git tag -a -m "fact v${VERSION}.${PATCH} release" "${RELEASE}.${PATCH}"
- name: Push tag
if: ${{ ! inputs.dry-run }}
run: |
git push origin "${VERSION}.${PATCH}"
- name: Create release tag
run: |
git tag -a \
-m "fact v${VERSION}.${{ steps.patch.outputs.patch }} release" \
"${VERSION}.${{ steps.patch.outputs.patch }}"
- name: Push tag
if: ${{ ! inputs.dry-run }}
run: |
git push origin "${VERSION}.${{ steps.patch.outputs.patch }}"
🤖 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/release.yml around lines 51 - 60, The tag is constructed
with undefined variable RELEASE and PATCH isn't exported to the Push tag step;
update the Create release tag step to build the tag using the defined VERSION
and the patch from steps.patch.outputs.patch (e.g., use "${VERSION}.${{
steps.patch.outputs.patch }}") and export or set PATCH consistently so the Push
tag step pushes the exact same ref (or change the Push tag step to push
"${VERSION}.${{ steps.patch.outputs.patch }}" too); ensure both steps reference
the same variables (replace RELEASE with VERSION and either set env PATCH from
steps.patch.outputs.patch or inline the steps.patch.outputs.patch expression in
both steps) so the tag name is correct and consistent.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant