Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .github/ISSUE_TEMPLATE/release.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
name: Release
about: Track a versioned release from prep to publish
title: "Release vX.Y.Z"
labels: documentation
assignees: ""
---

## Target version
- [ ] Version: `vX.Y.Z`
- [ ] Release date confirmed

## Pre-release prep
- [ ] Create branch: `chore/<issue-id>-release-vX-Y-Z`
- [ ] Ensure `Cargo.toml` version is `X.Y.Z`
- [ ] Move `Unreleased` entries into `## [X.Y.Z] - YYYY-MM-DD` in `CHANGELOG.md`
- [ ] Include issue/PR references in changelog entries where possible
- [ ] Open release PR linked to this issue

## Validation
- [ ] `cargo fmt --all -- --check`
- [ ] `cargo clippy --all-features -- -D warnings`
- [ ] `cargo test --all`
- [ ] `cargo test --no-default-features`
- [ ] `./scripts/release-check.sh`

## Publish
- [ ] Merge release PR to `main`
- [ ] Create and push annotated tag: `vX.Y.Z`
- [ ] Confirm GitHub `Release` workflow passes on tag
- [ ] Confirm crate published to crates.io
- [ ] Confirm GitHub Release notes match changelog section

## Post-release
- [ ] Restore/keep `## [Unreleased]` section in changelog
- [ ] Announce release notes
99 changes: 99 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
name: Release

on:
push:
tags:
- "v*"

permissions:
contents: write

jobs:
validate:
name: Validate release tag
runs-on: ubuntu-latest

steps:
- name: Checkout sources
uses: actions/checkout@v4

- name: Install Rust (stable)
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
profile: minimal
components: clippy, rustfmt

- name: Cache cargo registry + build
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-release-${{ hashFiles('**/Cargo.lock') }}

- name: Run release preflight
run: ./scripts/release-check.sh

publish:
name: Publish crate and GitHub release
runs-on: ubuntu-latest
needs: validate

steps:
- name: Checkout sources
uses: actions/checkout@v4

- name: Install Rust (stable)
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
profile: minimal

- name: Verify tag matches crate version
shell: bash
run: |
set -euo pipefail
tag="${GITHUB_REF_NAME}"
crate_version=$(cargo pkgid | sed -E 's|.*@([^ ]+)$|\1|')

if [[ "${tag}" != "v${crate_version}" ]]; then
echo "Tag ${tag} does not match crate version v${crate_version}" >&2
exit 1
fi

- name: Cargo publish (dry-run)
run: cargo publish --dry-run

- name: Cargo publish
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
run: cargo publish

- name: Build release notes from changelog
shell: bash
run: |
set -euo pipefail
tag="${GITHUB_REF_NAME#v}"
awk -v version="${tag}" '
BEGIN { in_section=0 }
$0 ~ "^## \\[" version "\\]" { in_section=1; next }
/^## \[/ && in_section { exit }
in_section { print }
' CHANGELOG.md > release-notes.md

if [[ ! -s release-notes.md ]]; then
echo "No changelog section found for ${tag}" >&2
exit 1
fi

- name: Create GitHub release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.ref_name }}
body_path: release-notes.md
draft: false
prerelease: false
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ and its version numbers follow [Semantic Versioning](https://semver.org/).
control/ticker context without carrying a `RuntimeGuard` field (`#21`).
- New `axum` example showing how to run a web server under `ProcessManager`
with graceful shutdown and reload handling (`#11`).
- Release process documentation and release issue template for standardized
versioned publish workflows (`#47`).

### Changed
- `process_handle()` now returns `Arc<dyn ProcessControlHandler>` (cheap cloning,
Expand All @@ -53,6 +55,8 @@ and its version numbers follow [Semantic Versioning](https://semver.org/).
context-based runnable API covered (`#21`).
- CI now executes the `axum` example to keep web-framework integration sample
code validated (`#11`).
- Added tag-driven `Release` workflow to validate, publish to crates.io, and
create GitHub releases from changelog sections (`#47`).
- Added `RestartSupervisor` with configurable exponential backoff to
automatically restart failed child runnables (`#19`).

Expand Down
65 changes: 65 additions & 0 deletions docs/release-process.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Release Process

This document defines the canonical release flow for `mrcrgl/processmanager-rs`.

## Prerequisites
- GitHub access with tag/release permissions
- crates.io publish token configured as `CARGO_REGISTRY_TOKEN` in repository secrets
- Clean working tree

## 1. Open a tracked release issue
Use the `Release` issue template and fill target version/date.

## 2. Prepare release branch
Follow branch policy from `AGENTS.md`:

```bash
git checkout main
git pull --ff-only origin main
git checkout -b chore/<issue-id>-release-vX-Y-Z
```

## 3. Prepare release PR
- Set `Cargo.toml` package version to the target `X.Y.Z`
- Move `CHANGELOG.md` entries from `## [Unreleased]` into:
- `## [X.Y.Z] - YYYY-MM-DD`
- Open PR with issue link (`Closes #<issue-id>`)

## 4. Validate before merge
Run the required checks locally:

```bash
./scripts/release-check.sh
```

This script enforces:
- `cargo fmt --all -- --check`
- `cargo clippy --all-features -- -D warnings`
- `cargo test --all`
- `cargo test --no-default-features`
- all maintained examples with bounded runtimes

## 5. Merge and tag
After release PR is merged to `main`, create and push an annotated tag:

```bash
git checkout main
git pull --ff-only origin main
git tag -a vX.Y.Z -m "vX.Y.Z"
git push origin vX.Y.Z
```

## 6. Automated publish + GitHub release
Tag push triggers `.github/workflows/release.yml`.

The workflow:
1. re-runs release preflight checks
2. verifies tag `vX.Y.Z` matches crate version `X.Y.Z`
3. runs `cargo publish --dry-run`
4. publishes crate via `cargo publish`
5. creates GitHub Release notes from the matching `CHANGELOG.md` section

## 7. Post-release checks
- Verify crates.io package page/version
- Verify GitHub Release body content
- Confirm `## [Unreleased]` remains ready for next cycle
14 changes: 14 additions & 0 deletions scripts/release-check.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -euo pipefail

cargo fmt --all -- --check
cargo clippy --all-features -- -D warnings
cargo test --all
cargo test --no-default-features

# Keep examples under CI-appropriate upper bounds.
timeout 30s cargo run --example simple
timeout 45s cargo run --example dynamic_add
timeout 30s cargo run --example restart_supervisor
timeout 30s cargo run --example runtime_context
timeout 30s cargo run --example axum
Loading