Watch
1
0
Fork
You've already forked souveraine
0
souveraine/.gitea/workflows/ci.yml

215 lines
10 KiB
YAML

name: ci
# CI for souveraine — Rust crate. Tests + clippy on push/PR to primary (dev)
# and public (published). On push to public, mirror public:public to Codeberg
# on green. primary stays the private dev branch; public is what publishes.
#
# Required repo secrets:
# CODEBERG_TOKEN — push to codeberg.org/Fimeg/Souveraine (public branch)
on:
push:
branches: [primary, public]
pull_request:
branches: [primary, public]
jobs:
rust-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Install system deps
run: sudo apt-get update -qq && sudo apt-get install -y -qq libasound2-dev libchafa-dev
# Pinned fork on our Gitea (rgb patch committed there) — upstream HEAD
# must never decide whether our build passes.
- name: Clone tuie (pinned fork)
run: |
git -c http.extraheader="Authorization: token ${{ secrets.LOCAL_GITEA_TOKEN }}" \
clone "${GITHUB_SERVER_URL}/Fimeg/tuie.git" /workspace/Fimeg/tuie
git -C /workspace/Fimeg/tuie checkout aa43e335c8f5a3cd2c78e397a1a8dfe534a6bc35
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8
with:
toolchain: "1.94"
components: clippy
- name: cargo test
run: cargo test
- name: cargo clippy
run: cargo clippy -- -D warnings
no-ai-attribution:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 0
- name: Check commit messages for AI attribution
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
RANGE="${{ github.event.pull_request.base.sha }}..${{ github.sha }}"
else
RANGE="${{ github.event.before }}..${{ github.sha }}"
if [ "${{ github.event.before }}" = "0000000000000000000000000000000000000000" ]; then
RANGE="HEAD~10..HEAD"
fi
fi
# CO assembled from fragments so this guard file does not itself trip
# the public-branch pre-commit scanner (which bans the literal token).
CO="Co-Authored""-By:"
PATTERNS="${CO}.*[Cc]laude|${CO}.*OpenAI|${CO}.*ChatGPT|${CO}.*Copilot|${CO}.*Letta|${CO}.*Cursor|Generated by|Generated with|AI-assisted|Auto-generated by"
FAIL=0
while IFS= read -r msg; do
if echo "$msg" | grep -qiE "$PATTERNS"; then
echo "::error::AI attribution found in commit: $msg"
FAIL=1
fi
done < <(git log --format='%s%n%b' $RANGE 2>/dev/null)
if [ "$FAIL" -eq 1 ]; then
echo "::error::Commits contain AI attribution lines. Remove them before merging."
exit 1
fi
echo "No AI attribution found in commits."
action-pins:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Check for floating action refs
run: |
if grep -rE 'uses:.*@(v[0-9]+|stable|main|master)(\s|$)' .gitea/workflows/; then
echo "::error::Floating action refs found — pin every action to a commit SHA"
exit 1
fi
echo "All action refs are SHA-pinned."
# Phone artifact on green. Runs on the ArchDev build node (host mode, label
# archdev) where the aarch64 sysroot lives — no docker, no node, plain shell.
# Publishes the cross-built binary to a rolling `edge` prerelease; the phone
# updates itself from there instead of waiting on a laptop scp.
aarch64-artifact:
runs-on: archdev
needs: [rust-test, no-ai-attribution, action-pins]
if: github.event_name == 'push' && github.ref == 'refs/heads/public'
steps:
- name: Clone repo + pinned tuie
run: |
set -euo pipefail
rm -rf "$GITHUB_WORKSPACE/src"
git -c http.extraheader="Authorization: token ${{ secrets.LOCAL_GITEA_TOKEN }}" \
clone "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git" "$GITHUB_WORKSPACE/src/Souveraine"
git -C "$GITHUB_WORKSPACE/src/Souveraine" checkout "$GITHUB_SHA"
git -c http.extraheader="Authorization: token ${{ secrets.LOCAL_GITEA_TOKEN }}" \
clone "${GITHUB_SERVER_URL}/Fimeg/tuie.git" "$GITHUB_WORKSPACE/src/tuie"
git -C "$GITHUB_WORKSPACE/src/tuie" checkout aa43e335c8f5a3cd2c78e397a1a8dfe534a6bc35
- name: Build release binaries
run: |
set -euo pipefail
cd "$GITHUB_WORKSPACE/src/Souveraine"
# Persistent target dirs: fresh clones per run, warm compile cache.
export CARGO_TARGET_DIR="$HOME/.cache/souveraine-ci-target"
export SOUVERAINE_AARCH64_SYSROOT="$HOME/aarch64-sysroot"
./scripts/build-cross.sh
BIN="$CARGO_TARGET_DIR/aarch64-unknown-linux-gnu/release/souveraine"
file "$BIN" | grep -q aarch64 || { echo "built binary is not aarch64" >&2; exit 1; }
cp "$BIN" souveraine-aarch64
export CARGO_TARGET_DIR="$HOME/.cache/souveraine-ci-target-x86_64"
cargo build --release
BIN="$CARGO_TARGET_DIR/release/souveraine"
file "$BIN" | grep -q 'x86-64' || { echo "built binary is not x86_64" >&2; exit 1; }
cp "$BIN" souveraine-x86_64
sha256sum souveraine-aarch64 souveraine-x86_64 > souveraine-binaries.sha256
- name: Package and sign pacman repository
run: |
set -euo pipefail
cd "$GITHUB_WORKSPACE/src/Souveraine"
PKGVER="0.1.r$(git rev-list --count HEAD).g${GITHUB_SHA:0:12}"
WORK="$GITHUB_WORKSPACE/pacman-package"
REPO="$GITHUB_WORKSPACE/pacman-repo"
ARCHIVE_KEY="3CD9E99E222C2A174986FC9AFF4949AA20C8E911"
rm -rf "$WORK" "$REPO"
mkdir -p "$WORK" "$REPO"
for ARCH in aarch64 x86_64; do
PKG_WORK="$WORK/$ARCH"
ARCH_REPO="$REPO/$ARCH"
mkdir -p "$PKG_WORK" "$ARCH_REPO"
cp "souveraine-$ARCH" "$PKG_WORK/souveraine-binary"
cp packaging/souveraine.service LICENSE "$PKG_WORK/"
cp packaging/arch/PKGBUILD.prebuilt "$PKG_WORK/PKGBUILD"
(
cd "$PKG_WORK"
export SOUVERAINE_PKGVER="$PKGVER"
export SOUVERAINE_PKGARCH="$ARCH"
CARCH="$ARCH" makepkg --nodeps --noconfirm --cleanbuild
)
PKG=$(find "$PKG_WORK" -maxdepth 1 -name 'souveraine-*.pkg.tar.zst' -print -quit)
test -n "$PKG"
bsdtar -tf "$PKG" | grep -qx 'usr/bin/souveraine'
cp "$PKG" "$ARCH_REPO/"
gpg --batch --yes --local-user "$ARCHIVE_KEY" \
--detach-sign "$ARCH_REPO/$(basename "$PKG")"
# Pacman databases are architecture-specific: one database cannot
# retain two same-named, same-version packages for different
# architectures. Keep each database and its assets distinct.
DB="souveraine-${ARCH}"
repo-add --include-sigs --sign --key "$ARCHIVE_KEY" \
"$ARCH_REPO/$DB.db.tar.zst" "$ARCH_REPO"/*.pkg.tar.zst
# repo-add makes .db and .db.sig symlinks. Release assets cannot
# preserve those, so replace both links with real files.
rm -f "$ARCH_REPO/$DB.db" "$ARCH_REPO/$DB.db.sig"
cp "$ARCH_REPO/$DB.db.tar.zst" "$ARCH_REPO/$DB.db"
cp "$ARCH_REPO/$DB.db.tar.zst.sig" "$ARCH_REPO/$DB.db.sig"
sha256sum "$ARCH_REPO"/*.pkg.tar.zst "$ARCH_REPO/$DB.db" \
> "$REPO/$DB-repo.sha256"
done
cp packaging/arch/souveraine-archive-key.asc "$REPO/"
- name: Publish rolling edge prerelease
run: |
set -euo pipefail
cd "$GITHUB_WORKSPACE/src/Souveraine"
API="${GITHUB_SERVER_URL}/api/v1"
AUTH="Authorization: token ${{ secrets.GITHUB_TOKEN }}"
DESC=$(git describe --tags --always)
OLD_ID=$(curl -s -H "$AUTH" "$API/repos/${GITHUB_REPOSITORY}/releases/tags/edge" \
| python3 -c "import json,sys
try: print(json.load(sys.stdin).get('id',''))
except Exception: print('')")
if [ -n "$OLD_ID" ]; then
curl -s -X DELETE -H "$AUTH" "$API/repos/${GITHUB_REPOSITORY}/releases/$OLD_ID"
curl -s -X DELETE -H "$AUTH" "$API/repos/${GITHUB_REPOSITORY}/tags/edge"
fi
REL_ID=$(curl -sf -X POST -H "$AUTH" -H "Content-Type: application/json" \
"$API/repos/${GITHUB_REPOSITORY}/releases" \
-d "{\"tag_name\":\"edge\",\"target_commitish\":\"${GITHUB_SHA}\",\"name\":\"edge (${DESC})\",\"body\":\"Rolling aarch64 build of public HEAD (${GITHUB_SHA}). Built on the archdev node, published only when CI is green.\",\"prerelease\":true}" \
| python3 -c "import json,sys; print(json.load(sys.stdin)['id'])")
for f in souveraine-aarch64 souveraine-x86_64 souveraine-binaries.sha256 \
$(find "$GITHUB_WORKSPACE/pacman-repo" -type f -print); do
curl -sf -X POST -H "$AUTH" \
"$API/repos/${GITHUB_REPOSITORY}/releases/${REL_ID}/assets?name=$(basename "$f")" \
-F "attachment=@${f}" -o /dev/null
done
echo "published edge (${DESC}) with aarch64 package + pacman database"
# Mirror the published branch only. primary (dev) never reaches Codeberg.
sync-codeberg:
runs-on: ubuntu-latest
needs: [rust-test, no-ai-attribution, action-pins]
if: github.event_name == 'push' && github.ref == 'refs/heads/public'
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 0
- name: Push public to Codeberg
run: |
if [ -z "${{ secrets.CODEBERG_TOKEN }}" ]; then
echo "[INFO] [sync] CODEBERG_TOKEN not set — skipping codeberg push"
exit 0
fi
git remote add codeberg-ci "https://${{ secrets.CODEBERG_TOKEN }}@codeberg.org/Fimeg/Souveraine.git"
git push codeberg-ci public:public
echo "Pushed public to codeberg.org/Fimeg/Souveraine"