Files
dashcaddy/scripts/release.sh
T
SamiandClaude Opus 4.7 f65af5d7fd fix(updater): stop false-positive "update available" loop when commit is unknown
Dockerfile never received DASHCADDY_COMMIT at build, so /app/VERSION held
'unknown'. _isNewer then treated same-version-different-commit as newer,
making the auto-updater rebuild the container indefinitely (each rebuild
still produced commit='unknown').

- self-updater._isNewer: normalize commits; treat unknown/null/empty as no
  commit info and fall back to pure version comparison
- self-updater._autoCheckAndApply + routes/updates: refuse to apply when
  local version >= remote version (belt-and-suspenders)
- update-management.js: hide '(unknown)' from version label
- Dockerfile: COPY VERSION instead of writing from build arg
- VERSION: committed placeholder ('dev'); scripts/release.sh now writes
  the real short SHA into the tarball's VERSION before tar-ing, so every
  published release ships with an accurate commit

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 18:20:59 -07:00

137 lines
6.7 KiB
Bash

#!/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
# Bake the actual commit SHA into the api VERSION file so containers built
# from this tarball report a real commit (not the 'dev' placeholder).
echo \"$COMMIT\" > dashcaddy-api/VERSION
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."