# CI/CD release cycle

This document explains how CacheKit’s release cycle works in practice: what runs in CI,
what makes `main` “releasable”, and how a version becomes a GitHub Release and (optionally)
a crates.io publish.

For the hands-on, step-by-step release procedure, see [Releasing CacheKit](releasing.md).

## Mental model

- **All change goes through PRs into `main`.**
- **`main` should always be releasable.** CI is set up so that obvious breakages are caught
  before merge (format/lint/tests/docs/audit/MSRV).
- **A “release” is signaled by a git tag.**
  - Stable releases: `vX.Y.Z` (example: `v0.1.0`)
  - Pre-releases: `vX.Y.Z-alpha` / `vX.Y.Z-rc.1`, etc.
- **Crate versions do not use `v`.** In `Cargo.toml`, use `0.1.0-alpha`, not `v0.1.0-alpha`.

## What runs when

### Pull requests and pushes to `main` (`.github/workflows/ci.yml`)

CI runs on:

- `pull_request` targeting `main`
- `push` to `main`

What it does (project-specific):

- **Formatting:** `cargo fmt --check`
- **Lint:** `cargo clippy --all-targets --all-features -- -D warnings`
- **Tests:** `cargo test --all-features --all-targets` on Linux/macOS/Windows
- **Docs build:** `RUSTDOCFLAGS='-Dwarnings' cargo doc --no-deps --all-features`
- **Security audit:** `rustsec/audit-check`
- **Benchmarks:** `cargo bench --no-fail-fast` (only on `main`, not required for PRs)
- **MSRV check:** `cargo check --all-features` on Rust `1.85.0`
- **Miri:** curated subset on nightly for Linux/macOS (slower; not on Windows)

Local equivalents (useful before opening a PR):

```bash
cargo fmt
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-features --all-targets
RUSTDOCFLAGS='-Dwarnings' cargo doc --no-deps --all-features
```

### Release automation on tags (`.github/workflows/release.yml`)

The release workflow runs on:

- `push` tags matching `v*.*.*`

Important:

- This tag pattern matches stable tags like `v0.1.0`.
- It does **not** match pre-release tags like `v0.1.0-alpha` or `v0.2.0-rc.1` unless you
  expand the trigger pattern.

What the workflow does:

1. Verifies the tag commit is reachable from `origin/main`.
2. Re-runs full validation: fmt, clippy, tests, docs.
3. Verifies the crate packages cleanly: `cargo package` and `cargo publish --dry-run`.
4. Creates a GitHub Release (currently using auto-generated release notes).
5. Optionally publishes to crates.io.

crates.io publishing:

- The publish job only runs if the repository variable `CARGO_REGISTRY_TOKEN` is set.
- When enabled, the job runs `cargo publish` using that token.

### Scheduled maintenance (`.github/workflows/maintenance.yml`)

Maintenance runs on a schedule and manually (`workflow_dispatch`) to catch:

- New RustSec advisories and dependency issues
- Ecosystem drift when there isn’t active development

### Docs site publishing (`.github/workflows/jekyll-gh-pages.yml`)

On each push to `main` (or manually), GitHub Pages builds the site from `docs/` via Jekyll.
This is for the documentation site under the repo’s Pages URL (not `cargo doc` output).

## How a release happens (end-to-end)

### 1) Prepare a release PR

In a PR that targets `main`:

- Bump `Cargo.toml` `version = "X.Y.Z(...)"` (no `v`).
- Finalize `CHANGELOG.md` for that version/date.
- (Optional) Update [Benchmarks](../benchmarks/overview.md) after a local run:
  - `cargo bench`
  - `scripts/update_docs_benchmarks.sh target/criterion docs/benchmarks.md`

### 2) Merge to `main`

Merge once CI is green. This keeps `main` always in a releasable state.

### 3) Tag the release

Tag the exact commit on `main` you want to release.

- **Stable tags** (`vX.Y.Z`) will trigger the automated release workflow.
- **Pre-release tags** (`vX.Y.Z-alpha`, etc.) currently will not trigger the release
  workflow with the default tag pattern.

### 4) Watch the automation

For stable tags, GitHub Actions validates, creates the GitHub Release, and optionally
publishes to crates.io if configured.

### 5) After the release

- Verify the GitHub Release notes/tag/version.
- If published, verify the crates.io page and metadata.
- Keep `[Unreleased]` in `CHANGELOG.md` ready for the next cycle.

## Troubleshooting

- **Release workflow didn’t run:** the tag must match `v*.*.*` (stable) unless you change
  the workflow trigger.
- **Publish job skipped:** ensure `CARGO_REGISTRY_TOKEN` is configured as a repository
  variable (or update the workflow to use secrets).
- **Docs site didn’t update:** confirm the Pages workflow is enabled and the `docs/`
  folder builds successfully with Jekyll.
