set -euo pipefail
source "$(dirname "$0")/lib.sh"
source "${CI_REPO_ROOT}/scripts/version.sh"
DRY_RUN=false
VERSION=""
while [ $# -gt 0 ]; do
case "$1" in
--dry-run)
DRY_RUN=true
info "Running in dry-run mode"
shift
;;
*)
VERSION="$1"
shift
;;
esac
done
if [ -z "$VERSION" ]; then
err "VERSION argument is required (e.g., ./publish-release.sh 2.0.0)"
fi
if ! validate_semver "$VERSION"; then
err "Invalid version format: $VERSION (expected X.Y.Z)"
fi
info "Publishing release for version: $VERSION"
info "Validating environment"
assert_cmd git
assert_cmd gh
assert_cmd cargo
assert_cmd curl
if is_version_tagged "$VERSION"; then
warn "Version $VERSION is already tagged"
if [ "$DRY_RUN" = false ]; then
err "Cannot publish already-tagged version"
fi
fi
if [ "$DRY_RUN" = false ]; then
if [ -z "${CARGO_REGISTRY_TOKEN-}" ]; then
warn "CARGO_REGISTRY_TOKEN not set, crates.io publish will fail"
fi
if ! gh auth status >/dev/null 2>&1; then
err "gh CLI not authenticated (set GITHUB_TOKEN or run 'gh auth login')"
fi
fi
info "Extracting changelog for v$VERSION"
TAG_NAME=$(format_tag_name "$VERSION")
CHANGELOG_SECTION=$(sed -n "/^## \[${TAG_NAME}\]/,/^## \[${TAG_PREFIX}/p" CHANGELOG.md | sed '$d')
if [ -z "$CHANGELOG_SECTION" ]; then
CHANGELOG_SECTION=$(sed -n "/^## \[${TAG_NAME}\]/,\$p" CHANGELOG.md)
fi
CHANGELOG_SECTION=$(echo "$CHANGELOG_SECTION" | sed '1d')
if [ -z "$CHANGELOG_SECTION" ]; then
warn "Could not extract changelog for v$VERSION from CHANGELOG.md"
CHANGELOG_SECTION="Release v$VERSION"
fi
debug "Changelog excerpt:\n$CHANGELOG_SECTION"
configure_git_auth
TAG_NAME=$(format_tag_name "$VERSION")
info "Creating git tag: $TAG_NAME"
if [ "$DRY_RUN" = false ]; then
if git config user.signingkey >/dev/null 2>&1; then
echo "$CHANGELOG_SECTION" | ensure git tag -a "$TAG_NAME" -F - -s
info "Created signed tag: $TAG_NAME"
else
echo "$CHANGELOG_SECTION" | ensure git tag -a "$TAG_NAME" -F -
info "Created tag: $TAG_NAME"
fi
ensure git push origin "refs/tags/$TAG_NAME"
info "Pushed tag to origin"
else
info "Would create tag: $TAG_NAME"
info "Would push tag to origin"
fi
info "Creating GitHub Release"
if [ "$DRY_RUN" = false ]; then
NOTES_FILE=$(mktemp)
echo "$CHANGELOG_SECTION" >"$NOTES_FILE"
ensure gh release create "$TAG_NAME" \
--title "Release v$VERSION" \
--notes-file "$NOTES_FILE" \
--latest
rm -f "$NOTES_FILE"
RELEASE_URL=$(gh release view "$TAG_NAME" --json url -q .url)
info "GitHub Release created: $RELEASE_URL"
else
info "Would create GitHub Release for tag: $TAG_NAME"
fi
info "Publishing to crates.io"
if [ "$DRY_RUN" = false ]; then
if [ -n "${CARGO_REGISTRY_TOKEN-}" ]; then
ensure cargo publish --token "${CARGO_REGISTRY_TOKEN}"
else
ensure cargo publish
fi
else
info "Would publish to crates.io"
fi
info "Release v$VERSION published successfully"
if [ "$DRY_RUN" = false ]; then
info "Tag: $(format_tag_name "$VERSION")"
if [ -n "${RELEASE_URL-}" ]; then
info "Release: $RELEASE_URL"
fi
info "Crate: https://crates.io/crates/amber-api"
fi