Compare commits

..

5 commits

Author SHA1 Message Date
Tom Foster
1498ff17e8 fix(ci): Correct SRPM architecture to prevent binary RPM overwrite
Source RPMs were incorrectly being registered with x86_64 architecture
instead of 'src', causing them to overwrite the binary RPM in the package
registry. This resulted in the 16MB binary being replaced by the 847KB
source package. SRPMs now correctly use 'src' architecture.
2025-08-31 16:43:41 +01:00
Tom Foster
20ec1e0290 fix(ci): Fix RPM key import using local file instead of curl
The curl pipe to rpm --import was failing with 'rpmkeys: no arguments given'
error. Use direct import from the local repository file at
fedora/RPM-GPG-KEY-continuwuity.asc which is simpler, more reliable, and
removes an unnecessary network dependency.
2025-08-31 15:54:50 +01:00
Tom Foster
4ffabfb7e1 fix(ci): Fix RPM signing loops and ensure failures are caught
Replace while-read loops with for loops to avoid subshell variable scoping
issues. Export GPG_TTY=/dev/null to suppress terminal warnings. Provide
empty passphrase via stdin for batch signing without interaction.

Both signing and verification now properly track failures and exit with
non-zero status if any RPMs fail to sign or verify, preventing misleading
successful pipeline runs.
2025-08-30 23:18:47 +01:00
Tom Foster
b86d9c15a7 fix(ci): Correct GPG key extraction and RPM selection in Fedora workflow
Fix GPG signing failures caused by incorrect key ID extraction that was
parsing the uid line instead of the secret key line. Also exclude debug
packages from RPM selection to ensure the main binary package is tested
and published.

Increase sccache cache size to 10GB to accommodate the project's extensive
dependency tree and improve build performance.
2025-08-30 22:27:33 +01:00
Tom Foster
98775d915c feat(ci): Add Fedora RPM package build workflow
Following PR #950 which introduced the RPM spec and systemd unit files,
this adds a comprehensive CI workflow for building, signing, testing, and
publishing RPM packages. Includes GPG signing infrastructure with Ed25519
keys and automatic package registry deployment for stable, development,
and feature branch builds.

Add documentation for RPM installation methods, repository configuration,
and package management. Fix linting issues in spec file for pre-commit
compliance.
2025-08-30 21:31:52 +01:00
5 changed files with 86 additions and 190 deletions

View file

@ -26,7 +26,3 @@ max_line_length = 98
[*.yml]
indent_size = 2
indent_style = space
[*.json]
indent_size = 4
indent_style = space

View file

@ -1,4 +1,4 @@
name: Build / Fedora RPM
name: Build Fedora RPM
concurrency:
group: "build-fedora-${{ github.ref }}"
@ -6,10 +6,6 @@ concurrency:
on:
push:
branches:
- '**'
tags:
- 'v*'
paths:
- 'fedora/**'
- 'src/**'
@ -114,33 +110,27 @@ jobs:
cd "$GITHUB_WORKSPACE"
# Determine release suffix and version based on ref type and branch
# 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=""
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}"
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
@ -374,8 +364,6 @@ jobs:
# 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
@ -410,63 +398,23 @@ jobs:
"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 "✅ Published 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" -o -name "*debugsource*.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")"
# Extract debug RPM info
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}"
# Try to delete existing debug package first
curl -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" \
|| echo "Debug package didn't exist or deletion failed (this is OK)"
# Upload debug RPM
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
# Also upload the SRPM
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"
# Extract SRPM info
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}"
# SRPMs always have architecture "src"
SRPM_ARCH="src"
# Try to delete existing SRPM first
echo "Removing any existing SRPM: $SRPM_NAME-$SRPM_FULL_VERSION.src"
# 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}-src/package/$SRPM_NAME/$SRPM_FULL_VERSION/src" \
"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 \
@ -474,7 +422,5 @@ jobs:
-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"
"https://forgejo.ellis.link/api/packages/continuwuation/rpm/$GROUP/upload"
fi

View file

