Skip to content

Commit c906848

Browse files
olivermeyerclaude
andcommitted
docs: update release workflow for release branch strategy
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 9d12633 commit c906848

3 files changed

Lines changed: 130 additions & 55 deletions

File tree

.github/CLAUDE.md

Lines changed: 47 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ This file provides comprehensive guidance for Claude Code and human engineers wo
66

77
The Aignostics Python SDK uses a **sophisticated multi-stage CI/CD pipeline** built on GitHub Actions with:
88

9-
* **19 workflow files** (8 entry points + 11 reusable workflows)
9+
* **22 workflow files** (11 entry points + 11 reusable workflows)
1010
* **Reusable workflow architecture** for modularity and maintainability
1111
* **Environment-based testing** (staging/production with scheduled validation)
1212
* **Multi-category test execution** (unit, integration, e2e, long_running, very_long_running, scheduled)
@@ -21,7 +21,7 @@ The Aignostics Python SDK uses a **sophisticated multi-stage CI/CD pipeline** bu
2121
```text
2222
┌─────────────────────────────────────────────────────────────────────┐
2323
│ ci-cd.yml (Main Orchestrator) │
24-
Triggered on: push to main, PR, release, tag v*.*.*
24+
│ Triggered on: push to main/release/v*, PR, release, tag v*.*.* │
2525
├─────────────────────────────────────────────────────────────────────┤
2626
│ │
2727
│ ┌────────┐ ┌───────┐ ┌────────────────┐ ┌────────┐ │
@@ -56,6 +56,9 @@ The Aignostics Python SDK uses a **sophisticated multi-stage CI/CD pipeline** bu
5656
┌───────────────────────────────────────────────────────────────┐
5757
│ Parallel Entry Points │
5858
├───────────────────────────────────────────────────────────────┤
59+
│ prepare-release.yml → Create release branch │
60+
│ publish-release.yml → Tag + changelog → CI/CD publish │
61+
│ merge-release.yml → Merge branch into main │
5962
│ build-native-only.yml → Native executables (6 platforms) │
6063
│ claude-code-*.yml → PR reviews + interactive sessions │
6164
│ test-scheduled-*.yml → Staging (6h) + Production (24h) │
@@ -70,7 +73,10 @@ The Aignostics Python SDK uses a **sophisticated multi-stage CI/CD pipeline** bu
7073

7174
| Workflow | Triggers | Purpose | Calls |
7275
|----------|----------|---------|-------|
73-
| **ci-cd.yml** | push(main), PR, release, tag | Main CI/CD pipeline | _lint,_audit, _test,_codeql, _ketryx,_package-publish, _docker-publish |
76+
| **ci-cd.yml** | push(main, release/v*), PR, release, tag | Main CI/CD pipeline | _lint,_audit, _test,_codeql, _ketryx,_package-publish, _docker-publish |
77+
| **prepare-release.yml** | workflow_dispatch | Create release branch + bump version ||
78+
| **publish-release.yml** | workflow_dispatch | Generate changelog, tag, push → CI/CD ||
79+
| **merge-release.yml** | workflow_dispatch | Merge release branch into main ||
7480
| **build-native-only.yml** | push, PR, release (if msg contains `build:native:only`) | Native executable builds | _build-native-only |
7581
| **claude-code-interactive.yml** | workflow_dispatch (manual) | Manual Claude sessions | _claude-code (interactive) |
7682
| **claude-code-automation-pr-review.yml** | PR opened/sync (excludes bots) | Automated PR reviews | _claude-code (automation) |
@@ -379,7 +385,7 @@ uv run pytest -m "(scheduled or scheduled_only)" -v
379385
* `build:native:only` - Only build native executables
380386
* `skip:test:long_running` - Skip long-running tests
381387
* `enable:test:very_long_running` - Enable very long running tests
382-
* `Bump version:` - Skip CI (version bump commits)
388+
* `Bump version:` - Skip CI on `main` only (does **not** skip CI on `release/v*` branches)
383389

384390
**Usage**:
385391

@@ -398,6 +404,7 @@ git commit -m "fix: issue skip:test:long_running"
398404
**Triggers**:
399405

400406
* `push` to `main` branch
407+
* `push` to `release/v*` branches (release branch CI)
401408
* `pull_request` to `main` (opened, synchronize, reopened)
402409
* `release` created
403410
* `tags` matching `v*.*.*`
@@ -415,7 +422,7 @@ Cancels in-progress runs when new commits are pushed to same PR/branch.
415422
416423
* Commit message contains `skip:ci`
417424
* Commit message contains `build:native:only`
418-
* Commit starts with `Bump version:`
425+
* Commit starts with `Bump version:` **on the `main` branch only** (on `release/v*` branches the bump commit intentionally runs CI)
419426
* PR has label `skip:ci` or `build:native:only`
420427

421428
**Job Dependencies**:
@@ -1006,26 +1013,42 @@ make dist_native
10061013

10071014
### Releasing a Version
10081015

1009-
1. Ensure `main` branch is clean and all tests pass
1010-
2. Run version bump:
1016+
Releases use a four-phase workflow triggered from the developer's machine via `gh workflow run`. This lets Ketryx compliance approvals be collected *before* the tag (and thus before publishing to PyPI).
10111017

1012-
```bash
1013-
make bump patch # or minor, major
1014-
```
1018+
**Phase 1 — Prepare the release branch** (triggers `prepare-release.yml`):
10151019

1016-
3. This creates a commit and git tag
1017-
4. Push with tags:
1020+
```bash
1021+
make prepare-release patch # 1.0.0 → 1.0.1
1022+
make prepare-release minor # 1.0.0 → 1.1.0
1023+
make prepare-release major # 1.0.0 → 2.0.0
1024+
make prepare-release 1.2.3 # explicit version
1025+
```
1026+
1027+
Creates `release/vX.Y.Z` from `main`, commits version bump + `uv.lock`, pushes. CI runs on the branch automatically.
1028+
1029+
**Phase 2 — Collect Ketryx approvals:**
1030+
1031+
Point the Ketryx release to `release/vX.Y.Z` and collect approvals. Ensure CI is green.
1032+
1033+
**Phase 3 — Publish** (triggers `publish-release.yml`):
1034+
1035+
```bash
1036+
make publish-release # auto-detects release/v* branch
1037+
make publish-release release/v1.2.3 # explicit branch
1038+
```
1039+
1040+
Generates `CHANGELOG.md`, creates annotated `vX.Y.Z` tag, pushes → CI/CD fires on tag → Ketryx check must pass before PyPI publish.
1041+
1042+
**Phase 4 — Merge back to main** (triggers `merge-release.yml`):
1043+
1044+
```bash
1045+
make merge-release # auto-detects release/v* branch
1046+
make merge-release release/v1.2.3 # explicit branch
1047+
```
10181048

1019-
```bash
1020-
git push --follow-tags
1021-
```
1049+
Merges `release/vX.Y.Z` into `main` with `--no-ff`, pushes `main`, deletes the release branch.
10221050

1023-
5. CI detects tag and triggers:
1024-
* Full CI pipeline (lint, audit, test, CodeQL)
1025-
* Package build and publish to PyPI
1026-
* Docker image build and publish
1027-
* GitHub release creation
1028-
* Slack notification to team
1051+
**Note on branch protection**: `release/v*` branches should be protected so that only the GitHub Actions bot (`aignostics-release-bot[bot]`) can push to them. This enforces the server-side workflow. Configure in GitHub Settings → Branches → Branch protection rules.
10291052

10301053
### Manual Testing with Claude
10311054

@@ -1070,6 +1093,9 @@ make dist_native
10701093
| File | Type | Purpose | Duration |
10711094
|------|------|---------|----------|
10721095
| `ci-cd.yml` | Entry | Main pipeline orchestration | ~20 min |
1096+
| `prepare-release.yml` | Entry | Create release branch + bump version | ~2 min |
1097+
| `publish-release.yml` | Entry | Generate changelog, create tag, push | ~2 min |
1098+
| `merge-release.yml` | Entry | Merge release branch into main | ~1 min |
10731099
| `build-native-only.yml` | Entry | Native build trigger | ~60 min (6 platforms) |
10741100
| `claude-code-interactive.yml` | Entry | Manual Claude sessions | varies |
10751101
| `claude-code-automation-pr-review.yml` | Entry | Automated PR reviews | ~10 min |

CLAUDE.md

Lines changed: 55 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,48 +1277,76 @@ uv sync --all-extras # Install all optional groups
12771277

12781278
### Version Bumping and Releases
12791279

1280-
**Bump version (via Nox):**
1280+
Releases follow a **four-phase GitHub workflow–based strategy** that allows Ketryx compliance approvals to be collected *before* publishing:
12811281

1282-
```bash
1283-
# Patch version (1.0.0 -> 1.0.1)
1284-
make bump patch
1282+
```
1283+
Phase 0 (anytime): Create the Ketryx release in the Ketryx portal
1284+
Phase 1: make prepare-release patch|minor|major|x.y.z
1285+
Phase 2: Point Ketryx release to release/vX.Y.Z; collect approvals
1286+
Phase 3: make publish-release
1287+
Phase 4: make merge-release
1288+
```
12851289

