From 02b6370ec5b0186fc56b8f844b53f10d94e92d45 Mon Sep 17 00:00:00 2001 From: Horst Gutmann Date: Wed, 9 Oct 2024 12:03:22 +0200 Subject: [PATCH 1/5] chore(ci): Add release-please for release-automation --- .github/workflows/release-binaries.yml | 98 ++++++++++++++++++++++++++ .github/workflows/release-please.yml | 33 +++++++++ .github/workflows/release.yml | 50 ------------- .release-please-manifest.json | 1 + .release-please.json | 60 ++++++++++++++++ CHANGELOG.md | 2 +- 6 files changed, 193 insertions(+), 51 deletions(-) create mode 100644 .github/workflows/release-binaries.yml create mode 100644 .github/workflows/release-please.yml delete mode 100644 .github/workflows/release.yml create mode 100644 .release-please-manifest.json create mode 100644 .release-please.json diff --git a/.github/workflows/release-binaries.yml b/.github/workflows/release-binaries.yml new file mode 100644 index 000000000..f0f4fe837 --- /dev/null +++ b/.github/workflows/release-binaries.yml @@ -0,0 +1,98 @@ +name: Release binaries + +on: + release: + types: + - created + +jobs: + build-binaries: + runs-on: ubuntu-latest + steps: + - id: get-secrets + uses: grafana/shared-workflows/actions/get-vault-secrets@main + with: + repo_secrets: | + TANKABOT_APP_ID=tankabot_app:id + TANKABOT_APP_PRIVATE_KEY=tankabot_app:private_key + + - uses: actions/create-github-app-token@5d869da34e18e7287c1daad50e0b8ea0f506ce69 # v1.11.0 + id: app-token + with: + app-id: ${{ env.TANKABOT_APP_ID }} + private-key: ${{ env.TANKABOT_APP_PRIVATE_KEY }} + + # At first we should wait for a release to be created by the + # release-please workflow + - name: Check for release + id: lookup-release + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + script: | + const timers = require('node:timers/promises'); + const ref = context.ref; + if (!ref.startsWith('refs/tags/')) { + core.setFailed('Not a valid ref'); + return; + } + const currentTag = ref.substring('refs/tags/'.length); + core.info(`Looking for release associated with '${currentTag}'`); + let remainingAttempts = 6; + while (remainingAttempts > 0) { + try { + const release = await github.rest.repos.getReleaseByTag({owner: context.repo.owner, repo: context.repo.repo, tag: currentTag}); + core.info(`Release found: ${release.data.id}'`); + core.setOutput('release_id', release.data.id); + return; + } catch (e) { + if (remainingAttempts === 1) { + if (e.status !== 404) { + console.log(e); + } + } + remainingAttempts -= 1; + await timers.setTimeout(10000); + } + } + core.setFailed('Release not found'); + + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + with: + # https://github.com/actions/checkout/issues/1467 + fetch-depth: 0 + + - uses: ./.github/actions/setup-goversion + + - name: Build binaries + run: make cross + + - name: Attach binaries + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + github-token: ${{ steps.app-token.outputs.token }} + script: | + const path = require('node:path'); + const fs = require('node:fs/promises'); + + const releaseId = '${{ steps.lookup-release.outputs.release_id }}'; + const globber = await glob.create('dist/*'); + + for await (const file of globber.globGenerator()) { + const filename = path.basename(file); + try { + await github.rest.repos.uploadReleaseAsset({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: releaseId, + name: filename, + data: await fs.readFile(file), + }); + } catch (e) { + if (e.status === 422) { + core.setFailed(`${filename} already attached to release`); + return; + } + throw e; + } + } + diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml new file mode 100644 index 000000000..e30a552d5 --- /dev/null +++ b/.github/workflows/release-please.yml @@ -0,0 +1,33 @@ +on: + push: + branches: + - main + +permissions: + contents: write + pull-requests: write + +name: release-please + +jobs: + release-please: + runs-on: ubuntu-latest + steps: + - id: get-secrets + uses: grafana/shared-workflows/actions/get-vault-secrets@main + with: + repo_secrets: | + TANKABOT_APP_ID=tankabot_app:id + TANKABOT_APP_PRIVATE_KEY=tankabot_app:private_key + + - uses: actions/create-github-app-token@5d869da34e18e7287c1daad50e0b8ea0f506ce69 # v1.11.0 + id: app-token + with: + app-id: ${{ env.TANKABOT_APP_ID }} + private-key: ${{ env.TANKABOT_APP_PRIVATE_KEY }} + + - uses: googleapis/release-please-action@7987652d64b4581673a76e33ad5e98e3dd56832f # v4.1.3 + with: + config-file: .release-please.json + manifest-file: .release-please-manifest.json + github-token: ${{ steps.app-token.outputs.token }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index d170502e2..000000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: Release - -on: - push: - tags: - - v* - -permissions: - contents: write - -jobs: - release: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - # https://github.com/actions/checkout/issues/1467 - fetch-depth: 0 - - uses: ./.github/actions/setup-goversion - - run: make cross - - id: docker_tag - run: echo "DOCKER_TAG=${GITHUB_REF_NAME#v}" >> "$GITHUB_ENV" - - name: Release - uses: softprops/action-gh-release@e7a8f85e1c67a31e6ed99a94b41bd0b71bbee6b8 # v2.0.9 - with: - body: | - This is release `${{ github.ref_name }}` of Tanka (`tk`). - - ## Install instructions - - #### Binary: - ```bash - # download the binary (adapt os and arch as needed) - $ curl -fSL -o "/usr/local/bin/tk" "https://github.com/grafana/tanka/releases/download/${{ github.ref_name }}/tk-linux-amd64" - - # make it executable - $ chmod a+x "/usr/local/bin/tk" - - # have fun :) - $ tk --help - ``` - - #### Docker container: - https://hub.docker.com/r/grafana/tanka - ```bash - $ docker pull grafana/tanka:${{ env.DOCKER_TAG }} - ``` - draft: true - files: | - dist/* diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 000000000..2d8c67d51 --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1 @@ +{".": "0.28.3"} diff --git a/.release-please.json b/.release-please.json new file mode 100644 index 000000000..31be90c2d --- /dev/null +++ b/.release-please.json @@ -0,0 +1,60 @@ +{ + "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", + "changelog-sections": [ + { + "section": "🎉 Features", + "type": "feat" + }, + { + "section": "🐛 Bug Fixes", + "type": "fix" + }, + { + "section": "⚡ Performance Improvements", + "type": "perf" + }, + { + "section": "🔗 Dependencies", + "type": "deps" + }, + { + "section": "📝 Documentation", + "type": "docs" + }, + { + "section": "🏗️ Build System", + "type": "build" + }, + { + "section": "🤖 Continuous Integration", + "type": "ci" + }, + { + "section": "🔧 Miscellaneous Chores", + "type": "chore" + }, + { + "section": "⏪ Reverts", + "type": "revert" + }, + { + "section": "✅ Tests", + "type": "test" + }, + { + "section": "💄 Style", + "type": "style" + }, + { + "section": "♻️ Code Refactoring", + "type": "refactor" + } + ], + "draft-pull-request": true, + "include-v-in-tag": true, + "packages": { + ".": { + } + }, + "release-type": "go" +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 76fbbe1fb..1bdd2e5f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -For releases from v0.24.0 forward, you can find the changelog in Github releases: https://github.com/grafana/tanka/releases +For releases from v0.24.0 to v0.28.3, you can find the changelog in the GitHub releases: https://github.com/grafana/tanka/releases ## 0.23.1 (2022-09-28) From 852f08f52663d5725bdb549b2bd26d4d2991bdff Mon Sep 17 00:00:00 2001 From: Horst Gutmann Date: Wed, 13 Nov 2024 18:45:10 +0100 Subject: [PATCH 2/5] Merge release-please and release-binaries workflows --- .github/workflows/release-binaries.yml | 98 -------------------------- .github/workflows/release-please.yml | 83 ++++++++++++++++++---- 2 files changed, 71 insertions(+), 110 deletions(-) delete mode 100644 .github/workflows/release-binaries.yml diff --git a/.github/workflows/release-binaries.yml b/.github/workflows/release-binaries.yml deleted file mode 100644 index f0f4fe837..000000000 --- a/.github/workflows/release-binaries.yml +++ /dev/null @@ -1,98 +0,0 @@ -name: Release binaries - -on: - release: - types: - - created - -jobs: - build-binaries: - runs-on: ubuntu-latest - steps: - - id: get-secrets - uses: grafana/shared-workflows/actions/get-vault-secrets@main - with: - repo_secrets: | - TANKABOT_APP_ID=tankabot_app:id - TANKABOT_APP_PRIVATE_KEY=tankabot_app:private_key - - - uses: actions/create-github-app-token@5d869da34e18e7287c1daad50e0b8ea0f506ce69 # v1.11.0 - id: app-token - with: - app-id: ${{ env.TANKABOT_APP_ID }} - private-key: ${{ env.TANKABOT_APP_PRIVATE_KEY }} - - # At first we should wait for a release to be created by the - # release-please workflow - - name: Check for release - id: lookup-release - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 - with: - script: | - const timers = require('node:timers/promises'); - const ref = context.ref; - if (!ref.startsWith('refs/tags/')) { - core.setFailed('Not a valid ref'); - return; - } - const currentTag = ref.substring('refs/tags/'.length); - core.info(`Looking for release associated with '${currentTag}'`); - let remainingAttempts = 6; - while (remainingAttempts > 0) { - try { - const release = await github.rest.repos.getReleaseByTag({owner: context.repo.owner, repo: context.repo.repo, tag: currentTag}); - core.info(`Release found: ${release.data.id}'`); - core.setOutput('release_id', release.data.id); - return; - } catch (e) { - if (remainingAttempts === 1) { - if (e.status !== 404) { - console.log(e); - } - } - remainingAttempts -= 1; - await timers.setTimeout(10000); - } - } - core.setFailed('Release not found'); - - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - with: - # https://github.com/actions/checkout/issues/1467 - fetch-depth: 0 - - - uses: ./.github/actions/setup-goversion - - - name: Build binaries - run: make cross - - - name: Attach binaries - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 - with: - github-token: ${{ steps.app-token.outputs.token }} - script: | - const path = require('node:path'); - const fs = require('node:fs/promises'); - - const releaseId = '${{ steps.lookup-release.outputs.release_id }}'; - const globber = await glob.create('dist/*'); - - for await (const file of globber.globGenerator()) { - const filename = path.basename(file); - try { - await github.rest.repos.uploadReleaseAsset({ - owner: context.repo.owner, - repo: context.repo.repo, - release_id: releaseId, - name: filename, - data: await fs.readFile(file), - }); - } catch (e) { - if (e.status === 422) { - core.setFailed(`${filename} already attached to release`); - return; - } - throw e; - } - } - diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index e30a552d5..b75873f80 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -12,22 +12,81 @@ name: release-please jobs: release-please: runs-on: ubuntu-latest - steps: - - id: get-secrets - uses: grafana/shared-workflows/actions/get-vault-secrets@main - with: - repo_secrets: | - TANKABOT_APP_ID=tankabot_app:id - TANKABOT_APP_PRIVATE_KEY=tankabot_app:private_key + outputs: + release_created: "${{ steps.release-please.outputs.release_created }}" + release_tag: "${{ steps.release-please.outputs.tag_name }}" - - uses: actions/create-github-app-token@5d869da34e18e7287c1daad50e0b8ea0f506ce69 # v1.11.0 - id: app-token + steps: + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 with: - app-id: ${{ env.TANKABOT_APP_ID }} - private-key: ${{ env.TANKABOT_APP_PRIVATE_KEY }} + # https://github.com/actions/checkout/issues/1467 + fetch-depth: 0 - uses: googleapis/release-please-action@7987652d64b4581673a76e33ad5e98e3dd56832f # v4.1.3 + id: release-please with: config-file: .release-please.json manifest-file: .release-please-manifest.json - github-token: ${{ steps.app-token.outputs.token }} + github-token: ${{ github.secret }} + + # If a release was created, also create the binaries and attach them + release-binaries: + runs-on: ubuntu-latest + needs: + - release-please + if: needs.release-please.outputs.release_created + + steps: + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + with: + # https://github.com/actions/checkout/issues/1467 + fetch-depth: 0 + ref: "${{ needs.release-please.outputs.release_tag }}" + + - name: Look up release + id: lookup-release + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + script: | + const currentTag = "${{ needs.release-please.outputs.release_tag }}"; + core.info(`Looking for release associated with '${currentTag}'`); + const release = await github.rest.repos.getReleaseByTag({owner: context.repo.owner, repo: context.repo.repo, tag: currentTag}); + core.info(`Release found: ${release.data.id}'`); + core.setOutput('release_id', release.data.id); + + + - uses: ./.github/actions/setup-goversion + + - name: Build binaries + run: make cross + + - name: Attach binaries + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + github-token: ${{ github.token }} + script: | + const path = require('node:path'); + const fs = require('node:fs/promises'); + + const releaseId = '${{ steps.lookup-release.outputs.release_id }}'; + const globber = await glob.create('dist/*'); + + for await (const file of globber.globGenerator()) { + const filename = path.basename(file); + try { + await github.rest.repos.uploadReleaseAsset({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: releaseId, + name: filename, + data: await fs.readFile(file), + }); + } catch (e) { + if (e.status === 422) { + core.setFailed(`${filename} already attached to release`); + return; + } + throw e; + } + } + From dc0a4b5b7d5a3c048545b17aaefca78d773e56a4 Mon Sep 17 00:00:00 2001 From: Horst Gutmann Date: Wed, 13 Nov 2024 19:37:28 +0100 Subject: [PATCH 3/5] Update manifest --- .release-please-manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 2d8c67d51..0ccec384d 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1 +1 @@ -{".": "0.28.3"} +{".": "0.29.0"} From 1b21908784aab890b74a1333970b1a81c4729ee4 Mon Sep 17 00:00:00 2001 From: Horst Gutmann Date: Thu, 14 Nov 2024 07:35:47 +0100 Subject: [PATCH 4/5] Improve code formatting --- .github/workflows/release-please.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index b75873f80..18b32f1f1 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -50,7 +50,11 @@ jobs: script: | const currentTag = "${{ needs.release-please.outputs.release_tag }}"; core.info(`Looking for release associated with '${currentTag}'`); - const release = await github.rest.repos.getReleaseByTag({owner: context.repo.owner, repo: context.repo.repo, tag: currentTag}); + const release = await github.rest.repos.getReleaseByTag({ + owner: context.repo.owner, + repo: context.repo.repo, + tag: currentTag + }); core.info(`Release found: ${release.data.id}'`); core.setOutput('release_id', release.data.id); From 7963f63004d86a51f729619c16e46bc6fe723dcd Mon Sep 17 00:00:00 2001 From: Horst Gutmann Date: Thu, 14 Nov 2024 07:39:17 +0100 Subject: [PATCH 5/5] Update release guide --- docs/src/content/docs/internal/releasing.md | 23 +++++---------------- 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/docs/src/content/docs/internal/releasing.md b/docs/src/content/docs/internal/releasing.md index 2435d893c..347f8fb9a 100644 --- a/docs/src/content/docs/internal/releasing.md +++ b/docs/src/content/docs/internal/releasing.md @@ -2,23 +2,10 @@ title: "Releasing a new version" --- -Releasing a new version of Tanka requires a couple of manual and automated steps. -This guide will give you a runbook on how to do them in the right order. +For releasing Tanka we're using [release-please][]. +This workflow manages a release pull-request based on the content of the `main` branch that would update the changelog et al.. +Once you want to do a release, merge that prepared pull-request. +release-please will then do all the tagging and GitHub Release creation. -## 1. Create a release tag +[release-please]: https://github.com/googleapis/release-please-action -1. Pull the latest changes from the `main` branch to your local clone. -1. Create a new tag with the prefix `v` (e.g. `v0.28.0`). -1. Push that tag back to GitHub. - -This starts multiple GitHub workflows that will produce binaries, a Docker image, and also a new GitHub release that is *marked as draft*. - -## 2. Add changelog to the release notes - -Once all these actions have finished, go to and you should see the new draft release. -Click the pencil icon ("edit") at the top-right and go to the last line of the text body. -Now hit the "Generate release notes" button to add a changelog to the end of the release notes. - -## 3. Publish the release notes - -Once you've check that the release looks fine (e.g. no broken links, no missing version numbers in the download paths) click the "Publish release" button.