ci: Do release tagging in CI and add --draft support (#5652)

* ci: Do release tagging in CI and add --draft support

* Add -h, --help to release.sh

* Add -h, --help to increment_version_tag.sh

* Limit release concurrency

* Add automatic release watching

* ci: Add git config, tag as "GitHub Actions Bot"

Co-authored-by: Dean Sheather <dean@deansheather.com>
This commit is contained in:
Mathias Fredriksson
2023-01-11 18:38:01 +02:00
committed by GitHub
co-authored by Dean Sheather
parent e72a2ad907
commit 8e4af79cb2
6 changed files with 359 additions and 92 deletions
+14 -5
View File
@@ -34,6 +34,10 @@ dependencies gh
COMMIT_METADATA_BREAKING=0
declare -A COMMIT_METADATA_TITLE COMMIT_METADATA_CATEGORY
# This environment variable can be set to 1 to ignore missing commit metadata,
# useful for dry-runs.
ignore_missing_metadata=${CODER_IGNORE_MISSING_COMMIT_METADATA:-0}
main() {
# Match a commit prefix pattern, e.g. feat: or feat(site):.
prefix_pattern="^([a-z]+)(\([a-z]*\))?:"
@@ -87,9 +91,11 @@ main() {
commit_sha_long=${parts[1]}
commit_prefix=${parts[2]}
# Safety-check, guarantee all commits had their metadata fetched.
if [[ ! -v labels[$commit_sha_long] ]]; then
error "Metadata missing for commit $commit_sha_short"
if [[ $ignore_missing_metadata != 1 ]]; then
# Safety-check, guarantee all commits had their metadata fetched.
if [[ ! -v labels[$commit_sha_long] ]]; then
error "Metadata missing for commit $commit_sha_short"
fi
fi
# Store the commit title for later use.
@@ -99,11 +105,11 @@ main() {
# First, check the title for breaking changes. This avoids doing a
# GH API request if there's a match.
if [[ $commit_prefix =~ $breaking_title ]] || [[ ${labels[$commit_sha_long]} = *"label:$breaking_label"* ]]; then
if [[ $commit_prefix =~ $breaking_title ]] || [[ ${labels[$commit_sha_long]:-} = *"label:$breaking_label"* ]]; then
COMMIT_METADATA_CATEGORY[$commit_sha_short]=$breaking_category
COMMIT_METADATA_BREAKING=1
continue
elif [[ ${labels[$commit_sha_long]} = *"label:$security_label"* ]]; then
elif [[ ${labels[$commit_sha_long]:-} = *"label:$security_label"* ]]; then
COMMIT_METADATA_CATEGORY[$commit_sha_short]=$security_label
continue
fi
@@ -137,6 +143,9 @@ export_commit_metadata() {
if [[ ${_COMMIT_METADATA_CACHE:-} == "${range}:"* ]]; then
eval "${_COMMIT_METADATA_CACHE#*:}"
else
if [[ $ignore_missing_metadata == 1 ]]; then
log "WARNING: Ignoring missing commit metadata, breaking changes may be missed."
fi
main
fi
+3 -3
View File
@@ -59,10 +59,10 @@ if [[ -z $ref ]]; then
fi
# shellcheck source=scripts/release/check_commit_metadata.sh
source "$SCRIPT_DIR/release/check_commit_metadata.sh" "${old_version}" "${ref}"
source "$SCRIPT_DIR/release/check_commit_metadata.sh" "$old_version" "$ref"
# Sort commits by title prefix, then by date, only return sha at the end.
mapfile -t commits < <(git log --no-merges --pretty=format:"%ct %h %s" "${old_version}..${ref}" | sort -k3,3 -k1,1n | cut -d' ' -f2)
mapfile -t commits < <(git log --no-merges --pretty=format:"%ct %h %s" "$old_version..$ref" | sort -k3,3 -k1,1n | cut -d' ' -f2)
# From: https://github.com/commitizen/conventional-commit-types
# NOTE(mafredri): These need to be supported in check_commit_metadata.sh as well.
@@ -140,7 +140,7 @@ image_tag="$(execrelative ./image_tag.sh --version "$new_version")"
echo -e "## Changelog
$changelog
Compare: [\`${old_version}...${new_version}\`](https://github.com/coder/coder/compare/${old_version}...${new_version})
Compare: [\`$old_version...$new_version\`](https://github.com/coder/coder/compare/$old_version...$new_version)
## Container image
+26 -22
View File
@@ -34,9 +34,11 @@ if [[ "${CI:-}" == "" ]]; then
fi
version=""
release_notes_file=""
draft=0
dry_run=0
args="$(getopt -o "" -l version:,dry-run -- "$@")"
args="$(getopt -o "" -l version:,release-notes-file:,draft,dry-run -- "$@")"
eval set -- "$args"
while true; do
case "$1" in
@@ -44,6 +46,14 @@ while true; do
version="$2"
shift 2
;;
--release-notes-file)
release_notes_file="$2"
shift 2
;;
--draft)
draft=1
shift
;;
--dry-run)
dry_run=1
shift
@@ -67,6 +77,10 @@ if [[ "$version" == "" ]]; then
version="$(execrelative ./version.sh)"
fi
if [[ -z $release_notes_file ]]; then
error "No release notes files specified, use --release-notes-file."
fi
# realpath-ify all input files so we can cdroot below.
files=()
for f in "$@"; do
@@ -96,25 +110,6 @@ if [[ "$(git describe --always)" != "$new_tag" ]]; then
log "The provided version does not match the current git tag, but --dry-run was supplied so continuing..."
fi
# This returns the tag before the current tag.
old_tag="$(git describe --abbrev=0 HEAD^1)"
# For dry-run builds we want to use the SHA instead of the tag, because the new
# tag probably doesn't exist.
new_ref="$new_tag"
if [[ "$dry_run" == 1 ]]; then
new_ref="$(git rev-parse --short HEAD)"
fi
# shellcheck source=scripts/release/check_commit_metadata.sh
source "$SCRIPT_DIR/release/check_commit_metadata.sh" "$old_tag" "$new_ref"
# Craft the release notes.
release_notes="$(execrelative ./release/generate_release_notes.sh --old-version "$old_tag" --new-version "$new_tag" --ref "$new_ref")"
release_notes_file="$(mktemp)"
echo "$release_notes" >"$release_notes_file"
# Create temporary release folder so we can generate checksums. Both the
# sha256sum and gh binaries support symlinks as input files so this works well.
temp_dir="$(mktemp -d)"
@@ -127,10 +122,10 @@ pushd "$temp_dir"
sha256sum ./* | sed -e 's/\.\///' - >"coder_${version}_checksums.txt"
popd
log "--- Creating release $new_tag"
log "--- Publishing release $new_tag on GitHub"
log
log "Description:"
echo "$release_notes" | sed -e 's/^/\t/' - 1>&2
sed -e 's/^/\t/' - <"$release_notes_file" 1>&2
log
log "Contents:"
pushd "$temp_dir"
@@ -139,11 +134,20 @@ popd
log
log
log "Pushing git tag"
maybedryrun "$dry_run" git push --quiet origin "$new_tag"
args=()
if ((draft)); then
args+=(--draft)
fi
# We pipe `true` into `gh` so that it never tries to be interactive.
true |
maybedryrun "$dry_run" gh release create \
--title "$new_tag" \
--notes-file "$release_notes_file" \
"${args[@]}" \
"$new_tag" \
"$temp_dir"/*
+126
View File
@@ -0,0 +1,126 @@
#!/usr/bin/env bash
set -euo pipefail
# shellcheck source=scripts/lib.sh
source "$(dirname "$(dirname "${BASH_SOURCE[0]}")")/lib.sh"
cdroot
usage() {
cat <<EOH
Usage: ./version_tag.sh [--dry-run] [--ref <ref>] <--major | --minor | --patch>
This script should be called to tag a new release. It will take the suggested
increment (major, minor, patch) and optionally promote e.g. patch -> minor if
there are breaking changes between the previous version and the given --ref
(or HEAD).
This script will create a git tag, so it should only be run in CI (or via
--dry-run).
EOH
}
dry_run=0
ref=HEAD
increment=
args="$(getopt -o h -l dry-run,help,ref:,major,minor,patch -- "$@")"
eval set -- "$args"
while true; do
case "$1" in
--dry-run)
dry_run=1
shift
;;
--ref)
ref="$2"
shift 2
;;
-h | --help)
usage
exit 0
;;
--major | --minor | --patch)
if [[ -n $increment ]]; then
error "Cannot specify multiple version increments."
fi
increment=${1#--}
shift
;;
--)
shift
break
;;
*)
error "Unrecognized option: $1"
;;
esac
done
# Check dependencies.
dependencies git
if [[ -z $increment ]]; then
error "No version increment provided."
fi
if [[ $dry_run != 1 ]] && [[ ${CI:-} == "" ]]; then
error "This script must be run in CI or with --dry-run."
fi
old_version="$(git describe --abbrev=0 "$ref^1")"
cur_tag="$(git describe --abbrev=0 "$ref")"
if [[ $old_version != "$cur_tag" ]]; then
message="Ref \"$ref\" is already tagged with a release ($cur_tag)"
if ! ((dry_run)); then
error "$message."
fi
log "DRYRUN: $message, echoing current tag."
echo "$cur_tag"
exit 0
fi
ref=$(git rev-parse --short "$ref")
log "Checking commit metadata for changes since $old_version..."
# shellcheck source=scripts/release/check_commit_metadata.sh
source "$SCRIPT_DIR/release/check_commit_metadata.sh" "$old_version" "$ref"
if ((COMMIT_METADATA_BREAKING == 1)); then
prev_increment=$increment
if [[ $increment == patch ]]; then
increment=minor
fi
if [[ $prev_increment != "$increment" ]]; then
log "Breaking change detected, changing version increment from \"$prev_increment\" to \"$increment\"."
else
log "Breaking change detected, provided increment is sufficient, using \"$increment\" increment."
fi
else
log "No breaking changes detected, using \"$increment\" increment."
fi
mapfile -d . -t version_parts <<<"${old_version#v}"
case "$increment" in
patch)
version_parts[2]=$((version_parts[2] + 1))
;;
minor)
version_parts[1]=$((version_parts[1] + 1))
version_parts[2]=0
;;
major)
version_parts[0]=$((version_parts[0] + 1))
version_parts[1]=0
version_parts[2]=0
;;
*)
error "Unrecognized version increment."
;;
esac
new_version="v${version_parts[0]}.${version_parts[1]}.${version_parts[2]}"
log "Old version: $old_version"
log "New version: $new_version"
maybedryrun "$dry_run" git tag -a "$new_version" -m "Release $new_version" "$ref"
echo "$new_version"