refactor(ci): split publish-repos into matrix with native containers

Each package format now runs in its native container image:
- apt: ubuntu:noble (reprepro)
- rpm: fedora:latest (createrepo_c)
- pacman: archlinux:latest (repo-add + bsdtar built-in)
- apk: alpine:latest (apk + abuild-sign built-in)

This eliminates cross-distro tool availability issues. Desktop
packages are downloaded and renamed per format to match the mage
target glob patterns. Also adds --allow-untrusted to apk index
since nfpm-produced .apk packages are unsigned.
This commit is contained in:
kolaente 2026-04-13 11:17:54 +02:00
parent 136fafdf37
commit cd61db4415
No known key found for this signature in database
GPG Key ID: F40E70337AB24C9B
2 changed files with 66 additions and 43 deletions

View File

@ -215,6 +215,24 @@ jobs:
needs: needs:
- os-package - os-package
- desktop - desktop
strategy:
fail-fast: false
matrix:
include:
- format: apt
image: ubuntu:noble
mage_target: release:repo-apt
- format: rpm
image: fedora:latest
mage_target: release:repo-rpm
- format: pacman
image: archlinux:latest
mage_target: release:repo-pacman
- format: apk
image: alpine:latest
mage_target: release:repo-apk
container:
image: ${{ matrix.image }}
env: env:
REPO_SUITE: ${{ github.ref_type == 'tag' && 'stable' || 'unstable' }} REPO_SUITE: ${{ github.ref_type == 'tag' && 'stable' || 'unstable' }}
steps: steps:
@ -238,70 +256,75 @@ jobs:
name: vikunja_desktop_packages_ubuntu-latest name: vikunja_desktop_packages_ubuntu-latest
path: dist/repo-work/incoming-desktop path: dist/repo-work/incoming-desktop
- name: Copy desktop repo packages to incoming - name: Copy desktop packages to incoming
run: | run: |
# Copy only the repo-compatible formats from desktop builds cd dist/repo-work/incoming-desktop
for ext in deb rpm apk pacman; do case "${{ matrix.format }}" in
cp dist/repo-work/incoming-desktop/*."$ext" dist/repo-work/incoming/ 2>/dev/null || true apt)
done cp *.deb ../incoming/ 2>/dev/null || true
;;
rpm)
# Add arch suffix so the mage target's *-x86_64.rpm glob matches
for f in *.rpm; do
[ -f "$f" ] && cp "$f" "../incoming/${f%.rpm}-x86_64.rpm"
done
;;
pacman)
# Rename .pacman to .archlinux with arch suffix
for f in *.pacman; do
[ -f "$f" ] && cp "$f" "../incoming/${f%.pacman}-x86_64.archlinux"
done
;;
apk)
# Add arch suffix so the mage target's *-x86_64.apk glob matches
for f in *.apk; do
[ -f "$f" ] && cp "$f" "../incoming/${f%.apk}-x86_64.apk"
done
;;
esac
- name: Install repository tools - name: Install tools (apt)
if: matrix.format == 'apt'
run: | run: |
sudo apt-get update apt-get update
sudo apt-get install -y --no-install-recommends \ apt-get install -y --no-install-recommends reprepro
reprepro \
createrepo-c \ - name: Install tools (rpm)
pacman-package-manager \ if: matrix.format == 'rpm'
makepkg \ run: dnf install -y createrepo_c
libarchive-tools
- name: Install tools (apk)
if: matrix.format == 'apk'
run: apk add --no-cache abuild
- name: GPG setup - name: GPG setup
if: matrix.format != 'apk'
uses: kolaente/action-gpg@main uses: kolaente/action-gpg@main
with: with:
gpg-passphrase: "${{ secrets.RELEASE_GPG_PASSPHRASE }}" gpg-passphrase: "${{ secrets.RELEASE_GPG_PASSPHRASE }}"
gpg-sign-key: "${{ secrets.RELEASE_GPG_SIGN_KEY }}" gpg-sign-key: "${{ secrets.RELEASE_GPG_SIGN_KEY }}"
- name: Export GPG public key - name: Export GPG public key
if: matrix.format == 'apt'
run: | run: |
mkdir -p dist/repo-output mkdir -p dist/repo-output
gpg --export --armor 7D061A4AA61436B40713D42EFF054DACD908493A > dist/repo-output/gpg.key gpg --export --armor 7D061A4AA61436B40713D42EFF054DACD908493A > dist/repo-output/gpg.key
- name: Generate APT repo metadata
env:
RELEASE_GPG_KEY: 7D061A4AA61436B40713D42EFF054DACD908493A
RELEASE_GPG_PASSPHRASE: ${{ secrets.RELEASE_GPG_PASSPHRASE }}
run: |
chmod +x ./mage-static
./mage-static release:repo-apt
- name: Generate RPM repo metadata
env:
RELEASE_GPG_KEY: 7D061A4AA61436B40713D42EFF054DACD908493A
RELEASE_GPG_PASSPHRASE: ${{ secrets.RELEASE_GPG_PASSPHRASE }}
run: ./mage-static release:repo-rpm
- name: Generate Pacman repo metadata
env:
RELEASE_GPG_KEY: 7D061A4AA61436B40713D42EFF054DACD908493A
RELEASE_GPG_PASSPHRASE: ${{ secrets.RELEASE_GPG_PASSPHRASE }}
run: ./mage-static release:repo-pacman
- name: Install apk-tools
run: |
wget -q https://gitlab.alpinelinux.org/alpine/apk-tools/-/releases/v2.14.6/downloads/apk.static-x86_64
chmod +x apk.static-x86_64
sudo mv apk.static-x86_64 /usr/local/bin/apk
- name: Setup APK signing key - name: Setup APK signing key
if: matrix.format == 'apk'
run: | run: |
mkdir -p ~/.abuild mkdir -p ~/.abuild
echo "${{ secrets.APK_SIGNING_KEY }}" > ~/.abuild/vikunja-apk.rsa echo "${{ secrets.APK_SIGNING_KEY }}" > ~/.abuild/vikunja-apk.rsa
echo "PACKAGER_PRIVKEY=$HOME/.abuild/vikunja-apk.rsa" > ~/.abuild/abuild.conf echo "PACKAGER_PRIVKEY=$HOME/.abuild/vikunja-apk.rsa" > ~/.abuild/abuild.conf
- name: Generate APK repo metadata - name: Generate repo metadata
env: env:
APK_SIGNING_KEY_PATH: ~/.abuild/vikunja-apk.rsa RELEASE_GPG_KEY: ${{ matrix.format != 'apk' && '7D061A4AA61436B40713D42EFF054DACD908493A' || '' }}
run: ./mage-static release:repo-apk RELEASE_GPG_PASSPHRASE: ${{ matrix.format != 'apk' && secrets.RELEASE_GPG_PASSPHRASE || '' }}
APK_SIGNING_KEY_PATH: ${{ matrix.format == 'apk' && '~/.abuild/vikunja-apk.rsa' || '' }}
run: |
chmod +x ./mage-static
./mage-static ${{ matrix.mage_target }}
- name: Upload repo metadata to R2 - name: Upload repo metadata to R2
uses: kolaente/s3-action@41963184b524ccac734ea4d8c964ac74b5b1af89 # v1.2.1 uses: kolaente/s3-action@41963184b524ccac734ea4d8c964ac74b5b1af89 # v1.2.1

View File

@ -1405,7 +1405,7 @@ func (Release) RepoApk(ctx context.Context) error {
// Collect all .apk paths in repo dir for apk index // Collect all .apk paths in repo dir for apk index
repoApks, _ := filepath.Glob(filepath.Join(repoDir, "*.apk")) repoApks, _ := filepath.Glob(filepath.Join(repoDir, "*.apk"))
indexArgs := append([]string{"index", "-o", filepath.Join(repoDir, "APKINDEX.tar.gz")}, repoApks...) indexArgs := append([]string{"index", "--allow-untrusted", "-o", filepath.Join(repoDir, "APKINDEX.tar.gz")}, repoApks...)
if err := runAndStreamOutput(ctx, "apk", indexArgs...); err != nil { if err := runAndStreamOutput(ctx, "apk", indexArgs...); err != nil {
return fmt.Errorf("apk index for %s: %w", repoArch, err) return fmt.Errorf("apk index for %s: %w", repoArch, err)
} }