1286-
# Minor version (1.0.0 -> 1.1.0)
1287-
make bump minor
1290+
**Phase 1 — Prepare the release branch:**
12881291

1289-
# Major version (1.0.0 -> 2.0.0)
1290-
make bump major
1292+
```bash
1293+
# Creates release/vX.Y.Z branch from main, bumps version files, and pushes.
1294+
# No tag is created yet.
1295+
make prepare-release patch # 1.0.0 → 1.0.1
1296+
make prepare-release minor # 1.0.0 → 1.1.0
1297+
make prepare-release major # 1.0.0 → 2.0.0
1298+
make prepare-release 1.2.3 # explicit version
12911299
```
12921300

1293-
**This process:**
1301+
This triggers `prepare-release.yml` on GitHub Actions, which:
12941302

1295-
1. Updates version in `pyproject.toml`
1296-
2. Creates git commit: "Bump version: 1.0.0 → 1.0.1"
1297-
3. Creates git tag: `v1.0.1`
1298-
4. Generates changelog from conventional commits
1303+
1. Creates `release/vX.Y.Z` branch from `main`
1304+
2. Runs `bump-my-version` (commits version files + `uv.lock`)
1305+
3. Pushes the branch — CI runs lint/test/audit on it
12991306

1300-
**Push with tags:**
1307+
**Phase 2 — Collect Ketryx approvals:**
1308+
1309+
Point the Ketryx release to the `release/vX.Y.Z` branch and collect required approvals. CI must be green on the branch before proceeding.
1310+
1311+
**Phase 3 — Publish (tag + PyPI):**
13011312

