62 lines
3.1 KiB
Bash
Executable File
62 lines
3.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -Eeuo pipefail
|
|
|
|
# Build a production release on the target Linux architecture. Native addons
|
|
# (SQLite, Argon2 and image processing) must be installed on the same
|
|
# architecture/libc as the artifact. Node.js itself is deliberately managed
|
|
# by the installer outside each release so application updates stay small.
|
|
ROOT=$(cd -- "$(dirname -- "$0")/.." && pwd -P)
|
|
VERSION=${1:-}
|
|
OUT_DIR=${2:-$ROOT/release}
|
|
[[ "$(uname -s)" == "Linux" ]] || { printf 'release builds must run on Linux; detected %s\n' "$(uname -s)" >&2; exit 2; }
|
|
if [[ -z "$VERSION" ]]; then
|
|
VERSION=$(node -p 'require("./package.json").version')
|
|
fi
|
|
VERSION=${VERSION#v}
|
|
[[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$ ]] || { printf 'invalid version: %s\n' "$VERSION" >&2; exit 2; }
|
|
PACKAGE_VERSION=$(node -p 'require("./package.json").version')
|
|
[[ "$VERSION" == "$PACKAGE_VERSION" ]] || { printf 'version mismatch: release %s does not match package.json %s\n' "$VERSION" "$PACKAGE_VERSION" >&2; exit 2; }
|
|
case "$(uname -m)" in
|
|
x86_64|amd64) ARCH=x64 ;;
|
|
aarch64|arm64) ARCH=arm64 ;;
|
|
armv7l|armv7|armhf) ARCH=armv7 ;;
|
|
*) printf 'unsupported architecture: %s\n' "$(uname -m)" >&2; exit 2 ;;
|
|
esac
|
|
LIBC=glibc
|
|
if command -v ldd >/dev/null 2>&1 && ldd --version 2>&1 | grep -qi musl; then LIBC=musl; fi
|
|
|
|
cd "$ROOT"
|
|
pnpm build
|
|
stage=$(mktemp -d)
|
|
trap 'rm -rf "$stage"' EXIT
|
|
mkdir -p "$stage/dist" "$stage/migrations" "$stage/bin" "$stage/scripts" "$stage/systemd"
|
|
# Copy only the production build outputs. In particular, do not carry a
|
|
# stale dist/web-next directory from a previous local preview build.
|
|
cp -a dist/server "$stage/dist/"
|
|
cp -a dist/shared "$stage/dist/"
|
|
cp -a dist/web "$stage/dist/"
|
|
cp -a migrations/. "$stage/migrations/"
|
|
cp package.json pnpm-lock.yaml "$stage/"
|
|
cp -a bin/. "$stage/bin/"
|
|
cp -a scripts/tallynote-update.sh scripts/tallynote-update-runner.sh "$stage/scripts/"
|
|
cp uninstall.sh "$stage/uninstall.sh"
|
|
cp -a systemd/tallynote.service systemd/tallynote-update.service systemd/tallynote-update.path systemd/tallynote.env.example "$stage/systemd/"
|
|
chmod 755 "$stage/bin/tallynote" "$stage/bin/tallynote-admin-init" "$stage/scripts"/*.sh "$stage/uninstall.sh"
|
|
|
|
# pnpm's default linker creates symlinks. A release archive is deliberately
|
|
# symlink-free so the installer can reject traversal links deterministically.
|
|
(cd "$stage" && pnpm install --prod --node-linker=hoisted --frozen-lockfile)
|
|
find "$stage" -type l -delete
|
|
|
|
mkdir -p "$OUT_DIR"
|
|
archive="$OUT_DIR/tallynote-${VERSION}-linux-${ARCH}-${LIBC}.tar.gz"
|
|
tar -C "$stage" -czf "$archive" --owner=0 --group=0 --numeric-owner .
|
|
|
|
# Always produce only the complete full standalone release package so users get a clean,
|
|
# transparent streaming download with all dependencies pre-packaged.
|
|
# Keep the sidecar useful when a caller builds more than one architecture into
|
|
# the same directory. The publishing script recomputes this list immediately
|
|
# before signing, so stale or hand-edited entries can never reach a Release.
|
|
(cd "$OUT_DIR" && sha256sum ./*.tar.gz | sed 's#^\./##' | LC_ALL=C sort > SHA256SUMS)
|
|
printf 'built %s\n' "$archive"
|