furtka/scripts/publish-release.sh
Daniel Maksymilian Syrnicki 0cad2e05c8 feat(website): download page for the ISO, homepage with download CTA and 3-step how-it-works
- /download/ and /de/download/: big download button, file name, size and
  release date, requirements (64-bit PC, UEFI or BIOS, >=16 GB disk that
  gets erased, USB stick, network cable with internet, second device),
  five install steps (Etcher / Rufus DD mode / dd, boot menu, Secure Boot
  off, proksi.local:5000, wizard, pull stick), checksum + verify commands
  when the release has one, alpha notice, link to all releases
- the release data comes from the Forgejo API at build time
  (partials/release.html): newest release with an .iso asset, falling back
  to params.version if the lookup fails; getresource cache disabled so a
  build never pins an old release
- homepage: status chip follows the latest release, 'Download ISO' primary
  CTA + 'Source code' ghost CTA, numbered how-it-works cards, download band
  before the closer
- releases now upload furtka-<ver>.iso.sha256, and release.yml rebuilds the
  site after publishing so the download page follows each release

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wq1hzUp4ZmCKHDuLKCnu73
2026-09-28 14:52:59 +02:00

127 lines
4.3 KiB
Bash
Executable file

#!/usr/bin/env bash
# Publish a Furtka release to the Forgejo releases page.
#
# Usage: ./scripts/publish-release.sh <version>
#
# Preconditions:
# - $FORGEJO_TOKEN set (PAT with write:repository)
# - dist/furtka-<version>.tar.gz + .sha256 + release.json already built
#
# Behaviour:
# 1. Read the [<version>] section from CHANGELOG.md for the release body.
# 2. Create a release on Forgejo (or fail if one already exists for the tag).
# 3. Upload the three assets sequentially (Forgejo's release API has been
# observed to choke on parallel uploads).
set -euo pipefail
VERSION="${1:?usage: $0 <version>}"
: "${FORGEJO_TOKEN:?FORGEJO_TOKEN must be set}"
HOST="${FORGEJO_HOST:-forgejo.sourcegate.online}"
REPO="${FORGEJO_REPO:-daniel/furtka}"
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
DIST_DIR="$REPO_ROOT/dist"
TARBALL="$DIST_DIR/furtka-$VERSION.tar.gz"
SHA_FILE="$TARBALL.sha256"
RELEASE_JSON="$DIST_DIR/release.json"
for f in "$TARBALL" "$SHA_FILE" "$RELEASE_JSON"; do
[ -f "$f" ] || { echo "missing: $f"; exit 1; }
done
# Extract the changelog section for this version. Matches `## [<version>]`
# up to (but not including) the next `## [` line.
BODY="$(awk -v v="$VERSION" '
BEGIN { inside=0 }
/^## \[/ {
if (inside) exit
if (index($0, "[" v "]") > 0) { inside=1; next }
}
inside { print }
' "$REPO_ROOT/CHANGELOG.md")"
if [ -z "$BODY" ]; then
BODY="Release $VERSION"
fi
PRERELEASE=false
if [[ "$VERSION" == *-alpha* || "$VERSION" == *-beta* || "$VERSION" == *-rc* ]]; then
PRERELEASE=true
fi
api() {
curl --silent --show-error --fail-with-body \
--header "Authorization: token $FORGEJO_TOKEN" \
"$@"
}
base="https://$HOST/api/v1/repos/$REPO"
# 1. Create the release. Python for JSON assembly so we don't depend on jq
# on the runner — the previous `apt-get install -y jq` step in release.yml
# hung for 15+ minutes on a slow mirror and stalled the whole publish.
release_body_json="$(
VERSION="$VERSION" BODY="$BODY" PRE="$PRERELEASE" python3 -c '
import json, os
print(json.dumps({
"tag_name": os.environ["VERSION"],
"name": os.environ["VERSION"],
"body": os.environ["BODY"],
"prerelease": os.environ["PRE"] == "true",
}))
'
)"
echo "==> Creating release $VERSION"
release_response="$(api --request POST "$base/releases" \
--header "Content-Type: application/json" \
--data "$release_body_json")"
release_id="$(echo "$release_response" | python3 -c 'import json, sys; print(json.load(sys.stdin).get("id", ""))')"
if [ -z "$release_id" ] || [ "$release_id" = "null" ]; then
echo "error: couldn't parse release id from response:"
echo "$release_response"
exit 1
fi
echo " release id: $release_id"
# 2. Upload assets — one at a time.
upload_asset() {
local path="$1"
local name
name="$(basename "$path")"
echo "==> Uploading $name"
api --request POST "$base/releases/$release_id/assets?name=$name" \
--form "attachment=@$path" > /dev/null
}
upload_asset "$TARBALL"
upload_asset "$SHA_FILE"
upload_asset "$RELEASE_JSON"
# Optional: attach the live-installer ISO when dist/furtka-<version>.iso
# exists. Release workflows that want this build the ISO via iso/build.sh
# and move the output here before calling publish-release. Local runs
# that skip the ISO step still publish the core release successfully.
#
# Soft-fail: the ISO is ~1 GB and Forgejo's reverse proxy has returned
# 504 on the upload even when the write eventually succeeds. The core
# tarball (which boxes need for self-update) is already uploaded above,
# so don't let an ISO transport hiccup fail the whole release.
ISO="$DIST_DIR/furtka-$VERSION.iso"
if [ -f "$ISO" ]; then
if ! upload_asset "$ISO"; then
echo "warning: ISO upload failed — release published without ISO asset" >&2
fi
# Checksum sidecar for the download page on furtka.org (and anyone
# verifying by hand). Uploaded even when the ISO upload reported a
# failure — a 504 there often still lands the file. Written from inside
# dist/ so the line carries the bare filename `sha256sum -c` expects.
ISO_SHA="$ISO.sha256"
(cd "$DIST_DIR" && sha256sum "$(basename "$ISO")" > "$(basename "$ISO_SHA")")
if ! upload_asset "$ISO_SHA"; then
echo "warning: ISO checksum upload failed" >&2
fi
fi
echo "Release $VERSION published: https://$HOST/$REPO/releases/tag/$VERSION"