@bpmn-io/release

中文文档
0.8.0发布于 2026/10/28MITES Module近 30 天下载 4155

Publish changed packages of an npm monorepo - bpmn.io style.

原始使用文档
文档目录14 节
  1. Usage
  2. Requirements
  3. Strategy
  4. Commit message
  5. CLI
  6. Version command
  7. Private packages
  8. Force release
  9. Build step
  10. GitHub release drafts
  11. Pre-releases
  12. Programmatic API
  13. setVersion
  14. License

@bpmn-io/release

CI

Publish changed packages of an npm monorepo.

Discovers workspace packages from package.json#workspaces (globs expanded; private packages are included by default, versioned + tagged but never published, unless --no-private is set), orders them topologically, detects what changed since the last release, asks for a version bump per package, then applies every bump in a single commit and publishes + tags each package against that one commit.

Usage

Use via command line or as a library.

Requirements

Strategy

The strategy is required and read from the root package.json:

{
  "releaseConfig": {
    "strategy": "independent" // or "fixed"
  }
}
  • independent — each package is versioned and released on its own; tags are name@version. Dependents cascade in when a workspace dependency is released.
  • fixed — released packages share one version, detected against the vX.Y.Z release tag and published together under a single new vX.Y.Z tag. Only packages that changed since the baseline (plus the dependents they cascade in) are released; unchanged packages keep their current version and rejoin the shared version the next time they change.

Commit message

The single release commit defaults to chore(packages): release — and chore(packages): release %version under the fixed strategy. Override it via releaseConfig.commitMessage:

{
  "releaseConfig": {
    "strategy": "fixed",
    "commitMessage": "chore(packages): release %version"
  }
}

The %version placeholder is replaced with the v-prefixed release version (e.g. v1.2.3, matching the vX.Y.Z release tag) — so the example above yields chore(packages): release v1.2.3. Because a single shared version only exists under the fixed strategy, %version may not be used with independent.

CLI

# interactive
npx @bpmn-io/release

# non-interactive (CI)
npx @bpmn-io/release --bump minor --yes
npx @bpmn-io/release --bump @scope/a=patch --bump @scope/b=minor --yes

# --bump also takes an explicit version (same grammar as `version`)
npx @bpmn-io/release --bump @scope/a=1.2.3 --bump @scope/b=minor --yes

# non-interactive: cut 1.3.0-alpha.0 under dist-tag "next"
npx @bpmn-io/release --bump preminor --preid alpha --dist-tag next --yes

# exclude private packages from the release entirely
npx @bpmn-io/release --no-private --bump minor --yes

# force every eligible package to release, even ones without changes
npx @bpmn-io/release --force-release --bump minor --yes

# skip the per-package build step entirely
npx @bpmn-io/release --no-build --bump minor --yes

# version-only: stamp an explicit version onto every package (no commit/tag/publish)
npx @bpmn-io/release version 1.2.0-nightly.0

For all flags, run npx @bpmn-io/release --help.

Version command

bio-release version <spec...> is the pure version primitive, deliberately distinct from a release. It stamps versions onto every workspace package (including private ones) and reconciles the lockfile — and does nothing else:

  • no commit, no git tag, no push
  • no prompt, no build, no publish
  • lockfile only — npm install --package-lock-only, so node_modules is left untouched

Where a release decides versions, commits, tags and (optionally) builds and publishes, version only writes versions you already decided onto disk. That makes it the right tool for a CI/nightly pipeline that needs to stamp a version (e.g. 1.2.0-nightly.20250811) across its workspaces before building artifacts — replacing hand-rolled set-version scripts.

