mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2025-09-09 19:13:03 +02:00
Move build dependency installation after SRPM generation to use dnf builddep, eliminating duplication between CI config and spec file. Dependencies are now sourced directly from the SRPM, ensuring consistency and reducing maintenance. Also fix test installation to properly fail when dependencies cannot be met, removing the fallback to --nodeps which could hide packaging issues.
469 lines
18 KiB
YAML
469 lines
18 KiB
YAML
name: Build / Fedora RPM
|
|
|
|
concurrency:
|
|
group: "build-fedora-${{ github.ref }}"
|
|
cancel-in-progress: true
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- '**'
|
|
tags:
|
|
- 'v*'
|
|
paths:
|
|
- 'fedora/**'
|
|
- 'src/**'
|
|
- 'Cargo.toml'
|
|
- 'Cargo.lock'
|
|
- '.forgejo/workflows/build-fedora.yml'
|
|
workflow_dispatch:
|
|
|
|
jobs:
|
|
build:
|
|
runs-on: fedora-latest
|
|
steps:
|
|
- name: Detect Fedora version
|
|
id: fedora
|
|
run: |
|
|
VERSION=$(rpm -E %fedora)
|
|
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
|
echo "Fedora version: $VERSION"
|
|
|
|
- name: Checkout repository with full history
|
|
uses: https://code.forgejo.org/actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
|
|
- name: Cache DNF packages
|
|
uses: https://code.forgejo.org/actions/cache@v4
|
|
with:
|
|
path: |
|
|
/var/cache/dnf
|
|
/var/cache/yum
|
|
key: dnf-fedora${{ steps.fedora.outputs.version }}-${{ hashFiles('fedora/continuwuity.spec.rpkg') }}-v1
|
|
restore-keys: |
|
|
dnf-fedora${{ steps.fedora.outputs.version }}-
|
|
|
|
- name: Cache Cargo registry
|
|
uses: https://code.forgejo.org/actions/cache@v4
|
|
with:
|
|
path: |
|
|
~/.cargo/registry
|
|
~/.cargo/git
|
|
key: cargo-fedora${{ steps.fedora.outputs.version }}-${{ hashFiles('**/Cargo.lock') }}
|
|
restore-keys: |
|
|
cargo-fedora${{ steps.fedora.outputs.version }}-
|
|
|
|
- name: Cache Rust build dependencies
|
|
uses: https://code.forgejo.org/actions/cache@v4
|
|
with:
|
|
path: |
|
|
~/rpmbuild/BUILD/*/target/release/deps
|
|
~/rpmbuild/BUILD/*/target/release/build
|
|
~/rpmbuild/BUILD/*/target/release/.fingerprint
|
|
~/rpmbuild/BUILD/*/target/release/incremental
|
|
key: rust-deps-fedora${{ steps.fedora.outputs.version }}-${{ hashFiles('**/Cargo.lock') }}
|
|
restore-keys: |
|
|
rust-deps-fedora${{ steps.fedora.outputs.version }}-
|
|
|
|
- name: Setup sccache
|
|
uses: https://github.com/mozilla-actions/sccache-action@v0.0.9
|
|
with:
|
|
token: ${{ secrets.GH_PUBLIC_RO }}
|
|
|
|
- name: Configure sccache environment
|
|
run: |
|
|
echo "RUSTC_WRAPPER=sccache" >> $GITHUB_ENV
|
|
echo "CMAKE_C_COMPILER_LAUNCHER=sccache" >> $GITHUB_ENV
|
|
echo "CMAKE_CXX_COMPILER_LAUNCHER=sccache" >> $GITHUB_ENV
|
|
echo "SCCACHE_CACHE_SIZE=10G" >> $GITHUB_ENV
|
|
# Aggressive GC since cache restores don't increment counter
|
|
echo "CARGO_INCREMENTAL_GC_TRIGGER=5" >> $GITHUB_ENV
|
|
|
|
- name: Install base RPM tools
|
|
run: |
|
|
dnf install -y --setopt=keepcache=1 \
|
|
wget \
|
|
rpm-build \
|
|
rpm-sign \
|
|
rpmdevtools \
|
|
rpkg \
|
|
cargo-rpm-macros \
|
|
systemd-rpm-macros \
|
|
python3-pip
|
|
|
|
- name: Setup build environment and build SRPM
|
|
run: |
|
|
git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
|
git config --global user.email "ci@continuwuity.org"
|
|
git config --global user.name "Continuwuity"
|
|
|
|
rpmdev-setuptree
|
|
|
|
cd "$GITHUB_WORKSPACE"
|
|
|
|
# Determine release suffix and version based on ref type and branch
|
|
if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then
|
|
# Tags get clean version numbers for stable releases
|
|
RELEASE_SUFFIX=""
|
|
TAG_NAME="${{ github.ref_name }}"
|
|
# Extract version from tag (remove v prefix if present)
|
|
TAG_VERSION=$(echo "$TAG_NAME" | sed 's/^v//')
|
|
|
|
# Create spec file with tag version
|
|
sed -e "s/^Version:.*$/Version: $TAG_VERSION/" \
|
|
-e "s/^Release:.*$/Release: 1%{?dist}/" \
|
|
fedora/continuwuity.spec.rpkg > continuwuity.spec.rpkg
|
|
elif [ "${{ github.ref_name }}" = "main" ]; then
|
|
# Main branch gets .dev suffix
|
|
RELEASE_SUFFIX=".dev"
|
|
|
|
# Replace the Release line to include our suffix
|
|
sed "s/^Release:.*$/Release: 1${RELEASE_SUFFIX}%{?dist}/" \
|
|
fedora/continuwuity.spec.rpkg > continuwuity.spec.rpkg
|
|
else
|
|
# Other branches get sanitized branch name as suffix
|
|
SAFE_BRANCH=$(echo "${{ github.ref_name }}" | sed 's/[^a-zA-Z0-9]/_/g' | cut -c1-20)
|
|
RELEASE_SUFFIX=".${SAFE_BRANCH}"
|
|
|
|
# Replace the Release line to include our suffix
|
|
sed "s/^Release:.*$/Release: 1${RELEASE_SUFFIX}%{?dist}/" \
|
|
fedora/continuwuity.spec.rpkg > continuwuity.spec.rpkg
|
|
fi
|
|
|
|
rpkg srpm --outdir "$HOME/rpmbuild/SRPMS"
|
|
|
|
ls -la $HOME/rpmbuild/SRPMS/
|
|
|
|
- name: Setup GPG for RPM signing
|
|
run: |
|
|
# Skip if no signing key is configured
|
|
if [ -z "${{ secrets.RPM_SIGNING_KEY }}" ]; then
|
|
echo "No RPM signing key configured - skipping signing setup"
|
|
exit 0
|
|
fi
|
|
|
|
echo "${{ secrets.RPM_SIGNING_KEY }}" | gpg --batch --import
|
|
|
|
# Get the key ID (look for the sec line, not the uid line)
|
|
KEY_ID=$(gpg --list-secret-keys --keyid-format=long | grep "^sec" | head -1 | awk '{print $2}' | cut -d'/' -f2)
|
|
echo "Using GPG key: $KEY_ID"
|
|
|
|
cat > ~/.rpmmacros << EOF
|
|
%_signature gpg
|
|
%_gpg_name $KEY_ID
|
|
%__gpg /usr/bin/gpg
|
|
EOF
|
|
|
|
- name: Install build dependencies from SRPM
|
|
run: |
|
|
SRPM=$(find "$HOME/rpmbuild/SRPMS" -name "*.src.rpm" | head -1)
|
|
|
|
if [ -z "$SRPM" ]; then
|
|
echo "Error: No SRPM file found"
|
|
exit 1
|
|
fi
|
|
|
|
echo "Installing build dependencies from: $(basename $SRPM)"
|
|
dnf builddep -y "$SRPM"
|
|
|
|
- name: Build RPM from SRPM
|
|
run: |
|
|
SRPM=$(find "$HOME/rpmbuild/SRPMS" -name "*.src.rpm" | head -1)
|
|
|
|
if [ -z "$SRPM" ]; then
|
|
echo "Error: No SRPM file found"
|
|
exit 1
|
|
fi
|
|
|
|
echo "Building from SRPM: $SRPM"
|
|
|
|
rpmbuild --rebuild "$SRPM" \
|
|
--define "_topdir $HOME/rpmbuild" \
|
|
--define "_sourcedir $GITHUB_WORKSPACE" \
|
|
--nocheck # Skip %check section to avoid test dependencies
|
|
|
|
- name: Sign RPM packages
|
|
run: |
|
|
# Skip if no signing key is configured
|
|
if [ -z "${{ secrets.RPM_SIGNING_KEY }}" ]; then
|
|
echo "No RPM signing key configured - skipping package signing"
|
|
exit 0
|
|
fi
|
|
|
|
# Export GPG_TTY to avoid terminal warnings
|
|
export GPG_TTY=/dev/null
|
|
|
|
for rpm in $(find "$HOME/rpmbuild" -name "*.rpm" -type f); do
|
|
echo "Signing: $(basename $rpm)"
|
|
|
|
# Use expect or provide empty passphrase via stdin for batch signing
|
|
if ! echo "" | rpmsign --addsign "$rpm" 2>&1; then
|
|
echo "ERROR: Failed to sign $rpm"
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
echo "Successfully signed all RPMs"
|
|
|
|
- name: Verify RPM signatures
|
|
run: |
|
|
# Skip if no signing key is configured
|
|
if [ -z "${{ secrets.RPM_SIGNING_KEY }}" ]; then
|
|
echo "No RPM signing key configured - skipping signature verification"
|
|
exit 0
|
|
fi
|
|
|
|
echo "Importing GPG public key for verification..."
|
|
rpm --import fedora/RPM-GPG-KEY-continuwuity.asc
|
|
|
|
FAILED_COUNT=0
|
|
TOTAL_COUNT=0
|
|
|
|
for rpm in $(find "$HOME/rpmbuild" -name "*.rpm" -type f); do
|
|
echo -n "Verifying $(basename $rpm): "
|
|
TOTAL_COUNT=$((TOTAL_COUNT + 1))
|
|
|
|
if rpm --checksig "$rpm"; then
|
|
echo " ✓"
|
|
else
|
|
echo " ✗ FAILED"
|
|
FAILED_COUNT=$((FAILED_COUNT + 1))
|
|
fi
|
|
done
|
|
|
|
# Fail if any RPMs failed verification
|
|
if [ "$FAILED_COUNT" -gt 0 ]; then
|
|
echo "ERROR: $FAILED_COUNT out of $TOTAL_COUNT RPMs failed signature verification"
|
|
exit 1
|
|
fi
|
|
|
|
echo "Successfully verified all $TOTAL_COUNT RPM signatures"
|
|
|
|
- name: Test RPM installation
|
|
run: |
|
|
# Find the main binary RPM (exclude debug and source RPMs)
|
|
RPM=$(find "$HOME/rpmbuild/RPMS" -name "continuwuity-*.rpm" \
|
|
! -name "*debuginfo*" \
|
|
! -name "*debugsource*" \
|
|
! -name "*.src.rpm" | head -1)
|
|
|
|
if [ -z "$RPM" ]; then
|
|
echo "Error: No binary RPM file found"
|
|
exit 1
|
|
fi
|
|
|
|
echo "Testing installation of: $RPM"
|
|
|
|
# Dry run first
|
|
rpm -qpi "$RPM"
|
|
echo ""
|
|
rpm -qpl "$RPM"
|
|
|
|
# Actually install it
|
|
dnf install -y "$RPM"
|
|
|
|
# Verify installation
|
|
rpm -qa | grep continuwuity
|
|
|
|
# Check that the binary exists
|
|
[ -f /usr/bin/conduwuit ] && echo "✅ Binary installed successfully"
|
|
[ -f /usr/lib/systemd/system/conduwuit.service ] && echo "✅ Systemd service installed"
|
|
[ -f /etc/conduwuit/conduwuit.toml ] && echo "✅ Config file installed"
|
|
|
|
- name: List built packages
|
|
run: |
|
|
echo "Binary RPMs:"
|
|
find "$HOME/rpmbuild/RPMS" -name "*.rpm" -type f -exec ls -la {} \;
|
|
|
|
echo ""
|
|
echo "Source RPMs:"
|
|
find "$HOME/rpmbuild/SRPMS" -name "*.rpm" -type f -exec ls -la {} \;
|
|
|
|
- name: Collect artifacts
|
|
run: |
|
|
mkdir -p artifacts
|
|
|
|
find "$HOME/rpmbuild/RPMS" -name "*.rpm" -type f -exec cp {} artifacts/ \;
|
|
find "$HOME/rpmbuild/SRPMS" -name "*.rpm" -type f -exec cp {} artifacts/ \;
|
|
|
|
cd artifacts
|
|
echo "Build Information:" > BUILD_INFO.txt
|
|
echo "==================" >> BUILD_INFO.txt
|
|
echo "Git commit: ${{ github.sha }}" >> BUILD_INFO.txt
|
|
echo "Git branch: ${{ github.ref_name }}" >> BUILD_INFO.txt
|
|
echo "Build date: $(date -u +%Y-%m-%d_%H:%M:%S_UTC)" >> BUILD_INFO.txt
|
|
echo "" >> BUILD_INFO.txt
|
|
echo "Package contents:" >> BUILD_INFO.txt
|
|
echo "-----------------" >> BUILD_INFO.txt
|
|
for rpm in *.rpm; do
|
|
echo "" >> BUILD_INFO.txt
|
|
echo "File: $rpm" >> BUILD_INFO.txt
|
|
rpm -qpi "$rpm" 2>/dev/null | grep -E "^(Name|Version|Release|Architecture|Size)" >> BUILD_INFO.txt
|
|
done
|
|
|
|
ls -la
|
|
|
|
- name: Upload binary RPM artifact
|
|
run: |
|
|
# Find the main binary RPM (exclude debug and source RPMs)
|
|
BIN_RPM=$(find artifacts -name "continuwuity-*.rpm" \
|
|
! -name "*debuginfo*" \
|
|
! -name "*debugsource*" \
|
|
! -name "*.src.rpm" \
|
|
-type f)
|
|
|
|
mkdir -p upload-bin
|
|
cp $BIN_RPM upload-bin/
|
|
|
|
- name: Upload binary RPM
|
|
uses: https://code.forgejo.org/actions/upload-artifact@v3
|
|
with:
|
|
name: continuwuity
|
|
path: upload-bin/
|
|
|
|
- name: Upload debug RPM artifact
|
|
uses: https://code.forgejo.org/actions/upload-artifact@v3
|
|
with:
|
|
name: continuwuity-debug
|
|
path: artifacts/*debuginfo*.rpm
|
|
|
|
- name: Publish to RPM Package Registry
|
|
if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }}
|
|
run: |
|
|
# Find the main binary RPM (exclude debug and source RPMs)
|
|
RPM=$(find artifacts -name "continuwuity-*.rpm" \
|
|
! -name "*debuginfo*" \
|
|
! -name "*debugsource*" \
|
|
! -name "*.src.rpm" \
|
|
-type f | head -1)
|
|
|
|
if [ -z "$RPM" ]; then
|
|
echo "No binary RPM found to publish"
|
|
exit 0
|
|
fi
|
|
|
|
RPM_BASENAME=$(basename "$RPM")
|
|
echo "Publishing: $RPM_BASENAME"
|
|
|
|
# Determine the group based on ref type and branch
|
|
if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then
|
|
GROUP="stable"
|
|
# For tags, extract the tag name for version info
|
|
TAG_NAME="${{ github.ref_name }}"
|
|
elif [ "${{ github.ref_name }}" = "main" ]; then
|
|
GROUP="dev"
|
|
else
|
|
# Use sanitized branch name as group for feature branches
|
|
GROUP=$(echo "${{ github.ref_name }}" | sed 's/[^a-zA-Z0-9]/-/g' | tr '[:upper:]' '[:lower:]' | cut -c1-30)
|
|
fi
|
|
|
|
PACKAGE_INFO=$(rpm -qpi "$RPM" 2>/dev/null)
|
|
PACKAGE_NAME=$(echo "$PACKAGE_INFO" | grep "^Name" | awk '{print $3}')
|
|
PACKAGE_VERSION=$(echo "$PACKAGE_INFO" | grep "^Version" | awk '{print $3}')
|
|
PACKAGE_RELEASE=$(echo "$PACKAGE_INFO" | grep "^Release" | awk '{print $3}')
|
|
PACKAGE_ARCH=$(echo "$PACKAGE_INFO" | grep "^Architecture" | awk '{print $2}')
|
|
|
|
# Full version includes release
|
|
FULL_VERSION="${PACKAGE_VERSION}-${PACKAGE_RELEASE}"
|
|
|
|
# Forgejo's RPM registry cannot overwrite existing packages, so we must delete first
|
|
# 404 is OK if package doesn't exist yet
|
|
echo "Removing any existing package: $PACKAGE_NAME-$FULL_VERSION.$PACKAGE_ARCH"
|
|
RESPONSE=$(curl -s -w "\n%{http_code}" -X DELETE \
|
|
-H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \
|
|
"https://forgejo.ellis.link/api/packages/continuwuation/rpm/$GROUP/package/$PACKAGE_NAME/$FULL_VERSION/$PACKAGE_ARCH")
|
|
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
|
|
|
|
if [ "$HTTP_CODE" != "204" ] && [ "$HTTP_CODE" != "404" ]; then
|
|
echo "ERROR: Failed to delete package (HTTP $HTTP_CODE)"
|
|
echo "$RESPONSE" | head -n -1
|
|
exit 1
|
|
fi
|
|
|
|
curl --fail-with-body \
|
|
-X PUT \
|
|
-H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \
|
|
-H "Content-Type: application/x-rpm" \
|
|
-T "$RPM" \
|
|
"https://forgejo.ellis.link/api/packages/continuwuation/rpm/$GROUP/upload"
|
|
|
|
echo ""
|
|
echo "✅ Published binary RPM to: https://forgejo.ellis.link/continuwuation/-/packages/rpm/continuwuity/"
|
|
echo "Group: $GROUP"
|
|
|
|
# Upload debug RPMs to separate group
|
|
DEBUG_RPMS=$(find artifacts -name "*debuginfo*.rpm")
|
|
if [ -n "$DEBUG_RPMS" ]; then
|
|
echo ""
|
|
echo "Publishing debug RPMs to group: ${GROUP}-debug"
|
|
|
|
for DEBUG_RPM in $DEBUG_RPMS; do
|
|
echo "Publishing: $(basename "$DEBUG_RPM")"
|
|
|
|
DEBUG_INFO=$(rpm -qpi "$DEBUG_RPM" 2>/dev/null)
|
|
DEBUG_NAME=$(echo "$DEBUG_INFO" | grep "^Name" | awk '{print $3}')
|
|
DEBUG_VERSION=$(echo "$DEBUG_INFO" | grep "^Version" | awk '{print $3}')
|
|
DEBUG_RELEASE=$(echo "$DEBUG_INFO" | grep "^Release" | awk '{print $3}')
|
|
DEBUG_ARCH=$(echo "$DEBUG_INFO" | grep "^Architecture" | awk '{print $2}')
|
|
DEBUG_FULL_VERSION="${DEBUG_VERSION}-${DEBUG_RELEASE}"
|
|
|
|
# Must delete existing package first (Forgejo limitation)
|
|
RESPONSE=$(curl -s -w "\n%{http_code}" -X DELETE \
|
|
-H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \
|
|
"https://forgejo.ellis.link/api/packages/continuwuation/rpm/${GROUP}-debug/package/$DEBUG_NAME/$DEBUG_FULL_VERSION/$DEBUG_ARCH")
|
|
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
|
|
|
|
if [ "$HTTP_CODE" != "204" ] && [ "$HTTP_CODE" != "404" ]; then
|
|
echo "ERROR: Failed to delete debug package (HTTP $HTTP_CODE)"
|
|
echo "$RESPONSE" | head -n -1
|
|
exit 1
|
|
fi
|
|
|
|
curl --fail-with-body \
|
|
-X PUT \
|
|
-H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \
|
|
-H "Content-Type: application/x-rpm" \
|
|
-T "$DEBUG_RPM" \
|
|
"https://forgejo.ellis.link/api/packages/continuwuation/rpm/${GROUP}-debug/upload"
|
|
done
|
|
|
|
echo "✅ Published debug RPMs to group: ${GROUP}-debug"
|
|
fi
|
|
|
|
# Also upload the SRPM to separate group
|
|
SRPM=$(find artifacts -name "*.src.rpm" | head -1)
|
|
if [ -n "$SRPM" ]; then
|
|
echo ""
|
|
echo "Publishing source RPM: $(basename "$SRPM")"
|
|
echo "Publishing to group: ${GROUP}-src"
|
|
|
|
SRPM_INFO=$(rpm -qpi "$SRPM" 2>/dev/null)
|
|
SRPM_NAME=$(echo "$SRPM_INFO" | grep "^Name" | awk '{print $3}')
|
|
SRPM_VERSION=$(echo "$SRPM_INFO" | grep "^Version" | awk '{print $3}')
|
|
SRPM_RELEASE=$(echo "$SRPM_INFO" | grep "^Release" | awk '{print $3}')
|
|
SRPM_FULL_VERSION="${SRPM_VERSION}-${SRPM_RELEASE}"
|
|
|
|
# Must delete existing SRPM first (Forgejo limitation)
|
|
echo "Removing any existing SRPM: $SRPM_NAME-$SRPM_FULL_VERSION.src"
|
|
RESPONSE=$(curl -s -w "\n%{http_code}" -X DELETE \
|
|
-H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \
|
|
"https://forgejo.ellis.link/api/packages/continuwuation/rpm/${GROUP}-src/package/$SRPM_NAME/$SRPM_FULL_VERSION/src")
|
|
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
|
|
|
|
if [ "$HTTP_CODE" != "204" ] && [ "$HTTP_CODE" != "404" ]; then
|
|
echo "ERROR: Failed to delete SRPM (HTTP $HTTP_CODE)"
|
|
echo "$RESPONSE" | head -n -1
|
|
exit 1
|
|
fi
|
|
|
|
curl --fail-with-body \
|
|
-X PUT \
|
|
-H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \
|
|
-H "Content-Type: application/x-rpm" \
|
|
-T "$SRPM" \
|
|
"https://forgejo.ellis.link/api/packages/continuwuation/rpm/${GROUP}-src/upload"
|
|
|
|
echo "✅ Published source RPM to group: ${GROUP}-src"
|
|
fi
|