Skip to content

ci: Revert to local tag creation and push for releases #5714

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

Merged
merged 9 commits into from
Jan 13, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
ci: Revert to local tag creation and push for releases
  • Loading branch information
mafredri committed Jan 13, 2023
commit a3e00d5ef9c8b9bde656b823fdf4c4fe931afd61
78 changes: 22 additions & 56 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# GitHub release workflow.
name: Release
run-name: Release ${{ github.ref_name }}${{ inputs.dry_run && ' (DRYRUN)' || '' }}
on:
push:
tags:
- "v*"
workflow_dispatch:
inputs:
increment:
Expand All @@ -13,20 +15,11 @@ on:
- patch
- minor
- major
draft:
description: Create a draft release (for manually editing release notes before publishing).
type: boolean
required: true
default: false
dry_run:
description: Perform a dry-run release.
type: boolean
required: true
default: false
ignore_missing_commit_metadata:
description: WARNING! This option disables the requirement that all commits have a PR. Not needed for dry_run.
type: boolean
default: false

permissions:
# Required to publish a release
Expand Down Expand Up @@ -55,17 +48,9 @@ jobs:
# Necessary for Docker manifest
DOCKER_CLI_EXPERIMENTAL: "enabled"
steps:
- name: Check release on main (or dry-run)
if: ${{ github.ref_name != 'main' && !inputs.dry_run }}
run: |
echo "Release not allowed on ${{ github.ref_name }}, use dry-run."
exit 1

- uses: actions/checkout@v3
with:
fetch-depth: 0
# Set token for pushing protected tag (vX.X.X).
token: ${{ secrets.RELEASE_GITHUB_PAT }}

# If the event that triggered the build was an annotated tag (which our
# tags are supposed to be), actions/checkout has a bug where the tag in
Expand All @@ -75,55 +60,39 @@ jobs:
- name: Fetch git tags
run: git fetch --tags --force

# Configure git user name/email for creating annotated version tag.
- name: Setup git config
run: |
git config user.name "Coder CI"
git config user.email "dean+cdrci@coder.com"

- name: Create release tag and release notes
- name: Create release notes
if: ${{ inputs.dry_run }}
env:
# We always have to set this since there might be commits on
# main that didn't have a PR.
CODER_IGNORE_MISSING_COMMIT_METADATA: "1"
run: |
set -euo pipefail
ref=HEAD
old_version="$(git describe --abbrev=0 "$ref^1")"

if [[ "${{ inputs.ignore_missing_commit_metadata }}" == *t* ]]; then
export CODER_IGNORE_MISSING_COMMIT_METADATA=1
fi

# Warn if CODER_IGNORE_MISSING_COMMIT_METADATA is set any other way
# than via dry-run.
if [[ ${CODER_IGNORE_MISSING_COMMIT_METADATA:-0} != 0 ]]; then
echo "WARNING: CODER_IGNORE_MISSING_COMMIT_METADATA is enabled and we will ignore missing commit metadata." 1>&2
fi

version_args=()
if [[ $CODER_DRY_RUN == *t* ]]; then
# Allow dry-run of branches to pass.
export CODER_IGNORE_MISSING_COMMIT_METADATA=1
version_args+=(--dry-run)
fi

# Cache commit metadata.
. ./scripts/release/check_commit_metadata.sh "$old_version" "$ref"

declare -p version_args

# Create new release tag (note that this tag is not pushed before
# release.sh is run).
version="$(
./scripts/release/tag_version.sh \
"${version_args[@]}" \
--ref "$ref" \
--"$CODER_RELEASE_INCREMENT"
)"
if [[ $CODER_DRY_RUN != *t* ]]; then
# This will fail if we're doing a non-dry-run without tag
# being present.
version="$(./scripts/version.sh)"
else
# Create a tag for this dry-run (local only, can't be uploaded).
version="$(
./scripts/release/tag_version.sh \
--ref "$ref" \
--"$CODER_RELEASE_INCREMENT"
)"
fi

# Generate notes.
release_notes_file="$(mktemp -t release_notes.XXXXXX)"
./scripts/release/generate_release_notes.sh --old-version "$old_version" --new-version "$version" --ref "$ref" >> "$release_notes_file"
echo CODER_RELEASE_NOTES_FILE="$release_notes_file" >> $GITHUB_ENV

