Skip to content
Closed
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
18 changes: 18 additions & 0 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,21 @@ jobs:
- uses: actions/checkout@v4
- name: Validate package rules
run: bash check

dco:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Check DCO sign-off
env:
BASE: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || github.event.before }}
HEAD: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
run: |
# New branch / unknown base -> fall back to comparing against master.
if [[ -z "$BASE" || "$BASE" =~ ^0+$ ]]; then
git fetch --no-tags origin master
BASE=$(git rev-parse origin/master)
fi
bash dco "$BASE..$HEAD"
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ pkgs/**/src/
!pkgs/**/*.tmpfiles
!pkgs/**/*.desktop
!pkgs/**/*.asc
# .install scriptlets only in -sys recipe dirs (the suffix that opts in).
!pkgs/*-sys/*.install

# --- editor / OS noise ---
*.swp
Expand Down
33 changes: 18 additions & 15 deletions check
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
#!/bin/bash
# ACR policy checks. Run from the repo root: ./check
# Validates every pkgs/<name>/PKGBUILD against the repository rules.
# 1. tracked-upstream source, by suffix:
# *-git -> source must be a git+ VCS source
# *-rel -> source must be a releases/download/ URL (a published git tag)
# 1. tracked-upstream source, by suffix (an optional trailing -sys is allowed):
# *-git[-sys] -> source must be a git+ VCS source
# *-rel[-sys] -> source must be a releases/download/ URL (a published git tag)
# any other pkgname suffix is rejected.
# 2. no .install pre/post scriptlets (no install= line, no *.install file)
# UNLESS the pkgname ends in -sys, which opts in to allowing them.
# 3. at least one '# Maintainer:' line
set -u
shopt -s nullglob
Expand All @@ -22,33 +23,35 @@ for pkgbuild in pkgs/*/PKGBUILD; do
# Rule 1: tracked-upstream source, validated against the pkgname suffix
pkgname=$(sed -n "s/^pkgname=//p" "$pkgbuild" | tr -d "'\"" | head -1)
case "$pkgname" in
*-git)
*-git|*-git-sys)
if ! grep -qE '^[[:space:]]*source.*=.*git\+' "$pkgbuild"; then
echo "FAIL [$name]: -git package has no git+ VCS source"
fail=1
fi
;;
*-rel)
*-rel|*-rel-sys)
if ! grep -qE '^[[:space:]]*source.*=.*releases/download/' "$pkgbuild"; then
echo "FAIL [$name]: -rel package has no releases/download/ source"
fail=1
fi
;;
*)
echo "FAIL [$name]: pkgname '$pkgname' must end in -git or -rel"
echo "FAIL [$name]: pkgname '$pkgname' must end in -git or -rel (optionally + -sys)"
fail=1
;;
esac

# Rule 2: no install scriptlets
if grep -qE '^[[:space:]]*install=' "$pkgbuild"; then
echo "FAIL [$name]: install= scriptlet declared in PKGBUILD"
fail=1
fi
installs=("$dir"/*.install)
if (( ${#installs[@]} > 0 )); then
echo "FAIL [$name]: .install file present in recipe dir"
fail=1
# Rule 2: no install scriptlets, unless the pkgname opts in with a -sys suffix
if [[ "$pkgname" != *-sys ]]; then
if grep -qE '^[[:space:]]*install=' "$pkgbuild"; then
echo "FAIL [$name]: install= scriptlet declared in PKGBUILD (use a -sys suffix to allow)"
fail=1
fi
installs=("$dir"/*.install)
if (( ${#installs[@]} > 0 )); then
echo "FAIL [$name]: .install file present in recipe dir (use a -sys suffix to allow)"
fail=1
fi
fi

# Rule 3: at least one Maintainer line
Expand Down
33 changes: 33 additions & 0 deletions dco
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/bin/bash
# DCO sign-off check. Verifies every non-merge commit in a range carries a
# 'Signed-off-by:' trailer matching the commit author (name <email>).
# This is the homebaked replacement for the DCO GitHub App.
#
# Usage: ./dco [<range>] (default: origin/master..HEAD)
set -u

range="${1:-origin/master..HEAD}"
fail=0
checked=0

while read -r sha; do
[[ -z "$sha" ]] && continue
# Skip merge commits (more than one parent) — sign-off lives on the real commits.
if (( $(git rev-list --parents -n1 "$sha" | wc -w) > 2 )); then
continue
fi
checked=$((checked + 1))

author=$(git show -s --format='%an <%ae>' "$sha")
short=$(git show -s --format='%h' "$sha")
if ! git show -s --format='%(trailers:key=Signed-off-by,valueonly)' "$sha" \
| grep -qxF "$author"; then
echo "FAIL [$short]: missing 'Signed-off-by: $author'"
fail=1
fi
done < <(git rev-list "$range")

if [[ $fail -eq 0 ]]; then
echo "ok: $checked commit(s) carry a matching DCO sign-off"
fi
exit $fail
22 changes: 16 additions & 6 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,15 @@ Every `pkgs/<name>/` recipe must satisfy (enforced by `./check`):
- `-rel` — `source=()` is a `releases/download/` URL (a published git tag).

Both track upstream git; they differ only in whether we build the clone or
install a published release artifact. No other suffix is allowed.
2. **No `.install` scriptlets** no `install=` line and no `*.install` file.
`*.install` is not on the allowlist, so it cannot even be committed.
install a published release artifact. No other source suffix is allowed.
A trailing `-sys` may be appended to either (`-git-sys` / `-rel-sys`) — see
rule 2.
2. **No `.install` scriptlets, unless the package is `-sys`.** By default a
recipe may have no `install=` line and no `*.install` file. A package that
genuinely needs pre/post scriptlets (systemd units, user creation, cache
refresh, …) must opt in by appending `-sys` to its `pkgname`
(e.g. `foo-git-sys`). Only `*-sys/` dirs can commit a `*.install` — the
allowlist forbids it everywhere else.
3. **At least one `# Maintainer:` line** in the PKGBUILD.

Run `./check` before committing; CI runs it on every PR.
Expand All @@ -45,6 +51,9 @@ Repo-root helper scripts:

- `./check` — validate every recipe against the package rules above. Exits
non-zero on any violation.
- `./dco [<range>]` — verify every non-merge commit in `<range>` (default
`origin/master..HEAD`) carries a `Signed-off-by:` trailer matching its
author. Homebaked DCO check; CI runs it on every push and PR.
- `./clean` — remove all git-ignored build debris (`pkg/`, `src/`, fetched
sources, built packages) repo-wide, after a confirmation prompt.
- `./bump [pkg...]` — refresh packages to the latest upstream state, by tier:
Expand All @@ -56,8 +65,9 @@ Packaging you'll want: `nvchecker`, `devtools`, `base-devel` and `pacman-contrib

## CI

GitHub Actions (`.github/workflows/check.yml`) runs `bash check` on **every
branch push and every pull request**. A branch that violates any package rule
fails CI and cannot be merged into `master`.
GitHub Actions (`.github/workflows/check.yml`) runs two jobs on **every branch
push and every pull request**: `policy` (`bash check`) and `dco` (`bash dco`).
A branch that violates any package rule, or carries a commit without a matching
`Signed-off-by:` trailer, fails CI and cannot be merged into `master`.

---
Loading