mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
## Summary Redesign the permanent Desktop release flow so unrelated merges to `main` cannot invalidate an already reviewed, green release candidate. - Tag the immutable, API-confirmed release PR head instead of its later squash commit. - Treat the merged PR—including an authorized owner/admin bypass—as publication authorization, while requiring trusted check evidence that was complete at merge time. - Make tag creation idempotent and collision-safe: an existing tag succeeds only at the exact candidate SHA, and create races refetch before accepting equality. - Replace ancestry-based previous-release discovery with a validated metadata ledger for side-history candidate tags. - Compute the next release from the prior frozen base to the new frozen base, excluding only the prior release squash SHA so unrelated commits remain in the changelog. - Preserve schema-1 production-tag migration and reject malformed metadata or equal/decreasing versions. - Update operator documentation for the normal squash-merge workflow. This is the reusable release process for `0.5.6` onward, not the retired one-shot `0.5.5` recovery path. ### Invariants covered - Candidate creation → unrelated `main` merge → authorized squash merge → immutable candidate tag. - Trusted producer IDs and merge-time completion timestamps; DCO's bounded post-merge exception remains isolated. - Missing/spoofed checks, tampered candidates, ambiguous PR associations, conflicting tags, and equal/decreasing versions fail closed. - Same-SHA retries succeed; different-SHA collisions fail. - Legacy schema-1 tag-on-main migration and schema-2 side-history accounting both preserve the correct next-release changelog. ### Related issue N/A — follows the Desktop release failures in #4788 and #4800 and the recovery revert in #4808. ### Testing At clean commit `6a91fbed8147a48cf174997de0c3e4cb2fb26474`: - `scripts/test-desktop-release-candidate.sh` - `scripts/test-release-ref-contract.sh` Both focused suites passed with HEAD unchanged. Princess Donut cleared the security/provenance surface, including the hostile merge-time timestamp cases. Mongo cleared the side-history ledger, migration, version-order, documentation, and contract-test surface. --------- Signed-off-by: Wes <wesbillman@users.noreply.github.com> Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
84 lines
3.3 KiB
Bash
Executable File
84 lines
3.3 KiB
Bash
Executable File
#!/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\`
|
|
|
|
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.
|
|
|
|
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.
|
|
EOF
|
|
if existing="$(gh pr list --head "$branch" --state open --json number --jq '.[0].number')" && [[ -n "$existing" ]]; then
|
|
gh pr edit "$existing" --title "chore(release): release Buzz Desktop version $version" --body-file "$body"
|
|
else
|
|
gh pr create --base main --head "$branch" \
|
|
--title "chore(release): release Buzz Desktop version $version" --body-file "$body"
|
|
fi
|