mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-08-28 05:27:41 +00:00
Drops `alpha` / `beta` / `rc` as accepted pre-release labels in bin/dev/release.sh. `nightly` is now the only pre-release descriptor, in preparation for automated nightly tags. Renames the Homebrew tap formula from `fabro-beta` to `fabro-nightly`: - installer/fabro-beta.rb.template -> installer/fabro-nightly.rb.template (class renamed FabroBeta -> FabroNightly, desc updated). - `update-homebrew-beta` job in release.yml is now `update-homebrew-nightly` with matching file paths and commit message. Breaking for existing `brew install fabro-sh/tap/fabro-beta` users: the old formula file stays in the tap for now (removed in a follow-up once fabro-nightly is populated) and stops receiving updates. Users should switch to `brew install fabro-sh/tap/fabro-nightly` once the new formula is published by the next pre-release tag. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
169 lines
4.1 KiB
Bash
Executable file
169 lines
4.1 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
die() {
|
|
printf '%s\n' "$1" >&2
|
|
exit 1
|
|
}
|
|
|
|
release_date() {
|
|
printf '%s\n' "${FABRO_RELEASE_DATE:-$(date "+%Y-%m-%d")}"
|
|
}
|
|
|
|
days_since_2026() {
|
|
local target_date="$1"
|
|
local epoch_2026 epoch_target
|
|
epoch_2026=$(date -j -f "%Y-%m-%d" "2026-01-01" "+%s")
|
|
epoch_target=$(date -j -f "%Y-%m-%d" "$target_date" "+%s")
|
|
printf '%s\n' $(( (epoch_target - epoch_2026) / 86400 ))
|
|
}
|
|
|
|
next_base_version() {
|
|
local date minor patch
|
|
date="$1"
|
|
minor=$(( $(days_since_2026 "$date") + 100 ))
|
|
patch=0
|
|
|
|
while git rev-parse "v0.${minor}.${patch}" >/dev/null 2>&1; do
|
|
patch=$((patch + 1))
|
|
done
|
|
|
|
printf '0.%s.%s\n' "$minor" "$patch"
|
|
}
|
|
|
|
validate_prerelease_label() {
|
|
local label="$1"
|
|
case "$label" in
|
|
nightly) ;;
|
|
*)
|
|
die "invalid pre-release label: $label (expected: nightly)"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
compute_release_version() {
|
|
local base_version="$1"
|
|
local prerelease_label="$2"
|
|
|
|
if [[ -z "$prerelease_label" ]]; then
|
|
printf '%s\n' "$base_version"
|
|
return 0
|
|
fi
|
|
|
|
local prerelease_number=0
|
|
while git rev-parse "v${base_version}-${prerelease_label}.${prerelease_number}" >/dev/null 2>&1; do
|
|
prerelease_number=$((prerelease_number + 1))
|
|
done
|
|
|
|
printf '%s-%s.%s\n' "$base_version" "$prerelease_label" "$prerelease_number"
|
|
}
|
|
|
|
parse_args() {
|
|
DRY_RUN=0
|
|
SKIP_TESTS=0
|
|
PRERELEASE_LABEL=""
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--dry-run)
|
|
DRY_RUN=1
|
|
;;
|
|
--skip-tests)
|
|
SKIP_TESTS=1
|
|
;;
|
|
--help|-h)
|
|
cat <<'EOF'
|
|
Usage: bin/dev/release.sh [nightly] [--dry-run] [--skip-tests]
|
|
|
|
Create the next stable release from main, or compute a prerelease tag.
|
|
|
|
Before tagging, runs the same release-mode test smoke the CI release
|
|
workflow does for the native target, with SEGMENT_WRITE_KEY baked in so
|
|
telemetry-active code paths are exercised. This catches regressions
|
|
like "uninstall recreates ~/.fabro via telemetry" or "sender tests
|
|
assume no write key" before we burn a 60-minute CI cycle. Skip only if
|
|
you've already run `cargo nextest run --workspace --release` yourself.
|
|
EOF
|
|
exit 0
|
|
;;
|
|
--*)
|
|
die "unknown option: $1"
|
|
;;
|
|
*)
|
|
if [[ -n "$PRERELEASE_LABEL" ]]; then
|
|
die "expected at most one pre-release label"
|
|
fi
|
|
validate_prerelease_label "$1"
|
|
PRERELEASE_LABEL="$1"
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
}
|
|
|
|
verify_spa_assets() {
|
|
local repo_root
|
|
repo_root="$(git rev-parse --show-toplevel)"
|
|
|
|
"${repo_root}/scripts/refresh-fabro-spa.sh"
|
|
|
|
if ! git -C "$repo_root" diff --exit-code -- lib/crates/fabro-spa/assets >/dev/null; then
|
|
die "fabro-spa assets are stale. Commit the refreshed assets before releasing."
|
|
fi
|
|
}
|
|
|
|
verify_release_tests() {
|
|
if [[ "$SKIP_TESTS" == "1" ]]; then
|
|
echo "--skip-tests set, skipping release-mode test smoke"
|
|
return 0
|
|
fi
|
|
|
|
echo "Running release-mode test smoke (SEGMENT_WRITE_KEY baked in)..."
|
|
SEGMENT_WRITE_KEY="fake-for-local-smoke" \
|
|
cargo nextest run \
|
|
--workspace \
|
|
--release \
|
|
--profile ci \
|
|
--status-level slow
|
|
}
|
|
|
|
main() {
|
|
parse_args "$@"
|
|
|
|
verify_spa_assets
|
|
verify_release_tests
|
|
|
|
local repo_root cargo_toml current_version base_version new_version tag
|
|
repo_root="$(git rev-parse --show-toplevel)"
|
|
cargo_toml="${repo_root}/Cargo.toml"
|
|
|
|
current_version=$(grep -m1 '^version = ' "$cargo_toml" | sed 's/version = "\(.*\)"/\1/')
|
|
echo "Current version: $current_version"
|
|
|
|
base_version=$(next_base_version "$(release_date)")
|
|
new_version=$(compute_release_version "$base_version" "$PRERELEASE_LABEL")
|
|
tag="v$new_version"
|
|
|
|
echo "Releasing $new_version (tag $tag)"
|
|
|
|
if [[ "$DRY_RUN" == "1" ]]; then
|
|
return 0
|
|
fi
|
|
|
|
sed -i '' "s/^version = \"$current_version\"/version = \"$new_version\"/" "$cargo_toml"
|
|
echo "Updated $cargo_toml"
|
|
|
|
cargo update --workspace
|
|
echo "Updated Cargo.lock"
|
|
|
|
git add "$cargo_toml" Cargo.lock
|
|
git commit -m "Bump version to $new_version"
|
|
git tag -a "$tag" -m "$tag"
|
|
git push origin main "$tag"
|
|
|
|
echo ""
|
|
echo "Released $tag"
|
|
echo "Watch the build: https://github.com/fabro-sh/fabro/actions"
|
|
}
|
|
|
|
main "$@"
|