pediatric-ai-scribe-v3/scripts/release.sh

118 lines
4.2 KiB
Bash
Executable file

#!/usr/bin/env bash
# ============================================================
# PedScribe release helper — one command to tag a new version.
#
# Usage:
# scripts/release.sh 6.1.1 # bump to 6.1.1
# scripts/release.sh 6.1.1 --push # also git push + tag push
#
# What it does:
# 1. Updates version in root package.json and package-lock.json (requires Node)
# 2. Updates version in mobile/package.json
# 3. Updates versionName + bumps versionCode in Android build.gradle
# 4. Commits the version bump
# 5. (optional) git push + push the new tag
#
# It does NOT:
# - Build the Docker image (run `./scripts/build-image.sh`/`docker compose up -d --no-build` yourself
# or wire it to a deploy script / CI hook)
# - Build the Android APK itself. Forgejo CI does that
# (.forgejo/workflows/android-apk.yml): any branch push builds a signed
# APK as a 30-day workflow artifact, and a v* tag push additionally
# attaches it to a Forgejo release, which is what Obtainium tracks for
# updates. So --push is all you need to ship a build.
# - Publish the release itself. CI does that on the tag push; there is no
# manual publish step to run.
# ============================================================
set -euo pipefail
VERSION="${1:-}"
PUSH=false
for arg in "${@:2}"; do
case "$arg" in
--push) PUSH=true ;;
esac
done
if [[ -z "$VERSION" ]]; then
echo "usage: $0 <version> [--push]"
echo " example: $0 6.1.1 --push"
exit 1
fi
if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "ERROR: version must be semver X.Y.Z (e.g. 6.1.1). got: $VERSION" >&2
exit 1
fi
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$ROOT"
if [[ -n "$(git status --porcelain)" ]]; then
echo "ERROR: working tree has uncommitted changes. commit or stash first." >&2
git status --short >&2
exit 1
fi
echo "==> Bumping to v$VERSION"
# Parse every manifest before writing; change metadata only, never resolve dependencies.
# Replace the lock atomically so its two version fields cannot be partially updated.
node - "$VERSION" <<'NODE'
const fs = require('node:fs');
const version = process.argv[2];
const files = ['package.json', 'package-lock.json', 'mobile/package.json'];
const updates = files.map(file => [file, JSON.parse(fs.readFileSync(file, 'utf8'))]);
for (const [file, data] of updates) {
data.version = version;
if (file === 'package-lock.json') data.packages[''].version = version;
}
for (const [file, data] of updates) {
fs.writeFileSync(file + '.tmp', JSON.stringify(data, null, 2) + '\n');
fs.renameSync(file + '.tmp', file);
}
NODE
echo " updated package.json, package-lock.json and mobile/package.json"
# Android build.gradle
# versionCode: encode X.Y.Z as X*100000 + Y*1000 + Z (room for 999 patches)
IFS='.' read -r MAJ MIN PAT <<< "$VERSION"
ANDROID_CODE=$(( MAJ * 100000 + MIN * 1000 + PAT ))
sed -i -E \
-e "s/versionCode +[0-9]+/versionCode ${ANDROID_CODE}/" \
-e "s/versionName +\"[^\"]+\"/versionName \"${VERSION}\"/" \
mobile/android/app/build.gradle
echo " updated mobile/android/app/build.gradle (code=$ANDROID_CODE, name=$VERSION)"
# Commit
git add package.json package-lock.json mobile/package.json mobile/android/app/build.gradle
git commit -m "Release v${VERSION}"
echo " committed"
# Tag
git tag -a "v${VERSION}" -m "Release v${VERSION}"
echo " tagged v${VERSION}"
if $PUSH; then
# This repo's remote is "forgejo", not "origin". Prefer forgejo, fall back
# to origin, otherwise use the only remote there is — so this keeps working
# if the remote is ever renamed. Pushing the tag is what makes CI attach the
# signed APK to a Forgejo release for Obtainium; the branch push alone only
# builds it as a 30-day workflow artifact.
REMOTE=""
for candidate in forgejo origin; do
if git remote get-url "$candidate" >/dev/null 2>&1; then REMOTE="$candidate"; break; fi
done
if [[ -z "$REMOTE" ]]; then
REMOTE=$(git remote | head -1)
fi
if [[ -z "$REMOTE" ]]; then
echo "ERROR: no git remote configured — cannot push. Commit and tag are still local." >&2
exit 1
fi
git push "$REMOTE" HEAD
git push "$REMOTE" "v${VERSION}"
echo " pushed to $REMOTE"
fi
echo "==> Done. v$VERSION."