Test / test (push) Successful in 49s
Forty releases carried only a version bump in their commit, so what changed lived in the commits between them and in the content repos' pin bumps. The changelog is reconstructed from that history, newest first, with an Unreleased section on top and a table of which version each of the four sites runs. The publish workflow now posts the tag's section as the Gitea release notes, and the README says to move the Unreleased lines under a version heading before cutting. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L4jrCgLiKKHAEFuZUJjckH
105 lines
5.2 KiB
YAML
105 lines
5.2 KiB
YAML
name: Publish release
|
|
|
|
# Portal does not deploy itself. Cutting a version is deliberate:
|
|
# `cargo release <level>` bumps Cargo.toml, commits, tags v<semver>,
|
|
# and pushes; this workflow reacts to the tag and publishes the
|
|
# artifact as a Gitea release. Each content repo (uhhm/questions,
|
|
# redoal/questions) pins PORTAL_RELEASE to one of these tags in its
|
|
# own deploy workflow - bumping the pin there is what rolls a version
|
|
# out to a site. Plain main pushes only run test.yml.
|
|
|
|
on:
|
|
push:
|
|
tags: ["v*"]
|
|
|
|
jobs:
|
|
publish:
|
|
runs-on: bare
|
|
env:
|
|
# The bare runner's own systemd service intentionally has a minimal
|
|
# PATH/HOME (no rustup default toolchain in reach) - point it at the
|
|
# shared toolchain install directly rather than assuming an ambient
|
|
# dev shell environment.
|
|
CARGO_HOME: /var/local/cargo
|
|
RUSTUP_HOME: /var/local/rustup
|
|
PATH: /var/local/cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/bin
|
|
# Shared with interactive dev builds (see ~/.config/fish/config.fish)
|
|
# so a crate compiled once, by either a manual build or CI, is
|
|
# cached for the other - real cache hits, not just a warm toolchain.
|
|
# SCCACHE_SERVER_PORT deliberately differs from the interactive
|
|
# dev shell's (4227): sccache's server is discovered by a fixed
|
|
# TCP port shared by every local user, so if both contexts used
|
|
# the same port, whichever one's server happened to be running
|
|
# would silently "win" and serve build requests it doesn't have
|
|
# filesystem permission for. Separate ports keep each context's
|
|
# own server answering its own requests; the cache directory
|
|
# (not the server process) is what's actually shared.
|
|
SCCACHE_DIR: /var/local/sccache
|
|
SCCACHE_SERVER_PORT: "4228"
|
|
CARGO_TARGET_DIR: /var/local/cargo-target
|
|
# cargo-leptos's own downloaded tools (wasm-bindgen, wasm-opt) cache
|
|
# under $XDG_CACHE_HOME - left at its default that resolves inside
|
|
# this unit's systemd StateDirectory, files it creates there end up
|
|
# owned by the kernel's overflow "nobody" uid instead of the
|
|
# runner's own dynamic uid (a StateDirectory quirk, not something
|
|
# in our control), so a later run can't execute what an earlier run
|
|
# downloaded. Redirecting it to our own known-good shared dir avoids
|
|
# that entirely.
|
|
XDG_CACHE_HOME: /var/local/leptos-cache
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
# SITE_NAME is read via option_env! (src/app.rs) - compile-time,
|
|
# not a runtime env var. It is only the last-resort fallback name:
|
|
# each instance's site.yaml (content-driven branding) overrides it,
|
|
# so one artifact serves every site.
|
|
- name: Build
|
|
run: SITE_NAME=${{ vars.PORTAL_SITE_NAME }} cargo leptos build --release
|
|
|
|
# cargo-leptos only builds the leptos bin-target ("portal") - the
|
|
# question-lint utility binary needs its own plain cargo build.
|
|
- name: Build question-lint
|
|
run: cargo build --release --bin question_lint --features ssr
|
|
|
|
- name: Package
|
|
run: |
|
|
set -euo pipefail
|
|
tag="${{ github.ref_name }}"
|
|
stage=$(mktemp -d)
|
|
cp "$CARGO_TARGET_DIR/release/portal" "$stage/portal"
|
|
cp "$CARGO_TARGET_DIR/release/question_lint" "$stage/question_lint"
|
|
# hash-files = true: leptos resolves hash.txt next to the running
|
|
# binary, so it ships beside portal in the release dir.
|
|
cp "$CARGO_TARGET_DIR/release/hash.txt" "$stage/hash.txt"
|
|
# site-root ("target/site" in Cargo.toml) is project-relative,
|
|
# not affected by CARGO_TARGET_DIR - only the plain `cargo build`
|
|
# outputs (release/, front/) move with that override.
|
|
cp -r target/site "$stage/site"
|
|
tar -C "$stage" -czf "portal-$tag.tar.gz" portal question_lint hash.txt site
|
|
rm -rf "$stage"
|
|
|
|
# The run's own ephemeral token has write access to this repo -
|
|
# no long-lived PAT to manage. The tag already exists (cargo
|
|
# release pushed it), so the release attaches to it; a re-run
|
|
# finds the existing release instead of failing.
|
|
- name: Publish release
|
|
run: |
|
|
set -euo pipefail
|
|
tag="${{ github.ref_name }}"
|
|
api="${{ github.server_url }}/api/v1/repos/${{ github.repository }}"
|
|
auth="Authorization: token ${{ secrets.GITHUB_TOKEN }}"
|
|
# The release notes are this version's section of CHANGELOG.md.
|
|
notes=$(awk -v v="${tag#v}" '/^## /{p = ($2 == v)} p' CHANGELOG.md | tail -n +2)
|
|
body=$(jq -n --arg tag "$tag" --arg notes "$notes" '{tag_name: $tag, name: $tag, body: $notes}')
|
|
id=$(curl -sf -X POST -H "$auth" -H 'Content-Type: application/json' \
|
|
-d "$body" "$api/releases" | jq .id) \
|
|
|| id=$(curl -sf -H "$auth" "$api/releases/tags/$tag" | jq .id)
|
|
# Replace the asset if a re-run already uploaded one.
|
|
for aid in $(curl -sf -H "$auth" "$api/releases/$id/assets" | jq '.[].id'); do
|
|
curl -sf -X DELETE -H "$auth" "$api/releases/$id/assets/$aid"
|
|
done
|
|
curl -sf -X POST -H "$auth" \
|
|
-F "attachment=@portal-$tag.tar.gz" \
|
|
"$api/releases/$id/assets?name=portal-$tag.tar.gz" > /dev/null
|
|
echo "published $tag"
|