-
-
Notifications
You must be signed in to change notification settings - Fork 0
CI CD
This document describes the continuous integration and deployment pipeline.
┌─────────────────────────────────────────────────────────────────────┐
│ Push / PR to main │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ CI: Lint & Validate │
│ • Bash syntax check (bash -n) │
│ • Source verification (makepkg --verifysource) │
│ • Detect changed packages │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ CD Phase 1: AUR Publish │
│ • For packages with .aur marker │
│ • Generate .SRCINFO │
│ • Push to AUR git repos │
│ • Must complete before Phase 2 │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ CD Phase 2: Local Build │
│ • For packages with .local marker │
│ • Resolve deps via yay (repos + AUR) │
│ • Build with makepkg │
│ • Run smoke tests (check.sh) │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ CD Phase 3: Release │
│ • Sign packages with GPG │
│ • Update repo database │
│ • Upload to GitHub releases │
└─────────────────────────────────────────────────────────────────────┘
CI uses yay to resolve package dependencies from multiple sources:
- Official repositories (core, extra, multilib)
- AUR (Arch User Repository)
- Custom repos (this repo, if configured)
# setup.sh installs yay
su builder -c "cd /tmp && git clone https://aur.archlinux.org/yay-bin.git && cd yay-bin && makepkg -si --noconfirm"
# build.sh uses yay for dependency resolution
DEPS=$(makepkg --printsrcinfo | awk '/depends|makedepends/ {print $3}')
yay -S --noconfirm --asdeps --needed $DEPS- Unified interface: Same command for repo and AUR packages
- Automatic AUR builds: Builds AUR deps from source automatically
- Dependency chains: Resolves transitive dependencies
When a package and its dependencies are both managed in this repo:
keeper-secrets-manager-cli (.local + .aur)
└── depends: keeper-secrets-manager-helper (.aur)
If both are updated in the same commit:
- CI detects both need publishing
- If
keeper-secrets-manager-clibuilds first... -
yaytries to fetchkeeper-secrets-manager-helperfrom AUR - But the new version isn't pushed yet → build fails
Phase 1 (AUR Publish) must complete before Phase 2 (Local Build):
jobs:
aur-publish:
# Push all .aur packages to AUR first
steps:
- run: push_to_aur.sh
local-build:
needs: [aur-publish] # Wait for AUR packages
strategy:
matrix:
package: ${{ needs.prepare.outputs.local_packages }}
steps:
- run: build.sh ${{ matrix.package }}This ensures:
- AUR-only deps are available before local builds start
- Packages with both markers get pushed to AUR, then built locally
For packages with local dependencies on other local packages (not via AUR):
Option A: Topological sort
- Parse depends from PKGBUILDs
- Build in dependency order
- Complex but robust
Option B: Multi-stage builds
- Stage 1: Packages with no local deps
- Stage 2: Packages depending on Stage 1
- Simpler but requires manual staging
Option C: Local repo bootstrap
- Build all packages
- Add built packages to local repo
- Rebuild failures with local repo available
- Self-healing but slower
Current implementation uses Option A with yay handling the complexity.
Automated version checks run on schedule (.github/workflows/watch.yml):
# scripts/packages/<pkgname>.sh
check_pkgname() {
# Fetch latest version from upstream
local latest=$(curl -s "https://pypi.org/pypi/package/json" | jq -r .info.version)
# Compare and update if needed
perform_update "pkgname" "$latest"
}Sources:
-
npm:
npm view @scope/package version -
PyPI:
https://pypi.org/pypi/<package>/json -
GitHub:
https://api.github.com/repos/org/repo/releases/latest
| Secret | Purpose |
|---|---|
GPG_PRIVATE_KEY |
Sign packages |
GPG_PASSPHRASE |
Unlock signing key |
AUR_SSH_KEY |
Push to AUR git repos |
GITHUB_TOKEN |
Upload release assets (auto-provided) |
Actions → "Build packages" → "Run workflow" → Check "Rebuild all packages"
Useful when:
- Dependency updated in repos
- Build environment changed
- Recovering from failed state
If packages exist but signatures are missing/invalid:
Actions → "Build packages" → "Run workflow" → Check "Fix signatures only"
GitHub Actions artifact names cannot contain: " : < > | * ? \r \n \ /
Since packages are in pkgs/<name>/, the matrix value contains a slash. Use basename to extract just the package name:
- name: Get package name
id: pkg
run: echo "name=$(basename ${{ matrix.package }})" >> $GITHUB_OUTPUT
- uses: actions/upload-artifact@v4
with:
name: pkg-${{ steps.pkg.outputs.name }} # Not pkg-${{ matrix.package }}The archlinux:base-devel container doesn't include openssh. Install it in setup:
pacman -S --noconfirm --needed opensshFor AUR publishing, use GIT_SSH_COMMAND to ensure git uses the correct SSH config:
export GIT_SSH_COMMAND="ssh -i ~/.ssh/aur -o StrictHostKeyChecking=no"Packages with epochs have colons in filenames (e.g., gemini-cli-1:0.26.0-1-any.pkg.tar.zst).
GitHub Actions cannot handle colons in artifact paths on some filesystems.
build.sh renames these before upload:
# Rename artifact if it contains colons (GitHub Actions compatibility)
for f in "$PKG"/*.pkg.tar.zst; do
if [[ "$f" == *:* ]]; then
new_name=$(echo "$f" | tr ':' '.')
mv "$f" "$new_name"
fi
doneNavigation
Build Patterns
Infrastructure