Watch Arch Linux package updates with a Forgejo Action
I wanted to know when specific Arch Linux packages got bumped -- for example when emacs moves from 30.2-2 to 30.2-3.
I don't want to run pacman -Syu just to find out, and the Arch website has a JSON API that makes this easy to poll.
The API call for a single package looks like this:
curl -s 'https://archlinux.org/packages/search/json/?name=emacs&repo=Extra&arch=x86_64' \ | jq -r '.results[0] | (.pkgver + "-" + (.pkgrel|tostring))'
This prints something like 30.2-2.
I wanted a generic solution, so the list of packages to watch lives in a packages.yaml file:
Adding another package means appending three more lines.
The Forgejo Action runs once a day, queries each entry, and compares the result to a file in state/ that stores the last seen pkgver-pkgrel.
If it differs, the Action sends a ntfy message (see previous post) and commits the new state file back to the repo.
That way the git log of state/ becomes the bump history.
name: Check Arch package updates on: schedule: - cron: '0 8 * * *' # Daily at 8:00 AM UTC workflow_dispatch: jobs: check: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 with: token: ${{ secrets.GITHUB_TOKEN }} - name: Install tools run: | command -v jq >/dev/null || { apt-get update -qq && apt-get install -y -qq jq; } if ! command -v yq >/dev/null; then case "$(uname -m)" in x86_64) arch=amd64 ;; aarch64|arm64) arch=arm64 ;; armv7l) arch=arm ;; *) echo "unsupported arch: $(uname -m)"; exit 1 ;; esac curl -fsSL -o /usr/local/bin/yq \ "https://github.com/mikefarah/yq/releases/latest/download/yq_linux_${arch}" chmod +x /usr/local/bin/yq fi - name: Check packages env: NTFY_TOKEN: ${{ secrets.NTFY_TOKEN }} run: | set -euo pipefail mkdir -p state yq -o=json '.packages' packages.yaml | jq -c '.[]' | while read -r pkg; do name=$(printf '%s' "$pkg" | jq -r '.name') repo=$(printf '%s' "$pkg" | jq -r '.repo') arch=$(printf '%s' "$pkg" | jq -r '.arch') url="https://archlinux.org/packages/search/json/?name=${name}&repo=${repo}&arch=${arch}" current=$(curl -sf "$url" \ | jq -r '.results[0] | if . == null then empty else (.pkgver + "-" + (.pkgrel|tostring)) end') if [ -z "${current:-}" ]; then echo "::warning::no result for ${name} (${repo}/${arch})" continue fi state_file="state/${repo}_${arch}_${name}.txt" previous=$(cat "$state_file" 2>/dev/null || true) if [ "$previous" != "$current" ]; then printf '%s\n' "$current" > "$state_file" if [ -n "$previous" ]; then curl -fsS \ -H "Authorization: Bearer ${NTFY_TOKEN}" \ -H "Title: Arch package updated: ${name}" \ -H "Priority: default" \ -H "Tags: package" \ -d "${repo}/${name} (${arch}): ${previous} -> ${current}" \ https://ntfy.madflex.de/forgejo else echo "initial state for ${name}, not notifying" fi fi done - name: Commit and push state changes run: | git config user.name "Automated" git config user.email "actions@forgejo.local" git remote set-url origin https://oauth2:${{ secrets.GITHUB_TOKEN }}@forgejo.tail07efb.ts.net/${{ github.repository }} git add state/ git diff --staged --quiet || git commit -m "Update package state - $(date +'%Y-%m-%d')" git push
One note about the state:
First-seen packages are recorded silently: when the state file does not exist yet, the current version is written but no ntfy is sent.
That avoids a flood of notifications after adding a batch of new packages to packages.yaml.
Now a few days after I wrote the post, the Emacs package was updated and the notification looks like this:

I am monitoring several other packages as well, but the problems with Emacs and Tree-sitter were the starting point.