13021313
```bash
1303-
# Push commits and tags
1304-
git push --follow-tags
1314+
# Generates CHANGELOG.md, creates vX.Y.Z tag, pushes → triggers CI/CD publish.
1315+
make publish-release
13051316
1306-
# CI detects tag and triggers:
1307-
# 1. Full CI pipeline (lint + test + audit)
1308-
# 2. Package build and publish to PyPI
1309-
# 3. Docker image build and publish
1310-
# 4. GitHub release creation
1311-
# 5. Slack notification
1317+
# Optionally specify a branch explicitly:
1318+
make publish-release release/v1.2.3
13121319
```
13131320

1314-
**Manual release (if needed):**
1321+
This triggers `publish-release.yml`, which:
1322+
1323+
1. Generates `CHANGELOG.md` for the release range
1324+
2. Commits the changelog
1325+
3. Creates and pushes the annotated `vX.Y.Z` tag
1326+
4. CI/CD fires on the tag; Ketryx check must pass before PyPI publish
1327+
1328+
**Phase 4 — Merge back to main:**
13151329

13161330
```bash
1317-
# Build package
1318-
uv build
1331+
# Merges the release branch into main (--no-ff) and deletes the branch.
1332+
make merge-release
1333+
1334+
# Optionally specify a branch explicitly:
1335+
make merge-release release/v1.2.3
1336+
```
1337+
1338+
This triggers `merge-release.yml`, which:
13191339

1320-
# Publish to PyPI (via UV_PUBLISH_TOKEN secret)
1321-
uv publish
1340+
1. Merges `release/vX.Y.Z` into `main` with `--no-ff`
1341+
2. Pushes `main`
1342+
3. Deletes the remote release branch
1343+
1344+
**What triggers CI/CD:**
1345+
1346+
```
1347+
make prepare-release → push to release/vX.Y.Z → lint + test + audit + Ketryx
1348+
make publish-release → push vX.Y.Z tag → full CI + PyPI + Docker + GitHub release
1349+
make merge-release → push to main → full CI pipeline
13221350
```
13231351
13241352
### CI/CD Integration

CONTRIBUTING.md

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -124,17 +124,38 @@ Notes:
124124

125125
### Publish Release
126126

127+
Releases follow a four-phase workflow that allows Ketryx compliance approvals to be collected before publishing:
128+
129+
**Phase 1 — Create the release branch:**
130+
127131
```shell
128-
make bump # Patch release
129-
make minor # Patch release
130-
make major # Patch release
131-
make x.y.z # Targeted release
132+
make prepare-release patch # 1.0.0 → 1.0.1
133+
make prepare-release minor # 1.0.0 → 1.1.0
134+
make prepare-release major # 1.0.0 → 2.0.0
135+
make prepare-release 1.2.3 # explicit version
132136
```
133137

134-
Notes:
138+
This triggers a GitHub Actions workflow that creates `release/vX.Y.Z` from `main`, bumps version files, and pushes the branch. CI runs automatically on the branch.
139+
140+
**Phase 2 — Collect Ketryx approvals:**
141+
142+
Point the Ketryx release to the `release/vX.Y.Z` branch and collect required approvals.
143+
144+
**Phase 3 — Publish (tag → PyPI):**
145+
146+
```shell
147+
make publish-release
148+
```
149+
150+
Generates `CHANGELOG.md`, creates the `vX.Y.Z` tag, and pushes — triggering CI/CD which publishes to PyPI, Docker registries, and creates a GitHub release (Ketryx check must pass first).
151+
152+
**Phase 4 — Merge back to main:**
153+
154+
```shell
155+
make merge-release
156+
```
135157

136-
1. Changelog generated automatically
137-
2. Publishes to PyPi, Docker Registries, Read The Docs, Streamlit and Auditing services
158+
Merges the release branch into `main` with `--no-ff` and deletes the branch.
138159

139160
## Advanced usage
140161

0 commit comments

Comments
 (0)