mirror of
https://github.com/awizemann/scarf.git
synced 2026-05-10 02:26:37 +00:00
chore: release script supports --draft + RELEASE_NOTES.md
Drafts skip the appcast push and main tag, so a draft release won't show up in users' Sparkle update feed and v1.6.0 stays "latest" until explicitly promoted. The signed appcast entry is saved to the release dir for later manual promotion. Also adds release notes file convention: releases/v<VERSION>/RELEASE_NOTES.md is auto-included in the version-bump commit and used as the GitHub release body. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+82
-26
@@ -2,7 +2,18 @@
|
||||
#
|
||||
# Scarf release pipeline — local, manual, repeatable.
|
||||
#
|
||||
# Usage: ./scripts/release.sh 1.7.0
|
||||
# Usage:
|
||||
# ./scripts/release.sh 1.7.0 # full release: build, sign, notarize,
|
||||
# # appcast push, GitHub release, tag
|
||||
# ./scripts/release.sh 1.7.0 --draft # everything builds + notarizes, but the
|
||||
# # GitHub release is created as draft, the
|
||||
# # appcast is NOT updated, and main is NOT
|
||||
# # tagged. Promote later with --promote.
|
||||
#
|
||||
# Release notes:
|
||||
# If `releases/v<VERSION>/RELEASE_NOTES.md` exists, it is committed alongside the
|
||||
# version bump and used as the GitHub release body. Otherwise a minimal autogenerated
|
||||
# note is used.
|
||||
#
|
||||
# Prerequisites (one-time setup):
|
||||
# 1. Developer ID Application cert installed in login Keychain.
|
||||
@@ -19,8 +30,20 @@
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
# ---------- arg parsing ----------
|
||||
VERSION=""
|
||||
DRAFT=0
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--draft) DRAFT=1 ;;
|
||||
-h|--help) sed -n '2,30p' "$0"; exit 0 ;;
|
||||
-*) printf '[ERR] unknown flag: %s\n' "$arg" >&2; exit 1 ;;
|
||||
*) [[ -z "$VERSION" ]] && VERSION="$arg" || { printf '[ERR] unexpected arg: %s\n' "$arg" >&2; exit 1; } ;;
|
||||
esac
|
||||
done
|
||||
[[ -n "$VERSION" ]] || { printf 'usage: ./scripts/release.sh <marketing-version> [--draft]\n' >&2; exit 1; }
|
||||
|
||||
# ---------- config ----------
|
||||
VERSION="${1:?usage: ./scripts/release.sh <marketing-version> e.g. 1.7.0}"
|
||||
TEAM_ID="3Q6X2L86C4"
|
||||
BUNDLE_ID="com.scarf.app"
|
||||
SCHEME="scarf"
|
||||
@@ -81,6 +104,11 @@ NEW_BUILD=$((CUR_BUILD + 1))
|
||||
sed -i '' -E "s/MARKETING_VERSION = [0-9]+\.[0-9]+\.[0-9]+;/MARKETING_VERSION = ${VERSION};/g" "$PBXPROJ"
|
||||
sed -i '' -E "s/CURRENT_PROJECT_VERSION = [0-9]+;/CURRENT_PROJECT_VERSION = ${NEW_BUILD};/g" "$PBXPROJ"
|
||||
git add "$PBXPROJ"
|
||||
# Include release notes in the bump commit if user prepared them ahead of time.
|
||||
NOTES_FILE="$RELEASE_DIR/RELEASE_NOTES.md"
|
||||
if [[ -f "$NOTES_FILE" ]]; then
|
||||
git add "$NOTES_FILE"
|
||||
fi
|
||||
git commit -m "chore: Bump version to ${VERSION}"
|
||||
|
||||
# ---------- build ----------
|
||||
@@ -154,17 +182,9 @@ ED_SIGNATURE="$(echo "$SIG_OUTPUT" | sed -nE 's/.*sparkle:edSignature="([^"]+)".
|
||||
FILE_LENGTH="$(echo "$SIG_OUTPUT" | sed -nE 's/.*length="([^"]+)".*/\1/p')"
|
||||
[[ -n "$ED_SIGNATURE" && -n "$FILE_LENGTH" ]] || die "sign_update did not produce signature: $SIG_OUTPUT"
|
||||
|
||||
# ---------- update appcast on gh-pages ----------
|
||||
log "Update appcast.xml on gh-pages worktree"
|
||||
if [[ ! -d "$GH_PAGES_WORKTREE" ]]; then
|
||||
git worktree add "$GH_PAGES_WORKTREE" gh-pages
|
||||
fi
|
||||
(
|
||||
cd "$GH_PAGES_WORKTREE"
|
||||
git pull --ff-only origin gh-pages
|
||||
PUB_DATE="$(LC_TIME=en_US.UTF-8 date -u +"%a, %d %b %Y %H:%M:%S +0000")"
|
||||
DOWNLOAD_URL="$DOWNLOAD_URL_BASE/v${VERSION}/Scarf-v${VERSION}-Universal.zip"
|
||||
NEW_ITEM=$(cat <<EOF
|
||||
DOWNLOAD_URL="$DOWNLOAD_URL_BASE/v${VERSION}/Scarf-v${VERSION}-Universal.zip"
|
||||
PUB_DATE="$(LC_TIME=en_US.UTF-8 date -u +"%a, %d %b %Y %H:%M:%S +0000")"
|
||||
APPCAST_ITEM=$(cat <<EOF
|
||||
<item>
|
||||
<title>Version ${VERSION}</title>
|
||||
<sparkle:version>${NEW_BUILD}</sparkle:version>
|
||||
@@ -178,8 +198,18 @@ fi
|
||||
</item>
|
||||
EOF
|
||||
)
|
||||
# Insert new item after <language>en</language> line
|
||||
python3 - "$NEW_ITEM" <<'PY'
|
||||
|
||||
# ---------- update appcast on gh-pages (skipped for drafts) ----------
|
||||
if [[ $DRAFT -eq 0 ]]; then
|
||||
log "Update appcast.xml on gh-pages worktree"
|
||||
if [[ ! -d "$GH_PAGES_WORKTREE" ]]; then
|
||||
git worktree add "$GH_PAGES_WORKTREE" gh-pages
|
||||
fi
|
||||
(
|
||||
cd "$GH_PAGES_WORKTREE"
|
||||
git pull --ff-only origin gh-pages
|
||||
# Insert new item after <language>en</language> line
|
||||
python3 - "$APPCAST_ITEM" <<'PY'
|
||||
import sys, pathlib
|
||||
new_item = sys.argv[1]
|
||||
p = pathlib.Path("appcast.xml")
|
||||
@@ -190,22 +220,48 @@ if marker not in xml:
|
||||
xml = xml.replace(marker, marker + "\n" + new_item, 1)
|
||||
p.write_text(xml)
|
||||
PY
|
||||
git add appcast.xml
|
||||
git commit -m "release: v${VERSION}"
|
||||
git push origin gh-pages
|
||||
)
|
||||
git add appcast.xml
|
||||
git commit -m "release: v${VERSION}"
|
||||
git push origin gh-pages
|
||||
)
|
||||
else
|
||||
log "Draft mode — skipping appcast push. Saving entry to $RELEASE_DIR/appcast-entry.xml for later promotion."
|
||||
printf '%s\n' "$APPCAST_ITEM" > "$RELEASE_DIR/appcast-entry.xml"
|
||||
fi
|
||||
|
||||
# ---------- github release ----------
|
||||
log "Create GitHub release and upload artifacts"
|
||||
GH_FLAGS=()
|
||||
[[ $DRAFT -eq 1 ]] && GH_FLAGS+=(--draft)
|
||||
if [[ -f "$NOTES_FILE" ]]; then
|
||||
GH_FLAGS+=(--notes-file "$NOTES_FILE")
|
||||
else
|
||||
GH_FLAGS+=(--notes "Release v${VERSION}. See commit history for details.")
|
||||
fi
|
||||
gh release create "v${VERSION}" \
|
||||
--title "Scarf v${VERSION}" \
|
||||
--notes "Release notes: https://github.com/awizemann/scarf/releases/tag/v${VERSION}" \
|
||||
"${GH_FLAGS[@]}" \
|
||||
"$UNIVERSAL_ZIP"
|
||||
|
||||
log "Tag main and push"
|
||||
git tag "v${VERSION}"
|
||||
git push origin main --tags
|
||||
# ---------- tag main (skipped for drafts) ----------
|
||||
if [[ $DRAFT -eq 0 ]]; then
|
||||
log "Tag main and push"
|
||||
git tag "v${VERSION}"
|
||||
git push origin main --tags
|
||||
else
|
||||
log "Draft mode — skipping tag. Bump commit is local only; push manually with: git push origin main"
|
||||
fi
|
||||
|
||||
log "Release v${VERSION} complete"
|
||||
log " Download: $DOWNLOAD_URL_BASE/v${VERSION}/Scarf-v${VERSION}-Universal.zip"
|
||||
log " Appcast: $APPCAST_URL"
|
||||
if [[ $DRAFT -eq 1 ]]; then
|
||||
log "Draft release v${VERSION} ready"
|
||||
log " Review: https://github.com/awizemann/scarf/releases"
|
||||
log " Promote: in GitHub UI, edit the draft and uncheck 'Set as a pre-release / draft' → Publish."
|
||||
log " Then commit + push appcast-entry.xml to gh-pages, and tag main:"
|
||||
log " git push origin main"
|
||||
log " git tag v${VERSION} && git push origin v${VERSION}"
|
||||
log " (manually merge $RELEASE_DIR/appcast-entry.xml into gh-pages branch's appcast.xml after <language>en</language>)"
|
||||
else
|
||||
log "Release v${VERSION} complete"
|
||||
log " Download: $DOWNLOAD_URL"
|
||||
log " Appcast: $APPCAST_URL"
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user