2026-07-30 12:27:56 -06:00
#!/usr/bin/env bash
set -euo pipefail
version = " ${ 1 :- } "
mode = " ${ 2 :- publish } "
[[ " $version " = ~ ^[ 0-9] +\. [ 0-9] +\. [ 0-9] +( -[ 0-9A-Za-z.-] +) ?$ ]] || {
echo "usage: $0 <semver> [publish|validate-only]" >& 2
exit 1
}
remote = " ${ RELEASE_REMOTE :- origin } "
git fetch " $remote " refs/heads/main:refs/remotes/origin/main --no-tags
git fetch " $remote " '+refs/tags/v*:refs/tags/v*' '+refs/tags/desktop-v*:refs/tags/desktop-v*'
base_sha = " $( git rev-parse refs/remotes/origin/main) "
branch = "version-bump/ $version "
remote_branch = "refs/heads/ $branch "
remote_oid = ""
if remote_oid = " $( git ls-remote " $remote " " $remote_branch " | awk '{print $1}' ) " && [[ -n " $remote_oid " ]] ; then
git fetch " $remote " " $remote_branch :refs/remotes/origin/ $branch "
fi
git checkout -B " $branch " " $base_sha "
just bump-desktop-version " $version "
scripts/desktop_release.py generate " $version " --base " $base_sha " --repo block/buzz
git add \
.release/desktop-candidate.json \
CHANGELOG.md \
desktop/package.json \
desktop/src-tauri/tauri.conf.json \
desktop/src-tauri/Cargo.toml \
desktop/src-tauri/Cargo.lock \
pnpm-lock.yaml
agent_name = " ${ RELEASE_AUTOMATION_NAME :- ${ AGENT_NAME :- Release Automation }} "
agent_email = " ${ RELEASE_AUTOMATION_EMAIL :- ${ AGENT_EMAIL :- release -automation@users.noreply.github.com }} "
msg = " $( mktemp) "
trap 'rm -f "$msg"' EXIT
cat >" $msg " <<EOF
chore(release): release Buzz Desktop version $version
Co-authored-by: $agent_name <$agent_email>
EOF
git -c user.name= 'Wes' -c user.email= 'wesbillman@users.noreply.github.com' \
commit -s -F " $msg "
scripts/desktop_release.py validate --candidate HEAD --version " $version " --repo block/buzz
candidate_sha = " $( git rev-parse HEAD) "
previous_tag = " $( python3 -c 'import json; print(json.load(open(".release/desktop-candidate.json"))["previous_tag"] or "initial")' ) "
printf 'base_sha=%s\ncandidate_sha=%s\nprevious_tag=%s\ntag=desktop-v%s\n' \
" $base_sha " " $candidate_sha " " $previous_tag " " $version "
if [[ " $mode " == validate-only ]] ; then
exit 0
fi
[[ " $mode " == publish ]] || { echo "unknown mode: $mode " >& 2; exit 1; }
if [[ -n " $remote_oid " ]] ; then
git push --force-with-lease= " $remote_branch : $remote_oid " " $remote " "HEAD: $remote_branch "
else
git push --force-with-lease= " $remote_branch :" " $remote " "HEAD: $remote_branch "
fi
body = " $( mktemp) "
trap 'rm -f "$msg" "$body"' EXIT
cat >" $body " <<EOF
## Buzz Desktop release v$version
- **Frozen main:** \`$base_sha\`
- **Reviewed candidate:** \`$candidate_sha\`
- **Previous desktop release:** \`$previous_tag\`
- **Proposed immutable tag:** \`desktop-v$version\`
2026-08-05 12:00:14 -06:00
This PR may be **squash merged** after the Desktop Release Candidate check and all protected-branch checks pass. Merging authorizes publication of the exact reviewed candidate; later or unrelated changes on \`main\` cannot alter it.
2026-07-30 12:27:56 -06:00
2026-08-05 12:00:14 -06:00
The checked-in changelog accounts for every non-merge commit in the release range. The Desktop tag points to the reviewed candidate commit, not the later squash commit. Publication remains bound to that immutable candidate tag.
2026-07-30 12:27:56 -06:00
EOF
2026-08-10 09:59:15 -06:00
if existing = " $( gh pr list --repo block/buzz --head " $branch " --state open --json number --jq '.[0].number' ) " && [[ -n " $existing " ]] ; then
gh pr edit --repo block/buzz " $existing " --title "chore(release): release Buzz Desktop version $version " --body-file " $body "
2026-07-30 12:27:56 -06:00
else
2026-08-10 09:59:15 -06:00
gh pr create --repo block/buzz --base main --head " $branch " \
2026-07-30 12:27:56 -06:00
--title "chore(release): release Buzz Desktop version $version " --body-file " $body "
fi