# Releasing delaunay

This guide documents the exact commands for performing a clean release using a
dedicated release PR, followed by tagging, publishing to crates.io, and
creating a GitHub release.

Applies to versions vX.Y.Z. Prefer updating documentation before publishing
to crates.io.

---

## Conventions and environment

Set these variables to avoid repeating the version string:

```bash
# tag has the leading v, version does not
TAG=vX.Y.Z
VERSION=${TAG#v}
```

Verify your git remotes:

```bash
git remote -v
```

Ensure your local main is up to date before beginning:

```bash
git checkout main
git pull --ff-only
```

---

## Step 1: Create a clean release PR

This PR should primarily include: version bumps, changelog updates, and documentation updates. All major code changes should already be on main.

**Exception:** Small, critical fixes discovered during the release process (e.g.,
documentation errors, script bugs, formatting issues) may be included but should
be minimal and release-critical only.

1. Create the release branch

```bash
git checkout -b release/$TAG
```

2. Bump versions

Preferred (if cargo-edit is installed):

```bash
# Bump package version in Cargo.toml
cargo set-version $VERSION
```

Alternative: edit `Cargo.toml` manually (update `version = "..."` under `[package]`).

Regenerate `Cargo.lock` and verify the build:

```bash
cargo check
```

Update references in documentation (search, then manually edit as needed):

```bash
# List occurrences of version-like strings to review
rg -n "\bv?[0-9]+\.[0-9]+\.[0-9]+\b" README.md docs/ || true
```

3. Verify CI passes and validate publish metadata

```bash
just fix
just ci
just publish-check
```

This ensures all tests, lints, and examples pass with the new version, and
validates that Cargo.toml metadata (keywords, categories, description) complies
with crates.io's server-side rules. Fix any issues before continuing.

4. Generate changelog using a temporary local tag (DO NOT PUSH this tag)

```bash
# Create a temporary annotated tag locally to enable changelog generation
# Do not push this tag; it will be recreated later after merge
git tag -a "$TAG" -m "delaunay $TAG"

# Generate changelog using the Python-based tool (improved error handling)
just changelog
# uv run changelog-utils generate
```

5. Generate performance results with fresh benchmark data

Run `just bench-perf-summary` for this step. It runs the summary benchmarks
with Cargo's `perf` profile and updates `benches/PERFORMANCE_RESULTS.md` for
the release.

```bash
# Run benchmarks and generate performance summary automatically
# This takes ~30-45 minutes and provides official performance data for the release
echo "Generating performance results for release $TAG..."
echo "This will run fresh benchmarks and update benches/PERFORMANCE_RESULTS.md"

just bench-perf-summary

echo "Performance results generated. Review benches/PERFORMANCE_RESULTS.md for accuracy."
```

6. Stage and commit release artifacts

```bash
git add Cargo.toml Cargo.lock CHANGELOG.md CITATION.cff docs/ tests/COVERAGE.md tests/README.md benches/PERFORMANCE_RESULTS.md docs/archive/changelog/

git commit -m "chore(release): release $TAG

- Bump version to $TAG
- Update changelog with latest changes
- Update documentation for release
- Add performance results for $TAG"
```

7. Push the branch and open a PR

```bash
git push -u origin "release/$TAG"
```

PR metadata:

- Title: chore(release): release $TAG
- Description: Clean release PR with version bump, changelog, and documentation updates. No code changes.

Note: Do NOT push the temporary tag created in step 4.

### Handling fixes discovered during release process

If you discover issues (bugs, formatting problems, etc.) after creating the changelog:

1. **For critical fixes that must be in this release:**

   ```bash
   # Make your fixes
   # Run code quality tools
   # Commit the fixes
   git add .
   git commit -m "fix: [description of fix]"
   
   # Delete the temporary tag and regenerate changelog
   git tag -d "$TAG"
   git tag -a "$TAG" -m "delaunay $TAG"
   just changelog
   # uv run changelog-utils generate
   
   # Commit updated changelog
   git add CHANGELOG.md docs/archive/changelog/
   git commit -m "docs: update changelog with release fixes"
   ```

2. **For non-critical fixes:**
   - Document them as known issues in the release notes
   - Include them in the next release
   - This avoids the changelog regeneration loop

---

## Step 2: After the PR is merged into main

1. Sync your local main to the merge commit

```bash
git checkout main
git pull --ff-only
```

2. Recreate the final annotated tag using the changelog content

```bash
# Remove the temporary local tag if it exists
git tag -d "$TAG" 2>/dev/null || true

# Create the final annotated tag with the changelog section as the tag message
# Using the new Python-based tagging tool
# Note: For large changelogs (>125KB), this automatically creates an annotated tag
# with a reference message pointing to CHANGELOG.md instead of the full content
just changelog-tag "$TAG"
# uv run changelog-utils tag "$TAG" --force
```

3. (Optional) Verify tag message content

```bash
git tag -l --format='%(contents)' "$TAG"

# Note: Large changelogs (>125KB) will show a reference message like:
# "Version X.Y.Z
#
# This release contains extensive changes. See full changelog:
# https://github.com/acgetchell/delaunay/blob/vX.Y.Z/CHANGELOG.md#xyz
#
# For detailed release notes, refer to CHANGELOG.md in the repository."
```

4. Push the tag

```bash
git push origin "$TAG"
```

5. (Recommended) Confirm CI baseline artifact generation

Pushing a version tag triggers `.github/workflows/generate-baseline.yml`, which generates a performance baseline
artifact named `performance-baseline-$TAG` with dots replaced by underscores (e.g., `performance-baseline-v0_6_2`).
This baseline is what `.github/workflows/benchmarks.yml` uses to compare future commits/PRs against the latest semver tag.

If you need to regenerate a missing/expired baseline artifact for a tag:

```bash
# Requires GitHub CLI (gh)
gh workflow run generate-baseline.yml -f tag="$TAG" --ref main
```

6. Create the GitHub release with notes from the tag annotation

```bash
# Requires GitHub CLI (gh) and authenticated session
# Works for both normal and large changelogs - always use --notes-from-tag
gh release create "$TAG" --notes-from-tag

# For large changelogs, the release will show the reference message with a link
# to the full changelog in CHANGELOG.md. Users can click the link to see all details.
```

7. Publish to crates.io

```bash
# Publish the crate (publish-check already ran in Step 1)
cargo publish --locked
```

8. Clean up the release branch

```bash
# Delete remote branch
git push origin --delete "release/$TAG"

# Delete local branch
git branch -d "release/$TAG"
```

---

## Notes and tips

- Never push the temporary tag created for changelog generation; only push the final tag after the PR is merged.
- Keep the release PR strictly to version + changelog + documentation to maintain a clean history.
- If multiple crates or files reference the version, confirm all of them are updated consistently.
- Always run `just ci` before committing the release to catch issues early.
- `just ci` is the comprehensive validation path for release work: checks,
  tests, and examples. Benchmark/profile-grade data must be produced separately
  with `just bench`, `just bench-ci`, or `just bench-perf-summary`.
- `just changelog` may create or update files under `docs/archive/changelog/`. Include these in the release PR.
- The root `CHANGELOG.md` only contains Unreleased + the active minor series. Completed minors are archived verbatim in `docs/archive/changelog/X.Y.md`.
- For future convenience, parts of this document can be automated into a release script.
