From ca4b8442a47af8644168b4b63e79123e2202c647 Mon Sep 17 00:00:00 2001 From: Mauro Ezequiel Moltrasio Date: Wed, 13 May 2026 18:20:28 +0200 Subject: [PATCH 1/3] feat(ci): add basic release workflows 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 --- .github/actions/validate-version/action.yml | 23 +++ .github/workflows/prepare-release.yml | 180 ++++++++++++++++++++ .github/workflows/release.yml | 71 ++++++++ 3 files changed, 274 insertions(+) create mode 100644 .github/actions/validate-version/action.yml create mode 100644 .github/workflows/prepare-release.yml create mode 100644 .github/workflows/release.yml diff --git a/.github/actions/validate-version/action.yml b/.github/actions/validate-version/action.yml new file mode 100644 index 00000000..c4974102 --- /dev/null +++ b/.github/actions/validate-version/action.yml @@ -0,0 +1,23 @@ +name: Validate . version +description: | + This is a pretty common format used during our release process, this + action can be used to uniformly validate such version format. + +inputs: + version: + description: | + The release version in . format. + required: true + +runs: + using: composite + steps: + - shell: bash + name: Validate version + env: + VERSION: ${{ inputs.version }} + run: | + if [[ ! "$VERSION" =~ ^([[:digit:]]+)\.([[:digit:]]+)$ ]] ; then + echo >&2 "Invalid version '$VERSION'. The expected format is ." + exit 1 + fi diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml new file mode 100644 index 00000000..44bdd4e3 --- /dev/null +++ b/.github/workflows/prepare-release.yml @@ -0,0 +1,180 @@ +name: Prepare Release Branch + +on: + workflow_dispatch: + inputs: + version: + description: | + The release version in . format. + required: true + type: string + next-version: + description: | + The . version that will be used for the next + release. + required: true + type: string + rust-version: + description: | + The Rust version that will be used for the new release branch. + required: true + type: string + dry-run: + description: Do not push anything + default: true + type: boolean + +jobs: + validate-version: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v6 + with: + submodules: false + + - uses: ./.github/actions/validate-version + name: Validate version + with: + version: ${{ inputs.version }} + + - uses: ./.github/actions/validate-version + name: Validate next-version + with: + version: ${{ inputs.next-version }} + + - uses: ./.github/actions/validate-version + name: Validate Rust version + with: + version: ${{ inputs.rust-version }} + + prepare-release-branch: + runs-on: ubuntu-24.04 + needs: + - validate-version + steps: + - uses: actions/checkout@v6 + with: + submodules: false + ref: main + token: ${{ secrets.RHACS_BOT_GITHUB_TOKEN }} + + - name: Initialize mandatory git config + run: | + git config user.name "${{ github.event.sender.login }}" + git config user.email noreply@github.com + + - 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 }}" + + pin-rust-version: + runs-on: ubuntu-24.04 + needs: + - validate-version + - prepare-release-branch + steps: + - uses: actions/checkout@v6 + with: + submodules: false + 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 + + - name: Pin Rust version + run: | + sed -i -e "s/^RUST_VERSION .*/RUST_VERSION ?= ${{ inputs.rust-version }}/" \ + constants.mk + + - name: Update fact version + run: | + sed -i \ + -e "/^version = / s/\".*\"/\"${{ inputs.version }}.0\"/" \ + fact/Cargo.toml + + cargo update -p fact + + - name: Print git diff for validation + run: | + git diff + + - name: Create Pull Request + if: ${{ ! inputs.dry-run }} + uses: peter-evans/create-pull-request@v8 + with: + token: '${{ secrets.RHACS_BOT_GITHUB_TOKEN }}' + commit-message: 'chore: pin Rust version and update fact version' + committer: '${{ secrets.RHACS_BOT_GITHUB_USERNAME }} <${{ secrets.RHACS_BOT_GITHUB_EMAIL }}>' + author: '${{ secrets.RHACS_BOT_GITHUB_USERNAME }} <${{ secrets.RHACS_BOT_GITHUB_EMAIL }}>' + branch: chore/pin-rust-update-version-${{ inputs.version }} + signoff: false + delete-branch: true + title: 'chore: pin Rust version and update fact version' + body: | + Pin Rust version to ${{ inputs.rust-version }} and update fact to version ${{ inputs.version }} + team-reviewers: | + collector-team + draft: false + + update-version: + runs-on: ubuntu-24.04 + needs: + - validate-version + - prepare-release-branch + steps: + - uses: actions/checkout@v6 + with: + submodules: false + ref: main + token: ${{ secrets.RHACS_BOT_GITHUB_TOKEN }} + + - name: Update CHANGELOG.md + run: | + sed -i \ + -e "s/^## Next/&\n\n## ${{ inputs.version }}.0/" \ + CHANGELOG.md + + - name: Update fact version + run: | + sed -i \ + -e "/^version = / s/\".*\"/\"${{ inputs.next-version }}.0-dev\"/" \ + fact/Cargo.toml + + cargo update -p fact + + - name: Print git diff for validation + run: | + git diff + + - name: Create Pull Request + if: ${{ ! inputs.dry-run }} + uses: peter-evans/create-pull-request@v8 + with: + token: '${{ secrets.RHACS_BOT_GITHUB_TOKEN }}' + commit-message: 'chore: update CHANGELOG.md and fact version' + committer: '${{ secrets.RHACS_BOT_GITHUB_USERNAME }} <${{ secrets.RHACS_BOT_GITHUB_EMAIL }}>' + author: '${{ secrets.RHACS_BOT_GITHUB_USERNAME }} <${{ secrets.RHACS_BOT_GITHUB_EMAIL }}>' + branch: chore/update-changelog-fact-${{ inputs.next-version }}-dev + signoff: false + delete-branch: true + title: 'chore(docs): Update CHANGELOG.md and fact version' + body: | + Cut the CHANGELOG.md changes and update fact to version ${{ inputs.next-version }}-dev + team-reviewers: | + collector-team + draft: false diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..3e4ed104 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,71 @@ +name: Release new version + +on: + workflow_dispatch: + inputs: + version: + description: | + The release version in . format. + required: true + type: string + dry-run: + description: Do not push anything + default: true + type: boolean + +concurrency: + group: release-${{ inputs.version }} + cancel-in-progress: false + +jobs: + release: + runs-on: ubuntu-24.04 + env: + VERSION: ${{ inputs.version }} + steps: + - uses: actions/checkout@v6 + with: + submodules: true + fetch-depth: 0 + ref: release-${{ inputs.version }} + token: ${{ secrets.RHACS_BOT_GITHUB_TOKEN }} + + - uses: ./.github/actions/validate-version + name: Validate version + with: + version: ${{ inputs.version }} + + - 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: Initialize mandatory git config + run: | + git config user.name "${{ github.event.sender.login }}" + git config user.email noreply@github.com + + - name: Create release tag + env: + PATCH: ${{ steps.patch.outputs.patch }} + run: | + git tag -a -m "fact v${VERSION}.${PATCH} release" "${VERSION}.${PATCH}" + + - name: Push tag + if: ${{ ! inputs.dry-run }} + env: + PATCH: ${{ steps.patch.outputs.patch }} + run: | + git push origin "${VERSION}.${PATCH}" From 621c29e6e35bf943a7fe4be9a209b8546bebf8c6 Mon Sep 17 00:00:00 2001 From: Mauro Ezequiel Moltrasio Date: Thu, 14 May 2026 13:19:45 +0200 Subject: [PATCH 2/3] chore(docs): update release.md to point to the automated workflows --- docs/release.md | 40 +++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/docs/release.md b/docs/release.md index 1d002c89..87b2b75f 100644 --- a/docs/release.md +++ b/docs/release.md @@ -1,6 +1,32 @@ # Managing a `fact` release -## Create the release branch +## Automated release + +There are two GHA workflows available to prepare a new release stream +and properly releasing a new version, they are aptly named: +- Prepare Release Branch +- Release New Version + +When a release cycle is coming to an end and a new X.Y stream is needed, +running the `Prepare Release Branch` will do all the heavy lifting, +creating the new `release-X.Y` branch, a new internal `X.Y.x` tag and +opening PRs for updating the cargo toml and lock files, pinning Rust +version to use and updating the CHANGELOG. + +Once a release engineer signals a new tag for fact is needed, the +`Release New Version` workflow can be used to push this tag +automatically. It will work for both the initial version of a new X.Y +stream, as well as for any future patch releases needed for that same +stream. + +## Manual release + +**Note**: This is a fallback method, only intended to be used if the +automated method fails for some reason. Stick to the automated method +whenever possible +--- + +### Create the release branch 1. Navigate to your local `stackrox/fact` git repository and ensure your `main` branch is up to date. @@ -31,14 +57,16 @@ which the release is forked. git push --set-upstream origin "release-${FACT_RELEASE}" ``` -## Update CHANGELOG.md and version on main +### Update CHANGELOG.md and version on main 1. Set the following environment variable: * `FACT_RELEASE`: The next version of fact to be released. + * `FACT_DEV`: The version of fact that will enter the dev phase. ```sh export FACT_RELEASE=0.2 + export FACT_DEV=0.3 ``` 1. On the `main` branch, run the following commands. @@ -49,8 +77,9 @@ which the release is forked. CHANGELOG.md sed -i \ - -e "/^version = / s/\".*\"/\"${FACT_RELEASE}.0-dev\"/" \ + -e "/^version = / s/\".*\"/\"${FACT_DEV}.0-dev\"/" \ fact/Cargo.toml + cargo update -p fact ``` 1. Create a new branch for these changes and push it to the repository. @@ -63,7 +92,7 @@ which the release is forked. 1. Create a PR pointing to the main branch and get it merged. -## Pin compiler version and update the application version +### Pin compiler version and update the application version 1. Set the following environment variables: @@ -89,6 +118,7 @@ which the release is forked. sed -i \ -e "/^version = / s/\".*\"/\"${FACT_RELEASE}.0\"/" \ fact/Cargo.toml + cargo update -p fact ``` 1. Create a new branch for these changes and push it to the repository. @@ -115,7 +145,7 @@ new tag with the following commands: 1. Ensure the Konflux and GitHub Actions builds succeed and the corresponding container images are pushed. -## Handling patch releases +### Handling patch releases 1. Merge any backport PRs you need into the desired release branch. 1. Figure out the patch version to be released. From 6fbcf24f6e35acb4577e79579b219c04b8c2519d Mon Sep 17 00:00:00 2001 From: Mauro Ezequiel Moltrasio Date: Thu, 14 May 2026 16:06:32 +0200 Subject: [PATCH 3/3] chore: use single quotes on strings that use GH interpolation --- .github/workflows/prepare-release.yml | 26 +++++++++++++------------- .github/workflows/release.yml | 4 ++-- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml index 44bdd4e3..daea94a5 100644 --- a/.github/workflows/prepare-release.yml +++ b/.github/workflows/prepare-release.yml @@ -60,21 +60,21 @@ jobs: - name: Initialize mandatory git config run: | - git config user.name "${{ github.event.sender.login }}" + git config user.name '${{ github.event.sender.login }}' git config user.email noreply@github.com - 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 }}" + 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 }}" + git push origin '${{ inputs.version }}.x' + git push --set-upstream origin 'release-${{ inputs.version }}' pin-rust-version: runs-on: ubuntu-24.04 @@ -89,22 +89,22 @@ jobs: - name: Switch to release branch run: | - if [[ "${{ inputs.dry-run }}" == "true" ]]; then - git checkout -b "release-${{ inputs.version }}" + 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 }}" + git fetch origin 'release-${{ inputs.version }}:release-${{ inputs.version }}' + git checkout 'release-${{ inputs.version }}' fi - name: Pin Rust version run: | - sed -i -e "s/^RUST_VERSION .*/RUST_VERSION ?= ${{ inputs.rust-version }}/" \ + sed -i -e 's/^RUST_VERSION .*/RUST_VERSION ?= ${{ inputs.rust-version }}/' \ constants.mk - name: Update fact version run: | sed -i \ - -e "/^version = / s/\".*\"/\"${{ inputs.version }}.0\"/" \ + -e '/^version = / s/".*"/"${{ inputs.version }}.0"/' \ fact/Cargo.toml cargo update -p fact @@ -146,13 +146,13 @@ jobs: - name: Update CHANGELOG.md run: | sed -i \ - -e "s/^## Next/&\n\n## ${{ inputs.version }}.0/" \ + -e 's/^## Next/&\n\n## ${{ inputs.version }}.0/' \ CHANGELOG.md - name: Update fact version run: | sed -i \ - -e "/^version = / s/\".*\"/\"${{ inputs.next-version }}.0-dev\"/" \ + -e '/^version = / s/".*"/"${{ inputs.next-version }}.0-dev"/' \ fact/Cargo.toml cargo update -p fact diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3e4ed104..a18a1475 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,4 +1,4 @@ -name: Release new version +name: Release New Version on: workflow_dispatch: @@ -54,7 +54,7 @@ jobs: - name: Initialize mandatory git config run: | - git config user.name "${{ github.event.sender.login }}" + git config user.name '${{ github.event.sender.login }}' git config user.email noreply@github.com - name: Create release tag