JerrettDavis commited on
Commit
c36529d
Β·
1 Parent(s): a2b9c9c

ci: force new run to test updated workflow

Browse files
Files changed (2) hide show
  1. .changelog.md +2 -0
  2. PR.md +170 -0
.changelog.md ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ ## [0.5.26] - 2026-04-15
2
+
PR.md ADDED
@@ -0,0 +1,170 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## Description
2
+
3
+ Implement unified CI/CD release automation with semantic versioning across all three packages:
4
+ - **Python (headroom-ai)** β€” pip package on PyPI
5
+ - **TypeScript SDK (headroom-ai)** β€” npm package on npmjs.org
6
+ - **OpenClaw plugin (headroom-openclaw)** β€” npm package on npmjs.org and GitHub Package Registry
7
+
8
+ Currently the three packages are independently versioned (0.5.25 / 0.1.0 / 0.1.0). This PR introduces a single-source-of-truth version in `pyproject.toml` that propagates to all packages on every release, driven by conventional commit messages.
9
+
10
+ Fixes #(issue number)
11
+
12
+ ## Type of Change
13
+
14
+ - [ ] Bug fix (non-breaking change that fixes an issue)
15
+ - [x] New feature (non-breaking change that adds functionality)
16
+ - [ ] Breaking change (fix or feature that would cause existing functionality to change)
17
+ - [x] Documentation update
18
+ - [ ] Performance improvement
19
+ - [x] Code refactoring (no functional changes)
20
+
21
+ ## Changes Made
22
+
23
+ ### New Files
24
+
25
+ **Scripts:**
26
+ - `scripts/version-sync.py` β€” Reads version from `pyproject.toml`, updates all 4 version files. Supports `--version X.Y.Z` and `--bump {major,minor,patch}`.
27
+ - `scripts/changelog-gen.py` β€” Parses conventional commits since last tag, groups by type, generates markdown changelog with breaking change detection.
28
+ - `scripts/verify-versions.py` β€” Pre-release sanity check that all 4 version files are in sync.
29
+ - `scripts/tests/test_version_sync.py` β€” 5 tests for version-sync.py
30
+ - `scripts/tests/test_changelog_gen.py` β€” 23 tests for changelog-gen.py
31
+
32
+ **Workflows:**
33
+ - `.github/workflows/release.yml` β€” Unified release pipeline: detect β†’ build β†’ publish-pypi β†’ publish-npm β†’ publish-github-packages β†’ create-release
34
+ - `.commitlintrc.json` β€” Conventional commit enforcement via `@commitlint/config-conventional`
35
+
36
+ **Local Testing (act):**
37
+ - `.actrc` β€” Default `act` flags (Ubuntu runner, reuse, quiet)
38
+ - `.github/act/dry-run.json` β€” `act` event file for dry-run testing
39
+ - `.github/act/push-feat.json` β€” `act` event file for simulating a feat commit
40
+ - `.actrc.local.example` β€” Local override template for `act`
41
+ - `.env.act.example` β€” Secrets documentation template for `act` local testing
42
+
43
+ **Documentation:**
44
+ - `docs/content/docs/releases.mdx` β€” Full documentation for the release pipeline, testing guide, and configuration reference
45
+
46
+ ### Modified Files
47
+
48
+ - `.github/workflows/ci.yml` β€” Added `commitlint` job to enforce conventional commits
49
+ - `.github/workflows/publish.yml` β€” Changed from `release` trigger to `workflow_dispatch` only (superseded by `release.yml`)
50
+ - `.github/workflows/release.yml` β€” **Rewritten** with canonical+commit-height algorithm (no more commit loop)
51
+ - `.gitignore` β€” Added `!scripts/version-sync.py`, `!scripts/changelog-gen.py`, `!scripts/verify-versions.py`, `!scripts/tests/`, `.env.act`, `.actrc.local`
52
+
53
+ ## Testing
54
+
55
+ - [x] Unit tests pass (`pytest`)
56
+ - `scripts/tests/test_version_sync.py` β€” 5/5 passing
57
+ - `scripts/tests/test_changelog_gen.py` β€” 23/23 passing
58
+ - [x] Linting passes (`ruff check .`)
59
+ - [ ] Type checking passes (`mypy headroom`) β€” pre-existing issue in `headroom/cli/wrap.py:487` (unrelated)
60
+ - [x] New tests added for new functionality
61
+ - [x] Workflow tested with `act` (dry-run passes all jobs through build step β€” no infinite loop)
62
+
63
+ ## Algorithm Validation
64
+
65
+ The canonical+commit-height algorithm was validated with test cases:
66
+ - Canonical `0.5.25`, no prior tag, `feat:` commit β†’ git tag `v0.6.0.0`, npm `0.6.0` βœ…
67
+ - Canonical `0.5.25`, tag `v0.5.25.2`, `fix:` commit β†’ git tag `v0.5.25.3`, npm `0.5.26` βœ…
68
+ - Canonical `0.5.25`, no prior tag, `fix:` commit β†’ git tag `v0.5.25.0`, npm `0.5.25` βœ…
69
+ - Manual override `1.2.3` β†’ git tag `v1.2.3`, npm `1.2.3` βœ…
70
+
71
+ ## Test Output
72
+
73
+ ```
74
+ scripts/tests/test_version_sync.py .....
75
+ scripts/tests/test_changelog_gen.py .......................
76
+ ```
77
+
78
+ ## Checklist
79
+
80
+ - [x] My code follows the project's style guidelines
81
+ - [x] I have performed a self-review of my code
82
+ - [x] I have commented my code, particularly in hard-to-understand areas
83
+ - [x] My changes generate no new warnings
84
+ - [x] I have added tests that prove my fix is effective or that my feature works
85
+ - [x] New and existing unit tests pass locally with my changes
86
+ - [x] I have made corresponding changes to the documentation
87
+ - [ ] I have updated the CHANGELOG.md if applicable
88
+
89
+ ## Additional Notes
90
+
91
+ ### Version Bump Logic
92
+
93
+ **Canonical + Commit Height Algorithm** β€” The workflow NEVER commits back to the repo. `pyproject.toml` is the canonical source of truth, updated manually before merging.
94
+
95
+ | Commit | Bump | Git Tag | npm Version |
96
+ |--------|------|---------|-------------|
97
+ | `fix:`, `ci:`, `chore:`, `perf:`, `refactor:` | patch | `v0.5.25.3` | `0.5.26` |
98
+ | `feat:` | minor | `v0.6.0.0` | `0.6.0` |
99
+ | `feat!:` or `feat:` + `BREAKING CHANGE` body | major | `v1.0.0.0` | `1.0.0` |
100
+
101
+ The git tag uses `v{canonical}.{height}` (e.g., `v0.5.25.3` = 3 commits since canonical `0.5.25`). npm versions use 3-part semver, bumped from canonical.
102
+
103
+ ### Package Publishing Targets
104
+
105
+ | Package | Target | Status |
106
+ |---------|--------|--------|
107
+ | `headroom-ai` (Python) | PyPI | βœ… via `pypa/gh-action-pypi-publish` |
108
+ | `headroom-ai` (TypeScript SDK) | npmjs.org | βœ… via `npm publish` |
109
+ | `headroom-openclaw` | npmjs.org | βœ… via `npm publish` |
110
+ | `headroom-openclaw` | GitHub Package Registry | βœ… via `npm publish --registry npm.pkg.github.com` |
111
+
112
+ ### Safety Gates
113
+
114
+ Each publish job requires both `dry_run != 'true'` **and** the corresponding skip variable not set:
115
+
116
+ | Variable | Effect |
117
+ |----------|--------|
118
+ | `PYPI_SKIP=true` | Skip PyPI publish |
119
+ | `NPM_SKIP=true` | Skip both npm publishes |
120
+ | `GITHUB_PKG_SKIP=true` | Skip GitHub Package Registry publish |
121
+
122
+ Set in: **GitHub repo β†’ Settings β†’ Variables β†’ Actions Variables**.
123
+
124
+ ### Workflow Triggers
125
+
126
+ - **Auto:** On push to `main` β€” analyzes latest commit, bumps version, builds, publishes, creates GitHub Release
127
+ - **Manual:** `workflow_dispatch` with optional `version` override and `dry_run` flag
128
+ - **Paths ignore:** Skips runs when only `docs/`, `.github/workflows/ci.yml`, `.github/workflows/publish.yml`, `scripts/`, `.commitlintrc.json`, `.actrc`, `.github/act/`, or `.env.act.example` change
129
+
130
+ ### Local Testing
131
+
132
+ ```bash
133
+ # Install act
134
+ winget install act
135
+
136
+ # Dry-run (no publishes)
137
+ act -W .github/workflows/release.yml -e .github/act/dry-run.json
138
+
139
+ # Test feat: commit (minor bump)
140
+ act -W .github/workflows/release.yml -e .github/act/push-feat.json
141
+ ```
142
+
143
+ ### Required GitHub Secrets
144
+
145
+ | Secret | Purpose |
146
+ |--------|---------|
147
+ | `NPM_TOKEN` | Publishing to npmjs.org |
148
+ | `GITHUB_TOKEN` | GitHub Package Registry (auto-provided by GitHub Actions) |
149
+
150
+ PyPI uses trusted publisher OIDC β€” no secret required, only the `pypi` GitHub Environment must be configured.
151
+
152
+ ### First Release Note
153
+
154
+ The TypeScript packages are currently at `0.1.0` while Python is at `0.5.25`. The first release will align all three to the same version. Update `pyproject.toml` to the desired canonical version before merging, then use `workflow_dispatch` with a manual `version` input to set the target explicitly.
155
+
156
+ After each release, update `pyproject.toml` to match the published version to keep the canonical current and ensure unique git tags.
157
+
158
+ ### Parameterized Configuration
159
+
160
+ All package names and registries are top-level `env` constants in `release.yml`:
161
+
162
+ ```yaml
163
+ env:
164
+ PYPI_PACKAGE: headroom-ai
165
+ PYPI_ENVIRONMENT: pypi
166
+ NPM_REGISTRY_URL: https://registry.npmjs.org
167
+ NPM_SDK_PACKAGE: headroom-ai
168
+ NPM_OPENCLAW_PACKAGE: headroom-openclaw
169
+ GITHUB_PACKAGES_REGISTRY_URL: https://npm.pkg.github.com
170
+ ```