Skip to content

Commit

Permalink
Merge pull request #4 from climatepolicyradar/merge-shared-actions-co…
Browse files Browse the repository at this point in the history
…de-into-repo

- Pull common github actions code into separate shared repo
- Separate tag and release into two reusable workflow files
  • Loading branch information
katybaulch authored Mar 4, 2024
2 parents 536ff7b + cfa89a9 commit cb96fc4
Show file tree
Hide file tree
Showing 10 changed files with 817 additions and 59 deletions.
15 changes: 15 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
###############################################################################
# GitHub Code-owner Configuration for Reusable Workflows
#
# Each line is a file pattern followed by one or more owners. See this link:
# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners#example-of-a-codeowners-file
# for more information on configuring GitHub code owners, including examples.
###############################################################################

# These owners will be the default owners for everything in
# the repo. Unless a later match takes precedence, members
# of @climatepolicyradar/tech-devs will be requested for
# review when someone opens a pull request. Teams should
# be identified in the format @org/team-name. Teams must have
# explicit write access to the repository.
* @climatepolicyradar/tech-devs
62 changes: 62 additions & 0 deletions .github/auto-tag.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/bin/bash
set -euo pipefail

script_folder=$(dirname "${BASH_SOURCE[0]}")
source "${script_folder}"/funcs.sh

# Get the latest Git tag.
latest_tag=$(get_latest_tag)
if [[ -z ${latest_tag} ]]; then
echo "No tags found. Please create first tag manually to enable auto-tagging."
exit 1
fi
echo "Latest tag: ${latest_tag}"

pr_body="$1"

# Get selected versioning checkboxes.
is_patch=$(is_patch_selected "${pr_body}")
is_minor=$(is_minor_selected "${pr_body}")
is_major=$(is_major_selected "${pr_body}")

pr_number="$2"

if { [[ ${is_minor} == true ]] && [[ ${is_patch} == true ]]; } ||
{ [[ ${is_minor} == true ]] && [[ ${is_major} == true ]]; } ||
{ [[ ${is_patch} == true ]] && [[ ${is_major} == true ]]; }; then
echo "Ambiguous tag information in body of pull request #${pr_number}. Auto-tagging will use most senior version option selected."
fi

