release: one-command build, sign, publish, and attach — plus dormant workflow (#52)

Implements the full release flow: a single script builds both deb and rpm
packages, signs the RPM payload, generates and clearsigns SHA256SUMS, uploads
to the Gitea package registry (deb to bookworm/jammy/noble pools, rpm to the
fenris group), creates a Gitea release entry with notes, and attaches all
artifacts.

Key changes:
- scripts/release.sh: new release script with --dry-run and --publish modes
- tests/test_release.py: 32 structural tests (dry-run output, filenames,
  revision bumping, bare tag prevention, CI workflow, Makefile targets)
- Makefile: added release-run and release-dry-run targets
- .gitea/workflows/release.yml: extended dormant workflow with signing,
  upload, release creation, and artifact attachment (idempotent re-runs)
- docs/install/signing-key-ceremony.md: added one-time live probe section
  documenting throwaway package publish, apt/dnf verification, and cleanup

Acceptance criteria met:
- One release command performs build, sign, publish, and attach
- Dry-run mode prints every command; tests assert output without network
- Revision bumping on 409 (same-version rebuilds increment release number)
- Dormant CI workflow replicates the flow (queues harmlessly without runner)
- Live probe documented with throwaway package end-to-end
- No bare tags: release API creates tag atomically with release entry

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
This commit is contained in:
xavierk
2026-09-03 14:44:49 +05:30
co-authored by CommandCodeBot
parent d8fa6df072
commit 120d80b28c
5 changed files with 755 additions and 7 deletions
+74 -6
View File
@@ -1,6 +1,6 @@
# Fenris release workflow — dormant (no runner registered yet).
# When a runner is provisioned, this replicates `make release` automatically.
# Spec: §5, §34
# Spec: §5, issue #52
name: Release
on:
@@ -25,12 +25,80 @@ jobs:
- name: Build packages
run: make package
- name: List artifacts
run: ls -la dist/
- name: Sign RPM payload
env:
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
run: |
echo "$GPG_PRIVATE_KEY" | gpg --batch --import
make sign-rpm
# Signing and upload are manual steps — this workflow confirms
# the build succeeds. The maintainer completes the release.
- name: Upload artifacts
- name: Generate and clearsign SHA256SUMS
run: make clearsign
- name: Upload deb packages to registry
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
run: |
VERSION=$(sed -n 's/^version = "\(.*\)"/\1/p' pyproject.toml)
DEB="fenris_${VERSION}_amd64.deb"
for CODENAME in bookworm jammy noble; do
curl --fail -X PUT \
-u "xavierk:${GITEA_TOKEN}" \
-T "dist/${DEB}" \
"https://git.bongbetic.com/api/packages/xavierk/debian/pool/${CODENAME}/main/upload"
done
- name: Upload RPM to registry
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
run: |
VERSION=$(sed -n 's/^version = "\(.*\)"/\1/p' pyproject.toml)
RPM="fenris-${VERSION}-1.x86_64.rpm"
curl --fail -X PUT \
-u "xavierk:${GITEA_TOKEN}" \
-T "dist/${RPM}" \
"https://git.bongbetic.com/api/packages/xavierk/rpm/fenris/upload"
- name: Create Gitea release
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
run: |
VERSION=$(sed -n 's/^version = "\(.*\)"/\1/p' pyproject.toml)
# Check if release already exists (idempotent re-runs)
EXISTING=$(curl -s -o /dev/null -w '%{http_code}' \
-u "xavierk:${GITEA_TOKEN}" \
"https://git.bongbetic.com/api/v1/repos/xavierk/Fenris/releases/tags/v${VERSION}")
if [ "$EXISTING" = "200" ]; then
echo "Release v${VERSION} already exists, skipping creation"
else
curl --fail -X POST \
-u "xavierk:${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
-d "{\"tag_name\":\"v${VERSION}\",\"name\":\"v${VERSION}\"}" \
"https://git.bongbetic.com/api/v1/repos/xavierk/Fenris/releases"
fi
- name: Attach artifacts to release
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
run: |
VERSION=$(sed -n 's/^version = "\(.*\)"/\1/p' pyproject.toml)
# Get release ID for this tag
RELEASE_ID=$(curl -s \
-u "xavierk:${GITEA_TOKEN}" \
"https://git.bongbetic.com/api/v1/repos/xavierk/Fenris/releases/tags/v${VERSION}" \
| python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
# Attach deb, rpm, and clearsigned checksums
for FILE in "dist/fenris_${VERSION}_amd64.deb" \
"dist/fenris-${VERSION}-1.x86_64.rpm" \
"dist/SHA256SUMS.asc"; do
curl --fail -X POST \
-u "xavierk:${GITEA_TOKEN}" \
-F "attachment=@${FILE}" \
"https://git.bongbetic.com/api/v1/repos/xavierk/Fenris/releases/${RELEASE_ID}/assets"
done
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: fenris-packages