feat(ci): Add Fedora RPM package build workflow

Implement automated RPM package building using rpkg-util in CI, publishing
to Forgejo's native RPM registry with three channels: stable (tags), dev
(main branch), and testing (feature branches).

Packages include branch-specific version suffixes to avoid registry conflicts.
Users can configure dnf repositories for automatic updates or directly install
specific builds. The workflow builds on all branches, uploads CI artifacts,
and publishes to the appropriate package registry channel.
This commit is contained in:
Tom Foster 2025-08-28 22:51:37 +01:00
commit 18e3967177
4 changed files with 547 additions and 5 deletions

View file

@ -0,0 +1,356 @@
name: Build RPM Package
concurrency:
group: "rpm-build-${{ github.ref }}"
cancel-in-progress: true
on:
push:
paths:
- 'fedora/**'
- 'src/**'
- 'Cargo.toml'
- 'Cargo.lock'
- '.forgejo/workflows/rpm-build.yml'
pull_request:
paths:
- 'fedora/**'
- 'src/**'
- 'Cargo.toml'
- 'Cargo.lock'
- '.forgejo/workflows/rpm-build.yml'
workflow_dispatch:
jobs:
rpm-build:
name: Build RPM Package
runs-on: ubuntu-latest
container:
image: fedora:latest
options: --privileged
steps:
- name: Detect Fedora version
id: fedora
run: |
VERSION=$(rpm -E %fedora)
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Fedora version: $VERSION"
- name: Install Node.js for GitHub Actions
run: |
dnf install -y nodejs git
node --version
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0 # rpkg needs full history for git macros
- name: Cache DNF packages
uses: 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: Install build dependencies
run: |
echo "::group::📦 Installing RPM build tools and dependencies"
# Keep DNF cache for reuse
dnf install -y --setopt=keepcache=1 \
wget \
rpm-build \
rpmdevtools \
rpkg \
cargo-rpm-macros \
systemd-rpm-macros \
clang \
liburing-devel \
rust \
cargo \
gcc \
gcc-c++ \
make \
openssl-devel \
pkg-config \
python3-pip
echo "::endgroup::"
- name: Cache Cargo registry
uses: 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: 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
# Set sccache cache size limit
echo "SCCACHE_CACHE_SIZE=2G" >> $GITHUB_ENV
- name: Setup build environment and build SRPM
run: |
echo "::group::🔧 Setting up build environment"
# Configure git for rpkg
git config --global --add safe.directory "$GITHUB_WORKSPACE"
git config --global user.email "ci@continuwuity.org"
git config --global user.name "Continuwuity"
# Setup RPM build tree
rpmdev-setuptree
echo "::endgroup::"
echo "::group::📦 Building source RPM with rpkg"
cd "$GITHUB_WORKSPACE"
# Determine release suffix based on ref type and branch
if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then
# Tags get clean version numbers for stable releases
RELEASE_SUFFIX=""
elif [ "${{ github.ref_name }}" = "main" ]; then
# Main branch gets .dev suffix
RELEASE_SUFFIX=".dev"
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}"
fi
# Create a temporary spec file with the release suffix
if [ -n "$RELEASE_SUFFIX" ]; then
# Replace the Release line to include our suffix
sed "s/^Release:.*$/Release: 1${RELEASE_SUFFIX}%{?dist}/" \
fedora/continuwuity.spec.rpkg > continuwuity.spec.rpkg
else
# Use the original spec file
ln -sf fedora/continuwuity.spec.rpkg continuwuity.spec.rpkg
fi
# Build the SRPM
rpkg srpm --outdir "$HOME/rpmbuild/SRPMS"
# List generated SRPM
echo "Generated SRPM:"
ls -la "$HOME/rpmbuild/SRPMS/"
echo "::endgroup::"
- name: Build RPM from SRPM
run: |
echo "::group::🔨 Building RPM package"
# Find the SRPM file
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"
# Build the binary RPM
# Note: Using rpmbuild directly since mock would need additional setup
rpmbuild --rebuild "$SRPM" \
--define "_topdir $HOME/rpmbuild" \
--define "_sourcedir $GITHUB_WORKSPACE" \
--nocheck # Skip %check section to avoid test dependencies
echo "::endgroup::"
- name: Show sccache statistics
run: |
echo "::group::📊 sccache statistics"
sccache --show-stats
echo "::endgroup::"
- name: List built packages
run: |
echo "::group::📋 Built RPM packages"
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 {} \;
echo "::endgroup::"
- name: Test RPM installation
run: |
echo "::group::🧪 Testing RPM installation"
# Find the binary RPM
RPM=$(find "$HOME/rpmbuild/RPMS" -name "continuwuity-*.rpm" ! -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 (would need --nodeps if dependencies aren't met)
dnf install -y "$RPM" || rpm -ivh --nodeps "$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"
echo "::endgroup::"
- name: Collect artifacts
if: success()
run: |
echo "::group::📦 Collecting artifacts"
mkdir -p artifacts
# Copy all RPMs to artifacts directory
find "$HOME/rpmbuild/RPMS" -name "*.rpm" -type f -exec cp {} artifacts/ \;
find "$HOME/rpmbuild/SRPMS" -name "*.rpm" -type f -exec cp {} artifacts/ \;
# Create metadata file
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
echo "::endgroup::"
- name: Upload RPM artifacts
if: success()
uses: actions/upload-artifact@v3
with:
name: rpm-packages-${{ github.sha }}
path: artifacts/
retention-days: 30
- name: Publish to RPM Package Registry
if: success() && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
run: |
echo "::group::📦 Publishing RPMs to Package Registry"
# Find the binary RPM (exclude source RPMs)
RPM=$(find artifacts -name "continuwuity-*.rpm" ! -name "*.src.rpm" | head -1)
if [ -z "$RPM" ]; then
echo "No binary RPM found to publish"
exit 0
fi
# Extract version from RPM filename
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"
elif [ "${{ github.ref_name }}" = "main" ]; then
GROUP="dev"
else
GROUP="testing"
fi
# Upload to Forgejo package registry
# Using the RPM registry endpoint with group support
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 to: https://forgejo.ellis.link/continuwuation/-/packages/rpm/continuwuity/"
echo "Group: $GROUP"
# Also upload the SRPM
SRPM=$(find artifacts -name "*.src.rpm" | head -1)
if [ -n "$SRPM" ]; then
echo ""
echo "Publishing source RPM: $(basename "$SRPM")"
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/upload"
fi
echo "::endgroup::"
echo "::group::📋 Repository Setup Instructions"
echo ""
echo "Users can install Continuwuity using:"
echo ""
if [ "$GROUP" = "stable" ]; then
echo "# For stable releases (tags):"
echo "sudo dnf config-manager --add-repo https://forgejo.ellis.link/api/packages/continuwuation/rpm/stable/continuwuation.repo"
elif [ "$GROUP" = "dev" ]; then
echo "# For development builds (main branch):"
echo "sudo dnf config-manager --add-repo https://forgejo.ellis.link/api/packages/continuwuation/rpm/dev/continuwuation.repo"
else
echo "# For testing builds (feature branches):"
echo "sudo dnf config-manager --add-repo https://forgejo.ellis.link/api/packages/continuwuation/rpm/testing/continuwuation.repo"
fi
echo "sudo dnf install continuwuity"
echo ""
echo "# Direct download of this specific build:"
echo "sudo dnf install https://forgejo.ellis.link/api/packages/continuwuation/rpm/$GROUP/$RPM_BASENAME"
echo "::endgroup::"
- name: Create release artifacts (on tag)
if: github.ref_type == 'tag'
run: |
echo "::group::🏷️ Preparing release artifacts"
cd artifacts
# Create tarball of all RPMs
tar -czf "continuwuity-rpms-${{ github.ref_name }}.tar.gz" *.rpm BUILD_INFO.txt
# Generate checksums
sha256sum *.rpm *.tar.gz > SHA256SUMS
ls -la
echo "::endgroup::"
- name: Upload to release (on tag)
if: github.ref_type == 'tag'
uses: https://github.com/softprops/action-gh-release@v2
with:
token: ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}
files: |
artifacts/*.rpm
artifacts/*.tar.gz
artifacts/SHA256SUMS

View file

@ -10,6 +10,7 @@
- [Kubernetes](deploying/kubernetes.md)
- [Arch Linux](deploying/arch-linux.md)
- [Debian](deploying/debian.md)
- [Fedora](deploying/fedora.md)
- [FreeBSD](deploying/freebsd.md)
- [TURN](turn.md)
- [Appservices](appservices.md)

186
docs/deploying/fedora.md Normal file
View file

@ -0,0 +1,186 @@
# RPM Installation Guide
Continuwuity is available as RPM packages for Fedora, RHEL, and compatible distributions.
## Quick install (stable)
For the latest stable version from release tags:
```bash
# Add the Continuwuity repository
sudo dnf config-manager --add-repo https://forgejo.ellis.link/api/packages/continuwuation/rpm/stable/continuwuation.repo
# Install Continuwuity
sudo dnf install continuwuity
# Enable automatic updates (optional)
sudo dnf install dnf-automatic
sudo systemctl enable --now dnf-automatic.timer
```
## Development builds
For development builds from the main branch:
```bash
# Add the dev repository
sudo dnf config-manager --add-repo https://forgejo.ellis.link/api/packages/continuwuation/rpm/dev/continuwuation.repo
# Install Continuwuity
sudo dnf install continuwuity
```
## Testing builds
For testing builds from feature branches:
```bash
# Add the testing repository
sudo dnf config-manager --add-repo https://forgejo.ellis.link/api/packages/continuwuation/rpm/testing/continuwuation.repo
# Install Continuwuity
sudo dnf install continuwuity
```
## Direct package installation
To install a specific version without adding the repository:
```bash
# Latest stable release
sudo dnf install https://forgejo.ellis.link/api/packages/continuwuation/rpm/stable/continuwuity
# Latest development build (main branch)
sudo dnf install https://forgejo.ellis.link/api/packages/continuwuation/rpm/dev/continuwuity
# Latest testing build (feature branches)
sudo dnf install https://forgejo.ellis.link/api/packages/continuwuation/rpm/testing/continuwuity
```
## Managing automatic updates
### Option 1: DNF Automatic (recommended)
```bash
# Install dnf-automatic
sudo dnf install dnf-automatic
# Configure update policy
sudo nano /etc/dnf/automatic.conf
# Set: apply_updates = yes
# Enable the service
sudo systemctl enable --now dnf-automatic.timer
```
### Option 2: Manual updates
```bash
# Check for updates
sudo dnf check-update continuwuity
# Update to latest version
sudo dnf update continuwuity
```
## Switching between channels
```bash
# Disable current repository
sudo dnf config-manager --set-disabled continuwuation-stable
# or
sudo dnf config-manager --set-disabled continuwuation-dev
# or
sudo dnf config-manager --set-disabled continuwuation-testing
# Enable desired repository
sudo dnf config-manager --set-enabled continuwuation-stable
# or
sudo dnf config-manager --set-enabled continuwuation-dev
# or
sudo dnf config-manager --set-enabled continuwuation-testing
# Update to the new channel's version
sudo dnf update continuwuity
```
## Verifying installation
```bash
# Check installed version
rpm -q continuwuity
# View package information
rpm -qi continuwuity
# List installed files
rpm -ql continuwuity
# Verify package integrity
rpm -V continuwuity
```
## Systemd service management
Continuwuity includes a systemd service file:
```bash
# Start the service
sudo systemctl start conduwuit
# Enable on boot
sudo systemctl enable conduwuit
# Check status
sudo systemctl status conduwuit
# View logs
sudo journalctl -u conduwuit -f
```
## Uninstallation
```bash
# Stop and disable the service
sudo systemctl stop conduwuit
sudo systemctl disable conduwuit
# Remove the package
sudo dnf remove continuwuity
# Remove the repository (optional)
sudo rm /etc/yum.repos.d/continuwuation-*.repo
```
## Troubleshooting
### GPG key issues
If you encounter GPG key errors, you can temporarily disable GPG checking:
```bash
sudo dnf --nogpgcheck install continuwuity
```
### Repository metadata issues
Clear and rebuild the cache:
```bash
sudo dnf clean all
sudo dnf makecache
```
### Finding specific versions
List all available versions:
```bash
dnf --showduplicates list continuwuity
```
Install a specific version:
```bash
sudo dnf install continuwuity-<version>
```

View file

@ -1,6 +1,5 @@
# This should be run using rpkg-util: https://docs.pagure.org/rpkg-util
# This should be run using rpkg: https://docs.pagure.org/rpkg
# it requires Internet access and is not suitable for Fedora main repos
# TODO: rpkg-util is no longer maintained, find a replacement
Name: continuwuity
Version: {{{ git_repo_version }}}
@ -38,7 +37,7 @@ sed -i 's/^offline = true$//' .cargo/config.toml
%cargo_build
# Here's the one legally required mystery incantation in this file.
# Some of our dependencies have source files which are (for some reason) marked as excutable.
# Some of our dependencies have source files which are (for some reason) marked as executable.
# Files in .cargo/registry/ are copied into /usr/src/ by the debuginfo machinery
# at the end of the build step, and then the BRP shebang mangling script checks
# the entire buildroot to find executable files, and fails the build because