Skip to content

Commit

Permalink
Migrate release process to GitHub Actions
Browse files Browse the repository at this point in the history
Initial migration to GitHub Actions that allows a release to be
staged.

See gh-411
  • Loading branch information
philwebb committed Jun 8, 2024
1 parent 541d529 commit 0d16661
Show file tree
Hide file tree
Showing 19 changed files with 690 additions and 23 deletions.
1 change: 1 addition & 0 deletions .github/actions/.bats/bats
Submodule bats added at 902578
1 change: 1 addition & 0 deletions .github/actions/.bats/test_helper/bats-assert
Submodule bats-assert added at e2d855
1 change: 1 addition & 0 deletions .github/actions/.bats/test_helper/bats-support
Submodule bats-support added at 9bf10e
22 changes: 22 additions & 0 deletions .github/actions/deduce-versions/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: 'Deduce Versions'
description: 'Deduce the version to stage and the next SNAPSHOT version'
inputs:
current-version:
required: true
release-type:
required: true
outputs:
release-version:
value: ${{ steps.deduce-versions.outputs.release-version }}
next-version:
value: ${{ steps.deduce-versions.outputs.next-version }}
runs:
using: composite
steps:
- name: Deduce Versions
id: deduce-versions
shell: bash
run: . ${{ github.action_path }}/deduce-versions.sh; deduce_versions
env:
CURRENT_VERSION: "${{ inputs.current-version }}"
RELEASE_TYPE: "${{ inputs.release-type }}"
116 changes: 116 additions & 0 deletions .github/actions/deduce-versions/deduce-versions.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#!/usr/bin/env bash

# Get the next milestone release for the given number by inspecting current tags
get_next_milestone_release() {
[[ -n $1 ]] || { echo "missing get_next_milestone_release() version argument" >&2; return 1; }
get_next_tag_based_release "$1" "M"
}

# Get the next RC release for the given number by inspecting current tags
get_next_rc_release() {
[[ -n $1 ]] || { echo "missing get_next_rc_release() version argument" >&2; return 1; }
get_next_tag_based_release "$1" "RC"
}

# Get the next release for the given number
get_next_release() {
[[ -n $1 ]] || { echo "missing get_next_release() version argument" >&2; return 1; }
if [[ $1 =~ ^(.*)\.BUILD-SNAPSHOT$ ]]; then
local join="."
else
local join="-"
fi
local version
local result
version=$( strip_snapshot_suffix "$1" )
if [[ -n $2 ]]; then
result="${version}${join}${2}"
else
result="${version}"
fi
echo $result
}

# Get the next milestone or RC release for the given number by inspecting current tags
get_next_tag_based_release() {
[[ -n $1 ]] || { echo "missing get_next_tag_based_release() version argument" >&2; return 1; }
[[ -n $2 ]] || { echo "missing get_next_tag_based_release() tag type argument" >&2; return 1; }
if [[ $1 =~ ^(.*)\.BUILD-SNAPSHOT$ ]]; then
local join="."
else
local join="-"
fi
local version
local last
version=$( strip_snapshot_suffix "$1" )
git fetch --tags --all > /dev/null
last=$( git tag --list "v${version}${join}${2}*" | sed -E "s/^.*${2}([0-9]+)$/\1/g" | sort -rn | head -n1 )
if [[ -z $last ]]; then
last="0"
fi
last="${version}${join}${2}${last}"
bump_version_number "$last"
}

# Remove any "-SNAPSHOT" or ".BUILD-SNAPSHOT" suffix
strip_snapshot_suffix() {
[[ -n $1 ]] || { echo "missing get_relase_version() argument" >&2; return 1; }
if [[ $1 =~ ^(.*)\.BUILD-SNAPSHOT$ ]]; then
echo "${BASH_REMATCH[1]}"
elif [[ $1 =~ ^(.*)-SNAPSHOT$ ]]; then
echo "${BASH_REMATCH[1]}"
else
echo "$1"
fi
}

