build(release): add make_release.sh + export-ignore for clean tarballs (phase A)

scripts/release/make_release.sh builds a versioned, checksum-verified release
artifact from the committed tree via 'git archive' — the basis for installing
LibrePortal without git/auth. Output lands in dist/<channel>/ laid out as the
hosting will serve it (libreportal-<ver>.tar.gz + .sha256 + latest.json), so it
can be served locally for testing via LP_RELEASE_BASE_URL.

.gitattributes marks dev-only trees export-ignore (scripts/unused, scripts/release,
site, .claude, CONTRIBUTING.md, the git meta files) so they never ship; validated
the archive includes init.sh/start.sh/scripts/configs/containers/VERSION and
excludes all of the above. dist/ gitignored.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
This commit is contained in:
librelad 2026-05-25 18:00:11 +01:00
parent 295ca2a9b4
commit 2ce0d22954
3 changed files with 65 additions and 0 deletions

10
.gitattributes vendored Normal file
View File

@ -0,0 +1,10 @@
# Paths excluded from release tarballs. `git archive` (used by
# scripts/release/make_release.sh) honours `export-ignore`, so these dev-only
# trees never ship in libreportal-<ver>.tar.gz.
scripts/unused export-ignore
scripts/release export-ignore
site export-ignore
.claude export-ignore
.gitignore export-ignore
.gitattributes export-ignore
CONTRIBUTING.md export-ignore

3
.gitignore vendored
View File

@ -10,3 +10,6 @@
# Node dependencies — installed via `npm ci` at image build, never vendored.
node_modules/
npm-debug.log*
# Release build output (scripts/release/make_release.sh).
/dist/

View File

@ -0,0 +1,52 @@
#!/bin/bash
#
# Build a versioned, checksum-verified LibrePortal release artifact.
#
# The stable install fetches a release tarball over plain HTTPS (no git, no auth),
# so it's reproducible and version-pinned. This builds that artifact from the
# COMMITTED tree via `git archive`, which honours the `export-ignore` rules in
# .gitattributes — so dev-only trees (scripts/unused, site, .claude, …) never ship.
#
# No infrastructure needed: output lands in dist/<channel>/ laid out exactly like
# the hosting will serve it, so you can point an install at it with:
# ( cd dist && python3 -m http.server 8000 )
# LP_RELEASE_BASE_URL=http://localhost:8000 ./install.sh ...
#
# Usage: scripts/release/make_release.sh [channel] [git-ref]
# channel stable (default) | edge
# git-ref HEAD (default) | a tag/commit to build from
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$REPO_ROOT"
CHANNEL="${1:-stable}"
REF="${2:-HEAD}"
VERSION="$(tr -d ' \t\n\r' < VERSION 2>/dev/null || true)"
[[ -n "$VERSION" ]] || { echo "make_release: VERSION file is empty or missing" >&2; exit 1; }
TARBALL="libreportal-${VERSION}.tar.gz"
PREFIX="libreportal-${VERSION}/" # top-level dir inside the tarball
OUT="$REPO_ROOT/dist/$CHANNEL"
mkdir -p "$OUT"
echo "Building $TARBALL (channel=$CHANNEL, ref=$REF) ..."
git archive --format=tar.gz --prefix="$PREFIX" -o "$OUT/$TARBALL" "$REF"
( cd "$OUT" && sha256sum "$TARBALL" > "$TARBALL.sha256" )
SHA="$(cut -d' ' -f1 < "$OUT/$TARBALL.sha256")"
cat > "$OUT/latest.json" <<EOF
{
"version": "$VERSION",
"channel": "$CHANNEL",
"url": "$TARBALL",
"sha256": "$SHA",
"notes": ""
}
EOF
echo "$OUT/$TARBALL"
echo "$OUT/$TARBALL.sha256 ($SHA)"
echo "$OUT/latest.json"