carrier/.forgejo/workflows/release.yml

230 lines
8.8 KiB
YAML
Raw Normal View History

name: Release
on:
push:
tags: ["v*"]
jobs:
macos:
runs-on: macos-arm64
steps:
- uses: https://code.forgejo.org/actions/checkout@v4
with:
path: carrier
- uses: https://code.forgejo.org/actions/checkout@v4
with:
repository: randogoth/fumi
ref: main
path: fumi
- uses: https://code.forgejo.org/actions/cache@v4
with:
path: |
~/.cargo/registry
carrier/target
fumi/target
key: cargo-macos-${{ hashFiles('carrier/Cargo.lock') }}
restore-keys: cargo-macos-
- run: devbox run build
working-directory: carrier
env:
GITHUB_TOKEN: ""
- run: mv target/release/carrier target/release/carrier-macos-arm64
working-directory: carrier
# This runner is a laptop that's frequently asleep/offline, so this
# job must not gate the release (and must not be gated by it either).
# Instead of going through actions/forgejo-release - which only knows
# how to blind-create a release, not append to one that may already
# exist - this polls for the release the linux+flatpak job creates
# and appends its own asset directly via the Forgejo API, landing
# next to whatever binaries are already there. grep (not jq, whose
# presence here isn't guaranteed) is safe for pulling the id out: per
# Forgejo's structs.Release, ID is the first declared field and Go's
# encoding/json marshals in declaration order, ahead of the nested
# per-asset "id" fields in the "assets" array.
- run: |
REPO="${{ forge.repository }}"
TAG="${{ forge.ref_name }}"
FORGEJO="${{ env.FORGEJO_SERVER_URL }}"
FORGEJO="${FORGEJO%%/}"
TOKEN="${{ forge.token }}"
FILE="target/release/carrier-macos-arm64"
NAME="carrier-macos-arm64"
release_id=""
for i in $(seq 1 40); do
body=$(curl --retry 5 -sS -H "Authorization: token $TOKEN" "$FORGEJO/api/v1/repos/$REPO/releases/tags/$TAG")
release_id=$(echo "$body" | grep -o '"id":[0-9]*' | head -1 | grep -o '[0-9]*')
if [ -n "$release_id" ]; then
break
fi
echo "release for $TAG not ready yet, waiting 15s ($i/40)"
sleep 15
done
if [ -z "$release_id" ]; then
echo "release for $TAG never appeared after 10 minutes" >&2
exit 1
fi
curl --retry 5 --fail -sS -X POST \
-H "Authorization: token $TOKEN" \
-H "Content-Type: multipart/form-data" \
-F "attachment=@$FILE" \
"$FORGEJO/api/v1/repos/$REPO/releases/$release_id/assets?name=$NAME"
working-directory: carrier
# Same non-gating strategy as the macos job above: this runner is a
# desktop machine that isn't guaranteed to be on when a tag is pushed,
# so it must never gate the release (and must not be gated by it
# either). It builds and bundles via windows/bundle.sh - the same
# script windows/setup.sh runs for local one-command builds - wraps
# the bundle in an Inno Setup installer (windows/installer.sh; Inno
# lives in this runner host's user profile), then appends both the
# portable zip and the setup.exe to the release the linux+flatpak jobs
# create, with the same poll-for-the-release the macos job does.
windows:
runs-on: windows-x86_64
steps:
- uses: https://code.forgejo.org/actions/checkout@v4
with:
path: carrier
- uses: https://code.forgejo.org/actions/checkout@v4
with:
repository: randogoth/fumi
ref: main
path: fumi
- uses: https://code.forgejo.org/actions/cache@v4
with:
path: |
~/.cargo/registry
carrier/target
fumi/target
key: cargo-windows-${{ hashFiles('carrier/Cargo.lock') }}
restore-keys: cargo-windows-
- run: bash windows/bundle.sh
working-directory: carrier
shell: bash
- run: bash windows/installer.sh
working-directory: carrier
shell: bash
- run: |
REPO="${{ forge.repository }}"
TAG="${{ forge.ref_name }}"
FORGEJO="${{ env.FORGEJO_SERVER_URL }}"
FORGEJO="${FORGEJO%%/}"
TOKEN="${{ forge.token }}"
VERSION=$(sed -n 's/^version = "\(.*\)"$/\1/p' Cargo.toml | head -1)
FILES="carrier-windows-$VERSION.zip carrier-windows-$VERSION-setup.exe"
release_id=""
for i in $(seq 1 40); do
body=$(curl --retry 5 -sS -H "Authorization: token $TOKEN" "$FORGEJO/api/v1/repos/$REPO/releases/tags/$TAG")
release_id=$(echo "$body" | grep -o '"id":[0-9]*' | head -1 | grep -o '[0-9]*')
if [ -n "$release_id" ]; then
break
fi
echo "release for $TAG not ready yet, waiting 15s ($i/40)"
sleep 15
done
if [ -z "$release_id" ]; then
echo "release for $TAG never appeared after 10 minutes" >&2
exit 1
fi
for FILE in $FILES; do
curl --retry 5 --fail -sS -X POST \
-H "Authorization: token $TOKEN" \
-H "Content-Type: multipart/form-data" \
-F "attachment=@$FILE" \
"$FORGEJO/api/v1/repos/$REPO/releases/$release_id/assets?name=$FILE"
done
working-directory: carrier
shell: bash
linux:
runs-on: linux-x86_64
steps:
- uses: https://code.forgejo.org/actions/checkout@v4
with:
path: carrier
- uses: https://code.forgejo.org/actions/checkout@v4
with:
repository: randogoth/fumi
ref: main
path: fumi
- uses: https://code.forgejo.org/actions/cache@v4
with:
path: |
~/.cargo/registry
carrier/target
fumi/target
key: cargo-linux-${{ hashFiles('carrier/Cargo.lock') }}
restore-keys: cargo-linux-
- run: devbox run build
working-directory: carrier
env:
GITHUB_TOKEN: ""
- run: mv target/release/carrier target/release/carrier-linux-x86_64
working-directory: carrier
- uses: https://code.forgejo.org/forgejo/upload-artifact@v5
with:
name: carrier-linux-x86_64
path: carrier/target/release/carrier-linux-x86_64
# Builds from source inside flatpak-builder's own sandbox, via the
# rust-stable SDK extension (same as com.randogoth.carrier.json already
# does for local `devbox run package`). Reusing the linux job's binary
# was tried and reverted: that binary is dynamically linked against ~100
# libraries at absolute /nix/store paths, including its own ELF
# interpreter - none of which exist inside the Flatpak sandbox, so it
# can never execute there regardless of how it's packaged in.
flatpak:
runs-on: linux-x86_64
steps:
- uses: https://code.forgejo.org/actions/checkout@v4
with:
path: carrier
- uses: https://code.forgejo.org/actions/checkout@v4
with:
repository: randogoth/fumi
ref: main
path: fumi
- run: devbox run bundle-flatpak
working-directory: carrier
env:
GITHUB_TOKEN: ""
- uses: https://code.forgejo.org/forgejo/upload-artifact@v5
with:
name: carrier-x86_64.flatpak
path: carrier/carrier-x86_64.flatpak
# forgejo-release.sh (the engine behind actions/forgejo-release) always
# does a blind create-then-upload of the release for the tag, with no
# check for one already existing - running it from two parallel jobs
# against the same tag either hard-fails the second create (override:
# false) or races a delete-and-recreate that can wipe out the first job's
# just-uploaded assets (override: true). So platform jobs only ever
# produce artifacts; exactly one job, gated on both finishing, does the
# single release create + upload. macos is deliberately left out of
# needs (see that job): re-running this job after macos has appended its
# asset will wipe that asset out via override - rerun macos again after
# to restore it.
release:
needs: [linux, flatpak]
runs-on: linux-x86_64
steps:
- uses: https://code.forgejo.org/forgejo/download-artifact@v7
with:
path: dist/release
merge-multiple: true
- uses: https://code.forgejo.org/actions/forgejo-release@v2.13.4
with:
direction: upload
release-dir: dist/release
# Safe here specifically because this is the only job that ever
# calls forgejo-release for a given tag: re-running this same job
# for the same tag (e.g. a manual rerun) replaces its release
# cleanly instead of failing on "already exists".
override: true