@ -161,7 +161,7 @@ jobs:
var-lib-apt-${{ matrix.slug }}
key: var-lib-apt-${{ matrix.slug }}
- name: inject cache into docker
uses: https://github.com/reproducible-containers/buildkit-cache-dance@v3.3.0
uses: https://github.com/reproducible-containers/buildkit-cache-dance@v3.1.0
with:
cache-map: |
{

View file

@ -39,73 +39,24 @@ jobs:
renovate:
name: Renovate
runs-on: ubuntu-latest
container:
image: ghcr.io/renovatebot/renovate:41
options: --tmpfs /tmp:exec
steps:
- name: Checkout
uses: actions/checkout@v4
with:
show-progress: false
- name: print node heap
run: /usr/local/renovate/node -e 'console.log(`node heap limit = ${require("v8").getHeapStatistics().heap_size_limit / (1024 * 1024)} Mb`)'
- name: Restore renovate repo cache
uses: https://github.com/actions/cache@v4
with:
path: |
/tmp/renovate/cache/renovate/repository
key: repo-cache-${{ github.run_id }}
restore-keys: |
repo-cache-
- name: Restore renovate package cache
uses: https://github.com/actions/cache@v4
with:
path: |
/tmp/renovate/cache/renovate/renovate-cache-sqlite
key: package-cache-${{ github.run_id }}
restore-keys: |
package-cache-
- name: Self-hosted Renovate
uses: https://github.com/renovatebot/github-action@v43.0.9
uses: https://github.com/renovatebot/github-action@v40.1.0
env:
LOG_LEVEL: ${{ inputs.logLevel || 'info' }}
RENOVATE_DRY_RUN: ${{ inputs.dryRun || 'false' }}
RENOVATE_PLATFORM: forgejo
RENOVATE_ENDPOINT: ${{ github.server_url }}
RENOVATE_AUTODISCOVER: 'false'
RENOVATE_REPOSITORIES: '["${{ github.repository }}"]'
RENOVATE_BINARY_SOURCE: 'install'
RENOVATE_DRY_RUN: ${{ inputs.dryRun || 'false' }}
RENOVATE_ENDPOINT: ${{ github.server_url }}/api/v1
RENOVATE_GIT_TIMEOUT: 60000
RENOVATE_REQUIRE_CONFIG: 'required'
RENOVATE_ONBOARDING: 'false'
RENOVATE_PR_COMMITS_PER_RUN_LIMIT: 3
RENOVATE_GIT_URL: 'endpoint'
RENOVATE_GITHUB_TOKEN_WARN: 'false'
RENOVATE_ONBOARDING: 'false'
RENOVATE_PLATFORM: 'forgejo'
RENOVATE_PR_COMMITS_PER_RUN_LIMIT: 3
RENOVATE_REPOSITORIES: '["${{ github.repository }}"]'
RENOVATE_REQUIRE_CONFIG: 'required'
RENOVATE_TOKEN: ${{ secrets.RENOVATE_TOKEN }}
GITHUB_COM_TOKEN: ${{ secrets.GH_PUBLIC_RO }}
RENOVATE_REPOSITORY_CACHE: 'enabled'
RENOVATE_X_SQLITE_PACKAGE_CACHE: true
- name: Save renovate repo cache
if: always() && env.RENOVATE_DRY_RUN != 'full'
uses: https://github.com/actions/cache@v4
with:
path: |
/tmp/renovate/cache/renovate/repository
key: repo-cache-${{ github.run_id }}
- name: Save renovate package cache
if: always() && env.RENOVATE_DRY_RUN != 'full'
uses: https://github.com/actions/cache@v4
with:
path: |
/tmp/renovate/cache/renovate/renovate-cache-sqlite
key: package-cache-${{ github.run_id }}

View file

@ -1,59 +1,62 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:recommended"],
"lockFileMaintenance": {
"enabled": true,
"schedule": ["at any time"]
},
"nix": {
"enabled": true
},
"labels": ["Dependencies", "Dependencies/Renovate"],
"ignoreDeps": [
"tikv-jemallocator",
"tikv-jemalloc-sys",
"tikv-jemalloc-ctl",
"opentelemetry",
"opentelemetry_sdk",
"opentelemetry-jaeger",
"tracing-opentelemetry"
],
"github-actions": {
"enabled": true,
"managerFilePatterns": [
"/(^|/)\\.forgejo/workflows/[^/]+\\.ya?ml$/",
"/(^|/)\\.forgejo/actions/[^/]+/action\\.ya?ml$/",
"/(^|/)\\.github/workflows/[^/]+\\.ya?ml$/",
"/(^|/)\\.github/actions/[^/]+/action\\.ya?ml$/"
]
},
"packageRules": [
{
"description": "Batch minor and patch GitHub Actions updates",
"matchManagers": ["github-actions"],
"matchUpdateTypes": ["minor", "patch"],
"groupName": "github-actions-non-major"
},
{
"description": "Group Rust toolchain updates into a single PR",
"matchManagers": ["custom.regex"],
"matchPackageNames": ["rust", "rustc", "cargo"],
"groupName": "rust-toolchain"
},
{
"description": "Group lockfile updates into a single PR",
"matchUpdateTypes": ["lockFileMaintenance"],
"groupName": "lockfile-maintenance"
},
{
"description": "Batch patch-level Rust dependency updates",
"matchManagers": ["cargo"],
"matchUpdateTypes": ["patch"],
"groupName": "rust-patch-updates"
},
{
"matchManagers": ["cargo"],
"prConcurrentLimit": 5
}
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended"
],
"lockFileMaintenance": {
"enabled": true,
"schedule": [
"at any time"
]
},
"nix": {
"enabled": true
},
"labels": [
"Dependencies",
"Dependencies/Renovate"
],
"ignoreDeps": [
"tikv-jemallocator",
"tikv-jemalloc-sys",
"tikv-jemalloc-ctl",
"opentelemetry",
"opentelemetry_sdk",
"opentelemetry-jaeger",
"tracing-opentelemetry"
],
"github-actions": {
"enabled": true,
"fileMatch": [
"(^|/)\\.forgejo/workflows/[^/]+\\.ya?ml$",
"(^|/)\\.forgejo/actions/[^/]+/action\\.ya?ml$",
"(^|/)\\.github/workflows/[^/]+\\.ya?ml$",
"(^|/)\\.github/actions/[^/]+/action\\.ya?ml$"
]
},
"packageRules": [
{
"description": "Batch minor and patch GitHub Actions updates",
"matchManagers": ["github-actions"],
"matchUpdateTypes": ["minor", "patch"],
"groupName": "github-actions-non-major"
},
{
"description": "Group Rust toolchain updates into a single PR",
"matchManagers": ["regex"],
"matchPackageNames": ["rust", "rustc", "cargo"],
"groupName": "rust-toolchain"
},
{
"description": "Group lockfile updates into a single PR",
"matchUpdateTypes": ["lockFileMaintenance"],
"groupName": "lockfile-maintenance"
},
{
"description": "Batch patch-level Rust dependency updates",
"matchManagers": ["cargo"],
"matchUpdateTypes": ["patch"],
"groupName": "rust-patch-updates"
}
]
}