set -euo pipefail
source "$(dirname "$0")/lib.sh"
source "${CI_REPO_ROOT}/scripts/version.sh"
DRY_RUN=false
OVERRIDE_VERSION=""
while [ $# -gt 0 ]; do
case "$1" in
--dry-run)
DRY_RUN=true
info "Running in dry-run mode"
shift
;;
*)
OVERRIDE_VERSION="$1"
shift
;;
esac
done
info "Validating environment"
assert_cmd git-cliff
assert_cmd cargo
assert_cmd git
assert_cmd sed
if [ -n "$(git status --porcelain)" ]; then
warn "Working directory has uncommitted changes"
if [ "$DRY_RUN" = false ]; then
err "Cannot prepare release with uncommitted changes"
fi
fi
HEAD_COMMIT_MSG=$(git log -1 --pretty=format:"%s" HEAD)
if [[ $HEAD_COMMIT_MSG =~ ^chore\(release\): ]]; then
info "HEAD commit is a release commit: $HEAD_COMMIT_MSG"
ci_append_output "skip=true" "reason=HEAD is already a release commit"
exit 0
fi
CURRENT_VERSION=$(get_current_version)
info "Current version: $CURRENT_VERSION"
if [ -n "$OVERRIDE_VERSION" ]; then
info "Using override version: $OVERRIDE_VERSION"
NEXT_VERSION="$OVERRIDE_VERSION"
if ! validate_semver "$NEXT_VERSION"; then
err "Invalid version format: $NEXT_VERSION (expected X.Y.Z)"
fi
else
info "Determining next version from conventional commits"
NEXT_VERSION=$(determine_next_version)
fi
if [ "$NEXT_VERSION" = "$CURRENT_VERSION" ]; then
info "No version change needed (current: $CURRENT_VERSION)"
ci_append_output "skip=true" "reason=No version change needed"
exit 0
fi
if is_version_tagged "$NEXT_VERSION"; then
warn "Version $NEXT_VERSION is already tagged"
ci_append_output "skip=true" "reason=Version already tagged"
exit 0
fi
info "Next version: $NEXT_VERSION"
info "Updating Cargo.toml version"
sed -i.bak "s/^\([[:space:]]*version[[:space:]]*=[[:space:]]*\)\".*\"/\1\"$NEXT_VERSION\"/" Cargo.toml
rm -f Cargo.toml.bak
UPDATED_VERSION=$(get_current_version)
if [ "$UPDATED_VERSION" != "$NEXT_VERSION" ]; then
err "Failed to update Cargo.toml version (got $UPDATED_VERSION, expected $NEXT_VERSION)"
fi
info "Updated Cargo.toml: $CURRENT_VERSION → $NEXT_VERSION"
info "Generating changelog for v$NEXT_VERSION"
TAG_NAME=$(format_tag_name "$NEXT_VERSION")
ensure git-cliff --unreleased --tag "$TAG_NAME" --prepend CHANGELOG.md --output CHANGELOG.release.md
echo "<!-- generated by git-cliff on $(date +%Y-%m-%d) -->" >>CHANGELOG.md
info "Prepended v$NEXT_VERSION to CHANGELOG.md"
CHANGELOG_STATUS=$(git status --porcelain CHANGELOG.md)
if [ -z "$CHANGELOG_STATUS" ]; then
info "No substantive changes to release (CHANGELOG.md unchanged)"
git checkout -- Cargo.toml
ci_append_output "skip=true" "reason=No substantive changes to release"
exit 0
else
info "CHANGELOG.md has substantive changes"
fi
info "Generating PR body"
cat >.github/release-pr-body.md <<EOF
# Release v${NEXT_VERSION}
This PR prepares the release for version ${NEXT_VERSION}.
### Checklist
- [ ] Changelog is accurate and complete
- [ ] Version bump is correct
- [ ] All CI checks pass
> [!WARNING]
>
> This PR is automatically maintained by the release automation. Any manual changes to files will be overwritten when the workflow runs again.
> To make changes, modify the source and push to main, which will trigger an update to this PR.
---
$(cat CHANGELOG.release.md)
---
_This PR is automatically maintained by the release automation._
EOF
info "Generated PR body at .github/release-pr-body.md"
ci_append_output "version=$NEXT_VERSION"
info "Files prepared for release v${NEXT_VERSION}"