chore: add scripts/release.sh for cutting + publishing releases
Automates what was previously a six-step manual process that, twice in this codebase's history, has produced version skew between git and the released tarball (v1.2.0 was published with package.json 1.2.0 in the tarball but the bump was never committed back to gitea — making "what code is in v1.2.0?" answerable only by extracting the tarball). The script: - Refuses to run with a dirty tree, off main, or already at the target version. - Bumps dashcaddy-api/package.json, rebuilds status/dist/, commits + pushes to gitea — so the released artifact and gitea HEAD are always in lockstep. - Clones gitea HEAD on the release host, verifies the cloned commit matches what we just pushed (catches a stale clone or a missed push), tars it, computes sha256, writes version.json. - Refreshes install.sh on the release host alongside the tarball (fresh installs use the install.sh from the latest release). - Mirrors the release dir to the get2 backup via rsync. - Verifies live by curling version.json and re-hashing the served tarball. Hosts overridable via DASHCADDY_RELEASE_HOST / DASHCADDY_MIRROR_HOST / DASHCADDY_GITEA_URL env vars. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
133
scripts/release.sh
Normal file
133
scripts/release.sh
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Cut a DashCaddy release: bump dashcaddy-api/package.json, commit, push,
|
||||||
|
# build tarball + version.json on DNS2 (the get.dashcaddy.net publishing
|
||||||
|
# host), refresh install.sh, then mirror everything to the dc-contabo-de
|
||||||
|
# get2 backup.
|
||||||
|
#
|
||||||
|
# Usage: scripts/release.sh <version>
|
||||||
|
# Example: scripts/release.sh 1.4.0
|
||||||
|
#
|
||||||
|
# Pre-flight: must be on `main`, working tree clean, gitea remote reachable.
|
||||||
|
#
|
||||||
|
# Hosts/URLs are overridable via env:
|
||||||
|
# DASHCADDY_RELEASE_HOST default root@100.104.4.5 (DNS2, hosts get.dashcaddy.net)
|
||||||
|
# DASHCADDY_MIRROR_HOST default root@dc-contabo-de (hosts get2.dashcaddy.net)
|
||||||
|
# DASHCADDY_GITEA_URL default http://100.98.123.59:3000/sami7777/dashcaddy.git
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
VERSION="${1:-}"
|
||||||
|
[[ -z "$VERSION" ]] && { echo "Usage: $0 <version>" >&2; exit 1; }
|
||||||
|
[[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || { echo "Invalid version (need X.Y.Z): $VERSION" >&2; exit 1; }
|
||||||
|
|
||||||
|
REPO_ROOT="$(git rev-parse --show-toplevel)"
|
||||||
|
RELEASE_HOST="${DASHCADDY_RELEASE_HOST:-root@100.104.4.5}"
|
||||||
|
MIRROR_HOST="${DASHCADDY_MIRROR_HOST:-root@dc-contabo-de}"
|
||||||
|
GITEA_URL="${DASHCADDY_GITEA_URL:-http://100.98.123.59:3000/sami7777/dashcaddy.git}"
|
||||||
|
|
||||||
|
cd "$REPO_ROOT"
|
||||||
|
|
||||||
|
# ── Pre-flight ─────────────────────────────────────────────────────────────
|
||||||
|
[[ -f dashcaddy-api/package.json ]] || { echo "Run from dashcaddy repo root (no dashcaddy-api/package.json)" >&2; exit 1; }
|
||||||
|
[[ -n "$(git status --porcelain)" ]] && { echo "Working tree must be clean" >&2; exit 1; }
|
||||||
|
BRANCH="$(git rev-parse --abbrev-ref HEAD)"
|
||||||
|
[[ "$BRANCH" == "main" ]] || { echo "Must be on main (current: $BRANCH)" >&2; exit 1; }
|
||||||
|
|
||||||
|
CURRENT="$(node -p "require('./dashcaddy-api/package.json').version")"
|
||||||
|
[[ "$CURRENT" == "$VERSION" ]] && { echo "package.json already at $VERSION — nothing to do" >&2; exit 1; }
|
||||||
|
|
||||||
|
echo "─── Cutting release ───"
|
||||||
|
echo " current: $CURRENT"
|
||||||
|
echo " target: $VERSION"
|
||||||
|
echo " release: $RELEASE_HOST"
|
||||||
|
echo " mirror: $MIRROR_HOST"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# ── 1. Bump dashcaddy-api/package.json ────────────────────────────────────
|
||||||
|
echo "[1/6] Bumping dashcaddy-api/package.json"
|
||||||
|
node -e "
|
||||||
|
const fs = require('fs');
|
||||||
|
const pkg = require('./dashcaddy-api/package.json');
|
||||||
|
pkg.version = '$VERSION';
|
||||||
|
fs.writeFileSync('./dashcaddy-api/package.json', JSON.stringify(pkg, null, 2) + '\n');
|
||||||
|
"
|
||||||
|
|
||||||
|
# ── 2. Rebuild status frontend so dist/*.js matches source ────────────────
|
||||||
|
if [[ -f status/build.js ]]; then
|
||||||
|
echo "[2/6] Rebuilding status frontend"
|
||||||
|
(cd status && node build.js >/dev/null)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── 3. Commit + push ──────────────────────────────────────────────────────
|
||||||
|
echo "[3/6] Committing + pushing"
|
||||||
|
git add dashcaddy-api/package.json
|
||||||
|
# status/dist/ is .gitignored but its tracked files still need re-staging on rebuild.
|
||||||
|
# -f bypasses the ignore for these specific paths.
|
||||||
|
[[ -d status/dist ]] && git add -f status/dist/ 2>/dev/null || true
|
||||||
|
git commit -m "chore(release): bump to $VERSION" >/dev/null
|
||||||
|
git push gitea main >/dev/null
|
||||||
|
COMMIT="$(git rev-parse --short HEAD)"
|
||||||
|
echo " → committed: $COMMIT"
|
||||||
|
|
||||||
|
# ── 4. Build tarball on the publishing host ───────────────────────────────
|
||||||
|
echo "[4/6] Building tarball on $RELEASE_HOST"
|
||||||
|
ssh "$RELEASE_HOST" "set -e
|
||||||
|
rm -rf /tmp/dashcaddy-build
|
||||||
|
mkdir -p /tmp/dashcaddy-build
|
||||||
|
cd /tmp/dashcaddy-build
|
||||||
|
git clone --depth 1 '$GITEA_URL' dashcaddy >/dev/null 2>&1
|
||||||
|
cd dashcaddy
|
||||||
|
ACTUAL_COMMIT=\$(git rev-parse --short HEAD)
|
||||||
|
if [ \"\$ACTUAL_COMMIT\" != \"$COMMIT\" ]; then
|
||||||
|
echo \" ! cloned commit \$ACTUAL_COMMIT does not match expected $COMMIT — aborting\" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
rm -rf .git
|
||||||
|
find . -type d -name node_modules -exec rm -rf {} + 2>/dev/null || true
|
||||||
|
cd /tmp/dashcaddy-build
|
||||||
|
tar zcf dashcaddy-$VERSION.tar.gz dashcaddy/
|
||||||
|
"
|
||||||
|
echo " → built /tmp/dashcaddy-build/dashcaddy-$VERSION.tar.gz"
|
||||||
|
|
||||||
|
# ── 5. Publish on the release host ────────────────────────────────────────
|
||||||
|
echo "[5/6] Publishing v$VERSION + refreshed install.sh on $RELEASE_HOST"
|
||||||
|
ssh "$RELEASE_HOST" "set -e
|
||||||
|
cd /var/www/get.dashcaddy.net
|
||||||
|
cp -a release release.backup-\$(date -u +%Y%m%d-%H%M%S)
|
||||||
|
cp /tmp/dashcaddy-build/dashcaddy-$VERSION.tar.gz release/
|
||||||
|
cp /tmp/dashcaddy-build/dashcaddy-$VERSION.tar.gz release/latest.tar.gz
|
||||||
|
( cd release && sha256sum latest.tar.gz > latest.tar.gz.sha256 )
|
||||||
|
cp /tmp/dashcaddy-build/dashcaddy/dashcaddy-installer/install.sh release/install.sh
|
||||||
|
chmod +x release/install.sh
|
||||||
|
SHA256=\$(sha256sum release/dashcaddy-$VERSION.tar.gz | cut -d' ' -f1)
|
||||||
|
cat > release/version.json <<EOF
|
||||||
|
{
|
||||||
|
\"version\": \"$VERSION\",
|
||||||
|
\"commit\": \"$COMMIT\",
|
||||||
|
\"date\": \"\$(date -u +%Y-%m-%dT%H:%M:%SZ)\",
|
||||||
|
\"sha256\": \"\$SHA256\",
|
||||||
|
\"changelog\": \"$COMMIT chore(release): bump to $VERSION\",
|
||||||
|
\"breaking\": false,
|
||||||
|
\"tarball\": \"dashcaddy-$VERSION.tar.gz\"
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
"
|
||||||
|
|
||||||
|
# ── 6. Mirror to backup host ──────────────────────────────────────────────
|
||||||
|
echo "[6/6] Mirroring to $MIRROR_HOST"
|
||||||
|
ssh "$RELEASE_HOST" "rsync -aq --delete /var/www/get.dashcaddy.net/release/ $MIRROR_HOST:/var/www/get2.dashcaddy.net/release/"
|
||||||
|
|
||||||
|
# ── Verify ───────────────────────────────────────────────────────────────
|
||||||
|
echo
|
||||||
|
echo "─── Verifying live ───"
|
||||||
|
SERVED_VER="$(curl -fsSL --max-time 5 https://get.dashcaddy.net/release/version.json | node -p "JSON.parse(require('fs').readFileSync('/dev/stdin')).version")"
|
||||||
|
[[ "$SERVED_VER" == "$VERSION" ]] || { echo "MISMATCH: get.dashcaddy.net serves $SERVED_VER, expected $VERSION" >&2; exit 1; }
|
||||||
|
echo " get.dashcaddy.net → $SERVED_VER ✓"
|
||||||
|
|
||||||
|
SHA_LOCAL="$(ssh "$RELEASE_HOST" "sha256sum /var/www/get.dashcaddy.net/release/dashcaddy-$VERSION.tar.gz | cut -d' ' -f1")"
|
||||||
|
SHA_HTTP="$(curl -fsSL --max-time 30 "https://get.dashcaddy.net/release/dashcaddy-$VERSION.tar.gz" | sha256sum | cut -d' ' -f1)"
|
||||||
|
[[ "$SHA_LOCAL" == "$SHA_HTTP" ]] || { echo "SHA mismatch on served tarball" >&2; exit 1; }
|
||||||
|
echo " tarball sha256 → $SHA_HTTP ✓"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "Done. v$VERSION published from commit $COMMIT."
|
||||||
Reference in New Issue
Block a user