105 lines
4.2 KiB
Bash
Executable File
105 lines
4.2 KiB
Bash
Executable File
#!/bin/sh
|
|
set -eu
|
|
|
|
script_dir=$(CDPATH= cd "$(dirname "$0")" && pwd -P)
|
|
# shellcheck source=release-lib.sh
|
|
. "$script_dir/release-lib.sh"
|
|
|
|
tool_name=release
|
|
|
|
if [ "$#" -ne 1 ]; then
|
|
narratio_release_fail "$tool_name" 'usage: scripts/release.sh VERSION'
|
|
fi
|
|
|
|
release_version=$1
|
|
if ! narratio_release_validate_version "$release_version"; then
|
|
narratio_release_fail "$tool_name" "invalid stable version: $release_version"
|
|
fi
|
|
|
|
repo_root=$(narratio_release_repo_root "$0") || narratio_release_fail "$tool_name" 'cannot locate repository root'
|
|
if ! cd "$repo_root"; then
|
|
narratio_release_fail "$tool_name" "cannot enter repository root: $repo_root"
|
|
fi
|
|
|
|
narratio_release_require_main_branch() {
|
|
current_branch=$(git branch --show-current) || narratio_release_fail "$tool_name" 'cannot determine current branch'
|
|
if [ "$current_branch" != main ]; then
|
|
narratio_release_fail "$tool_name" 'release checkout must be on main'
|
|
fi
|
|
}
|
|
|
|
narratio_release_require_clean_checkout() {
|
|
if [ -n "$(git status --porcelain)" ]; then
|
|
narratio_release_fail "$tool_name" 'release checkout must be clean'
|
|
fi
|
|
}
|
|
|
|
narratio_release_fetch_origin() {
|
|
if ! git fetch origin main --tags; then
|
|
narratio_release_fail "$tool_name" 'failed to fetch origin main and tags'
|
|
fi
|
|
}
|
|
|
|
narratio_release_require_no_local_tag() {
|
|
if git show-ref --verify --quiet "refs/tags/$release_version"; then
|
|
narratio_release_fail "$tool_name" "local tag already exists: $release_version"
|
|
fi
|
|
}
|
|
|
|
narratio_release_require_no_remote_tag() {
|
|
if ! remote_tag=$(git ls-remote --tags origin "refs/tags/$release_version"); then
|
|
narratio_release_fail "$tool_name" "cannot inspect tag at origin: $release_version"
|
|
fi
|
|
if [ -n "$remote_tag" ]; then
|
|
narratio_release_fail "$tool_name" "upstream tag already exists: $release_version"
|
|
fi
|
|
}
|
|
|
|
narratio_release_require_main_branch
|
|
narratio_release_require_clean_checkout
|
|
narratio_release_fetch_origin
|
|
|
|
candidate_commit=$(git rev-parse --verify 'HEAD^{commit}') || narratio_release_fail "$tool_name" 'cannot resolve HEAD commit'
|
|
upstream_commit=$(git rev-parse --verify 'origin/main^{commit}') || narratio_release_fail "$tool_name" 'cannot resolve origin/main commit'
|
|
if [ "$candidate_commit" != "$upstream_commit" ]; then
|
|
narratio_release_fail "$tool_name" 'HEAD must equal origin/main before release validation'
|
|
fi
|
|
release_note="docs/releases/$release_version.md"
|
|
if ! git cat-file -e "$candidate_commit:$release_note"; then
|
|
narratio_release_fail "$tool_name" "candidate commit is missing release note: $release_note"
|
|
fi
|
|
narratio_release_require_no_local_tag
|
|
narratio_release_require_no_remote_tag
|
|
|
|
if ! "$script_dir/check-release-candidate.sh" "$release_version"; then
|
|
narratio_release_fail "$tool_name" 'release candidate validation failed'
|
|
fi
|
|
|
|
narratio_release_fetch_origin
|
|
narratio_release_require_main_branch
|
|
narratio_release_require_clean_checkout
|
|
current_commit=$(git rev-parse --verify 'HEAD^{commit}') || narratio_release_fail "$tool_name" 'cannot resolve HEAD commit after validation'
|
|
current_upstream_commit=$(git rev-parse --verify 'origin/main^{commit}') || narratio_release_fail "$tool_name" 'cannot resolve origin/main commit after validation'
|
|
if [ "$current_commit" != "$candidate_commit" ] || [ "$current_upstream_commit" != "$candidate_commit" ]; then
|
|
narratio_release_fail "$tool_name" 'candidate or origin/main changed during release validation'
|
|
fi
|
|
narratio_release_require_no_local_tag
|
|
narratio_release_require_no_remote_tag
|
|
|
|
if ! git -c tag.gpgSign=false tag "$release_version" "$candidate_commit"; then
|
|
narratio_release_fail "$tool_name" "cannot create local tag: $release_version"
|
|
fi
|
|
if [ "$(git cat-file -t "refs/tags/$release_version")" != commit ]; then
|
|
narratio_release_fail "$tool_name" "local tag is not lightweight: $release_version"
|
|
fi
|
|
if [ "$(git rev-parse --verify "refs/tags/$release_version^{commit}")" != "$candidate_commit" ]; then
|
|
narratio_release_fail "$tool_name" "local tag does not resolve to candidate commit: $release_version"
|
|
fi
|
|
|
|
if ! git push origin "refs/tags/$release_version:refs/tags/$release_version"; then
|
|
printf 'release: local tag %s was created but not published; inspect it before retrying\n' "$release_version" >&2
|
|
exit 1
|
|
fi
|
|
printf 'release: published %s at %s\n' "$release_version" "$candidate_commit"
|
|
exit 0
|