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..daea94a5 --- /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..a18a1475 --- /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}" 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.