From 1f558baa9b7a74e0a841addd8406fbea095fbbd9 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Thu, 3 Apr 2025 16:24:35 +0200 Subject: [PATCH] add release workflows Signed-off-by: Andrei Kvapil --- .github/workflows/pull-requests-release.yaml | 96 ++++++++++++++++++++ .github/workflows/pull-requests.yaml | 6 +- .github/workflows/tags.yaml | 29 +++--- 3 files changed, 118 insertions(+), 13 deletions(-) create mode 100644 .github/workflows/pull-requests-release.yaml diff --git a/.github/workflows/pull-requests-release.yaml b/.github/workflows/pull-requests-release.yaml new file mode 100644 index 00000000..c20bf062 --- /dev/null +++ b/.github/workflows/pull-requests-release.yaml @@ -0,0 +1,96 @@ +name: Verify and Finalize Release PR + +on: + pull_request: + types: [labeled, opened, synchronize, reopened, closed] + +jobs: + verify: + name: Test Release PR + runs-on: [self-hosted] + permissions: + contents: read + packages: write + + if: | + contains(github.event.pull_request.labels.*.name, 'ok-to-test') && + contains(github.event.pull_request.labels.*.name, 'release') && + github.event.action != 'closed' + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + fetch-tags: true + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + registry: ghcr.io + + - name: Run tests + run: make test + + finalize: + name: Finalize Release + runs-on: [self-hosted] + permissions: + contents: write + + if: | + github.event.pull_request.merged == true && + contains(github.event.pull_request.labels.*.name, 'release') + + steps: + - name: Extract tag from branch name + id: get_tag + uses: actions/github-script@v7 + with: + script: | + const branch = context.payload.pull_request.head.ref; + const match = branch.match(/^release-(v\d+\.\d+\.\d+(?:[-\w\.]+)?)$/); + + if (!match) { + core.setFailed(`Branch '${branch}' does not match expected format 'release-vX.Y.Z[-suffix]'`); + } else { + const tag = match[1]; + core.setOutput('tag', tag); + console.log(`✅ Extracted tag: ${tag}`); + } + + - name: Checkout repo + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Create tag on merged commit + run: | + git tag ${{ steps.get_tag.outputs.tag }} ${{ github.sha }} + git push origin ${{ steps.get_tag.outputs.tag }} + + - name: Publish draft release + uses: actions/github-script@v7 + with: + script: | + const tag = '${{ steps.get_tag.outputs.tag }}'; + const releases = await github.rest.repos.listReleases({ + owner: context.repo.owner, + repo: context.repo.repo + }); + + const release = releases.data.find(r => r.tag_name === tag && r.draft); + if (!release) { + throw new Error(`Draft release with tag ${tag} not found`); + } + + await github.rest.repos.updateRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: release.id, + draft: false + }); + + console.log(`✅ Published release for ${tag}`); diff --git a/.github/workflows/pull-requests.yaml b/.github/workflows/pull-requests.yaml index 7cc92562..959c3968 100644 --- a/.github/workflows/pull-requests.yaml +++ b/.github/workflows/pull-requests.yaml @@ -6,13 +6,15 @@ on: jobs: e2e: - name: Build and Test + name: Build and Test for Pull Requests runs-on: [self-hosted] permissions: contents: read packages: write - if: contains(github.event.pull_request.labels.*.name, 'ok-to-test') + if: | + contains(github.event.pull_request.labels.*.name, 'ok-to-test') && + !contains(github.event.pull_request.labels.*.name, 'release') steps: - name: Checkout code diff --git a/.github/workflows/tags.yaml b/.github/workflows/tags.yaml index 2b4dbc17..a07c64e1 100644 --- a/.github/workflows/tags.yaml +++ b/.github/workflows/tags.yaml @@ -7,7 +7,7 @@ on: jobs: prepare-release: - name: Build, Test and Prepare Release + name: Build and Prepare Release runs-on: [self-hosted] permissions: contents: write @@ -56,10 +56,6 @@ jobs: if: steps.check_release.outputs.skip == 'false' run: make build - #- name: Test - # if: steps.check_release.outputs.skip == 'false' - # run: make test - - name: Commit release artifacts if: steps.check_release.outputs.skip == 'false' env: @@ -86,25 +82,36 @@ jobs: const version = context.ref.replace('refs/tags/v', ''); const branch = `release-${version}`; const base = 'main'; - + const prs = await github.rest.pulls.list({ owner: context.repo.owner, repo: context.repo.repo, head: `${context.repo.owner}:${branch}`, base }); - + if (prs.data.length === 0) { - await github.rest.pulls.create({ + const newPr = await github.rest.pulls.create({ owner: context.repo.owner, repo: context.repo.repo, head: branch, base: base, title: `Prepare release v${version}`, - body: `This PR prepares the release \`v${version}\`.`, - draft: true + body: + `This PR prepares the release \`v${version}\`.\n` + + `(Please merge it before releasing draft)`, + draft: false }); - console.log(`Created draft pull request from ${branch} to ${base}`); + + console.log(`Created pull request #${newPr.data.number} from ${branch} to ${base}`); + + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: newPr.data.number, + labels: ['release', 'ok-to-test'] + }); + } else { console.log(`Pull request already exists from ${branch} to ${base}`); }