From de2be11ed2caae1c38481934418b342ff5812aac Mon Sep 17 00:00:00 2001 From: Joshua Sing Date: Tue, 2 Jul 2024 01:32:52 +1000 Subject: [PATCH 1/3] scripts: add release script Add a _definitely not over engineered_ release script to easily and safely create and push git tags. --- .github/CODEOWNERS | 3 + scripts/release.sh | 164 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 167 insertions(+) create mode 100755 scripts/release.sh diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 46e5a28f..2512beba 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -32,3 +32,6 @@ # WASM PoP Miner (popmd/wasm) /web/ @hemilabs/dev @joshuasing + +# Release script +/scripts/release.sh @hemilabs/dev @joshuasing diff --git a/scripts/release.sh b/scripts/release.sh new file mode 100755 index 00000000..5a34dc7b --- /dev/null +++ b/scripts/release.sh @@ -0,0 +1,164 @@ +#!/bin/sh +# Copyright (c) 2024 Hemi Labs, Inc. +# Use of this source code is governed by the MIT License, +# which can be found in the LICENSE file. + +set -e + +# +# hemilabs/heminetwork release script +# +# Tags the latest remote commit in the heminetwork repository's main branch and +# pushes the tag to the repository, triggering the release CI which will build +# all necessary binaries, Docker images, etc. and create a GitHub release. +# +# This script will create a new remote called 'upstream' (configurable with +# REMOTE_NAME). This remote is used to fetch the latest commit on the main +# branch, allowing a tag to be created on the latest remote commit while +# ignoring any local changes. +# +# The provided version (and all version bumps) must follow the Semantic +# Versioning 2.0.0 specification (..), as per +# https://semver.org/. This allows the versioning to stay consistent while +# easily communicating the type of change the version contains to users. +# +# This script will always confirm with you before creating or pushing the tag, +# in an attempt to prevent accidental tag creation or pushes. +# +# Usage: +# release.sh +# +# Requirements: +# - git (configured correctly) +# - gpg (and git configured to use signing key) +# - ssh (and key with access to repository) +# - grep +# - sed +# + +REPOSITORY="https://github.com/hemilabs/heminetwork" +REMOTE_NAME=${REMOTE_NAME:-"upstream"} +REMOTE_URL=${REMOTE_URL:-"git+ssh://git@github.com/hemilabs/heminetwork.git"} +BRANCH_NAME="main" + +log() { + echo "release: $*" +} + +fatal() { + echo "release: $*" >&2 + exit 1 +} + +setup_remote() { + log "setting up remote '$REMOTE_NAME' for $REMOTE_URL" + + if ! git remote get-url "$REMOTE_NAME" >/dev/null 2>&1; then + log "remote '$REMOTE_NAME' does not exist, adding with URL $REMOTE_URL" + git remote add "$REMOTE_NAME" "$REMOTE_URL" || \ + fatal "failed to add remote '$REMOTE_NAME'" + return + fi + + old_remote_url="$(git remote get-url "$REMOTE_NAME")" + if [ "$old_remote_url" != "$REMOTE_URL" ]; then + log "remote '$REMOTE_NAME' exists with unexpected URL: $old_remote_url" + + if ! confirm "Override remote '$REMOTE_NAME' URL with $REMOTE_URL"; then + fatal "remote URL override aborted" + fi + git remote set-url "$REMOTE_NAME" "$REMOTE_URL" || \ + fatal "failed to set remote '$REMOTE_NAME' URL" + return + fi + + log "remote '$REMOTE_NAME' already exists with URL $REMOTE_URL" +} + +fetch_branch() { + log "fetching $REMOTE_NAME/$BRANCH_NAME" + git fetch -q "$REMOTE_NAME" "$BRANCH_NAME" || \ + fatal "failed to fetch remote branch $REMOTE_NAME/$BRANCH_NAME" + REF=$(git rev-parse --verify -q 'FETCH_HEAD') || \ + fatal "failed to verify FETCH_HEAD" +} + +create_tag() { + log "tagging $1 as $2" + skip_dryrun git tag -a -s -m "$2" "$2" "$1" +} + +push_tag() { + log "pushing $1 to $REMOTE_NAME ($REMOTE_URL)" + skip_dryrun git push "$REMOTE_NAME" "$1" +} + +confirm() { + echo + printf "%s [y/N]? " "$1" + read -r answer + if [ "$answer" = "${answer#[Yy]}" ]; then + return 1 + fi + return 0 +} + +skip_dryrun() { + if [ "$DRY_RUN" = true ]; then + log "dry-run mode: skipping: $*" + return + fi + "$@" +} + +print_success() { + log "successfully pushed tag $1 to $REMOTE_NAME!" + log "See workflow status: $REPOSITORY/actions/workflows/release.yml" + log "see release (once workflow has finished): $REPOSITORY/releases/tag/$1" +} + +# https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string +SEMVER_REGEX='^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$' + +release() { + VERSION=$(echo "$1" | sed -e 's/^v//') + TAG=$(echo "$1" | sed -E 's/^([^v])/v\1/g') + if ! echo "$1" | grep -Eq "$SEMVER_REGEX"; then + fatal "invalid version: $1. must be in semver format: https://semver.org/" + fi + TYPE='unstable' + if echo "$VERSION" | grep -Eq '^[1-9][0-9]*\.[0-9]+\.[0-9]+$'; then + TYPE='stable' + fi + + # Setup remote and fetch main branch + setup_remote + fetch_branch + + # Create tag + git --no-pager show "$REF" --pretty=fuller --show-signature --no-patch + if ! confirm "Do you want to tag $REF as $TAG ($TYPE)"; then + fatal "tagging aborted" + fi + create_tag "$REF" "$TAG" + + # Push tag + skip_dryrun git --no-pager show "$TAG" --pretty=fuller --show-signature --no-patch + if ! confirm "Do you want to push tag $TAG ($TYPE) to $REMOTE_NAME ($REMOTE_URL)"; then + fatal "push aborted" + fi + push_tag "$TAG" + + skip_dryrun print_success "$TAG" +} + +if [ $# -ne 1 ]; then + echo "usage: $0 " + exit 1 +fi + +if [ "$DRY_RUN" = true ]; then + log "running in dry-run mode. tags will not be created or pushed" +fi + +release "$1" From ef09818176fc7a3ff220298c11f2c807e632255a Mon Sep 17 00:00:00 2001 From: Joshua Sing Date: Wed, 3 Jul 2024 03:18:27 +1000 Subject: [PATCH 2/3] scripts: fix spacing in release script doc comment --- scripts/release.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/release.sh b/scripts/release.sh index 5a34dc7b..fea7ceca 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -26,13 +26,13 @@ set -e # in an attempt to prevent accidental tag creation or pushes. # # Usage: -# release.sh +# release.sh # # Requirements: -# - git (configured correctly) +# - git (configured correctly) # - gpg (and git configured to use signing key) # - ssh (and key with access to repository) -# - grep +# - grep # - sed # From 349425c4e9abf78429c5692f0b6cf98eb768c4d1 Mon Sep 17 00:00:00 2001 From: Joshua Sing Date: Wed, 3 Jul 2024 03:19:08 +1000 Subject: [PATCH 3/3] scripts: add env variable documentation for release script --- scripts/release.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/release.sh b/scripts/release.sh index fea7ceca..9a28340d 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -28,6 +28,9 @@ set -e # Usage: # release.sh # +# Environment variables: +# DRY_RUN - If set to `true`, the script will not create or push any tags. +# # Requirements: # - git (configured correctly) # - gpg (and git configured to use signing key)