Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add auto semver tagging for release automation #712

Merged
merged 12 commits into from Nov 2, 2022
231 changes: 231 additions & 0 deletions .github/actions/github-tag-action/entrypoint.sh
@@ -0,0 +1,231 @@
#!/bin/bash

set -o pipefail

# config
default_semvar_bump=${DEFAULT_BUMP:-minor}
with_v=${WITH_V:-false}
release_branches=${RELEASE_BRANCHES:-}
custom_tag=${CUSTOM_TAG:-}
source=${SOURCE:-.}
dryrun=${DRY_RUN:-false}
initial_version=${INITIAL_VERSION:-0.0.0}
tag_context=${TAG_CONTEXT:-repo}
prerelease=${PRERELEASE:-false}
suffix=${PRERELEASE_SUFFIX:-beta}
verbose=${VERBOSE:-false}
major_string_token=${MAJOR_STRING_TOKEN:-#major}
minor_string_token=${MINOR_STRING_TOKEN:-#minor}
patch_string_token=${PATCH_STRING_TOKEN:-#patch}
none_string_token=${NONE_STRING_TOKEN:-#none}
# since https://github.blog/2022-04-12-git-security-vulnerability-announced/ runner uses?
git config --global --add safe.directory /github/workspace

cd "${GITHUB_WORKSPACE}/${source}" || exit 1

echo "*** CONFIGURATION ***"
echo -e "\tDEFAULT_BUMP: ${default_semvar_bump}"
echo -e "\tWITH_V: ${with_v}"
echo -e "\tRELEASE_BRANCHES: ${release_branches}"
echo -e "\tCUSTOM_TAG: ${custom_tag}"
echo -e "\tSOURCE: ${source}"
echo -e "\tDRY_RUN: ${dryrun}"
echo -e "\tINITIAL_VERSION: ${initial_version}"
echo -e "\tTAG_CONTEXT: ${tag_context}"
echo -e "\tPRERELEASE: ${prerelease}"
echo -e "\tPRERELEASE_SUFFIX: ${suffix}"
echo -e "\tVERBOSE: ${verbose}"
echo -e "\tMAJOR_STRING_TOKEN: ${major_string_token}"
echo -e "\tMINOR_STRING_TOKEN: ${minor_string_token}"
echo -e "\tPATCH_STRING_TOKEN: ${patch_string_token}"
echo -e "\tNONE_STRING_TOKEN: ${none_string_token}"

# verbose, show everything
if $verbose
then
set -x
fi

setOutput() {
echo "${1}=${2}" >> "${GITHUB_OUTPUT}"
}

current_branch=$(git rev-parse --abbrev-ref HEAD)

pre_release="$prerelease"
IFS=',' read -ra branch <<< "$release_branches"
for b in "${branch[@]}"; do
# check if ${current_branch} is in ${release_branches} | exact branch match
if [[ "$current_branch" == "$b" ]]
then
pre_release="false"
fi
# verify non specific branch names like .* release/* if wildcard filter then =~
if [ "$b" != "${b//[\[\]|.? +*]/}" ] && [[ "$current_branch" =~ $b ]]
then
pre_release="false"
fi
done
echo "pre_release = $pre_release"

# fetch tags
git fetch --tags

tagFmt="^v?[0-9]+\.[0-9]+\.[0-9]+$"
preTagFmt="^v?[0-9]+\.[0-9]+\.[0-9]+(-$suffix\.[0-9]+)$"

# get latest tag that looks like a semver (with or without v)
case "$tag_context" in
*repo*)
tag="$(git for-each-ref --sort=-v:refname --format '%(refname:lstrip=2)' | grep -E "$tagFmt" | head -n 1)"
pre_tag="$(git for-each-ref --sort=-v:refname --format '%(refname:lstrip=2)' | grep -E "$preTagFmt" | head -n 1)"
;;
*branch*)
tag="$(git tag --list --merged HEAD --sort=-v:refname | grep -E "$tagFmt" | head -n 1)"
pre_tag="$(git tag --list --merged HEAD --sort=-v:refname | grep -E "$preTagFmt" | head -n 1)"
;;
* ) echo "Unrecognised context"
exit 1;;
esac

# if there are none, start tags at INITIAL_VERSION
if [ -z "$tag" ]
then
if $with_v
then
tag="v$initial_version"
else
tag="$initial_version"
fi
if [ -z "$pre_tag" ] && $pre_release
then
if $with_v
then
pre_tag="v$initial_version"
else
pre_tag="$initial_version"
fi
fi
fi

# get current commit hash for tag
tag_commit=$(git rev-list -n 1 "$tag")

# get current commit hash
commit=$(git rev-parse HEAD)

if [ "$tag_commit" == "$commit" ]
then
echo "No new commits since previous tag. Skipping..."
setOutput "new_tag" "$tag"
setOutput "tag" "$tag"
exit 0
fi

# get the merge commit message looking for #bumps
log=$(git show -s --format=%s)
echo "Last commit message: $log"

case "$log" in
*$major_string_token* ) new=$(semver -i major "$tag"); part="major";;
*$minor_string_token* ) new=$(semver -i minor "$tag"); part="minor";;
*$patch_string_token* ) new=$(semver -i patch "$tag"); part="patch";;
*$none_string_token* )
echo "Default bump was set to none. Skipping..."
setOutput "new_tag" "$tag"
setOutput "tag" "$tag"
exit 0;;
* )
if [ "$default_semvar_bump" == "none" ]
then
echo "Default bump was set to none. Skipping..."
setOutput "new_tag" "$tag"
setOutput "tag" "$tag"
exit 0
else
new=$(semver -i "${default_semvar_bump}" "$tag")
part=$default_semvar_bump
fi
;;
esac

