MCPcopy Create free account
hub / github.com/dmno-dev/bumpy / ciReleaseCommand

Function ciReleaseCommand

packages/bumpy/src/commands/ci.ts:547–622  ·  view source on GitHub ↗
(rootDir: string, opts: ReleaseOptions)

Source from the content-addressed store, hash-verified

545 * when the detected state doesn't match expectations (used by split-job workflows).
546 */
547export async function ciReleaseCommand(rootDir: string, opts: ReleaseOptions): Promise<void> {
548 const config = await loadConfig(rootDir);
549 ensureGitIdentity(rootDir, config);
550
551 // Snapshots are a one-shot transient release that can run from any branch (typically a
552 // feature PR), so they bypass the base/channel branch routing entirely.
553 if (opts.snapshot !== undefined) {
554 await ciSnapshotRelease(rootDir, opts);
555 return;
556 }
557
558 // Channel branches get the channel flow; unknown branches are refused (when channels
559 // are configured) so a misconfigured workflow can't publish from a feature branch.
560 const releaseBranch = detectReleaseBranch(rootDir);
561 const channel = matchChannelByBranch(config, releaseBranch);
562 if (channel) {
563 await ciChannelRelease(rootDir, config, channel, opts);
564 return;
565 }
566 if (Object.keys(config.channels || {}).length > 0 && releaseBranch && releaseBranch !== config.baseBranch) {
567 throw new Error(
568 `"bumpy ci release" ran on branch "${releaseBranch}", which is neither the base branch ` +
569 `("${config.baseBranch}") nor a configured channel branch. Refusing to release — ` +
570 'add the branch to "channels" in .bumpy/_config.json or fix the workflow trigger.',
571 );
572 }
573
574 const { packages } = await discoverWorkspace(rootDir, config);
575 const depGraph = new DependencyGraph(packages);
576 // Channel-dir bump files count as pending on the base branch — merging a channel
577 // into main brings its shipped files along, and the stable release consumes them
578 // (promotion). No special mode needed.
579 const { bumpFiles, errors: releaseParseErrors } = await readBumpFiles(rootDir, { channels: channelNames(config) });
580
581 if (releaseParseErrors.length > 0) {
582 for (const err of releaseParseErrors) {
583 log.error(err);
584 }
585 throw new Error('Bump file parse errors must be fixed before releasing.');
586 }
587
588 // Determine detected mode. "version-pr" = bump files exist with real releases.
589 // "publish" = no bump files, or only none-only files (version PR just merged).
590 const plan = bumpFiles.length > 0 ? assembleReleasePlan(bumpFiles, packages, depGraph, config) : null;
591 const detectedMode: 'version-pr' | 'publish' = plan && plan.releases.length > 0 ? 'version-pr' : 'publish';
592
593 if (opts.assertMode && opts.assertMode !== detectedMode) {
594 throw new Error(
595 `Expected mode "${opts.assertMode}" but detected "${detectedMode}". ` +
596 `Either remove --expect-mode, or gate this step on the output of "bumpy ci plan".`,
597 );
598 }
599
600 if (detectedMode === 'publish') {
601 // No bump files (or only none-only) — check for unpublished packages.
602 // Recover bump files deleted in the version commit so the formatter
603 // can generate proper GitHub release bodies.
604 const msg =

Callers 1

mainFunction · 0.85

Calls 14

loadConfigFunction · 0.90
detectReleaseBranchFunction · 0.90
matchChannelByBranchFunction · 0.90
discoverWorkspaceFunction · 0.90
readBumpFilesFunction · 0.90
channelNamesFunction · 0.90
assembleReleasePlanFunction · 0.90
recoverDeletedBumpFilesFunction · 0.90
ensureGitIdentityFunction · 0.85
ciSnapshotReleaseFunction · 0.85
ciChannelReleaseFunction · 0.85
publishCommandFunction · 0.85

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…