diff --git a/.chronus/changes/fix-exclude-version-2025-2-4-9-18-9.md b/.chronus/changes/fix-exclude-version-2025-2-4-9-18-9.md new file mode 100644 index 00000000..6ac23f30 --- /dev/null +++ b/.chronus/changes/fix-exclude-version-2025-2-4-9-18-9.md @@ -0,0 +1,7 @@ +--- +changeKind: fix +packages: + - "@chronus/chronus" +--- + +Fix `--exclude` not respected for `version`, `status` commands \ No newline at end of file diff --git a/packages/chronus/src/release-plan/assemble-release-plan.test.ts b/packages/chronus/src/release-plan/assemble-release-plan.test.ts index ab5ae829..14ca6bb2 100644 --- a/packages/chronus/src/release-plan/assemble-release-plan.test.ts +++ b/packages/chronus/src/release-plan/assemble-release-plan.test.ts @@ -249,4 +249,42 @@ describe("Assemble Release Plan", () => { expect(plan.changes[0]).toMatchObject({ usage: "partial", packages: ["pkg-a"] }); }); }); + + describe("partial release plan using exclude option", () => { + it("ignore packages with changes", () => { + const workspace: Workspace = mkWorkspace([mkPkg("pkg-a", {}), mkPkg("pkg-b", {})]); + const plan = assembleReleasePlan( + [mkChange("pkg-a", "minor"), mkChange("pkg-b", "minor")], + createChronusWorkspace(workspace, baseConfig), + { exclude: ["pkg-b"] }, + ); + expect(plan.actions).toHaveLength(1); + expect(plan.actions[0]).toMatchObject({ packageName: "pkg-a", oldVersion: "1.0.0", newVersion: "1.1.0" }); + }); + + it("ignore packages that would need to be bumped as dependent", () => { + const workspace: Workspace = mkWorkspace([ + mkPkg("pkg-a", {}), + mkPkg("pkg-b", { dependencies: { "pkg-a": "1.0.0" } }), + ]); + const plan = assembleReleasePlan([mkChange("pkg-a", "minor")], createChronusWorkspace(workspace, baseConfig), { + exclude: ["pkg-b"], + }); + expect(plan.actions).toHaveLength(1); + expect(plan.actions[0]).toMatchObject({ packageName: "pkg-a", oldVersion: "1.0.0", newVersion: "1.1.0" }); + }); + + it("report changes as partially used if only bumping some packages tagged in it", () => { + const workspace: Workspace = mkWorkspace([mkPkg("pkg-a", {}), mkPkg("pkg-b", {})]); + const plan = assembleReleasePlan( + [mkChange(["pkg-a", "pkg-b"], "minor")], + createChronusWorkspace(workspace, baseConfig), + { + exclude: ["pkg-b"], + }, + ); + expect(plan.changes).toHaveLength(1); + expect(plan.changes[0]).toMatchObject({ usage: "partial", packages: ["pkg-a"] }); + }); + }); }); diff --git a/packages/chronus/src/release-plan/assemble-release-plan.ts b/packages/chronus/src/release-plan/assemble-release-plan.ts index 5a5da1ff..ae3b086c 100644 --- a/packages/chronus/src/release-plan/assemble-release-plan.ts +++ b/packages/chronus/src/release-plan/assemble-release-plan.ts @@ -1,5 +1,6 @@ import type { ChangeDescription } from "../change/types.js"; import { getDependentsGraph } from "../dependency-graph/index.js"; +import { isPackageIncluded } from "../utils/misc-utils.js"; import type { ChronusWorkspace } from "../workspace/types.js"; import { applyDependents } from "./determine-dependents.js"; import { incrementVersion } from "./increment-version.js"; @@ -18,7 +19,10 @@ export function assembleReleasePlan( options?: AssembleReleasePlanOptions, ): ReleasePlan { const packagesByName = new Map(workspace.allPackages.map((pkg) => [pkg.name, pkg])); - const { changeApplications, actions: requested } = reduceChanges(changes, workspace, options?.only); + const { changeApplications, actions: requested } = reduceChanges(changes, workspace, { + only: options?.only, + exclude: options?.exclude, + }); const dependentsGraph = getDependentsGraph(workspace.packages); const internalActions = new Map(); @@ -46,6 +50,7 @@ export function assembleReleasePlan( internalActions.set(request.packageName, request); } } + // The map passed in to determineDependents will be mutated applyDependents({ actions: internalActions, @@ -76,7 +81,7 @@ export function assembleReleasePlan( function reduceChanges( changes: ChangeDescription[], workspace: ChronusWorkspace, - only?: string[], + filters: { only?: string[]; exclude?: string[] } = {}, ): { changeApplications: ReleasePlanChangeApplication[]; actions: Map } { const actions: Map = new Map(); const changeApplications: ReleasePlanChangeApplication[] = []; @@ -85,8 +90,8 @@ function reduceChanges( // Filter out ignored packages because they should not trigger a release // If their dependencies need updates, they will be added to releases by `determineDependents()` with release type `none` const packages = change.packages - .filter((name) => !only || only.includes(name)) .map((name) => workspace.getPackage(name)) + .filter((pkg) => isPackageIncluded(pkg, filters)) .filter((pkg) => pkg.state === "versioned" || pkg.state === "standalone"); changeApplications.push({ diff --git a/packages/chronus/src/utils/misc-utils.ts b/packages/chronus/src/utils/misc-utils.ts index b2808e45..30cc6326 100644 --- a/packages/chronus/src/utils/misc-utils.ts +++ b/packages/chronus/src/utils/misc-utils.ts @@ -67,8 +67,8 @@ export function isPackageIncluded( return false; } - if (only && (only.includes(pkgName) || only.includes(policyName))) { - return true; + if (only) { + return only.includes(pkgName) || only.includes(policyName); } return true;