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] [*.yml]
indent_size = 2 indent_size = 2
indent_style = space 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: concurrency:
group: "build-fedora-${{ github.ref }}" group: "build-fedora-${{ github.ref }}"
@ -6,10 +6,6 @@ concurrency:
on: on:
push: push:
branches:
- '**'
tags:
- 'v*'
paths: paths:
- 'fedora/**' - 'fedora/**'
- 'src/**' - 'src/**'
@ -114,33 +110,27 @@ jobs:
cd "$GITHUB_WORKSPACE" 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 if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then
# Tags get clean version numbers for stable releases # Tags get clean version numbers for stable releases
RELEASE_SUFFIX="" 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 elif [ "${{ github.ref_name }}" = "main" ]; then
# Main branch gets .dev suffix # Main branch gets .dev suffix
RELEASE_SUFFIX=".dev" 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 else
# Other branches get sanitized branch name as suffix # Other branches get sanitized branch name as suffix
SAFE_BRANCH=$(echo "${{ github.ref_name }}" | sed 's/[^a-zA-Z0-9]/_/g' | cut -c1-20) SAFE_BRANCH=$(echo "${{ github.ref_name }}" | sed 's/[^a-zA-Z0-9]/_/g' | cut -c1-20)
RELEASE_SUFFIX=".${SAFE_BRANCH}" 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 # Replace the Release line to include our suffix
sed "s/^Release:.*$/Release: 1${RELEASE_SUFFIX}%{?dist}/" \ sed "s/^Release:.*$/Release: 1${RELEASE_SUFFIX}%{?dist}/" \
fedora/continuwuity.spec.rpkg > continuwuity.spec.rpkg fedora/continuwuity.spec.rpkg > continuwuity.spec.rpkg
else
# Use the original spec file
ln -sf fedora/continuwuity.spec.rpkg continuwuity.spec.rpkg
fi fi
# Build the SRPM # Build the SRPM
@ -374,8 +364,6 @@ jobs:
# Determine the group based on ref type and branch # Determine the group based on ref type and branch
if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then
GROUP="stable" GROUP="stable"
# For tags, extract the tag name for version info
TAG_NAME="${{ github.ref_name }}"
elif [ "${{ github.ref_name }}" = "main" ]; then elif [ "${{ github.ref_name }}" = "main" ]; then
GROUP="dev" GROUP="dev"
else else
@ -410,63 +398,23 @@ jobs:
"https://forgejo.ellis.link/api/packages/continuwuation/rpm/$GROUP/upload" "https://forgejo.ellis.link/api/packages/continuwuation/rpm/$GROUP/upload"
echo "" 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" echo "Group: $GROUP"
# Upload debug RPMs to separate group # Also upload the SRPM
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
SRPM=$(find artifacts -name "*.src.rpm" | head -1) SRPM=$(find artifacts -name "*.src.rpm" | head -1)
if [ -n "$SRPM" ]; then if [ -n "$SRPM" ]; then
echo "" echo ""
echo "Publishing source RPM: $(basename "$SRPM")" echo "Publishing source RPM: $(basename "$SRPM")"
echo "Publishing to group: ${GROUP}-src"
# Extract SRPM info # SRPMs always have architecture "src"
SRPM_INFO=$(rpm -qpi "$SRPM" 2>/dev/null) SRPM_ARCH="src"
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}"
# Try to delete existing SRPM first # Try to delete existing SRPM first (using same name/version as binary RPM)
echo "Removing any existing SRPM: $SRPM_NAME-$SRPM_FULL_VERSION.src" echo "Removing any existing SRPM: $PACKAGE_NAME-$FULL_VERSION.$SRPM_ARCH"
curl -X DELETE \ curl -X DELETE \
-H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \ -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)" || echo "SRPM didn't exist or deletion failed (this is OK)"
curl --fail-with-body \ curl --fail-with-body \
@ -474,7 +422,5 @@ jobs:
-H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \ -H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \
-H "Content-Type: application/x-rpm" \ -H "Content-Type: application/x-rpm" \
-T "$SRPM" \ -T "$SRPM" \
"https://forgejo.ellis.link/api/packages/continuwuation/rpm/${GROUP}-src/upload" "https://forgejo.ellis.link/api/packages/continuwuation/rpm/$GROUP/upload"
echo "✅ Published source RPM to group: ${GROUP}-src"
fi fi

View file

@ -161,7 +161,7 @@ jobs:
var-lib-apt-${{ matrix.slug }} var-lib-apt-${{ matrix.slug }}
key: var-lib-apt-${{ matrix.slug }} key: var-lib-apt-${{ matrix.slug }}
- name: inject cache into docker - 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: with:
cache-map: | cache-map: |
{ {

View file

@ -39,73 +39,24 @@ jobs:
renovate: renovate:
name: Renovate name: Renovate
runs-on: ubuntu-latest runs-on: ubuntu-latest
container:
image: ghcr.io/renovatebot/renovate:41
options: --tmpfs /tmp:exec
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 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 - 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: env:
LOG_LEVEL: ${{ inputs.logLevel || 'info' }} LOG_LEVEL: ${{ inputs.logLevel || 'info' }}
RENOVATE_DRY_RUN: ${{ inputs.dryRun || 'false' }}
RENOVATE_PLATFORM: forgejo
RENOVATE_ENDPOINT: ${{ github.server_url }}
RENOVATE_AUTODISCOVER: 'false' 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_GIT_TIMEOUT: 60000
RENOVATE_GIT_URL: 'endpoint'
RENOVATE_REQUIRE_CONFIG: 'required'
RENOVATE_ONBOARDING: 'false'
RENOVATE_PR_COMMITS_PER_RUN_LIMIT: 3
RENOVATE_GITHUB_TOKEN_WARN: 'false' 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 }} 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", "$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:recommended"], "extends": [
"lockFileMaintenance": { "config:recommended"
"enabled": true, ],
"schedule": ["at any time"] "lockFileMaintenance": {
}, "enabled": true,
"nix": { "schedule": [
"enabled": true "at any time"
},
"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
}
] ]
},
"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"
}
]
} }