name: "RELEASE: Start Release" on: workflow_dispatch: inputs: version: description: Release version (A.B.C[-N]) required: true default: 0.0.0 type: string ref: description: Override release branch starting ref required: false default: "" type: string dry-run: description: Dry-run required: false default: false type: boolean env: USER_REF: ${{ inputs.ref }} main_branch: ${{github.event.repository.default_branch}} script_url: /repos/${{ github.repository }}/contents/.github/workflows/scripts/common.sh?ref=${{ github.ref_name }} DRY_RUN: ${{ fromJSON('["true", "false"]')[github.event.inputs.dry-run != 'true'] }} ACCEPT_RAW: "Accept: application/vnd.github.v3.raw" GH_TOKEN: ${{ github.token }} GH_NO_UPDATE_NOTIFIER: 1 run-name: >- ${{ format('Start release {0} from {1}{2}', inputs.version, fromJSON(format('["{0}","{1}"]', inputs.ref, 'the last nightly branching point'))[inputs.ref == ''], fromJSON('[" (dry-run)", ""]')[inputs.dry-run != true] ) }} # Ensure that only a single automation workflow can run at a time for each release. concurrency: Release automation ${{ inputs.version }} jobs: start-sha: name: Find commit for release branch runs-on: ubuntu-24.04 outputs: start-sha: ${{ fromJSON(format('["{0}","{1}"]', env.USER_REF, steps.find.outputs.merge_base))[env.USER_REF == ''] }} steps: - name: Check out code uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 with: ref: ${{ github.event.repository.default_branch }} fetch-depth: 0 - name: Print user-provided input run: | if [ "${{ env.USER_REF }}" != '' ]; then echo "User provided the following override for the git-sha: \`${{ env.USER_REF }}\`" >> "$GITHUB_STEP_SUMMARY" else echo "User did not provide override for the git-sha" >> "$GITHUB_STEP_SUMMARY" fi - name: Find merge-base for ${{ github.event.repository.default_branch }} and 'origin/nightlies' id: find run: | MERGEBASE="$(git merge-base origin/nightlies ${{ github.event.repository.default_branch }})" echo "merge_base=${MERGEBASE}" >> "$GITHUB_OUTPUT" echo "Found the following git-sha as a branching point for the release branch: [\`${MERGEBASE}\`](${{github.server_url}}/${{github.repository}}/commits/${MERGEBASE})" >> "$GITHUB_STEP_SUMMARY" properties: name: Read repository properties runs-on: ubuntu-24.04 outputs: docs-repository: ${{ steps.properties.outputs.docs-repository }} slack-channel: ${{ fromJSON(format('["{0}","{1}"]', steps.properties.outputs.dry-slack-channel, steps.properties.outputs.slack-channel))[github.event.inputs.dry-run != 'true'] }} jira-project: ${{ steps.properties.outputs.jira-project }} steps: - name: Read workflow properties file id: properties env: PROPERTIES_URL: /repos/${{ github.repository }}/contents/.github/properties?ref=${{ github.ref_name }} run: gh api -H "$ACCEPT_RAW" "$PROPERTIES_URL" >> "$GITHUB_OUTPUT" run-parameters: name: Run parameters runs-on: ubuntu-24.04 steps: - run: | [ "$DRY_RUN" = "true" ] && echo "::warning::This is a dry run" echo "Event: ${{github.event_name}}" >>"$GITHUB_STEP_SUMMARY" cat <>"$GITHUB_STEP_SUMMARY" \`\`\` ${{toJSON(inputs)}} \`\`\` EOF variables: name: Setup variables uses: ./.github/workflows/variables.yml with: version: ${{github.event.inputs.version}} assert-format: A.B.C[-N] check-jira: name: Check Jira release needs: [variables, properties] runs-on: ubuntu-24.04 outputs: release-date: ${{steps.check-jira-release.outputs.date}} steps: - name: Check that Jira release ${{needs.variables.outputs.release}}.${{needs.variables.outputs.patch}} is not released id: check-jira-release env: JIRA_USER: ${{ vars.RHACS_BOT_GITHUB_EMAIL }} JIRA_TOKEN: ${{ secrets.JIRA_TOKEN }} JIRA_BASE_URL: ${{ vars.JIRA_BASE_URL }} run: | set -uo pipefail gh api -H "$ACCEPT_RAW" "${{env.script_url}}" | bash -s -- \ check-jira-release \ "${{needs.variables.outputs.release}}.${{needs.variables.outputs.patch}}" \ "${{needs.properties.outputs.jira-project}}" branch: name: Prepare release branch needs: [variables, start-sha, check-jira] runs-on: ubuntu-24.04 steps: - name: Check out code (normal release) if: needs.variables.outputs.patch == 0 uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 with: ref: ${{ needs.start-sha.outputs.start-sha }} fetch-depth: 0 token: ${{ secrets.RHACS_BOT_GITHUB_TOKEN }} - name: Check out code (patch release) if: needs.variables.outputs.patch != 0 uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 with: ref: ${{ needs.variables.outputs.branch }} submodules: true token: ${{ secrets.RHACS_BOT_GITHUB_TOKEN }} - name: Check remote branch exists id: check-existing run: | if git ls-remote --quiet --exit-code origin "${{needs.variables.outputs.branch}}"; then echo "branch-exists=true" >> "$GITHUB_OUTPUT" else echo "branch-exists=false" >> "$GITHUB_OUTPUT" fi - name: Fail if there is no branch for patch release if: steps.check-existing.outputs.branch-exists == 'false' && needs.variables.outputs.patch != 0 run: exit 1 - name: Initialize mandatory git config run: | git config user.name "${{github.event.sender.login}}" git config user.email noreply@github.com - name: Create release branch ${{needs.variables.outputs.branch}} if: steps.check-existing.outputs.branch-exists == 'false' run: | git switch --create "${{needs.variables.outputs.branch}}" git commit --allow-empty --message \ "Empty commit to diverge ${{needs.variables.outputs.release}} from ${{env.main_branch}}" - name: Tag release branch with rc.0 ${{needs.variables.outputs.branch}} run: | git tag --annotate --message "Upstream automation" \ "${{needs.variables.outputs.release}}.${{needs.variables.outputs.patch}}-rc.0" HEAD - name: Update the changelog on the release branch run: | set -uo pipefail gh api -H "$ACCEPT_RAW" "${{env.script_url}}" | bash -s -- \ patch-release-changelog \ "${{inputs.version}}" - name: Tag ${{env.main_branch}} for next release if: steps.check-existing.outputs.branch-exists == 'false' run: | # There could be several commits between the starting point of the release branch and the HEAD # on main/master tagged with the next release. While this leaves those intermediate # commits tagged with the previous release, this is better than changing the build tag for # those commits after all their artifacts have already been built and tested. git switch ${{env.main_branch}} git pull origin --rebase ${{env.main_branch}} git tag --annotate --message "Upstream automation" \ "${{needs.variables.outputs.next-minor-release}}.x" HEAD - name: Push changes if: env.DRY_RUN == 'false' env: GH_TOKEN: "${{ secrets.RHACS_BOT_GITHUB_TOKEN }}" run: | git switch "${{needs.variables.outputs.branch}}" # This command pushes all new tags, not just the ones on the current branch. Therefore, it will push the tag we put on ${{env.main_branch}}. git push --follow-tags --set-upstream origin "${{needs.variables.outputs.branch}}" ci: name: Configure OpenShift CI jobs needs: [variables, branch] if: needs.variables.outputs.patch == 0 runs-on: ubuntu-24.04 env: RELEASE: "${{needs.variables.outputs.release}}" BRANCH: "stackrox-release-${{needs.variables.outputs.release}}" steps: - name: Check remote branch exists id: check-existing run: | if gh api --silent -H "$ACCEPT_RAW" "/repos/stackrox/openshift-release/branches/${BRANCH}"; then echo "branch-exists=true" >> "$GITHUB_OUTPUT" echo "::notice::OpenShift CI configuration branch exists. Assuming CI is ready." else echo "branch-exists=false" >> "$GITHUB_OUTPUT" fi - name: Synchronize fork from openshift/release if: env.DRY_RUN == 'false' && steps.check-existing.outputs.branch-exists == 'false' env: GH_TOKEN: "${{ secrets.RHACS_BOT_GITHUB_TOKEN }}" run: | gh repo sync stackrox/openshift-release --source openshift/release - name: Check out stackrox/openshift-release uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 with: repository: stackrox/openshift-release token: "${{ secrets.RHACS_BOT_GITHUB_TOKEN }}" - name: Initialize git config and create new branch if: steps.check-existing.outputs.branch-exists == 'false' run: | git config user.name "${{github.event.sender.login}}" git config user.email noreply@github.com git switch --create "$BRANCH" - name: Make configuration if: steps.check-existing.outputs.branch-exists == 'false' env: CFG_DIR: "ci-operator/config/stackrox/stackrox" run: | # Duplicate the template configurations for yaml in "$CFG_DIR"/stackrox-stackrox-release-x.y*.yaml ; do yq eval ".zz_generated_metadata.branch=\"release-$RELEASE\"" "$yaml" > "${yaml//stackrox-release-x.y/$BRANCH}" done - name: Make update if: steps.check-existing.outputs.branch-exists == 'false' run: | make update git add ci-operator git commit -m "Release $RELEASE files" >> "$GITHUB_STEP_SUMMARY" - name: Push and create PR if: env.DRY_RUN == 'false' && steps.check-existing.outputs.branch-exists == 'false' env: GH_TOKEN: "${{ secrets.RHACS_BOT_GITHUB_TOKEN }}" run: | git push --set-upstream origin "$BRANCH" PR_URL=$(gh pr create --repo openshift/release \ --title "Stackrox release $RELEASE" \ --base "master" \ --body "CI configuration files to support Stackrox release \`$RELEASE\`.") PR_NUMBER="$(echo "${PR_URL}" | rev | cut -d '/' -f1 | rev)" gh pr comment "${PR_NUMBER}" --repo openshift/release --body "/assign ${GITHUB_ACTOR}" echo ":arrow_right: Review and merge the [PR]($PR_URL) that has been created for the \`openshift/release\` repository." >> "$GITHUB_STEP_SUMMARY" patch-main-changelog: name: Patch CHANGELOG.md on the default branch needs: [variables, branch, start-sha] if: needs.variables.outputs.patch == 0 runs-on: ubuntu-24.04 steps: - name: Check out code uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 with: # Working on `start-sha` instead of `env.main_branch` may help # to spot changes happened to CHANGELOG.md after `start-sha`. ref: ${{ needs.start-sha.outputs.start-sha }} - name: Initialize mandatory git config run: | git config user.name "${{github.event.sender.login}}" git config user.email noreply@github.com - name: Patch CHANGELOG.md on ${{ needs.start-sha.outputs.start-sha }} env: GH_TOKEN: ${{ secrets.RHACS_BOT_GITHUB_TOKEN }} run: | set -uo pipefail gh api -H "$ACCEPT_RAW" "${{env.script_url}}" | bash -s -- \ patch-main-changelog \ "${{needs.variables.outputs.release}}.${{needs.variables.outputs.patch}}" \ "${{ needs.start-sha.outputs.start-sha }}" \ "${{needs.variables.outputs.branch}}" patch-scanner-versions: name: Patch Scanner updater configuration needs: [variables, branch] runs-on: ubuntu-24.04 steps: - name: Check out code uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 with: ref: ${{ env.main_branch }} - name: Initialize mandatory git config run: | git config user.name "${{github.event.sender.login}}" git config user.email noreply@github.com - name: Patch scanner/updater/version/RELEASE_VERSION for ${{needs.variables.outputs.release}}.${{needs.variables.outputs.patch}} env: GH_TOKEN: ${{ secrets.RHACS_BOT_GITHUB_TOKEN }} run: | set -uo pipefail gh api -H "$ACCEPT_RAW" "${{env.script_url}}" | bash -s -- \ patch-scanner-updater-configuration \ "${{needs.variables.outputs.release}}.${{needs.variables.outputs.patch}}" milestone: name: Create milestone needs: [variables] runs-on: ubuntu-24.04 steps: - name: Create ${{needs.variables.outputs.next-milestone}} milestone if: env.DRY_RUN == 'false' run: | set -u if ! http_code=$(gh api --silent -X POST \ "repos/${{github.repository}}/milestones" \ -f title="${{needs.variables.outputs.next-milestone}}" \ 2>&1); then if grep "HTTP 422" <<< "$http_code"; then echo ":arrow_right: Milestone ${{needs.variables.outputs.next-milestone}} already exists." \ "**Close it once it's finished.**" >> "$GITHUB_STEP_SUMMARY" else echo "::error::Couldn't create milestone ${{needs.variables.outputs.next-milestone}}: $http_code" exit 1 fi else echo ":arrow_right: Milestone ${{needs.variables.outputs.next-milestone}} has been created." \ "**Close it once it's finished.**" >> "$GITHUB_STEP_SUMMARY" fi notify: name: Notify everybody needs: [variables, properties, branch, milestone] runs-on: ubuntu-24.04 steps: - name: Post to Slack (normal release) if: needs.variables.outputs.patch == 0 uses: slackapi/slack-github-action@45a88b9581bfab2566dc881e2cd66d334e621e2c # ratchet:slackapi/slack-github-action@v3.0.3 with: method: chat.postMessage token: ${{ secrets.SLACK_BOT_TOKEN }} payload: | channel: "${{ needs.properties.outputs.slack-channel }}" text: "Upstream release ${{needs.variables.outputs.named-release-patch}} has been triggered. Consult the tracker for next steps." blocks: - type: "section" text: type: "mrkdwn" text: | :${{ fromJSON('["desert", "white_check_mark"]')[github.event.inputs.dry-run != 'true'] }}: *Upstream release ${{needs.variables.outputs.named-release-patch}} has been triggered on <${{github.server_url}}/${{github.repository}}|${{github.repository}}> by ${{ github.event.sender.login }}.* - type: "section" text: type: "mrkdwn" text: | Branch `${{needs.variables.outputs.branch}}` and milestone `${{needs.variables.outputs.next-milestone}}` have been created. PRs merged to the ${{env.main_branch}} branch and assigned to RC milestones will be cherry-picked when closing the respective milestones. For the urgent fixes that must go exclusively to this release open PRs to the `${{needs.variables.outputs.branch}}` branch. - type: "divider" - type: "section" text: type: "mrkdwn" text: | > Repository: <${{github.server_url}}/${{github.repository}}|${{github.repository}}> > Release: ${{needs.variables.outputs.named-release-patch}} > Workflow: <${{github.server_url}}/${{github.repository}}/actions/runs/${{github.run_id}}|${{github.workflow}}> - name: Post to Slack (patch release) if: needs.variables.outputs.patch != 0 uses: slackapi/slack-github-action@45a88b9581bfab2566dc881e2cd66d334e621e2c # ratchet:slackapi/slack-github-action@v3.0.3 with: method: chat.postMessage token: ${{ secrets.SLACK_BOT_TOKEN }} payload: | channel: "${{ needs.properties.outputs.slack-channel }}" text: "Upstream patch release ${{needs.variables.outputs.named-release-patch}} has been triggered. Consult the tracker for next steps." blocks: - type: "section" text: type: "mrkdwn" text: | :${{ fromJSON('["desert", "white_check_mark"]')[github.event.inputs.dry-run != 'true'] }}: *Upstream patch release ${{needs.variables.outputs.named-release-patch}} has been triggered on <${{github.server_url}}/${{github.repository}}|${{github.repository}}> by ${{ github.event.sender.login }}.* - type: "section" text: type: "mrkdwn" text: | Milestone `${{needs.variables.outputs.next-milestone}}` has been created. PRs merged to the ${{env.main_branch}} branch and assigned to RC milestones will be cherry-picked when closing the respective milestones. For the urgent fixes that must go exclusively to this release open PRs to the `${{needs.variables.outputs.branch}}` branch. - type: "divider" - type: "section" text: type: "mrkdwn" text: | > Repository: <${{github.server_url}}/${{github.repository}}|${{github.repository}}> > Release: ${{needs.variables.outputs.named-release-patch}} > Workflow: <${{github.server_url}}/${{github.repository}}/actions/runs/${{github.run_id}}|${{github.workflow}}>