From b3502e059d7a2032534d1a688bbc2ef625db3624 Mon Sep 17 00:00:00 2001 From: Pranshu Srivastava Date: Mon, 19 Feb 2024 13:33:09 +0530 Subject: [PATCH] chore: automate release workflow Signed-off-by: Pranshu Srivastava --- .github/workflows/release.yml | 86 ++++++++++++++++++++++++++ Makefile | 2 +- README.md | 14 ++--- scripts/generate-release-notes.sh | 20 ++++++ scripts/update-compatibility-matrix.sh | 48 ++++++++++++++ 5 files changed, 162 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/release.yml create mode 100755 scripts/generate-release-notes.sh create mode 100755 scripts/update-compatibility-matrix.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000..1f959528a5 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,86 @@ +name: Release + +on: + push: + tags: + - v* + +permissions: + contents: write + pull-requests: write + +env: + GO_VERSION: "^1.21" + GOLANGCI_LINT_VERSION: "v1.54.2" + E2E_SETUP_KIND: yes + E2E_SETUP_KUBECTL: yes + +jobs: + release: + runs-on: ubuntu-latest + steps: + - name: Extract pushed release tag + id: extract_tag + run: echo "::set-output name=tag::${GITHUB_REF##*/}" + - name: Checkout into the corresponding release branch + uses: actions/checkout@v4 + - name: Create VCS sandbox + run: | + git checkout -b release-${{ steps.extract_tag.outputs.tag }} + - name: Set up the Go@${{ env.GO_VERSION }} environment + uses: actions/setup-go@v5 + with: + go-version: ${{ env.GO_VERSION }} + - name: Get the pushed tag + id: get_tag + run: echo ::set-output name=tag::${GITHUB_REF#refs/*/} + - name: Store the previous tag + id: get_previous_tag + run: echo ::set-output name=previous_tag::$(cat VERSION | cut -d. -f1,2) + - name: Update the VERSION manifest to the pushed tag + run: echo "${{ steps.get_tag.outputs.tag }}" | sed 's/^v//' > VERSION + - name: Update the compatibility matrix (README.md) + run: ./scripts/update-compatibility-matrix.sh + - name: Generate the release notes (CHANGELOG.md) + run: ./scripts/generate-release-notes.sh + - name: Install tools + run: make install-tools +# - name: Lint +# run: | +# curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | \ +# sh -s -- -b $(go env GOPATH)/bin ${{ env.GOLANGCI_LINT_VERSION }} +# make lint-fix + - name: Generate manifests + run: make examples +# - name: Run rule tests +# run: PROMTOOL_CLI=./promtool make install-promtool test-rules +# - name: Run unit tests +# run: make test-unit +# - name: Run end-to-end tests +# run: make e2e + - name: Update the remote and commit the changes + run: | + git config --local user.email "ksm-release-bot@mock-k8s.io" + git config --local user.name "KSM Release Bot" + git add . + git commit -m "chore: Cut ${{ steps.get_tag.outputs.tag }}" + git push origin HEAD:release-${{ steps.get_tag.outputs.tag }} --force-with-lease +# - name: Benchmark tests +# run: LATEST_RELEASE_BRANCH=release-${{ steps.get_previous_tag.outputs.previous_tag }} make test-benchmark-compare +# - name: Validate docs +# run: make doccheck +# - name: Validate manifests +# run: make validate-manifests +# - name: Validate go modules +# run: make validate-modules + - name: Create a pull request + run: | + gh pr create \ + --title "chore: Cut ${{ steps.get_tag.outputs.tag }}" \ + --body "This PR was automatically created by the release workflow." \ + --base main \ + --head release-${{ steps.get_tag.outputs.tag }} +# --reviewer @sig-instrumentation-approvers \ +# --assignee @sig-instrumentation-leads + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/Makefile b/Makefile index 3d1288f535..ac8b7ba8af 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ REGISTRY ?= gcr.io/k8s-staging-kube-state-metrics TAG_PREFIX = v VERSION = $(shell cat VERSION) TAG ?= $(TAG_PREFIX)$(VERSION) -LATEST_RELEASE_BRANCH := release-$(shell grep -ohE "[0-9]+.[0-9]+" VERSION) +LATEST_RELEASE_BRANCH ?= release-$(shell grep -ohE "[0-9]+.[0-9]+" VERSION) BRANCH = $(strip $(shell git rev-parse --abbrev-ref HEAD)) DOCKER_CLI ?= docker PROMTOOL_CLI ?= promtool diff --git a/README.md b/README.md index 319963791b..05854bc447 100644 --- a/README.md +++ b/README.md @@ -48,12 +48,12 @@ At most, 5 kube-state-metrics and 5 [kubernetes releases](https://github.com/kub | kube-state-metrics | Kubernetes client-go Version | |--------------------|:----------------------------:| -| **v2.6.0** | v1.24 | -| **v2.7.0** | v1.25 | -| **v2.8.2** | v1.26 | -| **v2.9.2** | v1.26 | -| **v2.10.1** | v1.27 | -| **main** | v1.28 | +| **v2.6.0** | v1.24 | +| **v2.7.0** | v1.25 | +| **v2.8.2** | v1.26 | +| **v2.9.2** | v1.26 | +| **v2.10.1** | v1.27 | +| **main** | v1.28 | #### Resource group version compatibility @@ -270,7 +270,7 @@ To have Prometheus discover kube-state-metrics instances it is advised to create kubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin --user=$(gcloud info --format='value(config.account)') ``` -Note that your GCP identity is case sensitive but `gcloud info` as of Google Cloud SDK 221.0.0 is not. This means that if your IAM member contains capital letters, the above one-liner may not work for you. If you have 403 forbidden responses after running the above command and `kubectl apply -f examples/standard`, check the IAM member associated with your account at https://console.cloud.google.com/iam-admin/iam?project=PROJECT_ID. If it contains capital letters, you may need to set the --user flag in the command above to the case-sensitive role listed at https://console.cloud.google.com/iam-admin/iam?project=PROJECT_ID. +Note that your GCP identity is case sensitive but `gcloud info` as of Google Cloud SDK 221.0.0 is not. This means that if your IAM member contains capital letters, the above one-liner may not work for you. If you have 403 forbidden responses after running the above command and `kubectl apply -f examples/standard`, check the IAM member associated with your account at . If it contains capital letters, you may need to set the --user flag in the command above to the case-sensitive role listed at . After running the above, if you see `Clusterrolebinding "cluster-admin-binding" created`, then you are able to continue with the setup of this service. diff --git a/scripts/generate-release-notes.sh b/scripts/generate-release-notes.sh new file mode 100755 index 0000000000..9d1cafa487 --- /dev/null +++ b/scripts/generate-release-notes.sh @@ -0,0 +1,20 @@ +#!/bin/bash +set -exuo pipefail + +CHANGELOG="CHANGELOG.md" + +# Fetch the latest two tags. +# NOTE: This assumes a patch release for an older release is not made after a later minor release (which is the case right now). +# Backports will be handled manually, on a case-by-case basis. +last_two_tags=$(git tag --sort=-creatordate | head -n 2) + +# read will return a non-zero exit code when it hits EOF, so we need to disable the exit-on-error option. +set +e +IFS=$'\n' read -d '' -r -a tags <<< "$last_two_tags" +set -e + +# Get the commits between the two tags. +commits=$(git log --pretty=format:"%h: %an <%ae>: %s" "${tags[1]}".."${tags[0]}" | grep -i -v -e 'fixup' -e 'merge' -e 'dependabot') + +# Update the changelog with the latest release notes. +echo -e "## ${tags[0]} / $(date "+%Y-%m-%d")\n\n$commits\n\n$(cat $CHANGELOG)" > $CHANGELOG diff --git a/scripts/update-compatibility-matrix.sh b/scripts/update-compatibility-matrix.sh new file mode 100755 index 0000000000..d637a44a85 --- /dev/null +++ b/scripts/update-compatibility-matrix.sh @@ -0,0 +1,48 @@ +#!/bin/bash +set -exuo pipefail + +# Determine the OS to use the correct version of sed and awk. +SED=sed +AWK=awk +if [[ $(uname) == "Darwin" ]]; then + # Check if gnu-sed and gawk are installed. + if ! command -v gsed &> /dev/null; then + echo "gnu-sed is not installed. Please install it using 'brew install gnu-sed'." >&2 + exit 1 + fi + if ! command -v gawk &> /dev/null; then + echo "gawk is not installed. Please install it using 'brew install gawk'." >&2 + exit 1 + fi + AWK=gawk + SED=gsed +fi + +# Fetch the latest tag. +git fetch --tags +latest_tag=$(git describe --tags "$(git rev-list --tags --max-count=1)") + +# Determine if it's a patch release or not (minor and major releases are handled the same way in the compatibility matrix). +if [[ $latest_tag =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + IFS='.' read -ra TAG <<< "$latest_tag" + if [[ ${#TAG[@]} -eq 2 || ${#TAG[@]} -eq 3 && ${TAG[2]} -eq 0 ]]; then + # Prep for a non-patch release. + main_client_go_version=$($AWK '/\| \*\*main\*\*/ {print $4}' README.md) + $SED -i "/|\s*\*\*main\*\*\s*|\s*$main_client_go_version\s*|/i| \*\*$latest_tag\*\* | $main_client_go_version |" README.md + oldest_supported_client_go_version=$($AWK '/\| kube-state-metrics \| Kubernetes client-go Version \|/ {getline; getline; print $4; exit}' README.md) + # Remove the first row (i.e., the oldest supported client-go version). + $SED -i "/|\s*\*\*.*\*\*\s*|\s*$oldest_supported_client_go_version\s*|/d" README.md + else + # Prep for a patch release. + minor_release="${TAG[0]}.${TAG[1]}" + # Get the client-go version of the corresponding minor release row (that needs to be updated with the patch release version). + last_client_go_version=$($AWK '/\| kube-state-metrics \| Kubernetes client-go Version \|/ {getline; getline; getline; getline; getline; getline; print $4; exit}' README.md) + # Update the row with the latest tag and client-go version. + $SED -i "s/|\s*\*\*$minor_release.*\*\*\s*|\s*$last_client_go_version\s*|/| \*\*$latest_tag\*\* | $last_client_go_version |/" README.md + fi +else + echo -e "Bad tag format: $latest_tag, expected one of the following formats:\n + * vMAJOR.MINOR (non-patch release)\n + * vMAJOR.MINOR.PATCH (patch release)" + exit 1 +fi