Spaces:
Build error
Build error
Commit Β·
c36529d
1
Parent(s): a2b9c9c
ci: force new run to test updated workflow
Browse files- .changelog.md +2 -0
- 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 |
+
```
|