- name: Echo release notes
- name: Show release notes
run: |
set -euo pipefail
cat "$CODER_RELEASE_NOTES_FILE"
Expand Down Expand Up @@ -243,9 +212,6 @@ jobs:
set -euo pipefail

publish_args=()
if [[ $CODER_RELEASE_DRAFT == *t* ]]; then
publish_args+=(--draft)
fi
if [[ $CODER_DRY_RUN == *t* ]]; then
publish_args+=(--dry-run)
fi
Expand Down
84 changes: 21 additions & 63 deletions scripts/release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ cdroot

usage() {
cat <<EOH
Usage: ./release.sh [--branch <name>] [--draft] [--dry-run] [--ref <ref>] [--major | --minor | --patch]
Usage: ./release.sh [--dry-run] [--ref <ref>] [--major | --minor | --patch]

This script should be called to create a new release.

Expand All @@ -23,47 +23,24 @@ be tagged at, otherwise the latest commit will be used.
Set --minor to force a minor version bump, even when there are no breaking
changes. Likewise for --major. By default a patch version will be created.

Set --dry-run to run the release workflow in CI as a dry-run (no release will
be created).
Set --dry-run to see what this script would do without making actual changes.

To mark a release as containing breaking changes, the commit title should
either contain a known prefix with an exclamation mark ("feat!:",
"feat(api)!:") or the PR that was merged can be tagged with the
"release/breaking" label.

To test changes to this script, you can set --branch <my-branch>, which will
run the release workflow in CI as a dry-run and use the latest commit on the
specified branch as the release commit. This will also set --dry-run.
EOH
}

# Warn if CODER_IGNORE_MISSING_COMMIT_METADATA is set any other way than via
# --branch.
if [[ ${CODER_IGNORE_MISSING_COMMIT_METADATA:-0} != 0 ]]; then
log "WARNING: CODER_IGNORE_MISSING_COMMIT_METADATA is enabled externally, we will ignore missing commit metadata."
fi

branch=main
draft=0
dry_run=0
ref=
increment=

args="$(getopt -o h -l branch:,draft,dry-run,help,ref:,major,minor,patch -- "$@")"
args="$(getopt -o h -l dry-run,help,ref:,major,minor,patch -- "$@")"
eval set -- "$args"
while true; do
case "$1" in
--branch)
branch="$2"
log "Using branch $branch, implies DRYRUN and CODER_IGNORE_MISSING_COMMIT_METADATA."
dry_run=1
export CODER_IGNORE_MISSING_COMMIT_METADATA=1
shift 2
;;
--draft)
draft=1
shift
;;
--dry-run)
dry_run=1
shift
Expand Down Expand Up @@ -109,70 +86,51 @@ git fetch --quiet --tags origin "$branch"
ref=$(git rev-parse --short "${ref:-origin/$branch}")

# Make sure that we're running the latest release script.
if [[ -n $(git diff --name-status origin/"$branch" -- ./scripts/release.sh) ]]; then
error "Release script is out-of-date. Please check out the latest version and try again."
fi
# if [[ -n $(git diff --name-status origin/"$branch" -- ./scripts/release.sh) ]]; then
# error "Release script is out-of-date. Please check out the latest version and try again."
# fi

# Check the current version tag from GitHub (by number) using the API to
# ensure no local tags are considered.
log "Checking GitHub for latest release..."
mapfile -t versions < <(gh api -H "Accept: application/vnd.github+json" /repos/coder/coder/git/refs/tags -q '.[].ref | split("/") | .[2]' | grep '^v' | sort -r -V)
old_version=${versions[0]}
log "Latest release: $old_version"
log

trap 'log "Check commit metadata failed, you can try to set \"export CODER_IGNORE_MISSING_COMMIT_METADATA=1\" and try again, if you know what you are doing."' EXIT
# shellcheck source=scripts/release/check_commit_metadata.sh
source "$SCRIPT_DIR/release/check_commit_metadata.sh" "$old_version" "$ref"
trap - EXIT

new_version="$(execrelative ./release/tag_version.sh --dry-run --ref "$ref" --"$increment")"
log "Executing DRYRUN of release tagging..."
new_version="$(execrelative ./release/tag_version.sh --old-version "$old_version" --ref "$ref" --"$increment" --dry-run)"
log
read -p "Continue? (y/n) " -n 1 -r show_reply

