Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 85 additions & 28 deletions .github/workflows/check-updates.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,23 +40,24 @@ jobs:
fi
echo "ref=$ref" >>"$GITHUB_OUTPUT"

# Every step that executes a PKGBUILD from the AUR runs here, without
# secrets. Only the check step, which runs no PKGBUILD, gets the
# read-only token.
prepare:
# Runs the strategies with the read-only token and decides what the run
# does. No PKGBUILD runs here, so the jobs after it trust the statuses
# this job hands over.
check:
needs: image
runs-on: ubuntu-latest
container: ${{ needs.image.outputs.ref }}
timeout-minutes: 30
outputs:
work: ${{ steps.handoff.outputs.work }}
prepare: ${{ steps.decide.outputs.prepare }}
work: ${{ steps.decide.outputs.work }}

steps:
- name: Install dependencies
run: |
pacman-key --init
pacman -Sy --noconfirm --needed archlinux-keyring
pacman -Su --noconfirm --needed sudo git openssh namcap jq go-yq pacman-contrib
pacman -Su --noconfirm --needed sudo git go-yq
useradd -m builder

- name: Checkout
Expand All @@ -72,22 +73,71 @@ jobs:
chown -R builder:builder .
sudo --preserve-env=GITHUB_TOKEN -u builder ./scripts/check-all.sh

- name: Decide
id: decide
run: |
# prepare runs for an outdated package, publish also for a change
# in the status table
prepare=false
if grep -qsE '^(new_version|available_downgrade): ' .status/*; then
prepare=true
fi
sudo -u builder ./scripts/update-readme.sh
work=$prepare
git diff --quiet README.md || work=true
echo "prepare=$prepare" >>"$GITHUB_OUTPUT"
echo "work=$work" >>"$GITHUB_OUTPUT"

- name: Upload statuses
if: steps.decide.outputs.work == 'true'
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: checked
path: .status/
include-hidden-files: true
if-no-files-found: error
retention-days: 1

# Every step that executes a PKGBUILD from the AUR runs here, without
# secrets and without a token. Code from one PKGBUILD can write the files
# of every package here, so this job only hands over prepared files and
# update failures, and decides nothing.
prepare:
needs: [image, check]
if: needs.check.outputs.prepare == 'true'
runs-on: ubuntu-latest
container: ${{ needs.image.outputs.ref }}
timeout-minutes: 30

steps:
- name: Install dependencies
run: |
pacman-key --init
pacman -Sy --noconfirm --needed archlinux-keyring
pacman -Su --noconfirm --needed sudo git openssh namcap jq go-yq pacman-contrib
useradd -m builder

- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Download statuses
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
name: checked
path: .status

- name: Prepare updates
run: sudo -u builder ./scripts/check-all.sh --prepare handoff
shell: bash
run: |
chown -R builder:builder .
# Root prefixes every line, so no output of a PKGBUILD reaches
# the runner as a workflow command
sudo -u builder ./scripts/check-all.sh --prepare handoff 2>&1 | sed 's/^/| /'

- name: Hand over
id: handoff
run: |
# The workspace now belongs to code from PKGBUILDs, .git/config
# included, so only builder touches it. publish runs only for an
# update or a change in the status table.
work=$(sudo -u builder bash -c '
./scripts/update-readme.sh >&2
if [[ -n "$(ls -A handoff/prepared 2>/dev/null)" ]] || ! git diff --quiet README.md; then
echo true
fi
')

# A process started by a PKGBUILD can outlive its step. Stop all
# of them before root reads anything builder wrote.
pkill -KILL -u builder || true
Expand All @@ -110,12 +160,7 @@ jobs:
done
fi

if [[ "$work" == "true" ]]; then
echo "work=true" >>"$GITHUB_OUTPUT"
fi

- name: Upload handoff
if: steps.handoff.outputs.work == 'true'
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: handoff
Expand All @@ -131,7 +176,6 @@ jobs:
# stay out of the job with the keys.
verify:
needs: [image, prepare]
if: needs.prepare.outputs.work == 'true'
runs-on: ubuntu-latest
container: ${{ needs.image.outputs.ref }}
timeout-minutes: 30
Expand Down Expand Up @@ -166,11 +210,17 @@ jobs:
if-no-files-found: error
retention-days: 1

# Pushes what verify passed on. Nothing here executes a PKGBUILD:
# publish-pkg.sh checks the prepared files against the AUR copy.
# Pushes what verify passed on and records the statuses of the check job.
# Runs also when prepare is skipped, for a change in the status table.
# Nothing here executes a PKGBUILD: publish-pkg.sh checks the prepared
# files against the AUR copy.
publish:
needs: [image, prepare, verify]
if: needs.prepare.outputs.work == 'true'
needs: [image, check, prepare, verify]
if: >-
!cancelled() &&
needs.check.outputs.work == 'true' &&
contains(fromJSON('["success", "skipped"]'), needs.prepare.result) &&
contains(fromJSON('["success", "skipped"]'), needs.verify.result)
runs-on: ubuntu-latest
container: ${{ needs.image.outputs.ref }}
timeout-minutes: 30
Expand All @@ -191,7 +241,14 @@ jobs:
with:
persist-credentials: false

- name: Download statuses
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
name: checked
path: .status

- name: Download verified handoff
if: needs.verify.result == 'success'
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
name: verified
Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,16 @@ Automated AUR package updates from a single GitHub repo.

```mermaid
graph LR
A[GitHub Actions<br/>on schedule] -->|for each package| B[prepare job, no secrets<br/>run strategy<br/>clone AUR repo<br/>sed pkgver<br/>updpkgsums<br/>makepkg --printsrcinfo]
B -->|update or status change| V[verify job, no secrets<br/>download the sources<br/>check the checksums]
A[GitHub Actions<br/>on schedule] -->|for each package| K[check job, read-only token<br/>run strategy<br/>decide the run]
K -->|new version| B[prepare job, no secrets<br/>clone AUR repo<br/>sed pkgver<br/>updpkgsums<br/>makepkg --printsrcinfo]
B --> V[verify job, no secrets<br/>download the sources<br/>check the checksums]
V --> C[publish job<br/>check the prepared files<br/>git push to AUR]
K -->|status change only| C
C -->|check or update failed| D[create GitHub Issue<br/>with error details]
C -->|done| E[update-readme.sh<br/>commit badges + status table]
```

Each package has a YAML config pointing to an upstream source. When a new version is detected, aurtomator clones the existing AUR repo, bumps `pkgver`, regenerates checksums and `.SRCINFO`, and pushes. A PKGBUILD is code, so these steps run in a job without secrets. A second job without secrets downloads the sources and checks the checksums, and the job that pushes checks the result once more. It does not generate PKGBUILDs or modify anything else. If anything fails, a GitHub Issue is opened automatically.
Each package has a YAML config pointing to an upstream source. A first job runs the strategies and decides what the run does. When a new version is detected, aurtomator clones the existing AUR repo, bumps `pkgver`, regenerates checksums and `.SRCINFO`, and pushes. A PKGBUILD is code, so these steps run in a job without secrets, and the jobs after it take the statuses from the first job. A second job without secrets downloads the sources and checks the checksums, and the job that pushes checks the result once more. It does not generate PKGBUILDs or modify anything else. If anything fails, a GitHub Issue is opened automatically.

## Quick start

Expand Down
Loading
Loading