Files
PacketStation/deploy/vm/make-release.sh
T

108 lines
4.7 KiB
Bash
Raw Normal View History

#!/usr/bin/env bash
# Build a release archive for the native VMs. Runs on a build host as a normal user, inside a git
# checkout of this repository: docker-1 (with --image) or a PC with Node (with --npm). Never on a VM.
#
# Usage:
# make-release.sh --image gt.pescoinc.biz/spencerm/packetstation:sha-<sha> [--out DIR]
# make-release.sh --npm [--ref REF] [--build NAME] [--out DIR]
#
# --image IMAGE take the built frontend out of a CI-tested image (docker create and docker cp,
# nothing runs). The build name and the commit come from the image's build label,
# so the source and the frontend are the tested commit.
# --npm build the frontend here with npm ci and npm run build, from the same commit.
# --ref REF the commit for --npm (default HEAD). Uncommitted changes are never included.
# --build NAME the build name for --npm (default sha-<full sha>, as CI names images).
# --out DIR where to write the archive (default the current folder).
#
# Writes packetstation-<build>.tar.gz and packetstation-<build>.tar.gz.sha256. The archive holds one
# folder, packetstation-<build>/, with BUILD, pyproject.toml, README.md, server/, deploy/, scripts/,
# docs/ and static/ (the built frontend). Python packages are not in it: ps-upgrade builds the venv
# on the VM from the pinned requirements.
set -euo pipefail
umask 022
DOCKER="${DOCKER:-docker}"
LABEL=biz.pescoinc.packetstation.build
log() { printf 'make-release: %s\n' "$*" >&2; }
die() { printf 'make-release: ERROR: %s\n' "$*" >&2; exit 1; }
usage() { sed -n '2,21p' "$0" | sed 's/^# \{0,1\}//' >&2; exit 2; }
image=""
npm=0
ref=""
build=""
out="."
while [[ $# -gt 0 ]]; do
case "$1" in
--image) [[ $# -ge 2 ]] || usage; image="$2"; shift 2 ;;
--npm) npm=1; shift ;;
--ref) [[ $# -ge 2 ]] || usage; ref="$2"; shift 2 ;;
--build) [[ $# -ge 2 ]] || usage; build="$2"; shift 2 ;;
--out) [[ $# -ge 2 ]] || usage; out="$2"; shift 2 ;;
-h|--help) usage ;;
*) log "unknown argument $1"; usage ;;
esac
done
if [[ -n "$image" && $npm -eq 1 ]] || [[ -z "$image" && $npm -eq 0 ]]; then
die "give exactly one of --image or --npm"
fi
if [[ -n "$image" && ( -n "$ref" || -n "$build" ) ]]; then
die "--ref and --build come from the image's label with --image"
fi
[[ "$image" != *:latest && ( -z "$image" || "$image" == *:* ) ]] || die "pull an image by its tag, never latest"
repo="$(git rev-parse --show-toplevel 2>/dev/null)" || die "run inside a git checkout of Packet Station"
cd -- "$repo"
if [[ -n "$image" ]]; then
"$DOCKER" image inspect "$image" >/dev/null 2>&1 || "$DOCKER" pull "$image" >/dev/null
build="$("$DOCKER" image inspect -f "{{ index .Config.Labels \"$LABEL\" }}" "$image")"
[[ "$build" =~ ^sha-[0-9a-f]{7,40}$ ]] || die "image label $LABEL is '$build', expected sha-<commit>"
ref="${build#sha-}"
else
ref="${ref:-HEAD}"
fi
sha="$(git rev-parse --verify --quiet "$ref^{commit}")" || die "commit $ref is not in this checkout (git fetch first)"
if [[ -z "$build" ]]; then
build="sha-$sha"
fi
[[ "$build" =~ ^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$ ]] || die "build name '$build' must be letters, digits, '.', '_' or '-'"
name="packetstation-$build"
mkdir -p -- "$out"
out="$(cd -- "$out" && pwd)"
work="$(mktemp -d)"
cid=""
cleanup() {
if [[ -n "$cid" ]]; then "$DOCKER" rm -f "$cid" >/dev/null 2>&1 || true; fi
rm -rf -- "$work"
}
trap cleanup EXIT
log "source of $sha"
# LF line endings whatever the checkout's autocrlf: these files run on Linux.
git -c core.autocrlf=false -c core.eol=lf archive --format=tar --prefix="$name/" "$sha" \
pyproject.toml README.md server deploy scripts docs | tar -xf - -C "$work"
printf '%s\n' "$build" > "$work/$name/BUILD"
[[ -f "$work/$name/deploy/vm/ps-launch.sh" ]] || die "commit $sha has no deploy/vm (older than phase 10)"
chmod 0755 "$work/$name"/deploy/vm/*.sh "$work/$name"/scripts/backup/*.sh
if [[ -n "$image" ]]; then
log "frontend from $image"
cid="$("$DOCKER" create "$image")"
"$DOCKER" cp "$cid:/app/static" "$work/$name/static"
else
log "frontend: npm ci and npm run build at $sha"
git -c core.autocrlf=false -c core.eol=lf archive --format=tar --prefix=frontend/ "$sha:frontend" \
| tar -xf - -C "$work"
( cd -- "$work/frontend" && npm ci --no-audit --no-fund && npm run build ) >&2
cp -R -- "$work/frontend/dist" "$work/$name/static"
fi
[[ -f "$work/$name/static/index.html" ]] || die "no static/index.html in the built frontend"
log "writing $out/$name.tar.gz"
tar -czf "$out/$name.tar.gz" -C "$work" --owner=0 --group=0 --numeric-owner --sort=name "$name"
( cd -- "$out" && sha256sum -- "$name.tar.gz" > "$name.tar.gz.sha256" )
log "done: $out/$name.tar.gz ($(wc -c < "$out/$name.tar.gz") bytes) and its .sha256"