release_notes="$(execrelative ./release/generate_release_notes.sh --old-version "$old_version" --new-version "$new_version" --ref "$ref")"

log
read -p "Preview release notes? (y/n) " -n 1 -r show_reply
log
if [[ $show_reply =~ ^[Yy]$ ]]; then
log
echo -e "$release_notes\n"
fi

create_message="Create release"
if ((draft)); then
create_message="Create draft release"
fi
if ((dry_run)); then
create_message+=" (DRYRUN)"
fi
read -p "$create_message? (y/n) " -n 1 -r create
read -p "Create release? (y/n) " -n 1 -r create
log
if ! [[ $create =~ ^[Yy]$ ]]; then
exit 0
fi

args=()

# Draft and dry-run are required args.
if ((draft)); then
args+=(-F draft=true)
else
args+=(-F draft=false)
fi
if ((dry_run)); then
args+=(-F dry_run=true)
else
args+=(-F dry_run=false)

# We only set this on non-dry-run releases because it will show a
# warning in CI.
if [[ ${CODER_IGNORE_MISSING_COMMIT_METADATA:-0} == 1 ]]; then
args+=(-F ignore_missing_commit_metadata=true)
fi
fi

log
logrun gh workflow run release.yaml \
--ref "$branch" \
-F increment="$increment" \
"${args[@]}"
log
# Run without dry-run to actually create the tag, note we don't update the
# new_version variable here to ensure we're pushing what we showed before.
maybedryrun "$dry_run" execrelative ./release/tag_version.sh --old-version "$old_version" --ref "$ref" --"$increment" >/dev/null
maybedryrun "$dry_run" git push --tags -u origin "$new_version"

log
read -p "Watch release? (y/n) " -n 1 -r watch
log
if ! [[ $watch =~ ^[Yy]$ ]]; then
Expand Down
8 changes: 5 additions & 3 deletions scripts/release/check_commit_metadata.sh
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,12 @@ main() {
commit_sha_long=${parts[1]}
commit_prefix=${parts[2]}

if [[ $ignore_missing_metadata != 1 ]]; then
# Safety-check, guarantee all commits had their metadata fetched.
if [[ ! -v labels[$commit_sha_long] ]]; then
# Safety-check, guarantee all commits had their metadata fetched.
if [[ ! -v labels[$commit_sha_long] ]]; then
if [[ $ignore_missing_metadata != 1 ]]; then
error "Metadata missing for commit $commit_sha_short"
else
log "WARING: Metadata missing for commit $commit_sha_short"
fi
fi

Expand Down
9 changes: 0 additions & 9 deletions scripts/release/publish.sh
Original file line number Diff line number Diff line change
Expand Up @@ -134,20 +134,11 @@ 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"/*

Expand Down
32 changes: 16 additions & 16 deletions scripts/release/tag_version.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,38 @@ cdroot

usage() {
cat <<EOH
Usage: ./version_tag.sh [--dry-run] [--ref <ref>] <--major | --minor | --patch>
Usage: ./version_tag.sh [--dry-run] [--old-version <version>] [--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).
Pass --old-version optionally to ensure that the version is bumped from the
provided version instead of the latest tag (for use in release.sh).

This script will create a git tag, it should only be called by release.sh or in
CI.
EOH
}

dry_run=0
old_version=
ref=HEAD
increment=

args="$(getopt -o h -l dry-run,help,ref:,major,minor,patch -- "$@")"
args="$(getopt -o h -l dry-run,help,old-version:,ref:,major,minor,patch -- "$@")"
eval set -- "$args"
while true; do
case "$1" in
--dry-run)
dry_run=1
shift
;;
--old-version)
old_version="$2"
shift 2
;;
--ref)
ref="$2"
shift 2
Expand Down Expand Up @@ -63,20 +71,12 @@ 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."
if [[ -z $old_version ]]; then
old_version="$(git describe --abbrev=0 "$ref^1" --always)"
fi

old_version="$(git describe --abbrev=0 "$ref^1")"
cur_tag="$(git describe --abbrev=0 "$ref")"
cur_tag="$(git describe --abbrev=0 "$ref" --always)"
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
error "A newer tag than \"$old_version\" already exists for \"$ref\" ($cur_tag), aborting."
fi
ref=$(git rev-parse --short "$ref")

Expand Down