From bcc14fe9b7cfd42ce06efb280f32546d3a8da6c2 Mon Sep 17 00:00:00 2001 From: Alejandro Pedraza Date: Wed, 9 Mar 2022 09:26:29 -0500 Subject: [PATCH] Release workflow (#88) * Release workflow Closes #72 This change proposes to start using semver from the get-go. This means the `edge` particle would go last, so we'd start with `0.0.1-edge`. The charts' `version` and `appVersion` entries would match that, with `version` being able to drift when chart-only changes happen (I added details into the `RELEASE.md` file). After multiple edge releases we could issue the stable by bumping the minor part and dropping the suffix: `0.1.0`. Unlike linkerd2, the latest image tag (currently `0.0.1-edge`) is hard-coded into the `values.yaml` file. It needs to be manually bumped on each release, but this allows people (and us during testing) to consume the chart directly from the source code without any preprocessing. As described in `RELEASE.md`, after having merged the release notes in `CHANGES.md`, one would need to tag `main` and that triggers the new `release.yml` workflow, which: - builds and pushes the docker image - runs the integration tests pulling that image - creates the release in github (currently won't hold any assets, just the change notes) - will publish the chart into the `https://helm.linkerd.io` helm repo. --- .github/workflows/release.yml | 143 +++++++++++++++++++++++ CHANGES.md | 7 ++ RELEASE.md | 95 +++++++++++++++ bin/_release.sh | 28 +++++ charts/linkerd-failover-tests/Chart.yaml | 3 +- charts/linkerd-failover-tests/README.md | 3 +- charts/linkerd-failover/Chart.yaml | 3 +- charts/linkerd-failover/README.md | 5 +- charts/linkerd-failover/values.yaml | 2 +- 9 files changed, 283 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/release.yml create mode 100644 CHANGES.md create mode 100644 RELEASE.md create mode 100755 bin/_release.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..9ccb7c04 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,143 @@ +name: Release + +on: + push: + tags: + - "[0-9]+.[0-9]+.[0-9]+*" + +permissions: + contents: read + +env: + DOCKER_REGISTRY: ghcr.io/linkerd + +jobs: + + docker-build: + runs-on: ubuntu-20.04 + timeout-minutes: 10 + steps: + - name: Checkout code + uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579 + - name: Docker build + uses: ./.github/actions/docker-build + with: + docker-registry: ${{ env.DOCKER_REGISTRY }} + docker-tag: ${{ github.ref_name }} + docker-target: linux-amd64 + docker-push: 1 + docker-ghcr-username: ${{ secrets.DOCKER_GHCR_USERNAME }} + docker-ghcr-pat: ${{ secrets.DOCKER_GHCR_PAT }} + component: failover + + integration-tests: + runs-on: ubuntu-20.04 + timeout-minutes: 10 + needs: [docker-build] + steps: + - name: Checkout code + uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579 + - name: Set up Helm + uses: azure/setup-helm@a517f2ff6560563a369e16ca7c7d136b6164423f + - name: Create cluster + uses: AbsaOSS/k3d-action@5d155528f6d4a35f72c4cf3590e22fa0dde1e28a + with: + cluster-name: testing + - name: Install linkerd + run: | + curl -sL https://run.linkerd.io/install-edge | sh + export PATH=$PATH:~/.linkerd2/bin + linkerd install | kubectl apply -f - + linkerd check + - name: Install linkerd-smi + run: | + helm repo add linkerd-smi https://linkerd.github.io/linkerd-smi + helm repo up + helm install linkerd-smi -n linkerd-smi --create-namespace --wait linkerd-smi/linkerd-smi + - name: Install current linkerd-failover + run: | + helm install linkerd-failover -n linkerd-failover --create-namespace --wait \ + --set image.registry=${{ env.DOCKER_REGISTRY }} \ + --set image.tag=${{ github.ref_name }} \ + charts/linkerd-failover + - name: Test routing to primary + uses: ./.github/actions/failover-test + with: + westReplicas: 1 + westShouldReceiveTraffic: true + centralReplicas: 1 + centralShouldReceiveTraffic: false + eastReplicas: 1 + eastShouldReceiveTraffic: false + - name: Test failover to secondaries + uses: ./.github/actions/failover-test + with: + westReplicas: 0 + westShouldReceiveTraffic: false + centralReplicas: 1 + centralShouldReceiveTraffic: true + eastReplicas: 1 + eastShouldReceiveTraffic: true + - name: Test removal of one secondary + uses: ./.github/actions/failover-test + with: + westReplicas: 0 + westShouldReceiveTraffic: false + centralReplicas: 0 + centralShouldReceiveTraffic: false + eastReplicas: 1 + eastShouldReceiveTraffic: true + - name: Test reestablishment of primary + uses: ./.github/actions/failover-test + with: + westReplicas: 1 + westShouldReceiveTraffic: true + centralReplicas: 0 + centralShouldReceiveTraffic: false + eastReplicas: 1 + eastShouldReceiveTraffic: false + + gh-release: + name: Create GH release + timeout-minutes: 10 + runs-on: ubuntu-20.04 + needs: [integration-tests] + permissions: + contents: write + steps: + - name: Checkout code + uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846 + - name: Extract release notes + run: | + . bin/_release.sh + extract_release_notes NOTES.md + - name: Create release + id: create_release + uses: softprops/action-gh-release@fb0163a75bee697a9cfec2c931801de7c7f10042 + with: + draft: false + prerelease: false + body_path: NOTES.md + + chart-deploy: + name: Helm chart deploy + timeout-minutes: 10 + runs-on: ubuntu-20.04 + needs: [gh-release] + steps: + - name: Checkout code + uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846 + - name: Set up Helm + uses: azure/setup-helm@a517f2ff6560563a369e16ca7c7d136b6164423f + - name: Log into GCP + uses: 'google-github-actions/auth@8d125895b958610ec414ca4dae010257eaa814d3' + with: + credentials_json: ${{ secrets.LINKERD_SITE_TOKEN }} + - name: Helm chart creation and upload + run: | + mkdir -p target/helm + helm --app-version "${{ github.ref_name }}" -d target/helm package charts/linkerd-failover + # backup index file before changing it + gsutil cp gs://helm.linkerd.io/edge/index.yaml "target/helm/index-pre-failover-${{ github.ref_name }}".yaml + helm repo index --url https://helm.linkerd.io/edge/ --merge "target/helm/index-pre-failover-${{ github.ref_name }}".yaml target/helm + gsutil rsync target/helm gs://helm.linkerd.io/edge diff --git a/CHANGES.md b/CHANGES.md new file mode 100644 index 00000000..e6a6d4e2 --- /dev/null +++ b/CHANGES.md @@ -0,0 +1,7 @@ +# Changes + +## 0.0.1-edge + +First release! + +Please check the README.md for instructions. diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 00000000..f0e3c4c4 --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,95 @@ +# Linkerd-failover Release + +This document contains instructions for releasing the Linkerd-failover +extension. + +## Version schema + +### Example + +```text +0.0.1-edge +0.0.2-edge +0.0.3-edge +0.1.0 +0.2.0-edge +0.2.1-edge +0.2.2-edge +... +0.1.1 (maintenance release for 0.1.0 stable) +... + +``` + +### Explanation + +Note we use semver, both for edge and stable releases. Edge releases use the +pattern `major.minor.patch-edge` and stable releases just drop the `edge` +suffix. + +Successive edge releases only bump the patch part, regardless of how big the +changes are. When an edge release is ready to become the next stable release, we +bump the minor part (or major if there are backwards-incompatible changes) and +drop the `edge` suffix. The following edge release will bump the minor part, as +to leave room for maintenance releases of the previous stable release. + +## Release procedure + +### 1. Create the release branch + +Create a branch in the `linkerd-failover` repo, `username/X.X.X-edge` (replace +with your username and the actual release number). + +### 2. Update the Helm charts versions + +- Update the `appVersion` in the `Chart.yaml` files for the `linkerd-failover` + and `linkerd-failover` charts. `appVersion` should match the actual + version/tag. +- Also update their `version` entry. During the first few releases this will + match `appVersion`, but may drift apart in the future when there are changes + to the chart templates but no changes in the underlying `failover` docker + image. +- Update the `tag` entry in the `linkerd-failover` chart with the same value you + used for `version`. + +Rules for changes in the `version` entry: + +- patch bump for minor changes +- minor bump for additions/removals +- major bump for backwards-incompatible changes, most notably changes that + change the structure of `values.yaml` + +Finally, keep in mind chart version changes require updating the charts README +files (through `bin/helm-docs`). + +### 3. Update the release notes + +On this branch, add the release notes for this version in `CHANGES.md`. + +Note: To see all of the changes since the previous release, run the command +below in the `linkerd-failover` repo. + +```bash +git log Y.Y.Y-edge..HEAD +``` + +### 4. Post a PR that includes the changes + +This PR needs an approval from a "code owner." Feel free to ping one of the code +owners if you've gotten feedback and approvals from other team members. + +### 5. Merge release notes branch, then create the release tag + +After the review has passed and the branch has been merged, follow the +instructions below to properly create and push the release tag from the +appropriate branch. Replace `TAG` below with the `appVersion` you used in step 2 +above. + +**Note**: This will create a GPG-signed tag, so users must have GPG signing +setup in their local git config. + +```bash +git checkout main git pull notes=$(. "bin"/_release.sh; extract_release_notes) +git tag -s -F "$notes" TAG +git push origin TAG +``` diff --git a/bin/_release.sh b/bin/_release.sh new file mode 100755 index 00000000..b7b08ee8 --- /dev/null +++ b/bin/_release.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +# shellcheck disable=SC2120 +# (disabling SC2120 so that we can use functions with optional args +# see https://github.com/koalaman/shellcheck/wiki/SC2120#exceptions ) + +set -eu + +extract_release_notes() { + bindir=$( cd "${BASH_SOURCE[0]%/*}" && pwd ) + rootdir=$( cd "$bindir"/.. && pwd ) + + if [ $# -eq 0 ] + then + # Make temporary file to save the release commit message into. + tmp=$(mktemp -t release-commit-message.XXX.txt) + else + tmp="$rootdir/$1" + fi + + # Save commit message into temporary file. + # + # Match each occurrence of the regex and increment `n` by 1. While n == 1 + # (which is true only for the first section) print that line of `CHANGES.md`. + # This ends up being the first section of release changes. + awk '/^## [0-9]+\.[0-9]+\.[0-9]+.*/{n++} n==1' "$rootdir"/CHANGES.md > "$tmp" + + echo "$tmp" +} diff --git a/charts/linkerd-failover-tests/Chart.yaml b/charts/linkerd-failover-tests/Chart.yaml index d7e5025c..84ee0083 100644 --- a/charts/linkerd-failover-tests/Chart.yaml +++ b/charts/linkerd-failover-tests/Chart.yaml @@ -7,7 +7,8 @@ keywords: kubeVersion: ">=1.20.0-0" sources: - https://github.com/linkerd/linkerd-failover/ -version: 0.1.0 +appVersion: 0.0.1-edge +version: 0.0.1-edge icon: https://linkerd.io/images/logo-only-200h.png maintainers: - name: Linkerd authors diff --git a/charts/linkerd-failover-tests/README.md b/charts/linkerd-failover-tests/README.md index 89ff8e26..180faa0b 100644 --- a/charts/linkerd-failover-tests/README.md +++ b/charts/linkerd-failover-tests/README.md @@ -1,8 +1,9 @@ # linkerd-failover-tests -![Version: 0.1.0](https://img.shields.io/badge/Version-0.1.0-informational?style=flat-square) +![Version: 0.0.1-edge](https://img.shields.io/badge/Version-0.0.1--edge-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) +![AppVersion: 0.0.1-edge](https://img.shields.io/badge/AppVersion-0.0.1--edge-informational?style=flat-square) **Homepage:** diff --git a/charts/linkerd-failover/Chart.yaml b/charts/linkerd-failover/Chart.yaml index fb4ab985..0dfe40a7 100644 --- a/charts/linkerd-failover/Chart.yaml +++ b/charts/linkerd-failover/Chart.yaml @@ -7,7 +7,8 @@ keywords: kubeVersion: ">=1.20.0-0" sources: - https://github.com/linkerd/linkerd-failover/ -version: 0.1.0 +appVersion: 0.0.1-edge +version: 0.0.1-edge icon: https://linkerd.io/images/logo-only-200h.png maintainers: - name: Linkerd authors diff --git a/charts/linkerd-failover/README.md b/charts/linkerd-failover/README.md index 4aee8373..db03c57d 100644 --- a/charts/linkerd-failover/README.md +++ b/charts/linkerd-failover/README.md @@ -1,8 +1,9 @@ # linkerd-failover -![Version: 0.1.0](https://img.shields.io/badge/Version-0.1.0-informational?style=flat-square) +![Version: 0.0.1-edge](https://img.shields.io/badge/Version-0.0.1--edge-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) +![AppVersion: 0.0.1-edge](https://img.shields.io/badge/AppVersion-0.0.1--edge-informational?style=flat-square) **Homepage:** @@ -52,7 +53,7 @@ Kubernetes: `>=1.20.0-0` | Key | Type | Default | Description | |-----|------|---------|-------------| -| image | object | `{"name":"failover","registry":"cr.l5d.io/linkerd","tag":"latest"}` | Docker image | +| image | object | `{"name":"failover","registry":"cr.l5d.io/linkerd","tag":"0.0.1-edge"}` | Docker image | | logFormat | string | `"plain"` | Log format (`plain` or `json`) | | logLevel | string | `"linkerd=info,warn"` | Log level | | selector | string | `nil` | Determines which `TrafficSplit` instances to consider for failover. If empty, defaults to failover.linkerd.io/controlled-by={{ .Release.Name }} | diff --git a/charts/linkerd-failover/values.yaml b/charts/linkerd-failover/values.yaml index 05452364..d95b1ece 100644 --- a/charts/linkerd-failover/values.yaml +++ b/charts/linkerd-failover/values.yaml @@ -8,7 +8,7 @@ logFormat: plain image: registry: cr.l5d.io/linkerd name: failover - tag: latest + tag: 0.0.1-edge # -- Determines which `TrafficSplit` instances to consider for failover. If # empty, defaults to failover.linkerd.io/controlled-by={{ .Release.Name }}