if $pre_release
then
# already a pre-release available, bump it
if [[ "$pre_tag" =~ $new ]] && [[ "$pre_tag" =~ $suffix ]]
then
if $with_v
then
new=v$(semver -i prerelease "${pre_tag}" --preid "${suffix}")
else
new=$(semver -i prerelease "${pre_tag}" --preid "${suffix}")
fi
echo -e "Bumping ${suffix} pre-tag ${pre_tag}. New pre-tag ${new}"
else
if $with_v
then
new="v$new-$suffix.0"
else
new="$new-$suffix.0"
fi
echo -e "Setting ${suffix} pre-tag ${pre_tag} - With pre-tag ${new}"
fi
part="pre-$part"
else
if $with_v
then
new="v$new"
fi
echo -e "Bumping tag ${tag} - New tag ${new}"
fi

# as defined in readme if CUSTOM_TAG is used any semver calculations are irrelevant.
if [ -n "$custom_tag" ]
then
new="$custom_tag"
fi

# set outputs
setOutput "new_tag" "$new"
setOutput "part" "$part"
setOutput "tag" "$new" # this needs to go in v2 is breaking change
setOutput "old_tag" "$tag"

# dry run exit without real changes
if $dryrun
then
exit 0
fi

# create local git tag
git tag "$new"

# push new tag ref to github
dt=$(date '+%Y-%m-%dT%H:%M:%SZ')
full_name=$GITHUB_REPOSITORY
git_refs_url=$(jq .repository.git_refs_url "$GITHUB_EVENT_PATH" | tr -d '"' | sed 's/{\/sha}//g')

echo "$dt: **pushing tag $new to repo $full_name"

git_refs_response=$(
curl -s -X POST "$git_refs_url" \
-H "Authorization: token $GITHUB_TOKEN" \
-d @- << EOF

{
"ref": "refs/tags/$new",
"sha": "$commit"
}
EOF
)

git_ref_posted=$( echo "${git_refs_response}" | jq .ref | tr -d '"' )

echo "::debug::${git_refs_response}"
if [ "${git_ref_posted}" = "refs/tags/${new}" ]
then
exit 0
else
echo "::error::Tag was not created properly."
exit 1
fi
2 changes: 1 addition & 1 deletion .github/workflows/goreleaser.yaml
Expand Up @@ -3,7 +3,7 @@ name: goreleaser
on:
push:
tags:
- 'v*.*.*'
- '[0-9]+.[0-9]+.[0-9]+'
elliotmjackson marked this conversation as resolved.
Show resolved Hide resolved

permissions:
contents: write
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/maven-deploy.yaml
Expand Up @@ -6,7 +6,7 @@ name: Maven Deploy
on:
push:
tags:
- 'v*.*.*'
- '[0-9]+.[0-9]+.[0-9]+'
elliotmjackson marked this conversation as resolved.
Show resolved Hide resolved

jobs:
build:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/python-package.yaml
Expand Up @@ -3,7 +3,7 @@ name: Release Python Package
on:
push:
tags:
- 'v*.*.*'
- '[0-9]+.[0-9]+.[0-9]+'
elliotmjackson marked this conversation as resolved.
Show resolved Hide resolved

env:
IMAGE_TAG: protoc-gen-validate:${{ github.sha }}
Expand Down
31 changes: 31 additions & 0 deletions .github/workflows/semver.yaml
@@ -0,0 +1,31 @@
name: Bump version
elliotmjackson marked this conversation as resolved.
Show resolved Hide resolved
on:
push:
branches:
- main
workflow_dispatch:
inputs:
release:
type: boolean
description: Remove SNAPSHOT?

jobs:
build:
runs-on: ubuntu-22.04
steps:
- if: ${{ github.event.inputs.release == false }}
run: echo "PRERELEASE=true" >> $GITHUB_ENV
- uses: actions/checkout@v3
with:
fetch-depth: "0"
- uses: actions/setup-node@v3
with:
node-version: 16
- run: npm install -g semver
- name: Bump version and push tag
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
WITH_V: true
DEFAULT_BUMP: "minor"
PRERELEASE_SUFFIX: "SNAPSHOT"
run: .github/actions/github-tag-action/entrypoint.sh