From fb000b1098e5bc42581e076efac35658160bfdd4 Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Fri, 21 Apr 2023 10:01:23 -0400 Subject: [PATCH] Initial commit of release scripts (#20) Copy releasing scripts from Mimir and adapt for this repository. Hand-tested. --- .goreleaser.yaml | 2 - CHANGELOG.md | 10 +++ README.md | 25 +++++++ VERSION | 1 + scripts/release/common.sh | 65 ++++++++++++++++ scripts/release/create-draft-release-notes.sh | 75 +++++++++++++++++++ scripts/release/create-draft-release.sh | 39 ++++++++++ scripts/release/tag-release.sh | 44 +++++++++++ 8 files changed, 259 insertions(+), 2 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 VERSION create mode 100755 scripts/release/common.sh create mode 100755 scripts/release/create-draft-release-notes.sh create mode 100755 scripts/release/create-draft-release.sh create mode 100755 scripts/release/tag-release.sh diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 3c11a70..7db998e 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -19,5 +19,3 @@ archives: files: - none* name_template: "mimir-whisper-converter_{{ .Tag }}_{{ .Os }}_{{ .Arch }}" -changelog: - skip: true diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..f358521 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,10 @@ +# CHANGELOG for mimir-proxies + +## 0.0.2 + +Release mimir-whisper-converter, a utility for converting large Graphite Whisper +databases of untagged metrics to mimir blocks. + +## 0.0.1 + +Initial release \ No newline at end of file diff --git a/README.md b/README.md index fe1555b..94409ea 100644 --- a/README.md +++ b/README.md @@ -19,3 +19,28 @@ There is plenty of work planned to refactor the existing proxies, and a common f Because of this, there may be changes to interfaces, code structure, command-line-arguments, etc but we will try to only make breaking changes where necessary. Despite these warnings, this is the fundamentally the code that is running in production at scale within Grafana Labs. We welcome issues/PRs if you have any suggestions or contributions for new proxies/formats/protocols to support. + +## Releasing + +Releasing is done manually, and is based on the scripts that Mimir uses. +Releases will appear in the github project for mimir-proxies. + +Currently the release configuration only builds the mimir-whisper-converter, not +all of the commands. + +1. Increment the version number in VERSION. +2. Add a heading to CHANGELOG.md to describe the major changes. +3. Create a release branch: `git checkout -b release-$(cat VERSION)` +4. run `./scripts/release/tag-release.sh` to sign and tag the branch. +5. run `./scripts/release/create-draft-release.sh`. +6. Go to the link printed at the end of the build and upload, and check that the + release makes sense. +7. Either fix it, or click Edit and Publish the release. + +If you run into problems with the tagged release, you can delete it. You'll need +to do that both locally and remotely: + +```sh +git tag -d mimir-proxies-$(cat VERSION) +git push --delete origin mimir-proxies-$(cat VERSION) +``` \ No newline at end of file diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..7bcd0e3 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.0.2 \ No newline at end of file diff --git a/scripts/release/common.sh b/scripts/release/common.sh new file mode 100755 index 0000000..757f398 --- /dev/null +++ b/scripts/release/common.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: AGPL-3.0-only +# +# This is a library shared between scripts for managing the release process. +# + +set -e + +check_required_setup() { + # Ensure "gh" tool is installed. + if ! command -v gh &> /dev/null; then + echo "The 'gh' command cannot be found. Please install it: https://cli.github.com" > /dev/stderr + exit 1 + fi + + # Ensure the repository has a remote named "origin". If the repo has more than + # one remote, there will be an error and the user will be prompted to select a + # default remote. + if [ "$(git remote | grep origin)" != "origin" ]; then + echo "The release automation scripts require the git clone to have a remote named 'origin', but found:" + git remote + + exit 1 + fi +} + +find_last_release() { + LAST_RELEASE_TAG=$(git tag --list --sort=taggerdate 'mimir-proxies-[0-9]*' | tail -1) + + if [ -z "${LAST_RELEASE_TAG}" ]; then + echo "Unable to find the last release git tag" > /dev/stderr + exit 1 + fi + + # Find the last release version. Since all tags start with "mimir-proxies-" + # we can simply find the version: + LAST_RELEASE_VERSION=$(echo "${LAST_RELEASE_TAG}" | cut -c 15-) + + export LAST_RELEASE_TAG + export LAST_RELEASE_VERSION +} + +# Find the previous release. If the last release is a stable release then it only takes in account stable releases +# (the previous release of a stable release must be another stable release). +find_prev_release() { + find_last_release + + if [[ $LAST_RELEASE_VERSION =~ "-rc" ]]; then + PREV_RELEASE_TAG=$(git tag --list --sort=taggerdate 'mimir-proxies-[0-9]*' | tail -2 | head -1) + else + PREV_RELEASE_TAG=$(git tag --list --sort=taggerdate 'mimir-proxies-[0-9]*' | grep -v -- '-rc' | tail -2 | head -1) + fi + + if [ -z "${PREV_RELEASE_TAG}" ]; then + echo "Unable to find the previous release git tag" > /dev/stderr + exit 1 + fi + + # Find the prev release version. Since all tags start with "mimir-proxies-" + # we can simply find the version: + PREV_RELEASE_VERSION=$(echo "${PREV_RELEASE_TAG}" | cut -c 15-) + + export PREV_RELEASE_TAG + export PREV_RELEASE_VERSION +} diff --git a/scripts/release/create-draft-release-notes.sh b/scripts/release/create-draft-release-notes.sh new file mode 100755 index 0000000..a657439 --- /dev/null +++ b/scripts/release/create-draft-release-notes.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: AGPL-3.0-only + +set -e + +# Use GNU sed on MacOS falling back to `sed` everywhere else +SED=$(which gsed || which sed) + +# Load common lib. +CURR_DIR="$(dirname "$0")" +. "${CURR_DIR}/common.sh" + +check_required_setup +find_last_release +find_prev_release + +CHANGELOG_PATH="${CURR_DIR}/../../CHANGELOG.md" + +# +# Contributors +# + +# We use the 2-dots notation to diff because in this context we only want to get the new commits in the last release. +NUM_PRS=$(git log --pretty=format:"%s" "${PREV_RELEASE_TAG}..${LAST_RELEASE_TAG}" | grep -cE '#[0-9]+') +NUM_AUTHORS=$(git log --pretty=format:"%an" "${PREV_RELEASE_TAG}..${LAST_RELEASE_TAG}" | sort | uniq -i | wc -l | grep -Eo '[0-9]+') +NEW_AUTHORS=$(diff <(git log --pretty=format:"%an" "${PREV_RELEASE_TAG}" | sort | uniq -i) <(git log --pretty=format:"%an" "${LAST_RELEASE_TAG}" | sort | uniq -i) | grep -E '^>' | cut -c 3- | $SED -z 's/\n/, /g;s/, $//') + +if [ -z "${NEW_AUTHORS}" ]; then + printf "This release contains %s PRs from %s authors. Thank you!\n\n" "${NUM_PRS}" "${NUM_AUTHORS}" +else + printf "This release contains %s PRs from %s authors, including new contributors %s. Thank you!\n\n" "${NUM_PRS}" "${NUM_AUTHORS}" "${NEW_AUTHORS}" +fi + +# +# Release notes +# + +# We don't publish release notes for patch versions. +PREV_RELEASE_MINOR_VERSION=$(echo -n "${PREV_RELEASE_VERSION}" | grep -Eo '^[0-9]+\.[0-9]+') +LAST_RELEASE_MINOR_VERSION=$(echo -n "${LAST_RELEASE_VERSION}" | grep -Eo '^[0-9]+\.[0-9]+') + +if [ "${PREV_RELEASE_MINOR_VERSION}" != "${LAST_RELEASE_MINOR_VERSION}" ]; then + # Title + printf "# Grafana Mimir-proxies version %s release notes\n\n" "${LAST_RELEASE_VERSION}" + + # Add a place holder for the release notes. + printf "**TODO: add release notes here**\n\n" +fi + +# +# CHANGELOG +# + +# Find the line at which the CHANGELOG for this version begins. +CHANGELOG_SECTION_TITLE="## ${LAST_RELEASE_VERSION}" +CHANGELOG_BEGIN_LINE=$(awk "/^${CHANGELOG_SECTION_TITLE}$/{ print NR; exit }" "${CHANGELOG_PATH}") +if [ -z "${CHANGELOG_BEGIN_LINE}" ]; then + echo "Unable to find the section title '${CHANGELOG_SECTION_TITLE}' in the ${CHANGELOG_PATH}" > /dev/stderr + exit 1 +fi + +# Find the line at which the CHANGELOG for this version ends. +CHANGELOG_END_LINE=$(tail -n +$((CHANGELOG_BEGIN_LINE + 1)) "${CHANGELOG_PATH}" | awk "/^## /{ print NR - 1; exit }") +if [ -z "${CHANGELOG_END_LINE}" ]; then + echo "Unable to find the end of the section '${CHANGELOG_SECTION_TITLE}' in the ${CHANGELOG_PATH}" > /dev/stderr + exit 1 +fi + +# Append the CHANGELOG section to the release notes. +printf "# Changelog\n\n" +tail -n +"${CHANGELOG_BEGIN_LINE}" "${CHANGELOG_PATH}" | head -$((CHANGELOG_END_LINE + 1)) +printf "\n" + +# Link to changes. +printf "**All changes in this release**: https://github.com/grafana/mimir-proxies/compare/%s...%s\n" "${PREV_RELEASE_TAG}" "${LAST_RELEASE_TAG}" diff --git a/scripts/release/create-draft-release.sh b/scripts/release/create-draft-release.sh new file mode 100755 index 0000000..6bab057 --- /dev/null +++ b/scripts/release/create-draft-release.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: AGPL-3.0-only + +set -e + +# Load common lib. +CURR_DIR="$(dirname "$0")" +. "${CURR_DIR}/common.sh" + +check_required_setup +find_last_release + +# Build binaries and packages. +echo "Building binaries (this may take a while)..." +export GORELEASER_CURRENT_TAG=v"$(cat VERSION)" +cd "${CURR_DIR}"/../../ && goreleaser release --snapshot --rm-dist && cd - + +# Generate release notes draft. +echo "Generating the draft release notes..." +RELEASE_NOTES_FILE="./tmp-release-notes.md" +trap 'rm -f "${RELEASE_NOTES_FILE}"' EXIT +"${CURR_DIR}"/create-draft-release-notes.sh > "${RELEASE_NOTES_FILE}" + +# Create the draft release. +echo "Creating the draft release (uploading assets may take a while)..." +gh release create \ + --draft \ + --prerelease \ + --title "${LAST_RELEASE_VERSION}" \ + --notes-file "${RELEASE_NOTES_FILE}" \ + "${LAST_RELEASE_TAG}" "${CURR_DIR}"/../../dist/*.tar.gz + +# Print instructions to move on. +echo "" +echo "The draft release has been created. To continue:" +echo "1. Copy the release notes from the documentation and fix the links. Skip if publishing a patch release." +echo "2. Review the draft release." +echo "3. If this is a stable release, remove the tick from 'This is a pre-release'." +echo "4. Publish it." diff --git a/scripts/release/tag-release.sh b/scripts/release/tag-release.sh new file mode 100755 index 0000000..47e3b3f --- /dev/null +++ b/scripts/release/tag-release.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: AGPL-3.0-only + +set -e + +# Load common lib. +CURR_DIR="$(dirname "$0")" +. "${CURR_DIR}/common.sh" + +check_required_setup + +# The branch must be named release-X.Y.Z, and the corresponding +# tag will be mimir-proxies-X.Y.Z + +# Ensure the current branch is a release one. +BRANCH=$(git branch --show-current) +if [[ ! $BRANCH =~ ^release-([0-9]+\.[0-9]+\.[0-9]+)$ ]]; then + echo "The current branch '${BRANCH}' is not a release branch." > /dev/stderr + exit 1 +fi + +# Get the actual branch version from the previous regex. +BRANCH_VERSION=${BASH_REMATCH[1]} + +# Load the version and ensure it matches. +ACTUAL_VERSION=$(cat VERSION) +if [[ ! $ACTUAL_VERSION =~ ^$BRANCH_VERSION ]]; then + echo "The current branch '${BRANCH}' doesn't match the content of the VERSION file '${ACTUAL_VERSION}'" > /dev/stderr + exit 1 +fi + +# Ask confirmation. +read -p "You're about to tag the version mimir-proxies-${ACTUAL_VERSION}. Do you want to continue? (y/n) " -n 1 -r +echo "" +if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo "Aborting ..." > /dev/stderr + exit 1 +fi + +git tag -s "mimir-proxies-${ACTUAL_VERSION}" -m "v${ACTUAL_VERSION}" +git push origin "mimir-proxies-${ACTUAL_VERSION}" + +echo "" +echo "Version '${ACTUAL_VERSION}' successfully tagged."