Build Pacman Repo #427
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --- | |
| name: Build Pacman Repo | |
| on: | |
| push: | |
| branches: ["main"] | |
| pull_request: | |
| branches: ["main"] | |
| schedule: | |
| - cron: "0 0 * * *" | |
| # On demand: needed after changing the signing secrets, or to re-attempt a | |
| # package that failed under allow-failure, without waiting for the cron or | |
| # inventing a commit. | |
| workflow_dispatch: | |
| permissions: | |
| contents: write | |
| concurrency: | |
| group: "${{ github.workflow }}-${{ github.ref }}" | |
| # Only cancel on pull requests, where the branch churns and a superseded run | |
| # is genuinely worthless. On main this build runs for hours, and cancelling it | |
| # throws away every package it had already compiled -- a commit touching a | |
| # workflow this job does not even read was enough to destroy a run 30 minutes | |
| # in. Queue behind the running build instead. | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| env: | |
| REPO_NAME: custom | |
| RELEASE_TAG: custom-repo | |
| GH_REPO: ${{ github.repository }} | |
| jobs: | |
| build-pacman-repo: | |
| runs-on: ubuntu-latest | |
| # Bound the run. With 70 members, one package that hangs or grinds would | |
| # otherwise consume the 6 hour default and block the nightly build behind | |
| # it. allow-failure contains a build that fails; it cannot contain one that | |
| # never finishes. | |
| timeout-minutes: 300 | |
| environment: ${{ github.ref == 'refs/heads/main' && 'prod' || '' }} | |
| steps: | |
| - name: Free Disk Space (Ubuntu) | |
| uses: BRAINSia/free-disk-space@v2 | |
| with: | |
| # this might remove tools that are actually needed, | |
| # if set to "true" but frees about 6 GB | |
| tool-cache: false | |
| # all of these default to true, but feel free to set to | |
| # "false" if necessary for your workflow | |
| mandb: true | |
| android: true | |
| dotnet: true | |
| haskell: true | |
| large-packages: true | |
| docker-images: true | |
| # Keep the runner's 4 GB swapfile. Reclaiming it buys a little disk | |
| # but removes the headroom that large C++ builds rely on, and this | |
| # repo's builds were being OOM-killed rather than running out of disk. | |
| swap-storage: false | |
| - name: Checkout Pacman Repo Builder | |
| uses: actions/checkout@v7 | |
| with: | |
| repository: pacman-repo-builder/pacman-repo-builder | |
| path: pacman-repo-builder | |
| - name: Checkout yay | |
| uses: nick-fields/retry@v4 | |
| with: | |
| timeout_minutes: 10 | |
| max_attempts: 3 | |
| retry_wait_seconds: 10 | |
| command: | | |
| git clone https://aur.archlinux.org/yay.git yay | |
| - name: Checkout this repo | |
| uses: actions/checkout@v7 | |
| with: | |
| path: repo | |
| submodules: recursive | |
| - name: Seed the repository state from the release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| set -euo pipefail | |
| mkdir -p repo-out | |
| # Stamp the moment before reading the database. Anything uploaded to | |
| # the release after this is not represented in what we are about to | |
| # publish, so the prune must leave it alone -- heavy-build spends | |
| # hours with packages uploaded and not yet in the database. | |
| echo "SEED_TIME=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_ENV" | |
| # Only the database. build-pacman-repo works out what is outdated from | |
| # it, and repo-add keeps the entries of packages that are not present | |
| # locally, so there is no reason to pull down gigabytes of packages | |
| # that are already published and current. | |
| if gh release view "$RELEASE_TAG" >/dev/null 2>&1; then | |
| for f in "${REPO_NAME}.db.tar.gz" "${REPO_NAME}.files.tar.gz"; do | |
| gh release download "$RELEASE_TAG" --pattern "$f" --dir repo-out --clobber \ | |
| || echo "::warning::no $f published yet" | |
| done | |
| else | |
| echo "Release $RELEASE_TAG does not exist yet; starting from empty." | |
| gh release create "$RELEASE_TAG" --title "custom pacman repo" \ | |
| --notes-file repo/.github/release-notes/custom.md | |
| fi | |
| ls -l repo-out/ || true | |
| - name: Run build in Arch Linux container | |
| env: | |
| GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }} | |
| GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} | |
| run: | | |
| # -e VAR with no value forwards it from the runner environment, so the | |
| # key never appears on the command line where `ps` could read it. | |
| docker run --rm \ | |
| -v "${{ github.workspace }}:/workspace" \ | |
| -e GITHUB_WORKSPACE=/workspace \ | |
| -e GITHUB_OUTPUT=/workspace/.github-output \ | |
| -e GPG_SIGNING_KEY \ | |
| -e GPG_PASSPHRASE \ | |
| -e REPO_NAME \ | |
| -w /workspace \ | |
| archlinux:base-devel \ | |
| bash /workspace/repo/build-inside-container.sh | |
| - name: Re-index anything published while this build ran | |
| if: github.ref == 'refs/heads/main' | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }} | |
| GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} | |
| run: | | |
| set -euo pipefail | |
| # Compare against the release's assets, not against the published | |
| # database. heavy-build publishes into the same release and indexes | |
| # only when its whole matrix finishes, so anything it added while this | |
| # build ran is missing from the copy about to be written -- and once | |
| # one build-repo run has written a database without it, the published | |
| # copy no longer names it either. At that point only the assets still | |
| # say the package exists. | |
| out=$(bash repo/.github/scripts/reindex-orphans.sh \ | |
| repo-out "$REPO_NAME" "$RELEASE_TAG" | tee /dev/stderr) || exit 1 | |
| if grep -q '^REINDEXED=1$' <<<"$out"; then | |
| # The database changed after the container signed it, so the old | |
| # signature no longer matches -- and pacman rejects a bad database | |
| # signature far more harshly than a missing one. | |
| echo "Database changed; re-signing." | |
| rm -f repo-out/"${REPO_NAME}".db.sig repo-out/"${REPO_NAME}".files.sig \ | |
| repo-out/"${REPO_NAME}".db.tar.gz.sig repo-out/"${REPO_NAME}".files.tar.gz.sig | |
| bash repo/.github/scripts/sign-pacman-repo.sh repo-out "$REPO_NAME" | |
| fi | |
| - name: Publish to the release | |
| if: github.ref == 'refs/heads/main' | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: bash repo/.github/scripts/publish-release-repo.sh repo-out "$REPO_NAME" "$RELEASE_TAG" | |
| - name: Summary | |
| if: always() | |
| run: | | |
| { | |
| echo "### [custom]" | |
| echo | |
| echo '```' | |
| ls -lh repo-out/*.pkg.tar.zst 2>/dev/null | awk '{print $9, $5}' || echo "(none built)" | |
| echo '```' | |
| } >> "$GITHUB_STEP_SUMMARY" |