ci: improve release process reliability

- Add Docker build test to CI (rust.yml) to catch Dockerfile issues early
- Add publish-release job to release.yml that un-drafts the release
  before triggering Homebrew/Chocolatey, preventing 404 errors
- Add pre-release validation script (scripts/pre-release-check.sh)
  that checks version consistency, changelog, code quality, and Dockerfile
- Update RELEASE.md with new pre-release check step
This commit is contained in:
Marco Cadetg
2026-03-17 21:38:13 +01:00
parent 4f38ca6e5a
commit 2a38f2dffd
4 changed files with 224 additions and 8 deletions
+21 -2
View File
@@ -358,6 +358,25 @@ jobs:
env:
GH_TOKEN: ${{ github.token }}
# Publish the release (un-draft) after all assets are uploaded.
# This ensures downstream jobs (Homebrew, Chocolatey) can download assets.
publish-release:
name: publish-release
runs-on: ubuntu-latest
needs:
- create-release
- upload-arm-static
- upload-android-static
- package-installers
- package-macos
- package-windows
if: always() && needs.create-release.result == 'success'
steps:
- name: Publish release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh release edit ${{ github.ref_name }} --draft=false --repo ${{ github.repository }}
trigger-bsd-build:
name: trigger-bsd-build
runs-on: ubuntu-latest
@@ -375,7 +394,7 @@ jobs:
trigger-homebrew-update:
name: trigger-homebrew-update
runs-on: ubuntu-latest
needs: create-release
needs: publish-release
steps:
- name: Trigger Homebrew formula update
run: |
@@ -388,7 +407,7 @@ jobs:
trigger-chocolatey-update:
name: trigger-chocolatey-update
runs-on: ubuntu-latest
needs: create-release
needs: publish-release
steps:
- name: Trigger Chocolatey package update
run: |
+20
View File
@@ -10,6 +10,8 @@ on:
- 'assets/services'
- 'assets/oui.gz'
- 'build.rs'
- 'benches/**'
- 'Dockerfile'
- '.github/workflows/rust.yml'
pull_request:
branches: [ "main" ]
@@ -20,6 +22,8 @@ on:
- 'assets/services'
- 'assets/oui.gz'
- 'build.rs'
- 'benches/**'
- 'Dockerfile'
- '.github/workflows/rust.yml'
workflow_dispatch:
@@ -48,3 +52,19 @@ jobs:
run: cargo install cargo-audit --locked
- name: Run security audit
run: cargo audit
docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Build Docker image
uses: docker/build-push-action@v7
with:
context: .
push: false
load: true
tags: rustnet:ci-test
- name: Verify Docker image
run: docker run --rm rustnet:ci-test --version
+18 -6
View File
@@ -4,9 +4,20 @@ This document is for maintainers releasing new versions of RustNet.
## Creating a New Release
### 1. Test Platform Builds
### 1. Run Pre-Release Checks
Before making any release changes, verify all platform builds succeed on the current main branch:
After updating versions and changelog, run the pre-release validation script:
```bash
./scripts/pre-release-check.sh 1.2.0
```
This validates version consistency, changelog entries, code quality (fmt/clippy/test),
Dockerfile correctness, and git status. Fix any errors before proceeding.
### 2. Test Platform Builds
Before tagging, verify all platform builds succeed on the current main branch:
```bash
# Ensure you're on the main branch with latest changes
@@ -21,7 +32,7 @@ git pull origin main
This catches cross-platform and static linking issues before you invest time in release prep.
### 2. Prepare the Release
### 3. Prepare the Release
Update version in `Cargo.toml`, `rpm/rustnet.spec`, and update `CHANGELOG.md` with release notes:
@@ -35,7 +46,7 @@ cargo build --release
cargo test
```
### 3. Commit Release Changes
### 4. Commit Release Changes
```bash
# Stage and commit the version and changelog changes
@@ -47,7 +58,7 @@ git commit -m "Release v0.3.0
- And more changes"
```
### 4. Create and Push Git Tag
### 5. Create and Push Git Tag
```bash
# Create an annotated tag matching the version in Cargo.toml
@@ -69,7 +80,7 @@ git push origin v0.3.0
- Create a draft GitHub release with all artifacts attached
- Upload all binaries and installers to the release
### 5. Finalize the Release
### 6. Finalize the Release
Once the GitHub Actions workflow completes (~15-20 minutes):
@@ -110,6 +121,7 @@ The release process is fully automated via [`.github/workflows/release.yml`](.gi
Before pushing the tag, ensure:
- [ ] Pre-release checks pass: `./scripts/pre-release-check.sh x.y.z`
- [ ] Test Platform Builds workflow passes for all platforms (including static)
- [ ] Version number updated in `Cargo.toml`
- [ ] Version number updated in `rpm/rustnet.spec` (line 5: `Version: x.y.z`)
+165
View File
@@ -0,0 +1,165 @@
#!/usr/bin/env bash
# Pre-release validation script for RustNet.
# Run this before tagging a release to catch common issues.
#
# Usage: ./scripts/pre-release-check.sh [version]
# e.g.: ./scripts/pre-release-check.sh 1.2.0
set -euo pipefail
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
ERRORS=0
WARNINGS=0
pass() { echo -e " ${GREEN}${NC} $1"; }
fail() { echo -e " ${RED}${NC} $1"; ERRORS=$((ERRORS + 1)); }
warn() { echo -e " ${YELLOW}!${NC} $1"; WARNINGS=$((WARNINGS + 1)); }
VERSION="${1:-}"
echo "RustNet Pre-Release Checks"
echo "=========================="
echo
# --- Version consistency ---
echo "Version consistency:"
CARGO_VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
RPM_VERSION=$(grep '^Version:' rpm/rustnet.spec | awk '{print $2}')
if [ -n "$VERSION" ]; then
if [ "$CARGO_VERSION" = "$VERSION" ]; then
pass "Cargo.toml version: $CARGO_VERSION"
else
fail "Cargo.toml version is $CARGO_VERSION, expected $VERSION"
fi
if [ "$RPM_VERSION" = "$VERSION" ]; then
pass "rpm/rustnet.spec version: $RPM_VERSION"
else
fail "rpm/rustnet.spec version is $RPM_VERSION, expected $VERSION"
fi
else
if [ "$CARGO_VERSION" = "$RPM_VERSION" ]; then
pass "Versions match: Cargo.toml=$CARGO_VERSION, rustnet.spec=$RPM_VERSION"
else
fail "Version mismatch: Cargo.toml=$CARGO_VERSION, rustnet.spec=$RPM_VERSION"
fi
VERSION="$CARGO_VERSION"
fi
echo
# --- Changelog ---
echo "Changelog:"
if grep -q "## \[$VERSION\]" CHANGELOG.md; then
pass "CHANGELOG.md has entry for $VERSION"
else
fail "CHANGELOG.md missing entry for [$VERSION]"
fi
if grep -q "\[$VERSION\]: https://github.com" CHANGELOG.md; then
pass "CHANGELOG.md has comparison link for $VERSION"
else
fail "CHANGELOG.md missing comparison link for $VERSION"
fi
UNRELEASED_CONTENT=$(awk '/^## \[Unreleased\]/{found=1; next} /^## \[/{found=0} found{print}' CHANGELOG.md | grep -v '^$' | head -1)
if [ -z "$UNRELEASED_CONTENT" ]; then
pass "[Unreleased] section is empty (content moved to $VERSION)"
else
warn "[Unreleased] section still has content"
fi
echo
# --- Build checks ---
echo "Build checks:"
if cargo fmt --check > /dev/null 2>&1; then
pass "cargo fmt"
else
fail "cargo fmt --check has formatting issues"
fi
if cargo clippy -- -D warnings > /dev/null 2>&1; then
pass "cargo clippy"
else
fail "cargo clippy has warnings"
fi
if cargo test > /dev/null 2>&1; then
pass "cargo test"
else
fail "cargo test failed"
fi
echo
# --- Dockerfile ---
echo "Dockerfile:"
CARGO_BENCHES=$(grep -c '^\[\[bench\]\]' Cargo.toml || true)
if [ "$CARGO_BENCHES" -gt 0 ]; then
if grep -q 'COPY benches' Dockerfile; then
pass "Dockerfile copies benches/ directory"
else
fail "Cargo.toml defines $CARGO_BENCHES bench(es) but Dockerfile doesn't COPY benches/"
fi
fi
# Check that all include!() / assets referenced at compile time are in Dockerfile
for asset in $(grep -roh 'include_bytes!("[^"]*")' src/ 2>/dev/null | sed 's/include_bytes!("//;s/")//' | sort -u); do
# Resolve relative paths from src/
resolved=$(cd src && realpath --relative-to=.. "$asset" 2>/dev/null || echo "$asset")
if grep -q "$resolved\|$(basename "$resolved")" Dockerfile; then
pass "Dockerfile includes compile-time asset: $resolved"
else
fail "Compile-time asset $resolved not found in Dockerfile COPY commands"
fi
done
if docker info > /dev/null 2>&1; then
echo
echo "Docker build test:"
if docker build -t rustnet:pre-release-test . > /dev/null 2>&1; then
pass "Docker image builds successfully"
docker rmi rustnet:pre-release-test > /dev/null 2>&1 || true
else
fail "Docker build failed"
fi
else
warn "Docker not available, skipping Docker build test"
fi
echo
# --- Git status ---
echo "Git status:"
if git diff --quiet Cargo.lock; then
pass "Cargo.lock is up to date"
else
fail "Cargo.lock has uncommitted changes (run cargo build)"
fi
if [ -z "$(git status --porcelain -- src/ Cargo.toml Cargo.lock CHANGELOG.md rpm/)" ]; then
pass "No uncommitted changes in release files"
else
warn "Uncommitted changes in release files"
fi
echo
echo "=========================="
if [ "$ERRORS" -gt 0 ]; then
echo -e "${RED}$ERRORS error(s)${NC}, $WARNINGS warning(s) — fix errors before releasing"
exit 1
elif [ "$WARNINGS" -gt 0 ]; then
echo -e "${GREEN}0 errors${NC}, ${YELLOW}$WARNINGS warning(s)${NC} — review warnings before releasing"
else
echo -e "${GREEN}All checks passed!${NC} Ready to tag v$VERSION"
fi