feat(ci): Add Fedora RPM package build workflow

Building on the Fedora packaging files from #950, this adds a CI workflow
to automatically build RPM packages for Fedora distributions.

The workflow:
- Builds both binary and debug RPMs using rpkg
- Tests package installation in the CI environment
- Publishes packages to Forgejo's RPM registry
- Uploads artifacts for easy download

Thanks to ginger for providing the initial Fedora build files that made
this CI pipeline possible.
This commit is contained in:
Tom Foster 2025-08-28 22:51:37 +01:00
commit 726ae4931f
4 changed files with 529 additions and 5 deletions

View file

@ -0,0 +1,335 @@
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: fedora-latest
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: |
# 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
- 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: |
# 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 "::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: |
# 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
- 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: Test RPM installation
run: |
# 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"
- name: Collect artifacts
if: success()
run: |
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
- name: Upload binary RPM artifact
if: success()
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)
# Create temp directory for this artifact
mkdir -p upload-bin
cp $BIN_RPM upload-bin/
- name: Upload binary RPM
if: success()
uses: actions/upload-artifact@v3
with:
name: continuwuity
path: upload-bin/
- name: Upload debug RPM artifact
if: success()
uses: actions/upload-artifact@v3
with:
name: continuwuity-debug
path: artifacts/*debuginfo*.rpm
- name: Publish to RPM Package Registry
if: success() && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
run: |
# 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
# 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
# Extract package info from RPM for deletion
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}"
# Try to delete existing package first (ignore errors if it doesn't exist)
echo "Removing any existing package: $PACKAGE_NAME-$FULL_VERSION.$PACKAGE_ARCH"
curl -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" \
|| echo "Package didn't exist or deletion failed (this is OK)"
# 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")"
# Extract SRPM info for deletion
SRPM_INFO=$(rpm -qpi "$SRPM" 2>/dev/null)
SRPM_ARCH=$(echo "$SRPM_INFO" | grep "^Architecture" | awk '{print $2}')
# Try to delete existing SRPM first (using same name/version as binary RPM)
echo "Removing any existing SRPM: $PACKAGE_NAME-$FULL_VERSION.$SRPM_ARCH"
curl -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/$SRPM_ARCH" \
|| echo "SRPM didn't exist or deletion failed (this is OK)"
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

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)

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

@ -0,0 +1,189 @@
# 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
```
## Feature branch builds
Feature branches are published to their own groups. For example, for branch `tom/new-feature`:
```bash
# Add the branch-specific repository (replace branch name)
sudo dnf config-manager --add-repo https://forgejo.ellis.link/api/packages/continuwuation/rpm/tom-new-feature/continuwuation.repo
# Install Continuwuity
sudo dnf install continuwuity
```
Note: Branch names are sanitized (slashes become hyphens, lowercase only).
## 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
# Specific feature branch (replace branch-name)
sudo dnf install https://forgejo.ellis.link/api/packages/continuwuation/rpm/branch-name/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
# List enabled repositories
dnf repolist | grep continuwuation
# Disable current repository (use actual repo name from above)
sudo dnf config-manager --set-disabled continuwuation-stable
# or
sudo dnf config-manager --set-disabled continuwuation-dev
# or for feature branches
sudo dnf config-manager --set-disabled continuwuation-branch-name
# Enable desired repository
sudo dnf config-manager --set-enabled continuwuation-stable
# or
sudo dnf config-manager --set-enabled continuwuation-dev
# 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
@ -46,7 +45,7 @@ sed -i 's/^offline = true$//' .cargo/config.toml
# So we have to clear the executable bit on all of them before that happens.
find .cargo/registry/ -executable -name "*.rs" -exec chmod -x {} +
# TODO: this fails currently because it's forced to run in offline mode
# TODO: this fails currently because it's forced to run in offline mode
# {cargo_license -- --no-dev} > LICENSE.dependencies
%install
@ -77,4 +76,4 @@ install -Dpm0644 conduwuit-example.toml %{buildroot}%{_sysconfdir}/conduwuit/con
%systemd_postun_with_restart conduwuit.service
%changelog
{{{ git_repo_changelog }}}
{{{ git_repo_changelog }}}