Repository: atlassian/changesets
Pull request #382 (2020-06-01 20:36:23)

Fix a bug where packages that shouldn't get released get patch releases when the pre mode is exit
Fix a bug where packages that shouldn't get released get patch releases when the pre mode is exit

changeset-bot[bot]: ###  💥  No Changeset

Latest commit: de405a1a91b8b02caf7023af7a396d21291563df

Merging this PR will not cause any packages to be released. If these changes should not cause updates to packages in this repo, this is fine 🙂

**If these changes should be published to npm, you need to add a changeset.**

<details><summary>This PR includes no changesets</summary>

  When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

</details>

[Click here to learn what changesets are, and how to add one](https://github.com/changesets/changesets/blob/master/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add a changeset to this PR](https://github.com/Feiyang1/changesets/new/fei-fix?filename=.changeset/large-rings-invite.md&value=---%0A%22%40changesets%2Fassemble-release-plan%22%3A%20patch%0A---%0A%0AFix%20a%20bug%20where%20packages%20that%20shouldn't%20get%20released%20get%20patch%20releases%20when%20the%20pre%20mode%20is%20exit%0A)



Patch:
diff --git a/.changeset/large-rings-invite.md b/.changeset/large-rings-invite.md
new file mode 100644
index 0000000..f2b96da
--- /dev/null
+++ b/.changeset/large-rings-invite.md
@@ -0,0 +1,5 @@
+---
+"@changesets/assemble-release-plan": patch
+---
+
+Fix a bug where packages that shouldn't get released get patch releases when the pre mode is exit
diff --git a/__fixtures__/simple-project-caret-dep/.changeset/README.md b/__fixtures__/simple-project-caret-dep/.changeset/README.md
new file mode 100644
index 0000000..fd188f5
--- /dev/null
+++ b/__fixtures__/simple-project-caret-dep/.changeset/README.md
@@ -0,0 +1,3 @@
+# We just want a file in here so git collects it
+
+For this we have deliberately not included a config file, as we want to test the defaults
\ No newline at end of file
diff --git a/__fixtures__/simple-project-caret-dep/.changeset/config.json b/__fixtures__/simple-project-caret-dep/.changeset/config.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/__fixtures__/simple-project-caret-dep/.changeset/config.json
@@ -0,0 +1,1 @@
+{}
diff --git a/__fixtures__/simple-project-caret-dep/package.json b/__fixtures__/simple-project-caret-dep/package.json
new file mode 100644
index 0000000..2e742d8
--- /dev/null
+++ b/__fixtures__/simple-project-caret-dep/package.json
@@ -0,0 +1,11 @@
+{
+  "private": true,
+  "name": "simple-project",
+  "description": "three projects, each depending on one other",
+  "version": "1.0.0",
+  "bolt": {
+    "workspaces": [
+      "packages/*"
+    ]
+  }
+}
diff --git a/__fixtures__/simple-project-caret-dep/packages/pkg-a/package.json b/__fixtures__/simple-project-caret-dep/packages/pkg-a/package.json
new file mode 100644
index 0000000..7ba6cd0
--- /dev/null
+++ b/__fixtures__/simple-project-caret-dep/packages/pkg-a/package.json
@@ -0,0 +1,7 @@
+{
+  "name": "pkg-a",
+  "version": "1.0.0",
+  "dependencies": {
+    "pkg-b": "^1.0.0"
+  }
+}
diff --git a/__fixtures__/simple-project-caret-dep/packages/pkg-b/package.json b/__fixtures__/simple-project-caret-dep/packages/pkg-b/package.json
new file mode 100644
index 0000000..be4760e
--- /dev/null
+++ b/__fixtures__/simple-project-caret-dep/packages/pkg-b/package.json
@@ -0,0 +1,4 @@
+{
+  "name": "pkg-b",
+  "version": "1.0.0"
+}
diff --git a/packages/assemble-release-plan/src/index.ts b/packages/assemble-release-plan/src/index.ts
index f8735c4..344f80c 100644
--- a/packages/assemble-release-plan/src/index.ts
+++ b/packages/assemble-release-plan/src/index.ts
@@ -88,27 +88,29 @@ function assembleReleasePlan(
       changesets = changesets.filter(
         changeset => !usedChangesetIds.has(changeset.id)
       );
-      for (let pkg of packages.packages) {
-        preVersions.set(
-          pkg.packageJson.name,
-          getPreVersion(pkg.packageJson.version)
+    }
+
+    // Populate preVersion
+    // preVersion is the map between package name and its next pre version number.
+    for (let pkg of packages.packages) {
+      preVersions.set(
+        pkg.packageJson.name,
+        getPreVersion(pkg.packageJson.version)
+      );
+    }
+    for (let linkedGroup of config.linked) {
+      let highestPreVersion = 0;
+      for (let linkedPackage of linkedGroup) {
+        highestPreVersion = Math.max(
+          getPreVersion(packagesByName.get(linkedPackage)!.packageJson.version),
+          highestPreVersion
         );
       }
-      for (let linkedGroup of config.linked) {
-        let highestPreVersion = 0;
-        for (let linkedPackage of linkedGroup) {
-          highestPreVersion = Math.max(
-            getPreVersion(
-              packagesByName.get(linkedPackage)!.packageJson.version
-            ),
-            highestPreVersion
-          );
-        }
-        for (let linkedPackage of linkedGroup) {
-          preVersions.set(linkedPackage, highestPreVersion);
-        }
+      for (let linkedPackage of linkedGroup) {
+        preVersions.set(linkedPackage, highestPreVersion);
       }
     }
+
     for (let pkg of packages.packages) {
       packagesByName.set(pkg.packageJson.name, {
         ...pkg,
@@ -128,7 +130,10 @@ function assembleReleasePlan(
   if (updatedPreState !== undefined) {
     if (updatedPreState.mode === "exit") {
       for (let pkg of packages.packages) {
-        if (preVersions.get(pkg.packageJson.name) !== -1) {
+        // If a package had a prerelease, but didn't trigger a version bump in the regular release,
+        // we want to give it a patch release.
+        // Detailed explaination at https://github.com/atlassian/changesets/pull/382#discussion_r434434182
+        if (preVersions.get(pkg.packageJson.name) !== 0) {
           if (!releases.has(pkg.packageJson.name)) {
             releases.set(pkg.packageJson.name, {
               type: "patch",


Test patch:
diff --git a/packages/assemble-release-plan/src/index.test.ts b/packages/assemble-release-plan/src/index.test.ts
index a8055b8..6321156 100644
--- a/packages/assemble-release-plan/src/index.test.ts
+++ b/packages/assemble-release-plan/src/index.test.ts
@@ -348,6 +348,27 @@ describe("assemble-release-plan", () => {
     expect(releases[1].name).toEqual("pkg-b");
     expect(releases[1].newVersion).toEqual("2.0.0");
   });
+  describe("pre mode exit", () => {
+    it("should not generate a release for package that has no changesets and is not a dependent of any packages being released", () => {
+      const { releases } = assembleReleasePlan(
+        setup.changesets,
+        setup.packages,
+        {
+          ...defaultConfig
+        },
+        {
+          changesets: [],
+          tag: "next",
+          initialVersions: {},
+          mode: "exit"
+        }
+      );
+
+      expect(releases.length).toEqual(1);
+      expect(releases[0].name).toEqual("pkg-a");
+      expect(releases[0].newVersion).toEqual("1.0.1");
+    });
+  });
 });
 
 describe("version update thoroughness", () => {
diff --git a/packages/cli/src/commands/version/version.test.ts b/packages/cli/src/commands/version/version.test.ts
index 896eac2..f23096e 100644
--- a/packages/cli/src/commands/version/version.test.ts
+++ b/packages/cli/src/commands/version/version.test.ts
@@ -200,6 +200,54 @@ describe("running version in a simple project", () => {
   });
 });
 
+describe("running version in a simple project with caret dependencies", () => {
+  it("should bump patch version for packages that had prereleases, but dependencies are still in range", async () => {
+    let cwd = f.copy("simple-project-caret-dep");
+    await pre(cwd, { command: "enter", tag: "next" });
+    await writeChangeset(
+      {
+        releases: [{ name: "pkg-b", type: "patch" }],
+        summary: "a very useful summary for the first change"
+      },
+      cwd
+    );
+    await version(cwd, defaultOptions, modifiedDefaultConfig);
+
+    let packages = (await getPackages(cwd))!;
+    expect(packages.packages.map(x => x.packageJson)).toEqual([
+      {
+        dependencies: {
+          "pkg-b": "^1.0.1-next.0"
+        },
+        name: "pkg-a",
+        version: "1.0.1-next.0"
+      },
+      {
+        name: "pkg-b",
+        version: "1.0.1-next.0"
+      }
+    ]);
+
+    await pre(cwd, { command: "exit" });
+    await version(cwd, defaultOptions, modifiedDefaultConfig);
+
+    packages = (await getPackages(cwd))!;
+    expect(packages.packages.map(x => x.packageJson)).toEqual([
+      {
+        dependencies: {
+          "pkg-b": "^1.0.1"
+        },
+        name: "pkg-a",
+        version: "1.0.1"
+      },
+      {
+        name: "pkg-b",
+        version: "1.0.1"
+      }
+    ]);
+  });
+});
+
 describe("running version in a simple project with workspace range", () => {
   temporarilySilenceLogs();
   let cwd: string;