# Bump version number by incrementing the last numeric, RC or M token
bump_version_number() {
local version=$1
[[ -n $version ]] || { echo "missing bump_version_number() argument" >&2; return 1; }
if [[ $version =~ ^(.*(\.|-)([A-Za-z]+))([0-9]+)$ ]]; then
local prefix=${BASH_REMATCH[1]}
local suffix=${BASH_REMATCH[4]}
(( suffix++ ))
echo "${prefix}${suffix}"
return 0;
fi
local suffix
if [[ $version =~ ^(.*)(\-SNAPSHOT)$ ]]; then
version=${BASH_REMATCH[1]}
suffix="-SNAPSHOT"
fi
tokens=(${version//\./ })
local bumpIndex
for i in "${!tokens[@]}"; do
if [[ "${tokens[$i]}" =~ ^[0-9]+$ ]] ; then
bumpIndex=$i
fi
done
[[ -n $bumpIndex ]] || { echo "unsupported version number" >&2; return 1; }
(( tokens[bumpIndex]++ ))
local bumpedVersion
IFS=. eval 'bumpedVersion="${tokens[*]}"'
echo "${bumpedVersion}${suffix}"
}

# Deduce versions
deduce_versions() {
[[ -n ${GITHUB_OUTPUT} ]] || { echo "missing GITHUB_OUTPUT environment variable" >&2; return 1; }
[[ -n ${CURRENT_VERSION} ]] || { echo "missing CURRENT_VERSION environment variable" >&2; return 1; }
[[ -n ${RELEASE_TYPE} ]] || { echo "missing RELEASE_TYPE environment variable" >&2; return 1; }
if [[ ${RELEASE_TYPE,,} = "milestone" ]]; then
releaseVersion=$( get_next_milestone_release ${CURRENT_VERSION})
nextVersion=${CURRENT_VERSION}
elif [[ ${RELEASE_TYPE,,} = "release-candidate" ]]; then
releaseVersion=$( get_next_rc_release ${CURRENT_VERSION})
nextVersion=${CURRENT_VERSION}
elif [[ ${RELEASE_TYPE,,} = "release" ]]; then
releaseVersion=$( get_next_release ${CURRENT_VERSION})
nextVersion=$( bump_version_number ${CURRENT_VERSION})
else
echo "Unknown release type '${RELEASE_TYPE}'" >&2; exit 1;
fi
echo "release-version=${releaseVersion}" >> "$GITHUB_OUTPUT"
echo "next-version=${nextVersion}" >> "$GITHUB_OUTPUT"
}
1 change: 1 addition & 0 deletions .github/actions/deduce-versions/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
../.bats/bats/bin/bats test/*.bats
58 changes: 58 additions & 0 deletions .github/actions/deduce-versions/test/bump_version.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#!./test/libs/bats/bin/bats

load '../../.bats/test_helper/bats-support/load'
load '../../.bats/test_helper/bats-assert/load'

source "$PWD/deduce-versions.sh"

@test "bump_version_number() should bump '.M'" {
run bump_version_number "1.2.0.M2"
assert_output "1.2.0.M3"
}

@test "bump_version_number() should bump '.RC'" {
run bump_version_number "1.2.0.RC3"
assert_output "1.2.0.RC4"
}

@test "bump_version_number() should bump '-M'" {
run bump_version_number "1.2.0-M2"
assert_output "1.2.0-M3"
}

@test "bump_version_number() should bump '-RC'" {
run bump_version_number "1.2.0-RC3"
assert_output "1.2.0-RC4"
}

@test "bump_version_number() should bump without suffix" {
run bump_version_number "1.2.0"
assert_output "1.2.1"
}

@test "bump_version_number() should bump '.RELEASE'" {
run bump_version_number "1.2.0.RELEASE"
assert_output "1.2.1.RELEASE"
}

@test "bump_version_number() should bump '-SNAPSHOT'" {
run bump_version_number "1.2.0-SNAPSHOT"
assert_output "1.2.1-SNAPSHOT"
}

@test "bump_version_number() should bump '.BUILD-SNAPSHOT'" {
run bump_version_number "1.2.0.BUILD-SNAPSHOT"
assert_output "1.2.1.BUILD-SNAPSHOT"
}

@test "bump_version_number() when missing argument should fail" {
run bump_version_number
assert_output "missing bump_version_number() argument"
assert [ "$status" -eq 1 ]
}

@test "bump_version_number() when bad argument should fail" {
run bump_version_number "foo.bar.baz"
assert_output "unsupported version number"
assert [ "$status" -eq 1 ]
}
96 changes: 96 additions & 0 deletions .github/actions/deduce-versions/test/deduce_versions.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#!./test/libs/bats/bin/bats

load '../../.bats/test_helper/bats-support/load'
load '../../.bats/test_helper/bats-assert/load'

source "$PWD/deduce-versions.sh"

teardown() {
rm .githuboutput | true
}

@test "deduce_versions() when 'milestone' should export versions" {
repo=$( mock_git_repo "v1.2.3-M1" )
cd "$repo"
GITHUB_OUTPUT=".githuboutput"
CURRENT_VERSION="1.2.3-SNAPSHOT"
RELEASE_TYPE="milestone"
run deduce_versions
readarray -t githuboutput < .githuboutput
assert [ "$status" -eq 0 ]
assert [ "${githuboutput[0]}" = "release-version=1.2.3-M2" ]
assert [ "${githuboutput[1]}" = "next-version=1.2.3-SNAPSHOT" ]
}

@test "deduce_versions() when 'release-candidate' should export versions" {
repo=$( mock_git_repo "v1.2.3-M1" "v1.2.3-M2" "v1.2.3-RC1" )
cd "$repo"
GITHUB_OUTPUT=".githuboutput"
CURRENT_VERSION="1.2.3-SNAPSHOT"
RELEASE_TYPE="release-candidate"
run deduce_versions
readarray -t githuboutput < .githuboutput
assert [ "$status" -eq 0 ]
assert [ "${githuboutput[0]}" = "release-version=1.2.3-RC2" ]
assert [ "${githuboutput[1]}" = "next-version=1.2.3-SNAPSHOT" ]
}

@test "deduce_versions() when 'release' should export versions" {
repo=$( mock_git_repo "v1.2.3-M1" "v1.2.3-M2" "v1.2.3-RC1" )
cd "$repo"
GITHUB_OUTPUT=".githuboutput"
CURRENT_VERSION="1.2.3-SNAPSHOT"
RELEASE_TYPE="release"
run deduce_versions
readarray -t githuboutput < .githuboutput
assert [ "$status" -eq 0 ]
assert [ "${githuboutput[0]}" = "release-version=1.2.3" ]
assert [ "${githuboutput[1]}" = "next-version=1.2.4-SNAPSHOT" ]
}

@test "deduce_versions() when no GITHUB_OUTPUT should fail" {
CURRENT_VERSION="1.2.3-SNAPSHOT"
RELEASE_TYPE="release"
run deduce_versions
assert [ "$status" -eq 1 ]
assert_output "missing GITHUB_OUTPUT environment variable"
}

@test "deduce_versions() when no CURRENT_VERSION should fail" {
GITHUB_OUTPUT=".githuboutput"
RELEASE_TYPE="release"
run deduce_versions
assert [ "$status" -eq 1 ]
assert_output "missing CURRENT_VERSION environment variable"
}

@test "deduce_versions() when no RELEASE_TYPE should fail" {
GITHUB_OUTPUT=".githuboutput"
CURRENT_VERSION="1.2.3-SNAPSHOT"
run deduce_versions
assert [ "$status" -eq 1 ]
assert_output "missing RELEASE_TYPE environment variable"
}

@test "deduce_versions() when wrong RELEASE_TYPE should fail" {
GITHUB_OUTPUT=".githuboutput"
CURRENT_VERSION="1.2.3-SNAPSHOT"
RELEASE_TYPE="nope"
run deduce_versions
assert [ "$status" -eq 1 ]
assert_output "Unknown release type 'nope'"
}

mock_git_repo() {
local tmpdir=$(mktemp -d $BATS_TMPDIR/gitrepo.XXXXXX) >&2
mkdir -p "$tmpdir" >&2
cd "$tmpdir" >&2
git init >&2
echo "foo" > foo.txt
git add foo.txt >&2
git commit -m'Initial commit' >&2
for tag in "$@"; do
git tag "$tag" >&2
done
echo "$tmpdir"
}
Loading

0 comments on commit 0d16661

Please sign in to comment.