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: /work 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 # The build step's `docker run` talks to the runner's docker daemon, not to # this job container, so the two only share files through a Docker volume. # Without it the scripts prepared here never reach the build and the # tarball the build writes is invisible to the publish steps. Named volumes # rather than host paths: the runner does not expand ${{ vars }} in # container.volumes, and a host path would put runner internals in the repo. container: image: docker.gitea.com/runner-images:ubuntu-latest volumes: - jasp-build:/work 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 volume mount point, 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 jasp-build:/work \ -v 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