sotashimozono_obsidian-remo.../plugin/scripts/bump-stable.mjs
Souta 4757bb18e4 feat(release): formalize next=beta / main=stable two-channel model
Version shape is the single source of truth for the channel:
- X.Y.Z-beta.N → next (BRAT --beta consumers)
- X.Y.Z       → main (Obsidian Community Plugins store)

bump-version.mjs is now branch-aware: a beta bump only updates
plugin/manifest.json + manifest-beta.json (root manifest.json +
versions.json stay pinned to the last stable). A stable bump
advances every file together.

version-check.yml enforces the branch ↔ channel invariant:
- PR into next: head must be > base (semver-aware), root manifest.json
  + versions.json must NOT have moved
- PR into main: head must be plain X.Y.Z (no beta suffix), all
  manifests must agree
- Sync PRs (head=main → base=next) skip the workflow entirely

release.yml triggers on push to main AND next, picks prerelease vs
stable from the version shape, and gates: stable-on-next pushes
(promotion-staging commits) are skipped so only the eventual main
push publishes the stable release.

sync-main-to-next.yml automates the post-promotion sync: after a
push to main, it opens a PR main → next and enables auto-merge so
the histories rejoin without manual `git merge main` on next.
commitlint also skips on sync PRs (the autogenerated merge titles
don't follow Conventional Commits).

New npm scripts (run from plugin/):
- bump:beta:start  →  X.Y.Z → X.Y.(Z+1)-beta.0  (start of cycle)
- bump:beta        →  -beta.N → -beta.N+1       (within cycle)
- bump:stable      →  -beta.N suffix dropped    (promotion)

CONTRIBUTING.md documents the lifecycle + promotion flow.

Self-test: this PR bumps next from 1.0.43 to 1.0.44-beta.0 using
the new bump:beta:start script — only the beta-channel files moved.
2026-05-10 12:11:35 +09:00

49 lines
1.7 KiB
JavaScript

// Promotion helper: drop the `-beta.N` suffix from the current
// `plugin/package.json` version and run `npm version <stripped>` so
// the bump-version.mjs hook sees a plain stable version and updates
// every manifest accordingly.
//
// Usage (from plugin/):
// npm run bump:stable
//
// Examples:
// 1.0.44-beta.5 → 1.0.44 (cycle close — ready for promotion)
// 1.0.44 → error (already stable; use `npm version patch`)
//
// Why a separate script instead of `npm version patch`:
// `npm version patch` from `1.0.44-beta.5` produces `1.0.45`,
// skipping the planned `1.0.44` stable. This helper preserves the
// `X.Y.Z` core that the beta cycle was leading up to.
import { execFileSync } from 'child_process';
import * as fs from 'fs';
import * as path from 'path';
import { fileURLToPath } from 'url';
const here = path.dirname(fileURLToPath(import.meta.url));
const pluginRoot = path.resolve(here, '..');
const packagePath = path.join(pluginRoot, 'package.json');
const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
const current = pkg.version;
const m = /^(\d+\.\d+\.\d+)-beta\.\d+$/.exec(current);
if (!m) {
console.error(
`bump-stable: current version "${current}" is not a beta `
+ `(expected X.Y.Z-beta.N). Use 'npm version patch' for a stable bump.`,
);
process.exit(1);
}
const stable = m[1];
console.log(`bump-stable: ${current}${stable}`);
// `npm version <X.Y.Z> --no-git-tag-version` writes package.json,
// runs the `version` lifecycle hook (which calls bump-version.mjs),
// and stages everything per the script in package.json.
execFileSync('npm', ['version', stable, '--no-git-tag-version'], {
cwd: pluginRoot,
stdio: 'inherit',
shell: process.platform === 'win32',
});