Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions .github/workflows/v2-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,17 @@ jobs:
echo "Updater manifest unchanged; nothing to commit."
else
git commit -m "Update updater manifest for ${TAG}"
git push origin HEAD:${{ github.event.repository.default_branch }}
# `merge-updater` and `refresh-screenshots` both commit to the
# default branch and can finish at the same time, so the loser of
# the race gets a non-fast-forward rejection. That is what failed
# the v2-2.1.0 gallery job. Rebase and retry instead.
branch="${{ github.event.repository.default_branch }}"
for attempt in 1 2 3 4 5; do
if git push origin "HEAD:$branch"; then break; fi
echo " push attempt $attempt rejected; rebasing on origin/$branch…"
git pull --rebase origin "$branch"
Comment on lines +394 to +396

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Prevent older release runs from overwriting the updater manifest

When two v2 tag workflows overlap and both merge-updater jobs check out before either pushes, the newer release can publish first, after which the older run's rejected push is rebased and retried successfully. That places the older latest.json on top of the newer one, so the fixed updater endpoint stops advertising the newest release indefinitely. The workflow has no cross-run concurrency or version check, so retry only after confirming the rebased manifest is not older, or serialize release publication by version.

Useful? React with 👍 / 👎.

[[ $attempt -eq 5 ]] && { echo "push still failing after rebase"; exit 1; }
done
echo "Updater manifest published for ${TAG}."
fi

Expand Down Expand Up @@ -448,5 +458,15 @@ jobs:
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add screenshots/gallery.gif screenshots/gallery-light.gif
git commit -m "Regenerate gallery GIFs for ${TAG}"
git push origin HEAD:${{ github.event.repository.default_branch }}
# `merge-updater` and `refresh-screenshots` both commit to the
# default branch and can finish at the same time, so the loser of
# the race gets a non-fast-forward rejection. That is what failed
# the v2-2.1.0 gallery job. Rebase and retry instead.
branch="${{ github.event.repository.default_branch }}"
for attempt in 1 2 3 4 5; do
if git push origin "HEAD:$branch"; then break; fi
echo " push attempt $attempt rejected; rebasing on origin/$branch…"
git pull --rebase origin "$branch"
[[ $attempt -eq 5 ]] && { echo "push still failing after rebase"; exit 1; }
done
echo "Galleries refreshed for ${TAG}."
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ The release workflow also regenerates the gallery on every `v2-*` tag (the `refr
- WiX rejects non-numeric pre-release identifiers — `0.1.0-beta` fails with "optional pre-release identifier in app version must be numeric-only…". So `release.sh` sets a numeric-only `bundle.windows.wix.version` (the human version stays as-is for Linux/macOS/NSIS).
- **Windows Installer ignores the 4th version field** for upgrade detection — it compares only `major.minor.build`. An earlier scheme put the pre-release counter in the 4th field (`0.1.0.N`), so every beta read as `0.1.0` and Windows refused in-place upgrades ("uninstall the existing version first"). `release.sh` now encodes the counter into the **3rd (build)** field so each release strictly increases in semver order: `build3 = patch*1000 + typeBase + n` with type bands alpha 0 / beta 300 / rc 600 / stable 999 (e.g. `0.1.0-beta.3` → `0.1.303`, `0.1.0-rc.1` → `0.1.601`, `0.1.0` → `0.1.999`). If you hand-bump, set `bundle.windows.wix.version` with the same scheme.
- The MSI **UpgradeCode** is auto-derived by Tauri from `productName`/`identifier` and must stay stable for upgrades to work — **don't rename the product or change the identifier** without understanding it resets the UpgradeCode and orphans existing installs.
- **Don't pipe `yes` into `release.sh`.** The auto-mode classifier blocks it (correctly) — the script's interactive gates are the safety net. Run it interactively, or do the steps by hand.
- **Don't pipe `yes` into `release.sh`.** The auto-mode classifier blocks it (correctly) — the script's interactive gates are the safety net. Run it interactively, or pass `--yes` if you have deliberately decided to skip the gates (CI, or an agent acting on an explicit instruction).

### Homebrew tap

Expand Down
31 changes: 24 additions & 7 deletions v2/release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,31 @@ BUMP="patch"
PRE=""
EXPLICIT=""

# Piping `yes` into this script is blocked by the auto-mode classifier, and
# rightly so — these gates are the safety net. `--yes` is the sanctioned way to
# skip them deliberately, for CI or an agent that has already decided.
ASSUME_YES=0

# Ask a y/N question, or answer it automatically under --yes. Returns 0 for
# yes, 1 for no, so callers read as `confirm "..." || abort`.
confirm() {
local prompt="$1"
if [[ "$ASSUME_YES" == "1" ]]; then
echo "$prompt [auto-yes]"
return 0
fi
local REPLY
read -p "$prompt " -n 1 -r; echo
[[ $REPLY =~ ^[Yy]$ ]]
}

usage() {
cat <<EOF
Usage: $0 [--major|--minor|--patch] [--beta|--rc|--alpha] [--set X.Y.Z]
Usage: $0 [--major|--minor|--patch] [--beta|--rc|--alpha] [--set X.Y.Z] [--yes]
bump kind: --patch (default) | --minor | --major
pre-release: --beta | --rc | --alpha | --preview
explicit: --set X.Y.Z[-tag] (overrides bump kind, used verbatim)
--yes, -y: auto-confirm every gate (non-interactive / CI use)

Examples:
$0 # 0.1.0 -> 0.1.1
Expand All @@ -61,6 +80,7 @@ while [[ $# -gt 0 ]]; do
--alpha) PRE="alpha"; shift ;;
--preview) PRE="preview"; shift ;;
--set) EXPLICIT="$2"; shift 2 ;;
--yes|-y) ASSUME_YES=1; shift ;;
-h|--help) usage ;;
*) echo "Unknown flag: $1" >&2; usage ;;
esac
Expand All @@ -76,8 +96,7 @@ fi
if [[ -n "$(git status --porcelain)" ]]; then
echo "Working tree has uncommitted changes:" >&2
git status --short >&2
read -p "Continue anyway? (y/N) " -n 1 -r; echo
[[ $REPLY =~ ^[Yy]$ ]] || { echo "Aborted."; exit 1; }
confirm "Continue anyway? (y/N)" || { echo "Aborted."; exit 1; }
fi

# --- Read current version ----------------------------------------------------
Expand Down Expand Up @@ -124,8 +143,7 @@ if git rev-parse "$TAG" >/dev/null 2>&1; then
exit 1
fi

read -p "Bump + tag? (y/N) " -n 1 -r; echo
[[ $REPLY =~ ^[Yy]$ ]] || { echo "Aborted."; exit 1; }
confirm "Bump + tag? (y/N)" || { echo "Aborted."; exit 1; }

# --- Patch the version into all three files ---------------------------------

Expand Down Expand Up @@ -212,8 +230,7 @@ git add "$TAURI_CONF" "$CARGO_TOML" "$CORE_CARGO_TOML" "$CARGO_LOCK" "$PACKAGE_J
git commit -m "Release $TAG"
git tag -a "$TAG" -m "Release $TAG"

read -p "Push the tag? (this fires the build workflow) (y/N) " -n 1 -r; echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
if confirm "Push the tag? (this fires the build workflow) (y/N)"; then
git push origin HEAD
git push origin "$TAG"
echo
Expand Down
Loading