1 Commits

6 changed files with 587 additions and 60 deletions
+176
View File
@@ -0,0 +1,176 @@
name: Build and publish webkit2gtk
on:
workflow_dispatch:
inputs:
aur_version:
description: 'Full AUR version string to build (e.g. 2.46.3-1)'
required: true
type: string
jobs:
build-and-publish:
name: Build webkit2gtk ${{ inputs.aur_version }}
runs-on: ubuntu-latest-96-cores
container:
image: archlinux:latest
# Needed so makepkg can use FUSE/user namespaces inside the container
options: --privileged
permissions:
contents: write # create GitHub Releases and upload assets
env:
GITHUB_REPO: ${{ github.repository }}
AUR_PACKAGE_NAME: webkit2gtk-bin
AUR_MAINTAINER_NAME: ${{ secrets.AUR_MAINTAINER_NAME }}
AUR_MAINTAINER_EMAIL: ${{ secrets.AUR_MAINTAINER_EMAIL }}
steps:
- name: Checkout repository
uses: actions/checkout@v6.0.2
- name: Install build dependencies
run: |
pacman -Syu --noconfirm
pacman -S --noconfirm --needed \
base-devel \
git \
sudo \
curl \
jq \
openssh \
github-cli \
clang \
cmake \
gi-docgen \
glib2-devel \
gobject-introspection \
gperf \
gst-plugins-bad \
lld \
ninja \
python \
ruby \
ruby-stdlib \
systemd \
unifdef \
wayland-protocols \
at-spi2-core \
atk \
bubblewrap \
cairo \
enchant \
expat \
fontconfig \
freetype2 \
gdk-pixbuf2 \
glib2 \
glibc \
gst-plugins-bad-libs \
gst-plugins-base-libs \
gstreamer \
gtk3 \
harfbuzz \
harfbuzz-icu \
hyphen \
icu \
lcms2 \
libatomic \
libavif \
libdrm \
libegl \
libepoxy \
libgcrypt \
libgl \
libjpeg-turbo \
libjxl \
libmanette \
libpng \
libseccomp \
libsecret \
libsoup \
libsystemd \
libtasn1 \
libwebp \
libx11 \
libxml2 \
libxslt \
mesa \
openjpeg2 \
pango \
sqlite \
ttf-dejavu \
wayland \
woff2 \
xdg-dbus-proxy \
zlib
- name: Create builduser (makepkg refuses to run as root)
run: |
useradd -m -G wheel builduser
echo '%wheel ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers
# Allow builduser to write to the workspace
chown -R builduser:builduser "$GITHUB_WORKSPACE"
git config --system --add safe.directory '*'
- name: Set up AUR SSH key
env:
AUR_SSH_KEY: ${{ secrets.AUR_SSH_KEY }}
run: |
SSH_DIR=/home/builduser/.ssh
mkdir -p "${SSH_DIR}"
printf '%s\n' "${AUR_SSH_KEY}" > "${SSH_DIR}/aur_id_rsa"
chown -R builduser:builduser "${SSH_DIR}"
chmod 700 "${SSH_DIR}"
chmod 600 "${SSH_DIR}/aur_id_rsa"
printf 'Host aur.archlinux.org\n User aur\n IdentityFile /home/builduser/.ssh/aur_id_rsa\n StrictHostKeyChecking no\n' \
> "${SSH_DIR}/config"
chmod 600 "${SSH_DIR}/config"
- name: Configure git identity for builduser
run: |
sudo -u builduser HOME=/home/builduser git config --global user.name "${AUR_MAINTAINER_NAME}"
sudo -u builduser HOME=/home/builduser git config --global user.email "${AUR_MAINTAINER_EMAIL}"
- name: Import WebKitGTK PGP signing keys
run: |
sudo -u builduser HOME=/home/builduser gpg \
--keyserver keyserver.ubuntu.com \
--recv-keys \
5AA3BC334FD7E3369E7C77B291C559DBE4C9123B \
013A0127AC9C65B34FFA62526C1009B693975393 || \
sudo -u builduser HOME=/home/builduser gpg \
--keyserver hkps://keys.openpgp.org \
--recv-keys \
5AA3BC334FD7E3369E7C77B291C559DBE4C9123B \
013A0127AC9C65B34FFA62526C1009B693975393
- name: Clone webkit2gtk from AUR
run: |
sudo -u builduser HOME=/home/builduser \
git clone https://aur.archlinux.org/webkit2gtk.git "${GITHUB_WORKSPACE}/webkit2gtk"
- name: Build webkit2gtk
env:
NPROC: 96
run: |
sudo -u builduser \
HOME=/home/builduser \
GITHUB_WORKSPACE="${GITHUB_WORKSPACE}" \
NPROC="${NPROC}" \
bash "${GITHUB_WORKSPACE}/scripts/build.sh"
- name: Publish to GitHub Releases and AUR
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
sudo -u builduser \
HOME=/home/builduser \
GITHUB_WORKSPACE="${GITHUB_WORKSPACE}" \
GITHUB_TOKEN="${GITHUB_TOKEN}" \
GITHUB_REPO="${GITHUB_REPO}" \
AUR_PACKAGE_NAME="${AUR_PACKAGE_NAME}" \
AUR_MAINTAINER_NAME="${AUR_MAINTAINER_NAME}" \
AUR_MAINTAINER_EMAIL="${AUR_MAINTAINER_EMAIL}" \
bash "${GITHUB_WORKSPACE}/scripts/publish.sh"
+66
View File
@@ -0,0 +1,66 @@
name: Check for webkit2gtk update
on:
# schedule:
# Run every hour
# - cron: '0 * * * *'
workflow_dispatch:
jobs:
check:
name: Poll AUR for new version
runs-on: ubuntu-latest
permissions:
contents: read
actions: write # required to trigger workflow_dispatch on build.yml
steps:
- name: Fetch latest AUR version
id: aur
run: |
response=$(curl -fsSL "https://aur.archlinux.org/rpc/v5/info/webkit2gtk")
aur_version=$(echo "${response}" | jq -r '.results[0].Version')
if [[ -z "${aur_version}" || "${aur_version}" == "null" ]]; then
echo "ERROR: Failed to parse version from AUR response: ${response}" >&2
exit 1
fi
echo "AUR version: ${aur_version}"
echo "version=${aur_version}" >> "$GITHUB_OUTPUT"
- name: Fetch last published version from GitHub Releases
id: last
env:
GH_TOKEN: ${{ github.token }}
run: |
# Get the tag of the latest release; strip the leading 'v'
tag=$(gh release list \
--repo "${{ github.repository }}" \
--limit 1 \
--json tagName \
--jq '.[0].tagName // ""')
last_version="${tag#v}"
echo "Last published version: ${last_version:-<none>}"
echo "version=${last_version}" >> "$GITHUB_OUTPUT"
- name: Decide whether to build
id: decision
run: |
aur="${{ steps.aur.outputs.version }}"
last="${{ steps.last.outputs.version }}"
if [[ "${aur}" == "${last}" ]]; then
echo "Already up to date (${aur}), nothing to do"
echo "should_build=false" >> "$GITHUB_OUTPUT"
else
echo "New version detected: ${aur} (was: ${last:-<none>})"
echo "should_build=true" >> "$GITHUB_OUTPUT"
fi
- name: Trigger build workflow
if: steps.decision.outputs.should_build == 'true'
env:
GH_TOKEN: ${{ github.token }}
run: |
gh workflow run build.yml \
--repo "${{ github.repository }}" \
--field aur_version="${{ steps.aur.outputs.version }}"
echo "Dispatched build.yml for version ${{ steps.aur.outputs.version }}"
+284
View File
@@ -0,0 +1,284 @@
# AGENTS.md — webkit2gtk-automator
This file provides guidance for agentic coding agents working in this repository.
---
## Project Overview
This project is a Bash/Docker automation daemon that:
1. Polls the AUR RPC API for new `webkit2gtk` releases
2. Builds the package using `makepkg` inside an Arch Linux container
3. Publishes the resulting `.pkg.tar.zst` artifact to GitHub Releases
4. Generates and pushes an updated `webkit2gtk-bin` PKGBUILD to the AUR
The entire codebase is Bash scripts orchestrated via Docker Compose. There is no application framework, no package manager (npm/pip/cargo), and no test suite.
---
## Repository Structure
```
webkit2gtk-automator/
├── .env.example # Template for required environment variables
├── .gitignore
├── Dockerfile # Arch Linux image with build dependencies
├── docker-compose.yml # Defines the "builder" service
├── README.md
└── scripts/
├── entrypoint.sh # Container entrypoint; polling loop
├── check-update.sh # AUR API poll; triggers build + publish if new version
├── build.sh # Runs makepkg; collects .pkg.tar.zst artifacts
└── publish.sh # Uploads to GitHub Releases; pushes PKGBUILD to AUR
```
Runtime-generated (gitignored):
- `state/last_version` — tracks last published version
- `state/artifacts/` — holds built `.pkg.tar.zst` files
- `webkit2gtk/` — AUR source package clone
- `webkit2gtk-bin/` — AUR binary package clone
---
## Environment Setup
Copy `.env.example` to `.env` and fill in all required values before starting:
```bash
cp .env.example .env
# Edit .env with your GITHUB_TOKEN, AUR SSH key path, GPG key, etc.
```
All scripts validate required variables at startup using the pattern:
```bash
: "${GITHUB_TOKEN:?GITHUB_TOKEN is not set}"
```
Missing variables cause an immediate exit with a descriptive error.
---
## Build / Run Commands
| Purpose | Command |
|---|---|
| Start the daemon (detached) | `docker compose up -d` |
| Start and rebuild the image | `docker compose up -d --build` |
| Watch live logs | `docker compose logs -f` |
| Stop the daemon | `docker compose down` |
| Force a rebuild on next poll | `rm state/last_version && docker compose restart` |
---
## Running a Single Script
There is no test runner. To manually invoke a single script inside the container:
```bash
# Run check-update.sh (polls AUR and triggers build+publish if needed)
docker compose run --rm builder bash -c "source /workspace/.env && /workspace/scripts/check-update.sh"
# Run build.sh directly
docker compose run --rm builder bash -c "source /workspace/.env && /workspace/scripts/build.sh"
# Run publish.sh directly
docker compose run --rm builder bash -c "source /workspace/.env && /workspace/scripts/publish.sh"
```
To test publish without recompiling, pre-place an artifact in `state/artifacts/`:
```bash
# build.sh detects existing artifact and skips makepkg
cp some-existing.pkg.tar.zst state/artifacts/
docker compose run --rm builder bash -c "source /workspace/.env && /workspace/scripts/publish.sh"
```
---
## No Test Suite
There are no unit tests, integration tests, or test commands. Manual invocation of
individual scripts (see above) is the primary validation mechanism.
---
## Code Style Guidelines
### Shebang and Strict Mode
Every script **must** begin with:
```bash
#!/usr/bin/env bash
set -euo pipefail
```
- `set -e` — exit immediately on any non-zero return code
- `set -u` — treat unset variables as errors
- `set -o pipefail` — propagate errors through pipelines
### Variable Naming
| Scope | Convention | Example |
|---|---|---|
| All variables (env or local) | `UPPER_SNAKE_CASE` | `PKG_VERSION`, `BUILD_DIR` |
| Functions | `snake_case` | `log`, `die`, `check_deps` |
| Script files | `kebab-case.sh` | `check-update.sh`, `build.sh` |
### Quoting
Always double-quote variable expansions. Use `${VAR}` brace syntax:
```bash
# Correct
cp "${SRC_FILE}" "${DEST_DIR}/"
echo "Version: ${PKG_VERSION}"
# Wrong — never do this
cp $SRC_FILE $DEST_DIR/
```
### Sourcing Files
Use `source` (not the POSIX `.` shorthand):
```bash
# Correct
source /workspace/.env
# Avoid
. /workspace/.env
```
To auto-export all variables from a sourced file:
```bash
set -a
source /workspace/.env
set +a
```
### Logging
Every script defines a `log()` function with a consistent timestamp prefix:
```bash
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [script-name] $*"; }
```
Use `log` for all informational output. Use `log "ERROR: ..." >&2` (or `die`) for errors.
### Arrays
Use Bash arrays when collecting multiple items:
```bash
packages=()
packages+=("${pkg_file}")
```
---
## Error Handling Conventions
### Required Variable Checks
Use Bash parameter expansion to validate required env vars:
```bash
: "${GITHUB_TOKEN:?GITHUB_TOKEN is not set}"
: "${AUR_SSH_KEY:?AUR_SSH_KEY is not set}"
```
### `die()` Helper
Define and use a `die()` function for fatal errors:
```bash
die() {
log "ERROR: $*" >&2
exit 1
}
# Usage
[[ -f "${pkg_file}" ]] || die "Expected artifact not found: ${pkg_file}"
```
### Explicit Guard Blocks
Prefer explicit `if/else` over bare command calls for critical steps:
```bash
if "${SCRIPT_DIR}/build.sh"; then
log "Build succeeded"
else
log "ERROR: Build failed, aborting"
exit 1
fi
```
### Null/Empty API Response Checks
Always validate outputs from `curl | jq` pipelines:
```bash
aur_version=$(curl -s "${AUR_API_URL}" | jq -r '.results[0].Version')
if [[ -z "${aur_version}" || "${aur_version}" == "null" ]]; then
log "ERROR: Failed to parse version from AUR response"
exit 1
fi
```
### Graceful No-Op
For idempotent operations (e.g., git commit), allow the no-op case:
```bash
git commit -m "Update to ${FULL_VERSION}" || {
log "Nothing to commit, already at ${FULL_VERSION}"
exit 0
}
```
---
## External Tool Dependencies
These CLI tools are invoked directly by the scripts. They must be present in the container:
| Tool | Purpose |
|---|---|
| `curl` | HTTP requests to AUR RPC API |
| `jq` | JSON parsing of AUR API responses |
| `makepkg` | Arch Linux package build tool |
| `gh` | GitHub CLI — creating releases and uploading assets |
| `git` | Cloning/pulling AUR repos, committing, pushing |
| `gpg` | Verifying PGP signatures on source tarballs |
| `sha256sum` | Computing checksums for the artifact |
| `bsdtar` | Extracting the `.pkg.tar.zst` in the generated PKGBUILD |
| `sudo` | Dropping privileges from root to `builduser` for `makepkg` |
| `ssh` | AUR authentication via SSH key |
All of these are installed in the `Dockerfile`. If adding a new dependency, add it there.
---
## Dockerfile and docker-compose.yml
- The base image is Arch Linux. Keep it updated with `pacman -Syu` in the `Dockerfile`.
- The container runs as root but drops to a `builduser` account for `makepkg` (which
refuses to run as root).
- Secrets (`.env`, SSH keys, GPG keys) are mounted at runtime via volume mounts defined
in `docker-compose.yml`. Never bake secrets into the image.
---
## ShellCheck
ShellCheck is the recommended linter for Bash scripts. It is not formally enforced (no
`.shellcheckrc` or CI step), but inline directives are already used in the codebase
(e.g., `# shellcheck source=/dev/null`). When editing scripts, run ShellCheck locally:
```bash
shellcheck scripts/*.sh
```
Fix all warnings before committing. Use inline directives sparingly and only with a
comment explaining why the suppression is necessary.
---
## Adding a New Script
1. Create the file as `scripts/kebab-case-name.sh`
2. Start with `#!/usr/bin/env bash` and `set -euo pipefail`
3. Define a `log()` function matching the pattern above
4. Validate all required env vars with `: "${VAR:?...}"`
5. Define a `die()` helper for fatal errors
6. Make it executable: `chmod +x scripts/kebab-case-name.sh`
7. If it needs to run inside the container, invoke it via `docker compose run --rm builder`
+7 -3
View File
@@ -1,12 +1,16 @@
#!/usr/bin/env bash
# build.sh
# Runs INSIDE the Docker container as builduser.
# Runs as builduser (inside Docker or a GitHub Actions container job).
# Builds webkit2gtk from the AUR PKGBUILD and copies the resulting
# .pkg.tar.zst packages to /workspace/state/artifacts/.
# .pkg.tar.zst packages to <workspace>/state/artifacts/.
#
# Works in both environments:
# Docker / local: WORKSPACE=/workspace (default)
# GitHub Actions: WORKSPACE=$GITHUB_WORKSPACE (set by runner)
set -euo pipefail
WORKSPACE=/workspace
WORKSPACE="${GITHUB_WORKSPACE:-/workspace}"
SRC_DIR="${WORKSPACE}/webkit2gtk"
ARTIFACTS_DIR="${WORKSPACE}/state/artifacts"
+48 -55
View File
@@ -1,26 +1,38 @@
#!/usr/bin/env bash
# check-update.sh
# Polls the AUR RPC API for the latest webkit2gtk version.
# If a newer version is detected, runs build.sh then publish.sh directly.
# Called by entrypoint.sh on a loop — runs entirely inside the container.
# Queries the AUR RPC API for the latest webkit2gtk version and compares it
# against the last published version on GitHub Releases.
#
# Outputs:
# aur_version=<string> — latest AUR version string
# should_build=true|false — whether a new build is needed
#
# When run inside a GitHub Actions step, GITHUB_OUTPUT is set and the outputs
# are written there automatically. When run locally, they are printed to stdout.
#
# Required env vars (only when comparing against GitHub Releases):
# GITHUB_TOKEN — a token with 'contents: read' on GITHUB_REPO
# GITHUB_REPO — owner/repo, e.g. Brodino96/webkit2gtk-automator
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
# Paths
STATE_DIR="${ROOT_DIR}/state"
LAST_VERSION_FILE="${STATE_DIR}/last_version"
mkdir -p "${STATE_DIR}"
# Logging
# Output goes to stdout so docker compose logs picks it up automatically.
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [check-update] $*"
}
# Fetch latest AUR version
set_output() {
local key="$1"
local value="$2"
if [[ -n "${GITHUB_OUTPUT:-}" ]]; then
echo "${key}=${value}" >> "${GITHUB_OUTPUT}"
else
log "OUTPUT: ${key}=${value}"
fi
}
# ---------------------------------------------------------------------------
# 1. Fetch latest AUR version
# ---------------------------------------------------------------------------
AUR_API_URL="https://aur.archlinux.org/rpc/v5/info/webkit2gtk"
log "Querying AUR for webkit2gtk"
@@ -33,50 +45,31 @@ if [[ -z "${aur_version}" || "${aur_version}" == "null" ]]; then
fi
log "AUR version: ${aur_version}"
set_output "aur_version" "${aur_version}"
# Compare with last built version
last_version=""
if [[ -f "${LAST_VERSION_FILE}" ]]; then
last_version=$(cat "${LAST_VERSION_FILE}")
fi
# ---------------------------------------------------------------------------
# 2. Fetch last published version from GitHub Releases
# ---------------------------------------------------------------------------
: "${GITHUB_TOKEN:?GITHUB_TOKEN is not set}"
: "${GITHUB_REPO:?GITHUB_REPO is not set}"
log "Last built version: ${last_version:-<none>}"
log "Fetching latest GitHub Release tag from ${GITHUB_REPO}"
tag=$(gh release list \
--repo "${GITHUB_REPO}" \
--limit 1 \
--json tagName \
--jq '.[0].tagName // ""' 2>/dev/null || echo "")
last_version="${tag#v}"
log "Last published version: ${last_version:-<none>}"
# ---------------------------------------------------------------------------
# 3. Compare
# ---------------------------------------------------------------------------
if [[ "${aur_version}" == "${last_version}" ]]; then
log "Already up to date, nothing to do"
exit 0
fi
log "New version detected: ${aur_version} (was: ${last_version:-<none>}), starting build"
# Update the webkit2gtk AUR clone
WEBKIT2GTK_DIR="${ROOT_DIR}/webkit2gtk"
if [[ -d "${WEBKIT2GTK_DIR}/.git" ]]; then
log "Pulling latest PKGBUILD from AUR"
git -C "${WEBKIT2GTK_DIR}" pull --ff-only
log "Already up to date (${aur_version}), nothing to do"
set_output "should_build" "false"
else
log "Cloning webkit2gtk from AUR"
git clone https://aur.archlinux.org/webkit2gtk.git "${WEBKIT2GTK_DIR}"
log "New version detected: ${aur_version} (was: ${last_version:-<none>})"
set_output "should_build" "true"
fi
# Build
log "Running build"
if "${SCRIPT_DIR}/build.sh"; then
log "Build succeeded"
else
log "ERROR: Build failed, aborting"
exit 1
fi
# Publish
log "Running publish"
if "${SCRIPT_DIR}/publish.sh"; then
log "Publish succeeded"
else
log "ERROR: Publish failed, exit code: $?"
exit 1
fi
# Record new version
echo "${aur_version}" > "${LAST_VERSION_FILE}"
log "Updated last_version to ${aur_version}, done"
+6 -2
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
# publish.sh
# Runs INSIDE the Docker container as builduser.
# Runs as builduser (inside Docker or a GitHub Actions container job).
#
# Steps:
# 1. Find the built webkit2gtk .pkg.tar.zst in state/artifacts/
@@ -8,10 +8,14 @@
# 3. Update webkit2gtk-bin/PKGBUILD with the new version, URL and sha256sum
# 4. Regenerate webkit2gtk-bin/.SRCINFO
# 5. Commit and push webkit2gtk-bin/ to the AUR
#
# Works in both environments:
# Docker / local: WORKSPACE=/workspace (default)
# GitHub Actions: WORKSPACE=$GITHUB_WORKSPACE (set by runner)
set -euo pipefail
WORKSPACE=/workspace
WORKSPACE="${GITHUB_WORKSPACE:-/workspace}"
ARTIFACTS_DIR="${WORKSPACE}/state/artifacts"
BIN_PKG_DIR="${WORKSPACE}/webkit2gtk-bin"
SRC_PKGBUILD="${WORKSPACE}/webkit2gtk/PKGBUILD"