A spec is either an explicit semver version (e.g. 1.2.3, 1.2.0-nightly.0 — used verbatim) or a bump level (patch, minor, major, premajor, preminor, prepatch, prerelease — resolved off the package's current version). A bare spec applies to every package; a name=spec targets a specific one (and wins over the bare default). Packages left without a spec are untouched. This is the same per-package grammar as release's --bump, so the two commands are symmetric: version stamps, release also commits, tags and publishes.

# stamp 1.2.0-nightly.0 onto every workspace package, refresh the lockfile
npx @bpmn-io/release version 1.2.0-nightly.0

# stamp only the public packages
npx @bpmn-io/release version 1.2.3 --no-private

# bump every package by one minor, resolved off its current version
npx @bpmn-io/release version minor

# per-package: an explicit version for one, a level for another
npx @bpmn-io/release version @scope/a=1.2.3 @scope/b=minor

Internal workspace dependency ranges are pinned to ^<version> as part of the stamp. Run npx @bpmn-io/release version --help for all flags.

Private packages

By default private packages ("private": true in their package.json) are versioned, committed and tagged alongside the public ones — they are just never published to the registry. This is useful for monorepos whose deployable artifacts (apps, bundles) live in private workspaces but still need a shared version bump and a git tag to drive the actual release (e.g. through a CI pipeline build). With a fixed strategy this covers the common "bump everything, tag it, publish nothing" case. Pass --no-private to leave private packages out of the release entirely.

Force release

By default a package is only released if it changed since its last release tag. Pass --force-release to release every eligible package regardless of whether it changed. This is what you want when a set of packages form a single product that must always move in lock-step under one shared version — e.g. a fixed-strategy monorepo where a change to just one workspace should still bump and tag them all.

Build step

Before a package is published (or tagged) its all npm script is run as a build gate. This step is optional:

  • if a package has no all script it is skipped, with a warning;
  • pass --no-build to skip the build for every package regardless.

GitHub release drafts

After the release commit and tags are pushed, a pre-filled GitHub release draft opens in your browser for every release tag (mirroring np): one per name@version tag under independent, one for the shared vX.Y.Z tag under fixed. The draft body lists the shipped commit subjects; pre-releases are marked as such. Private packages are never published, so they get no draft.

Skipped when origin is not on GitHub; if no browser can be opened, the draft URL is printed instead. Pass --no-release-draft to turn it off.

Pre-releases

You can safely cut an alpha / rc release either through interactive selection (you are asked for the pre-release identifier and dist-tag) or non-interactively by passing a --preid alongside an explicit, non-latest --dist-tag to publish under.

Pre-release bump levels start or advance a pre-release, and plain patch / minor / major on a pre-release graduate it to the final version:

currentbumpresult
1.2.3preminor (--preid alpha)1.3.0-alpha.0
1.3.0-alpha.0prerelease (--preid alpha)1.3.0-alpha.1
1.3.0-alpha.1minor (graduate, no --preid)1.3.0

Passing --preid declares a pre-release run, so it can never release a stable version. Only pre* levels, skip and an explicit pre-release version carrying that identifier (e.g. 1.3.0-rc.2 for --preid rc) are accepted:

  • interactively, patch / minor / major are not offered; entering a stable level or version (or a pre-release of another identifier) re-asks
  • non-interactively, such a --bump — and likewise a stable spec given to bio-release version — fails before anything is touched
  • a missing or malformed --preid value fails, too

To graduate a pre-release, or to release stable and pre-release packages, run without --preid.

Because publishing a pre-release move (graduating, or re-cutting after a botched publish) may not touch any code since the last release tag, a package sitting on a pre-release version is always offered for release — the usual "nothing changed, skip it" gate does not apply while a pre-release is in progress.

Change detection and bump proposals start from the package.json version, not the highest version on npm — a pre-release cut from a feature branch does not affect releases from other branches.

Before releasing, origin is asked for the tip of the branch the release pushes to; the release fails on a detached HEAD or if that tip is not contained in your checkout (i.e. the push would not fast-forward).

A backport — a stable version below the highest stable on npm — needs an explicit, non-latest dist-tag: you are asked for one (suggesting backports), or pass --dist-tag <tag>.

Programmatic API

import { release, createScriptedPrompter } from '@bpmn-io/release';

const result = await release({
  cwd: process.cwd(),          // repository root
  logger: console,             // any { log, warn, error }
  distTag: 'next',             // required for pre-releases and backports; never `latest`
  releaseDraft: false,         // do not open GitHub release drafts (default: true)
  prompter: createScriptedPrompter({ bump: 'preminor', preid: 'alpha', yes: true })
});

// {
//   strategy, released: [{ name, version }], skipped: [name],
//   aborted?: boolean, tags?: [string]
// }

A prompter drives interactive decisions:

{
  bump({ name, currentVersion, publish, latestStable }): { type, preid, distTag } | 'skip',
  confirm({ plan, strategy }): boolean,
  close(): void
}

type is one of patch | minor | major | premajor | preminor | prepatch | prerelease, preid (e.g. alpha) is the pre-release identifier used by the pre* types, and distTag is the npm dist-tag for a pre-release or a backport — a stable version below latestStable, the highest stable version on npm. It is required for both and must not be latest; omit it only for a regular stable bump, which defaults to latest.

createInteractivePrompter({ preid, distTag }) (readline, the default) and createScriptedPrompter({ bumps, bump, preid, yes }) (head-less) are provided. Both take a governed preid, which makes the run a pre-release run: the scripted prompter throws a ReleaseError for a stable spec, the interactive one does not offer it (see Pre-releases).

release() returns its result rather than calling process.exit, and throws a ReleaseError for expected failures (dirty tree, missing npm auth, missing strategy). The CLI translates those into a non-zero exit.

setVersion

For the version-only primitive, use setVersion:

import { setVersion } from '@bpmn-io/release';

// stamp one version onto every package
const stamped = await setVersion('1.2.0-nightly.0', {
  cwd: process.cwd(),      // repository root
  logger: console,         // any { log, warn }
  excludePrivate: false    // stamp private packages too (default)
});

// [{ name, version }]

// or resolve per-package specs (explicit versions or bump levels)
await setVersion('minor', {
  overrides: { '@scope/a': '1.2.3' },  // wins over the default for @scope/a
  preid: 'alpha'                       // identifier for pre* levels
});

setVersion(defaultSpec, options) resolves a target version per package — defaultSpec applies to every discovered package, options.overrides[name] targets specific ones — then stamps it, pins internal workspace dependency ranges to ^<version> and runs a single npm install --package-lock-only (lockfile only, never node_modules). No commit, tag, prompt, build or publish. A spec is an explicit version (1.2.3, 1.2.0-nightly.0) or a bump level (patch, minor, …). Throws a ReleaseError for an invalid spec, an override naming an unknown package or — when preid is given — a stable spec or a pre-release of another identifier (nothing is mutated in these cases).

The spec resolver is also exported as resolveVersion(spec, current, preid), shared with release() so both accept the same grammar.

License

MIT

版本与发布记录

@bpmn-io/release 共发布 10 个版本,首次发布于 2026/07/01;过去 12 个月发布了 10 个版本。

版本发布日期距今
0.8.0latest2026/10/2811 天前
0.7.02026/10/0930 天前
0.6.12026/10/071 个月前
0.6.02026/09/211 个月前
0.5.12026/08/282 个月前
0.5.02026/08/182 个月前

关于 @bpmn-io/release 的常见问题

@bpmn-io/release 是什么?

Publish changed packages of an npm monorepo - bpmn.io style.

如何安装 @bpmn-io/release?

在项目目录运行 npm install @bpmn-io/release,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 bio-release,可以用 npx bio-release 直接运行。

@bpmn-io/release 支持 TypeScript 吗?

该包的 package.json 没有声明类型入口。需要类型提示时,可以在 npm 上查找社区维护的 @types/bpmn-io__release 是否存在。

@bpmn-io/release 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@bpmn-io/release 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@bpmn-io/release 可以商用吗?

@bpmn-io/release 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@bpmn-io/release 的下载量有多少?

根据 npm 官方下载统计,@bpmn-io/release 在 2026/10/09 – 2026/11/07 这 30 天内被下载 4,155 次,日均约 139 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@bpmn-io/release 还在维护吗?

最新版本 0.8.0 发布于 2026/10/28(11 天前);至今共发布 10 个版本,其中过去 12 个月发布了 10 个;首次发布于 2026/07/01。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。