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>
207 lines
7.6 KiB
Bash
Executable File
207 lines
7.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# Fenris one-command release flow (issue #52).
|
|
# Builds both packages, signs, uploads to registry, creates release entry,
|
|
# and attaches artifacts — or in dry-run mode, prints every command.
|
|
#
|
|
# Usage:
|
|
# scripts/release.sh --dry-run # Print commands without executing
|
|
# scripts/release.sh --publish # Execute the full release flow
|
|
#
|
|
# Environment:
|
|
# GITEA_TOKEN - API token for Gitea registry and release API
|
|
# PACKAGING_KEY - GPG key UID (default: packaging@bongbetic.com)
|
|
#
|
|
# Spec: release-packaging.md §5
|
|
|
|
# ── Defaults ─────────────────────────────────────────────────────────────
|
|
|
|
DRY_RUN=false
|
|
PUBLISH=false
|
|
GITEA_URL="https://git.bongbetic.com"
|
|
GITEA_OWNER="xavierk"
|
|
GITEA_REPO="Fenris"
|
|
PACKAGING_KEY="${PACKAGING_KEY:-packaging@bongbetic.com}"
|
|
|
|
CODENAMES=(bookworm jammy noble)
|
|
RPM_GROUP="fenris"
|
|
|
|
# ── Parse arguments ──────────────────────────────────────────────────────
|
|
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--dry-run) DRY_RUN=true ;;
|
|
--publish) PUBLISH=true ;;
|
|
--help|-h)
|
|
echo "Usage: $0 [--dry-run | --publish]"
|
|
echo ""
|
|
echo "Modes:"
|
|
echo " --dry-run Print commands without executing (default)"
|
|
echo " --publish Execute the full release flow"
|
|
echo ""
|
|
echo "Environment:"
|
|
echo " GITEA_TOKEN API token for Gitea registry and release API"
|
|
echo " PACKAGING_KEY GPG key UID (default: packaging@bongbetic.com)"
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Unknown argument: $arg" >&2
|
|
echo "Usage: $0 [--dry-run | --publish]" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if ! $DRY_RUN && ! $PUBLISH; then
|
|
DRY_RUN=true
|
|
fi
|
|
|
|
# ── Helpers ──────────────────────────────────────────────────────────────
|
|
|
|
_version() {
|
|
sed -n 's/^version = "\(.*\)"/\1/p' pyproject.toml
|
|
}
|
|
|
|
_deb_name() {
|
|
local ver="$1"
|
|
echo "fenris_${ver}_amd64.deb"
|
|
}
|
|
|
|
_rpm_name() {
|
|
local ver="$1" rel="$2"
|
|
echo "fenris-${ver}-${rel}.x86_64.rpm"
|
|
}
|
|
|
|
_run() {
|
|
if $DRY_RUN; then
|
|
echo " $*"
|
|
else
|
|
eval "$@"
|
|
fi
|
|
}
|
|
|
|
# ── Main ─────────────────────────────────────────────────────────────────
|
|
|
|
VERSION=$(_version)
|
|
REVISION=1
|
|
DEB=$(_deb_name "$VERSION")
|
|
RPM=$(_rpm_name "$VERSION" "$REVISION")
|
|
|
|
echo "=== Fenris Release v${VERSION} ==="
|
|
echo ""
|
|
|
|
if $DRY_RUN; then
|
|
echo "[dry-run] Commands below will be executed in --publish mode."
|
|
echo ""
|
|
fi
|
|
|
|
# ── Step 1: Build both formats ──────────────────────────────────────────
|
|
|
|
echo "--- Build packages ---"
|
|
_run "make package"
|
|
echo ""
|
|
|
|
# ── Step 2: Sign RPM payload ────────────────────────────────────────────
|
|
|
|
echo "--- Sign RPM payload ---"
|
|
_run "rpmsign --addsign --define '_gpg_name ${PACKAGING_KEY}' dist/${RPM}"
|
|
echo ""
|
|
|
|
# ── Step 3: Generate and clearsign SHA256SUMS ────────────────────────────
|
|
|
|
echo "--- Generate SHA256SUMS ---"
|
|
_run "cd dist && sha256sum ${DEB} ${RPM} > SHA256SUMS"
|
|
echo ""
|
|
|
|
echo "--- Clearsign SHA256SUMS ---"
|
|
_run "gpg --batch --yes --clearsign --local-user ${PACKAGING_KEY} dist/SHA256SUMS"
|
|
echo ""
|
|
|
|
# ── Step 4: Upload to Gitea package registry ─────────────────────────────
|
|
|
|
echo "--- Upload packages to registry ---"
|
|
for codename in "${CODENAMES[@]}"; do
|
|
_run "curl --fail -X PUT -u ${GITEA_OWNER}:\$GITEA_TOKEN -T dist/${DEB} '${GITEA_URL}/api/packages/${GITEA_OWNER}/debian/pool/${codename}/main/upload'"
|
|
done
|
|
_run "curl --fail -X PUT -u ${GITEA_OWNER}:\$GITEA_TOKEN -T dist/${RPM} '${GITEA_URL}/api/packages/${GITEA_OWNER}/rpm/${RPM_GROUP}/upload'"
|
|
echo ""
|
|
|
|
# ── Step 5: Create Gitea release with notes ─────────────────────────────
|
|
|
|
echo "--- Create Gitea release ---"
|
|
_release_notes="Release v${VERSION}
|
|
|
|
## Packages
|
|
|
|
Install via apt (Debian/Ubuntu):
|
|
|
|
\`\`\`bash
|
|
curl --fail -fsSL https://git.bongbetic.com/${GITEA_OWNER}/${GITEA_REPO}/raw/branch/main/packaging/keys/fenris-packaging.asc | sudo gpg --dearmor -o /etc/apt/keyrings/fenris.asc
|
|
echo \"deb [signed-by=/etc/apt/keyrings/fenris.asc] https://git.bongbetic.com/api/packages/${GITEA_OWNER}/debian bookworm main\" | sudo tee /etc/apt/sources.list.d/fenris.list
|
|
sudo apt update && sudo apt install fenris
|
|
\`\`\`
|
|
|
|
Install via dnf (Fedora):
|
|
|
|
\`\`\`bash
|
|
sudo dnf config-manager --add-repo https://git.bongbetic.com/${GITEA_OWNER}/${GITEA_REPO}/raw/branch/main/packaging/fenris.repo
|
|
sudo dnf install fenris
|
|
\`\`\`
|
|
|
|
## Verification
|
|
|
|
\`\`\`bash
|
|
rpm -Kv fenris-${VERSION}-1.x86_64.rpm
|
|
gpg --verify SHA256SUMS.asc SHA256SUMS
|
|
\`\`\`
|
|
|
|
## Artifacts
|
|
|
|
- \`dist/${DEB}\` (Debian/Ubuntu)
|
|
- \`dist/${RPM}\` (Fedora)
|
|
- \`dist/SHA256SUMS.asc\` (clearsigned checksums)
|
|
|
|
See [docs/install/signing-key-ceremony.md](docs/install/signing-key-ceremony.md) for key ceremony details.
|
|
See [docs/install/migrate-from-makeinstall.md](docs/install/migrate-from-makeinstall.md) for migration from make install."
|
|
|
|
if $DRY_RUN; then
|
|
_run "curl --fail -X POST -u ${GITEA_OWNER}:\$GITEA_TOKEN -H 'Content-Type: application/json' -d '{\"tag_name\":\"v${VERSION}\",\"name\":\"v${VERSION}\",\"body\":\"...\"}' '${GITEA_URL}/api/v1/repos/${GITEA_OWNER}/${GITEA_REPO}/releases'"
|
|
else
|
|
# Create release via Gitea API (creates the tag atomically — no bare tag)
|
|
RELEASE_RESPONSE=$(curl --fail -s -X POST \
|
|
-u "${GITEA_OWNER}:${GITEA_TOKEN}" \
|
|
-H "Content-Type: application/json" \
|
|
-d "$(jq -n \
|
|
--arg tag "v${VERSION}" \
|
|
--arg name "v${VERSION}" \
|
|
--arg body "$_release_notes" \
|
|
'{tag_name: $tag, name: $name, body: $body}')" \
|
|
"${GITEA_URL}/api/v1/repos/${GITEA_OWNER}/${GITEA_REPO}/releases")
|
|
|
|
RELEASE_ID=$(echo "$RELEASE_RESPONSE" | jq -r '.id')
|
|
echo " Release created: ${GITEA_URL}/${GITEA_OWNER}/${GITEA_REPO}/releases/tag/v${VERSION}"
|
|
fi
|
|
echo ""
|
|
|
|
# ── Step 6: Attach artifacts to release ──────────────────────────────────
|
|
|
|
echo "--- Attach artifacts to release ---"
|
|
for artifact in "dist/${DEB}" "dist/${RPM}" "dist/SHA256SUMS.asc"; do
|
|
_run "curl --fail -X POST -u ${GITEA_OWNER}:\$GITEA_TOKEN -F 'attachment=@${artifact}' '${GITEA_URL}/api/v1/repos/${GITEA_OWNER}/${GITEA_REPO}/releases/${RELEASE_ID:-0}/assets'"
|
|
done
|
|
echo ""
|
|
|
|
# ── Done ─────────────────────────────────────────────────────────────────
|
|
|
|
echo "=== Release v${VERSION} complete ==="
|
|
echo ""
|
|
echo "Summary:"
|
|
echo " Packages: ${DEB}, ${RPM}"
|
|
echo " Checksums: dist/SHA256SUMS.asc"
|
|
echo " Registry: deb → bookworm, jammy, noble; rpm → ${RPM_GROUP}"
|
|
echo " Release: ${GITEA_URL}/${GITEA_OWNER}/${GITEA_REPO}/releases/tag/v${VERSION}"
|
|
echo ""
|
|
echo "Key ceremony: delete the private key after release."
|
|
echo " See docs/install/signing-key-ceremony.md"
|