Files
jasp-desktop-bin/.gitea/workflows/build.yml
T
agw e8c3d775aa Run the scheduled build in the evening
The AUR push is made under the maintainer's name and should land in the
evening rather than during working hours. At 16:00 UTC a two-hour build
publishes around 19:00-20:30 local time.

Claude-Session: https://claude.ai/code/session_01GGe7kUhooMFuzY6GaDb2w9
2026-09-30 22:15:00 +02:00

190 lines
6.6 KiB
YAML

name: Build JASP binary and publish to AUR
# JASP publishes no Linux binary of its own, so this builds one on Arch and
# ships it as jasp-desktop-bin. Because JASP links against the system R and Qt6,
# a rebuild is needed both when JASP releases and when Arch bumps R or Qt6 —
# check-upstream.py decides which.
on:
schedule:
# 16:00 UTC is 18:00 CEST / 17:00 CET. A full build takes a little over two
# hours, so the AUR push (made under the maintainer's name) and the
# state.json commit land on an evening, not in working hours.
- cron: '0 16 * * *'
workflow_dispatch:
inputs:
jasp_tag:
description: 'Specific JASP tag to build (blank = latest release)'
required: false
default: ''
force:
description: 'Build even if nothing changed'
type: boolean
default: false
concurrency:
group: jasp-build
cancel-in-progress: false
# Nothing leaves the runner unless the repo variable PUBLISH is 'true'. Without
# it a run builds, verifies and generates the PKGBUILD, and leaves the tarball
# in ${WORK_DIR}/out for inspection: a dry run that cannot touch the tarball
# host, state.json or the AUR.
env:
AUR_MAINTAINER: ${{ vars.AUR_MAINTAINER }}
TARBALL_HOST: ${{ vars.TARBALL_HOST }}
TARBALL_PATH: ${{ vars.TARBALL_PATH }}
TARBALL_BASE_URL: ${{ vars.TARBALL_BASE_URL }}
WORK_DIR: /srv/jasp-build
jobs:
check:
runs-on: ubuntu-latest
outputs:
needs_build: ${{ steps.decide.outputs.needs_build }}
jasp_tag: ${{ steps.decide.outputs.jasp_tag }}
reasons: ${{ steps.decide.outputs.reasons }}
steps:
- uses: actions/checkout@v4
- name: Decide whether a rebuild is needed
id: decide
env:
JASP_TAG: ${{ inputs.jasp_tag }}
FORCE_BUILD: ${{ inputs.force }}
run: python3 scripts/check-upstream.py
build:
needs: check
if: needs.check.outputs.needs_build == 'true'
runs-on: ubuntu-latest
# The R module tree is several hundred packages compiled from source; the
# full build runs for hours. The act_runner timeout and Gitea's
# ENDLESS_TASK_TIMEOUT must both allow for this (see README).
timeout-minutes: 900
# `docker run -v ${WORK_DIR}:/work` below talks to the runner host's docker,
# so it mounts the *host's* WORK_DIR. Without this bind the job container
# has its own private copy: the scripts it prepares never reach the build
# (which then ran a stale script left on the host) and the tarball the
# build writes is invisible to the publish steps.
container:
image: docker.gitea.com/runner-images:ubuntu-latest
volumes:
- /srv/jasp-build:/srv/jasp-build
steps:
- uses: actions/checkout@v4
- name: Report plan
run: |
echo "Building JASP ${{ needs.check.outputs.jasp_tag }}"
echo "Reasons: ${{ needs.check.outputs.reasons }}"
- name: Prepare work directory
run: |
# WORK_DIR is a bind mount now, so empty it rather than removing it.
sudo find "${WORK_DIR}" -mindepth 1 -delete
sudo mkdir -p "${WORK_DIR}/out"
sudo cp -a build packaging scripts "${WORK_DIR}/"
df -h /
- name: Build JASP in an Arch container
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
run: |
docker rm -f jasp-build 2>/dev/null || true
docker run --rm --name jasp-build \
-v "${WORK_DIR}:/work" \
-v /srv/jasp-cache:/cache \
-e JASP_TAG="${{ needs.check.outputs.jasp_tag }}" \
-e OUT_DIR=/work/out \
-e JOBS=5 \
-e GITHUB_PAT="${GH_TOKEN}" \
archlinux:base-devel \
bash /work/build/build-jasp.sh
- name: Show build result
run: |
cat "${WORK_DIR}/out/build-info.json"
ls -lh "${WORK_DIR}/out/"
- name: Generate PKGBUILD
run: |
sudo cp "${WORK_DIR}/out/build-info.json" .
python3 scripts/gen-pkgbuild.py \
--build-info build-info.json \
--template packaging/PKGBUILD.in \
--out PKGBUILD \
--base-url "${TARBALL_BASE_URL}" \
--maintainer "${AUR_MAINTAINER}"
cat PKGBUILD
# Must run before the AUR push: the PKGBUILD's sha256sum refers to this
# file, so publishing the package before the tarball exists would leave
# users with a 404.
- name: Publish tarball to asger.weirsoe.dk
if: vars.PUBLISH == 'true'
env:
TARBALL_SSH_KEY: ${{ secrets.TARBALL_SSH_KEY }}
run: |
ASSET="$(python3 -c 'import json;print(json.load(open("release-meta.json"))["tarball"])')"
bash scripts/publish-tarball.sh "${WORK_DIR}/out/${ASSET}"
- name: Verify the published URL actually serves the tarball
if: vars.PUBLISH == 'true'
run: |
URL="$(python3 -c 'import json;print(json.load(open("release-meta.json"))["download_url"])')"
WANT="$(python3 -c 'import json;print(json.load(open("release-meta.json"))["sha256"])')"
echo "checking $URL"
GOT="$(curl -fsSL --retry 3 "$URL" | sha256sum | awk '{print $1}')"
if [ "$GOT" != "$WANT" ]; then
echo "error: what the public URL serves does not match the PKGBUILD sha256" >&2
echo " want $WANT" >&2
echo " got $GOT" >&2
exit 1
fi
echo "public URL serves the expected bytes"
# Only the PKGBUILD and metadata cross the job boundary — the tarball
# itself already lives on GitHub Releases.
- name: Hand PKGBUILD to the AUR job
if: vars.PUBLISH == 'true'
uses: actions/upload-artifact@v3
with:
name: aur-package
path: |
PKGBUILD
release-meta.json
- name: Record built state
if: vars.PUBLISH == 'true'
env:
STATE_PUSH_TOKEN: ${{ secrets.STATE_PUSH_TOKEN }}
run: bash scripts/record-state.sh
- name: Clean up build tree
if: always()
run: |
sudo rm -rf "${WORK_DIR}/jasp-desktop" "${WORK_DIR}/build" "${WORK_DIR}/stage" || true
df -h /
aur:
needs: [check, build]
if: vars.PUBLISH == 'true'
runs-on: ubuntu-latest
container:
image: archlinux:base-devel
steps:
- name: Install base tools
run: pacman -Syu --noconfirm git openssh pacman-contrib nodejs sudo
- uses: actions/checkout@v4
- uses: actions/download-artifact@v3
with:
name: aur-package
- name: Push to AUR
env:
AUR_SSH_PRIVATE_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
run: bash scripts/push-aur.sh PKGBUILD