Skip to content

Commit

Permalink
feat(version): add option to force version update (#3852)
Browse files Browse the repository at this point in the history
  • Loading branch information
amorscher authored Oct 11, 2023
1 parent be1f4e3 commit 914dd96
Show file tree
Hide file tree
Showing 10 changed files with 189 additions and 6 deletions.
104 changes: 104 additions & 0 deletions e2e/version/src/conventional-commits.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,55 @@ describe("lerna-version-conventional-commits", () => {
`);
});

it("should correctly bump versions when using --conventional-graduate and --force-conventional-graduate", async () => {
await fixture.createInitialGitCommit();

await fixture.lerna("create package-a -y");
await fixture.exec("git add --all");
await fixture.exec("git commit -m 'feat: add package-a'");

await fixture.lerna("create package-b -y");
await fixture.exec("git add --all");
await fixture.exec("git commit -m 'feat: add package-b'");

await fixture.exec("git push origin test-main");

// Initial versioning with two packages created
await fixture.lerna("version --conventional-commits -y", { silenceError: true });

// Update and version just package-a
await fixture.exec("echo update_package_a > packages/package-a/new_file.txt");
await fixture.exec("git add --all");
await fixture.exec("git commit -m 'fix: update package-a'");

// Create a version with force-conventional-graduate
const output = await fixture.lerna(
"version --conventional-commits --conventional-graduate --force-conventional-graduate -y",
{
silenceError: true,
}
);

expect(output.combinedOutput).toMatchInlineSnapshot(`
lerna notice cli v999.9.9-e2e.0
lerna info current version 0.1.0
lerna WARN conventional-graduate all packages
lerna info Graduating all prereleased packages
lerna info Looking for changed packages since v0.1.0
lerna info getChangelogConfig Successfully resolved preset "conventional-changelog-angular"
Changes:
- package-a: 0.1.0 => 0.1.1
- package-b: 0.1.0 => 0.1.1
lerna info auto-confirmed
lerna info execute Skipping releases
lerna info git Pushing tags...
lerna success version finished
`);
});

it("should correctly generate and bump prerelease versions when using --conventional-prerelease and --conventional-bump-prerelease", async () => {
await fixture.createInitialGitCommit();

Expand Down Expand Up @@ -532,6 +581,61 @@ describe("lerna-version-conventional-commits", () => {
(await fixture.exec("git ls-remote origin refs/tags/[email protected]")).combinedOutput
).toMatchInlineSnapshot(``);
});

it("should correctly bump versions when using --conventional-graduate and --force-conventional-graduate", async () => {
await fixture.createInitialGitCommit();

fixture.updateJson("lerna.json", (json) => {
// eslint-disable-next-line no-param-reassign
json.version = "independent";
return json;
});

await fixture.lerna("create package-a -y");
await fixture.exec("git add --all");
await fixture.exec("git commit -m 'feat: add package-a'");

await fixture.lerna("create package-b -y");
await fixture.exec("git add --all");
await fixture.exec("git commit -m 'feat: add package-b'");

await fixture.exec("git push origin test-main");

// Initial versioning with two packages created
await fixture.lerna("version --conventional-commits -y", { silenceError: true });

// Update and version just package-a
await fixture.exec("echo update_package_a > packages/package-a/new_file.txt");
await fixture.exec("git add --all");
await fixture.exec("git commit -m 'feat: update package-a'");

// Create a version with force-conventional-graduate
const output = await fixture.lerna(
"version --conventional-commits --conventional-graduate --force-conventional-graduate -y",
{
silenceError: true,
}
);

expect(output.combinedOutput).toMatchInlineSnapshot(`
lerna notice cli v999.9.9-e2e.0
lerna info versioning independent
lerna WARN conventional-graduate all packages
lerna info Graduating all prereleased packages
lerna info Looking for changed packages since [email protected]
lerna info getChangelogConfig Successfully resolved preset "conventional-changelog-angular"
Changes:
- package-a: 1.1.0 => 1.2.0
- package-b: 1.1.0 => 1.1.1
lerna info auto-confirmed
lerna info execute Skipping releases
lerna info git Pushing tags...
lerna success version finished
`);
});
});
});
});
1 change: 1 addition & 0 deletions libs/commands/changed/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ Unlike `lerna ls`, however, `lerna changed` **does not** support [filter options
`lerna changed` supports the following options of [`lerna version`](https://github.com/lerna/lerna/tree/main/libs/commands/version#options) (the others are irrelevant):

- [`--conventional-graduate`](https://github.com/lerna/lerna/tree/main/libs/commands/version#--conventional-graduate).
- [`--force-conventional-graduate`](https://github.com/lerna/lerna/tree/main/libs/commands/version#--force-conventional-graduate).
- [`--force-publish`](https://github.com/lerna/lerna/tree/main/libs/commands/version#--force-publish).
- [`--ignore-changes`](https://github.com/lerna/lerna/tree/main/libs/commands/version#--ignore-changes).
- [`--include-merged-tags`](https://github.com/lerna/lerna/tree/main/libs/commands/version#--include-merged-tags).
5 changes: 5 additions & 0 deletions libs/commands/changed/src/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ const command: CommandModule = {
describe: "Detect currently prereleased packages that would change to a non-prerelease version.",
// type must remain ambiguous because it is overloaded (boolean _or_ string _or_ array)
},
"force-conventional-graduate": {
describe:
"Always include all packages by specified by --conventional-graduate whether or not they are a prerelease or have changes since the previous version.",
type: "boolean",
},
"force-publish": {
describe: "Always include targeted packages when detecting changed packages, skipping default logic.",
// type must remain ambiguous because it is overloaded (boolean _or_ string _or_ array)
Expand Down
5 changes: 3 additions & 2 deletions libs/commands/changed/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ module.exports = function factory(argv: NodeJS.Process["argv"]) {

interface ChangedCommandOptions extends CommandConfigOptions {
conventionalCommits: boolean;
conventionalGraduate: boolean;
forcePublish: boolean;
conventionalGraduate: boolean | string;
forceConventionalGraduate: boolean;
forcePublish: boolean | string;
}

class ChangedCommand extends Command<ChangedCommandOptions> {
Expand Down
12 changes: 12 additions & 0 deletions libs/commands/version/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ Running `lerna version --conventional-commits` without the above flags will rele
- [`--changelog-entry-additional-markdown`](#--changelog-entry-additional-markdown)
- [`--conventional-commits`](#--conventional-commits)
- [`--conventional-graduate`](#--conventional-graduate)
- [`--force-conventional-graduate`](#--force-conventional-graduate)
- [`--conventional-prerelease`](#--conventional-prerelease)
- [`--conventional-bump-prerelease`](#--conventional-bump-prerelease)
- [`--create-release <type>`](#--create-release-type)
Expand Down Expand Up @@ -226,6 +227,17 @@ When run with this flag, `lerna version` will graduate the specified packages (c

> NOTE: when specifying packages, dependents of specified packages will be released, but will not be graduated.
### `--force-conventional-graduate`

```sh
lerna version --conventional-commits --conventional-graduate=package-2,package-4 --force-conventional-graduate

# force all prerelease packages to be graduated and updated if not a prerelease or having no change
lerna version --conventional-commits --conventional-graduate --force-conventional-graduate
```

When run with this flag, `lerna version` will graduate all packages specified by `--conventional-graduate`. Non-prerelease packages will not be ignored as it would be the case without the flag. In combination with single version mode this can be used to force all specified packages to be updated to a single version despite having no change or being a non-prerelease version. It works similar to `--force-publish` but is not ignored when `--conventional-commits` and `--conventional-graduate` are enabled. This flag is only applicable when having `--conventional-graduate` set, otherwise the option is ignored.

### `--conventional-prerelease`

```sh
Expand Down
5 changes: 5 additions & 0 deletions libs/commands/version/src/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ const command: CommandModule = {
describe: "Version currently prereleased packages to a non-prerelease version.",
// type must remain ambiguous because it is overloaded (boolean _or_ string _or_ array)
},
"force-conventional-graduate": {
describe:
"Forces all packages specified by --conventional-graduate to bump their version whether or not they are a prerelease or have changes since the previous version.",
type: "boolean",
},
"conventional-prerelease": {
describe: "Version changed packages as prereleases when using --conventional-commits.",
// type must remain ambiguous because it is overloaded (boolean _or_ string _or_ array)
Expand Down
1 change: 1 addition & 0 deletions libs/commands/version/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ interface VersionCommandConfigOptions extends CommandConfigOptions {
exact?: boolean;
conventionalPrerelease?: string;
conventionalGraduate?: string;
forceConventionalGraduate?: boolean;
private?: boolean;
forcePublish?: boolean | string | string[];
bump?: string;
Expand Down
36 changes: 36 additions & 0 deletions libs/core/src/lib/collect-updates/collect-project-updates.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,42 @@ describe("collectProjectUpdates", () => {
]);
});

it("always includes all nodes targeted by --conventional-graduate = pkg despite having no prerelease version when having -froce-convention-graduate set", () => {
changedPackages.add("package-dag-3");

const graph = buildGraph();
const nodes = Object.values(graph.nodes);
const execOpts = { cwd: "/test" };
setPrereleaseVersions(graph, ["package-standalone"]);

const updates = collectProjectUpdates(nodes, graph, execOpts, {
forceConventionalGraduate: true,
conventionalCommits: true,
conventionalGraduate: "package-dag-2b,package-dag-3",
});

expect(updates).toEqual([
expect.objectContaining({ name: "package-dag-2b" }),
expect.objectContaining({ name: "package-dag-3" }),
]);
});

it("always includes all nodes targeted by --conventional-graduate = * despite having no prerelease version when having -froce-convention-graduate set", () => {
changedPackages.add("package-dag-3");

const graph = buildGraph();
const nodes = Object.values(graph.nodes);
const execOpts = { cwd: "/test" };

const updates = collectProjectUpdates(nodes, graph, execOpts, {
forceConventionalGraduate: true,
conventionalCommits: true,
conventionalGraduate: "*",
});

expect(updates).toEqual(ALL_NODES);
});

it("uses revision range with --canary", () => {
changedPackages.add("package-dag-2a");

Expand Down
16 changes: 12 additions & 4 deletions libs/core/src/lib/collect-updates/collect-project-updates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export interface ProjectUpdateCollectorOptions {
since?: string;
conventionalCommits?: boolean;
conventionalGraduate?: string | boolean;
forceConventionalGraduate?: boolean;
excludeDependents?: boolean;
}

Expand All @@ -39,10 +40,16 @@ export function collectProjectUpdates(
execOpts: ExecOptions,
commandOptions: ProjectUpdateCollectorOptions
): ProjectGraphProjectNodeWithPackage[] {
const { forcePublish, conventionalCommits, conventionalGraduate, excludeDependents } = commandOptions;
const {
forcePublish,
conventionalCommits,
forceConventionalGraduate,
conventionalGraduate,
excludeDependents,
} = commandOptions;

// If --conventional-commits and --conventional-graduate are both set, ignore --force-publish
const useConventionalGraduate = conventionalCommits && conventionalGraduate;
// If --conventional-commits and --conventional-graduate are both set, ignore --force-publish but consider --force-conventional-graduate
const useConventionalGraduate = conventionalCommits && (conventionalGraduate || forceConventionalGraduate);
const forced = getPackagesForOption(useConventionalGraduate ? conventionalGraduate : forcePublish);

let committish = commandOptions.since ?? "";
Expand Down Expand Up @@ -107,7 +114,8 @@ export function collectProjectUpdates(
const isForced = (node: ProjectGraphProjectNodeWithPackage, name: string) =>
!!(
(forced.has("*") || forced.has(name)) &&
(useConventionalGraduate ? prereleaseIdFromVersion(getPackage(node).version) : true)
((useConventionalGraduate ? prereleaseIdFromVersion(getPackage(node).version) : true) ||
forceConventionalGraduate)
);

return collectProjects(filteredProjects, projectGraph, {
Expand Down
10 changes: 10 additions & 0 deletions packages/lerna/schemas/lerna-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,9 @@
"conventionalGraduate": {
"$ref": "#/$defs/commandOptions/shared/conventionalGraduate"
},
"forceConventionalGraduate": {
"$ref": "#/$defs/commandOptions/shared/forceConventionalGraduate"
},
"forcePublish": {
"$ref": "#/$defs/commandOptions/shared/forcePublish"
},
Expand Down Expand Up @@ -961,6 +964,9 @@
"conventionalGraduate": {
"$ref": "#/$defs/commandOptions/shared/conventionalGraduate"
},
"forceConventionalGraduate": {
"$ref": "#/$defs/commandOptions/shared/forceConventionalGraduate"
},
"conventionalPrerelease": {
"$ref": "#/$defs/commandOptions/version/conventionalPrerelease"
},
Expand Down Expand Up @@ -1752,6 +1758,10 @@
],
"description": "Detect currently prereleased packages that would change to a non-prerelease version. Relevant for `lerna changed` and `lerna version`."
},
"forceConventionalGraduate": {
"type": "boolean",
"description": "Forces all packages specified by --conventional-graduate to bump their version whether or not they are a prerelease or have changes since the previous version. Relevant for `lerna changed` and `lerna version`."
},
"forceLocal": {
"type": "boolean",
"description": "During `lerna bootstrap` and `lerna link`, when true, force local sibling links regardless of version range match."
Expand Down

0 comments on commit 914dd96

Please sign in to comment.