# Extract the version numbers from the tag
version_numbers=${latest_tag#v} # Remove the leading 'v'
version_numbers=${version_numbers%-*} # Remove the trailing '-beta'
major_version=$(get_major "${version_numbers}")
minor_version=$(get_minor "${version_numbers}")
patch_version=$(get_patch "${version_numbers}")
maturity=$(get_maturity "${latest_tag}")
if [[ -n ${maturity} ]]; then
maturity="-${maturity}"
fi

# Auto-tag based on most senior version selected.
if [[ ${is_major} == true ]]; then
new_major_version=$(increment "${major_version}")
new_tag=v${new_major_version}.0.0${maturity}
echo "Tagging as new major version ${new_tag}..."
elif [[ ${is_minor} == true ]]; then
new_minor_version=$(increment "${minor_version}")
new_tag="v${major_version}.${new_minor_version}.0${maturity}"
echo "Tagging as new minor version ${new_tag}..."
else
new_patch_version=$(increment "${patch_version}")
new_tag=v${major_version}.${minor_version}.${new_patch_version}${maturity}
echo "Tagging as new patch ${new_tag}..."
fi

# If multiple have been checked or none have been checked, don't auto tag.
if { [[ ${is_minor} == false ]] && [[ ${is_patch} == false ]] && [[ ${is_major} == false ]]; }; then
echo "No tag information found in body of pull request #${pr_number}. Auto-tagging failed..."
exit 1
fi

echo "${new_tag}"
113 changes: 113 additions & 0 deletions .github/funcs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#
# This is the core functionality taken out so it can be tested
#
# Core funcs.
increment() {
echo $(($1 + 1))
}

clean_string() {
echo "${1}" | tr -d '\n' | tr -d ' '
}

get_major() {
echo "${1}" | cut -d'.' -f1
}

get_minor() {
echo "${1}" | cut -d'.' -f2
}

get_patch() {
if [[ ${1} == *"-"* ]]; then
echo "${1}" | cut -d'.' -f3 | cut -d'-' -f1
else
echo "${1}" | cut -d'.' -f3
fi
}

get_maturity() {
if [[ ${1} == *"-"* ]]; then
echo "${1}" | cut -d'.' -f3 | cut -d'-' -f2
else
echo ""
fi
}

# Docker funcs.
is_tagged_version() {
if [[ $1 =~ refs/tags/v(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*) ]]; then
return 0
else
return 1
fi
}

get_docker_tags() {
# Arguments:
# - Name reference for the array
# - Name of the docker image
# - The semver we are using to create the tags

local -n arr=$1 # use nameref to create values
name=$2
semver=$3

major=$(get_major "${semver}")
minor=$(get_minor "${semver}")
patch=$(get_patch "${semver}")
maturity=$(get_maturity "${semver}")

if [ -z ${maturity} ]; then
echo "Detected Version: ${major} . ${minor} . ${patch}"
full_tag="${name}:${major}.${minor}.${patch}"
minor_tag="${name}:${major}.${minor}"
major_tag="${name}:${major}"
else
echo "Detected Version: ${major} . ${minor} . ${patch} [${maturity}]"
full_tag="${name}:${major}.${minor}.${patch}-${maturity}"
minor_tag="${name}:${major}.${minor}-${maturity}"
major_tag="${name}:${major}-${maturity}"
fi
arr=($full_tag $minor_tag $major_tag)
}

# Auto-tag funcs.
is_valid_tag_name() {
if [[ $1 =~ v(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*) ]]; then
return 0
else
return 1
fi
}

is_selected() {
body=$1
phrase=$2
if [ $(echo "${body}" | grep -c "\[x\] ${phrase}") -gt 0 ]; then
echo true
else
echo false
fi
}

is_patch_selected() {
local phrase=Patch
is_selected "$1" "${phrase}"
}

is_minor_selected() {
local phrase="Minor version"
is_selected "$1" "${phrase}"
}

is_major_selected() {
local phrase="Major version"
is_selected "$1" "${phrase}"
}

get_latest_tag() {
git fetch --prune --unshallow --tags --force # This is needed - without it no tags are found.
latest_tag=$(git tag --list 'v*' --sort=-v:refname | head -n1)
echo "${latest_tag}"
}
50 changes: 50 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Description

Please include:

- a summary of the changes
- links to any related issue/ticket
- any additional relevant motivation and context
- details of any dependency updates that are required for this change

## Proposed version

Please select the option below that is most relevant from the list below. This
will be used to generate the next tag version name during auto-tagging.

- [ ] Patch
- [ ] Minor version
- [ ] Major version

Visit the [Semver website](https://semver.org/#summary) to understand the
difference between `MAJOR`, `MINOR`, and `PATCH` versions.

Notes:

- If none of these options are selected, auto-tagging will fail
- Where multiple options are selected, the most senior option ticked will be
used -- e.g. Major > Minor > Patch
- If you are selecting the version in the list above using the textbox, make
sure your selected option is marked `[x]` with no spaces in between the
brackets and the `x`

## Type of change

Please select the option(s) below that are most relevant:

- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change

## How Has This Been Tested?

Please describe the tests that you added to verify your changes.

## Reviewer Checklist

- [ ] The PR represents a single feature (small drive-by fixes are also ok)
- [ ] The PR includes tests that are sufficient for the level of risk
- [ ] The code is sufficiently commented, particularly in hard-to-understand areas
- [ ] Any required documentation updates have been made
- [ ] Any TODOs added are captured in future tickets
- [ ] No FIXMEs remain
110 changes: 110 additions & 0 deletions .github/retag-and-push.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#!/bin/bash
set -e

script_folder=$(dirname "${BASH_SOURCE[0]}")
source $script_folder/funcs.sh

if [ "$#" -ne 2 ]; then
echo "Pushes a container image to ECR with tags"
echo
echo "Usage: $0 project input_tag"
echo "Example: $0 container-name 6cd9d7ebad4f16ef7273a7a831d79d5d5caf4164"
echo "Relies on the following environment variables:"
echo "- GITHUB_HEAD_REF, GITHUB_REF, GITHUB_SHA (GH Action default)"
echo "- DOCKER_REGISTRY"
exit 1
fi

[ "${DOCKER_REGISTRY}" == "" ] && (echo "DOCKER_REGISTRY is not set" ; exit 1)

project="$1"
image_tag="$2"

docker_tag() {
echo "Re-tagging $1 -> $2"
docker tag $1 $2
}

process_tagged_version() {
local tag_array
semver=$1
get_docker_tags tag_array ${name} ${semver}

for tag in "${tag_array[@]}" ; do
docker_tag "${input_image}" ${tag}
docker push "${tag}"
done
}

name=$(clean_string "${DOCKER_REGISTRY}/${project}")
input_image="${project}:${image_tag}"

if [[ -n "${NEW_TAG}" ]]; then
if is_valid_tag_name ${NEW_TAG} ; then
# push `semver` tagged image
semver="${NEW_TAG/v/}"
echo "Detected Tag: ${semver}"
process_tagged_version ${semver}
exit 0
else
echo "New tag ${NEW_TAG} is not a valid tag name"
exit 1
fi
fi

# login
# This should now be performed as a GA
# See: https://docs.docker.com/build/ci/github-actions/#step-three-define-the-workflow-steps

echo "-------------"
echo "Input : ${project}:${image_tag}"
echo "Output : ${name}"
echo "GitRef : ${GITHUB_REF}"
echo "GitHeadRef : ${GITHUB_HEAD_REF}"
echo "Branch : ${GITHUB_REF/refs\/heads\//}"
echo "Repo Tag : ${name}"
echo "-------------"

timestamp=$(date --utc -Iseconds | cut -c1-19 | tr -c '[0-9]T\n' '-')
short_sha=${GITHUB_SHA:0:8}

if [[ "${GITHUB_REF}" == "refs/heads"* ]]; then
# push `branch-sha` tagged image

# NOTE: Looks like the behaviour has changed for GITHHUB_REF
# See: https://github.com/semantic-release/env-ci/issues/157
# ... branches will no longer be handled here but in the 'else' statement below.

branch="${GITHUB_REF/refs\/heads\//}"
echo "Detected Branch: ${branch}"

# Only update latest if on main
if [[ "${branch}" = "main" ]]; then
# push `latest` tag
docker_tag "${input_image}" "${name}:latest"
docker push "${name}:latest"
# Also tag for any versioning that might get done
docker_tag "${input_image}" "${name}:${branch}-${timestamp}-${short_sha}"
docker push "${name}:${branch}-${timestamp}-${short_sha}"
# Also tag for any versioning that might get done
docker_tag "${input_image}" "${name}:${branch}-${short_sha}"
docker push "${name}:${branch}-${short_sha}"
fi

elif is_tagged_version ${GITHUB_REF} ; then
# push `semver` tagged image
semver="${GITHUB_REF/refs\/tags\/v/}"
echo "Detected Tag: ${semver}"
process_tagged_version ${semver}

else
echo "${GITHUB_REF} is neither a branch head nor valid semver tag"
echo "Assuming '${GITHUB_HEAD_REF}' is a branch"
if [[ -n "${GITHUB_HEAD_REF}" ]]; then
branch="$(echo ${GITHUB_HEAD_REF}| tr -c '[0-9,A-Z,a-z]' '-')"
docker_tag "${input_image}" "${name}:${branch}-${timestamp}-${short_sha}"
docker push "${name}:${branch}-${timestamp}-${short_sha}"
else
echo "No branch found, not a PR so not publishing."
fi
fi
Loading

0 comments on commit cb96fc4

Please sign in to comment.