Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,12 +118,14 @@ semantic-release. Two repo-specific rules:
reject an unscoped revert in that form — keep reverts conventional and scoped by hand, and
know that a scoped revert releases nothing: ship a rollback as `fix(<scope>)` (see
VERSIONING.md for why).
- **Packages release independently, keyed off the scope**: `feat(bulma-ui)` bumps only
`@allxsmith/bestax-bulma`; `fix(create-bestax)` bumps only `create-bestax`. The
`releaseRules` in each package's `release.config.js` are the source of truth.
- **Packages release independently, keyed off the scope**: `fix(create-bestax)` bumps only
Comment thread
claude[bot] marked this conversation as resolved.
`create-bestax`. The exception is bestax-mcp, which also cuts a patch with every
`@allxsmith/bestax-bulma` release because its index documents the library (VERSIONING.md,
"bestax-mcp releases with bestax-bulma"). The `releaseRules` in each package's
`release.config.js` are the source of truth.

```
feat(bulma-ui): add Collapse component → minor release of bulma-ui only
feat(bulma-ui): add Collapse component → minor release of bulma-ui, patch of bestax-mcp
fix(create-bestax): handle missing TTY → patch release of create-bestax only
docs: fix typo in contributing guide → no release; scope optional
```
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ The short version for contributors:
We use [Semantic Release](https://semantic-release.gitbook.io/) to automate publishing of every package to npm: `bulma-ui` as [`@allxsmith/bestax-bulma`](https://www.npmjs.com/package/@allxsmith/bestax-bulma), plus [`create-bestax`](https://www.npmjs.com/package/create-bestax), [`bestax-migrate`](https://www.npmjs.com/package/bestax-migrate), [`bestax-mcp`](https://www.npmjs.com/package/bestax-mcp) and `eslint-plugin` as [`@allxsmith/eslint-plugin-bestax`](https://www.npmjs.com/package/@allxsmith/eslint-plugin-bestax).

- Use [Conventional Commits](https://www.conventionalcommits.org/) to trigger releases — see [Commit Message Guidelines](#commit-message-guidelines).
- **Packages version and release independently, keyed off the commit scope** — `feat(bulma-ui)` releases only bestax-bulma. See [`VERSIONING.md`](./VERSIONING.md).
- **Packages version and release independently, keyed off the commit scope**: `fix(create-bestax)` releases only create-bestax, and the one exception is the bestax-mcp patch that follows every bestax-bulma release. See [`VERSIONING.md`](./VERSIONING.md).
- Only the `main` branch is published.

### npm authentication (OIDC trusted publishing)
Expand Down
49 changes: 30 additions & 19 deletions VERSIONING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

`@allxsmith/bestax-bulma`, `create-bestax`, `bestax-migrate`, `bestax-mcp`, and
`@allxsmith/eslint-plugin-bestax` are versioned
and released **independently**. Each package releases only when a commit is scoped to it — the
and released **independently**. Each package releases when a commit is scoped to it, except that
bestax-mcp also releases with bestax-bulma ([below](#bestax-mcp-releases-with-bestax-bulma)). The
version numbers are unrelated (e.g. bestax-bulma 5.x alongside create-bestax 3.x).

The source of truth is the `releaseRules` in each package's semantic-release config:
Expand All @@ -14,21 +15,21 @@ The source of truth is the `releaseRules` in each package's semantic-release con

## Release Rules

A commit releases **only** the package its scope names. Representative examples — the same
`feat`/`fix`/`perf`/`refactor`/`style` and `BREAKING CHANGE:` rules apply to every package
through its own scope:

| Commit | bestax-bulma | create-bestax | bestax-migrate | bestax-mcp | eslint-plugin |
| ----------------------------------------------------------------- | ------------ | ------------- | -------------- | ---------- | ------------- |
| `feat(bulma-ui): …` | minor | — | — | — | — |
| `fix(bulma-ui): …` | patch | — | — | — | — |
| `perf/refactor/style(bulma-ui): …` | patch | — | — | — | — |
| `feat(create-bestax): …` | — | minor | — | — | — |
| `fix(bestax-migrate): …` | — | — | patch | — | — |
| `feat(bestax-mcp): …` | — | — | — | minor | — |
| `feat(eslint-plugin): …` | — | — | — | — | minor |
| `feat(bulma-ui): …` + `BREAKING CHANGE:` footer | major | — | — | — | — |
| `docs: …`, `chore: …`, `ci: …`, `test: …`, `build: …` (any scope) | — | — | — | — | — |
A commit releases **only** the package its scope names, apart from the bestax-mcp patch that
follows every bestax-bulma release ([below](#bestax-mcp-releases-with-bestax-bulma)). Representative
examples follow, and the same `feat`/`fix`/`perf`/`refactor`/`style` and `BREAKING CHANGE:` rules
apply to every package through its own scope:

| Commit | bestax-bulma | create-bestax | bestax-migrate | bestax-mcp | eslint-plugin |
| ----------------------------------------------- | ------------ | ------------- | -------------- | ---------- | ------------- |
| `feat(bulma-ui): …` | minor | — | — | patch | — |
| `fix(bulma-ui): …` | patch | — | — | patch | — |
| `perf/refactor/style(bulma-ui): …` | patch | — | — | patch | — |
| `feat(create-bestax): …` | — | minor | — | — | — |
| `fix(bestax-migrate): …` | — | — | patch | — | — |
| `feat(bestax-mcp): …` | — | — | — | minor | — |
| `feat(eslint-plugin): …` | — | — | — | — | minor |
| `feat(bulma-ui): …` + `BREAKING CHANGE:` footer | major | — | — | patch | — |

Notes:

Expand All @@ -53,6 +54,15 @@ Notes:
keep reverts in conventional, scoped form, and don't expect them to publish on their own.
- A commit scoped to `docs` never releases any package.

### bestax-mcp releases with bestax-bulma

bestax-mcp ships an index of the library, and a new index only reaches npm when bestax-mcp
releases. So every commit that releases bestax-bulma releases bestax-mcp too, in the same run, and
the published index keeps up with the library (#932). That release is a patch whatever
bestax-bulma's own bump, a major included. The rules, the reasons for them and what they do to
bestax-mcp's changelog are in [`bestax-mcp/release.config.js`](./bestax-mcp/release.config.js),
and `scripts/release-rules.test.mjs` holds them to bulma-ui's.

## Tags & Changelogs

Each package tags and logs its own releases:
Expand Down Expand Up @@ -83,7 +93,8 @@ On merge to `main`, CI (`.github/workflows/ci.yml`) runs semantic-release in eac
- Note the ordering, because it decides what a failed publish costs: semantic-release runs
**every** `prepare` step — including the release commit and tag — before **any** `publish`
step. A publish that fails leaves the commit and tag behind, and that version is spent.
3. A push may release any subset of the packages — they never bump each other.
3. A push may release any subset of the packages. None bumps another, apart from bestax-mcp
following bestax-bulma.

For `bestax-mcp`, the GitHub release then triggers `.github/workflows/mcp-registry.yml`, which
lists that version in the official MCP Registry. The listing is metadata pointing at the npm
Expand Down Expand Up @@ -138,7 +149,7 @@ are in [`CONTRIBUTING.md`](./CONTRIBUTING.md#codemod-registry-bestax-migrate).

```bash
git commit -m "feat(bulma-ui): add new Modal variant"
# → bestax-bulma minor bump; create-bestax untouched
# → bestax-bulma minor bump, bestax-mcp patch; create-bestax untouched

git commit -m "fix(create-bestax): correct template scaffolding issue"
# → create-bestax patch bump; bestax-bulma untouched
Expand All @@ -147,7 +158,7 @@ git commit -m "docs: update README"
# → no release

git commit -m "feat(bulma-ui): rename Theme props" -m "BREAKING CHANGE: bulmaVars renamed to vars"
# → bestax-bulma major bump
# → bestax-bulma major bump, bestax-mcp patch
```

## History
Expand Down
5 changes: 3 additions & 2 deletions bestax-mcp/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,9 @@ test that stubs it proves nothing about what ships.

## Releases

Independent semantic-release keyed off the `bestax-mcp` commit scope
(`release.config.js`, tag `bestax-mcp@x.y.z`). It publishes with
Released by semantic-release, keyed off the `bestax-mcp` commit scope (`release.config.js`, tag
`bestax-mcp@x.y.z`), and patched with every bulma-ui release so the index ships with the
library (VERSIONING.md, "bestax-mcp releases with bestax-bulma"). It publishes with
`pnpm publish`, like every package here (#532) — the command, its flags, and the
ways that publish fails quietly are documented in `VERSIONING.md` and
`scripts/lib/pnpm-publish.mjs`.
Expand Down
66 changes: 53 additions & 13 deletions bestax-mcp/release.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,37 +8,77 @@ export default {
'@semantic-release/commit-analyzer',
{
preset: 'angular',
// commit-analyzer evaluates EVERY matching rule and a matching
// `release: false` always wins (its priority index is -1), so rules
// are not first-match-wins. Values are micromatch globs, hence the
// negated glob below; a `release: false` rule must never be able to
// match a commit that should release.
// commit-analyzer checks every rule against each commit, in this
// order, so rules are not first-match-wins. A matching
// `release: false` replaces whatever matched above it, a release type
// matching after a `false` replaces the `false`, the higher of two
// release types stays, and `major` ends the walk. So the place of a
// rule in this list can decide a commit, which the bulma-ui group at
// the end depends on. Values are micromatch globs, hence the negated
// glob below.
releaseRules: [
// Any commit scoped to something other than bestax-mcp never
// releases this package. Without this, commits matching no rule
// fall back to the angular defaults and would bump this package
// too. (Does not match unscoped commits — a scope on releasing
// types is enforced by commitlint instead.)
{ scope: '!(bestax-mcp)', release: false },
// Any commit scoped to something other than bestax-mcp or bulma-ui
// never releases this package. Without this, commits matching no
// rule fall back to the angular defaults and would bump this
// package too. bulma-ui is left out because its commits can release
// this package (the group at the end), so this `false` never meets
// them and its place in the list decides nothing. (Does not match
// unscoped commits: a scope on releasing types is enforced by
// commitlint instead.)
{ scope: '!(bestax-mcp|bulma-ui)', release: false },

// bestax-mcp releases. Breaking changes need a "BREAKING CHANGE:"
// footer — the angular preset does not parse "feat(x)!:".
// footer, since the angular preset does not parse "feat(x)!:".
{ breaking: true, scope: 'bestax-mcp', release: 'major' },
{ type: 'feat', scope: 'bestax-mcp', release: 'minor' },
{ type: 'fix', scope: 'bestax-mcp', release: 'patch' },
{ type: 'perf', scope: 'bestax-mcp', release: 'patch' },
{ type: 'refactor', scope: 'bestax-mcp', release: 'patch' },
{ type: 'style', scope: 'bestax-mcp', release: 'patch' },

// Non-releasing types, any scope (safe: never release-triggering)
// Types that release nothing, in any scope, unless a
// "BREAKING CHANGE:" footer brings in a breaking rule: the
// bestax-mcp `major` above ends the walk before these, and the
// bulma-ui rule below comes after them.
{ type: 'docs', release: false },
{ type: 'test', release: false },
{ type: 'chore', release: false },
{ type: 'ci', release: false },
{ type: 'build', release: false },

// Every commit that releases bulma-ui releases this package too,
// as a patch (#932). data/ indexes the library, so it ships when
// the library does: the release job regenerates it after bulma-ui's
// release and before this one, and this one packs it. These are
// the commits bulma-ui/release.config.js releases on, and
// scripts/release-rules.test.mjs holds the two lists together.
//
// Patch whatever bulma-ui's own bump, a major included. The
// server's tools and prompts stay as they were and only what they
// answer from moves, and a major here would leave every
// `bestax-mcp@1` install and listing behind.
//
// Last on purpose, for the breaking rule. bulma-ui releases a major
// for a breaking commit of any type, `build` and `chore` included,
// because its `major` ends the walk before the type's
// `release: false`. A patch ends nothing, so above the
// non-releasing types the breaking rule would lose to that `false`,
// and a library major would ship no index.
{ type: 'feat', scope: 'bulma-ui', release: 'patch' },
{ type: 'fix', scope: 'bulma-ui', release: 'patch' },
{ type: 'perf', scope: 'bulma-ui', release: 'patch' },
{ type: 'refactor', scope: 'bulma-ui', release: 'patch' },
{ type: 'style', scope: 'bulma-ui', release: 'patch' },
{ breaking: true, scope: 'bulma-ui', release: 'patch' },
],
},
],
// The notes list the feat, fix and perf commits since the last
// bestax-mcp tag whatever their scope, so a release the rules above take
// from bulma-ui lists bulma-ui's commits. Left that way: they are what
// the new index documents. A breaking one lands under BREAKING CHANGES
// in a patch, and that heading then describes the library, not this
// server.
'@semantic-release/release-notes-generator',
[
'@semantic-release/changelog',
Expand Down
8 changes: 3 additions & 5 deletions bestax-migrate/release.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@ export default {
'@semantic-release/commit-analyzer',
{
preset: 'angular',
// commit-analyzer evaluates EVERY matching rule and a matching
// `release: false` always wins (its priority index is -1), so rules
// are not first-match-wins. Values are micromatch globs, hence the
// negated glob below; a `release: false` rule must never be able to
// match a commit that should release.
// commit-analyzer evaluates EVERY matching rule, so rules are not
// first-match-wins. Values are micromatch globs, hence the negated
// glob below.
releaseRules: [
// Any commit scoped to something other than bestax-migrate never
// releases this package. Without this, commits matching no rule
Expand Down
4 changes: 3 additions & 1 deletion bulma-ui/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,9 @@ These keep it working, and each of them failed once:
## Releases

Independent semantic-release keyed off the `bulma-ui` commit scope
(`release.config.js`, tag `@allxsmith/bestax-bulma@x.y.z`). It publishes with
(`release.config.js`, tag `@allxsmith/bestax-bulma@x.y.z`). Each release also patches
bestax-mcp, so its index ships with the library (VERSIONING.md, "bestax-mcp releases with
bestax-bulma"). It publishes with
`pnpm publish`, like every package here (#532) — the command, its flags, and the
ways that publish fails quietly are documented in `VERSIONING.md` and
`scripts/lib/pnpm-publish.mjs`.
Expand Down
8 changes: 3 additions & 5 deletions bulma-ui/release.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@ export default {
'@semantic-release/commit-analyzer',
{
preset: 'angular',
// commit-analyzer evaluates EVERY matching rule and a matching
// `release: false` always wins (its priority index is -1), so rules
// are not first-match-wins. Values are micromatch globs, hence the
// negated glob below; a `release: false` rule must never be able to
// match a commit that should release.
// commit-analyzer evaluates EVERY matching rule, so rules are not
// first-match-wins. Values are micromatch globs, hence the negated
// glob below.
releaseRules: [
// Any commit scoped to something other than bulma-ui never
// releases this package. (Does not match unscoped commits — a
Expand Down
8 changes: 3 additions & 5 deletions create-bestax/release.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@ export default {
'@semantic-release/commit-analyzer',
{
preset: 'angular',
// commit-analyzer evaluates EVERY matching rule and a matching
// `release: false` always wins (its priority index is -1), so rules
// are not first-match-wins. Values are micromatch globs, hence the
// negated glob below; a `release: false` rule must never be able to
// match a commit that should release.
// commit-analyzer evaluates EVERY matching rule, so rules are not
// first-match-wins. Values are micromatch globs, hence the negated
// glob below.
releaseRules: [
// Any commit scoped to something other than create-bestax never
// releases this package. Without this, commits matching no rule
Expand Down
Loading
Loading