Repository: atlassian/changesets (ts)

Issue:
release plan is incorrectly bumping dependent versions when workspaces protocol is used
## Affected Packages

assemble-release-plan

## Problem

When I create a `none` type changeset for a package for chore commits, dependent packages are getting patch bumped even though the actual package is not being bumped. 

I'm noticing this specifically when using the workspace protocol ranges with pnpm.

## Proposed solution

Turns out it is just the upstream semver package not being able to evaluate it correctly.

```
> semver.satisfies('1.0.0' ,'workspace:^1.0.0')
false
> semver.satisfies('1.0.0' ,'^1.0.0')
true
```


Pull request:
fix: remove workspace: prefix from dependent version ranges so they can be semver evaluated
Fixes #440

Patch:
diff --git a/.changeset/chatty-eagles-look.md b/.changeset/chatty-eagles-look.md
new file mode 100644
index 0000000..365353f
--- /dev/null
+++ b/.changeset/chatty-eagles-look.md
@@ -0,0 +1,6 @@
+---
+"@changesets/apply-release-plan": none
+"@changesets/assemble-release-plan": patch
+---
+
+Fixed an issue with including dependents in the release plan for dependencies using `workspace:` protocol that had a `none` changeset for them.
diff --git a/packages/assemble-release-plan/src/determine-dependents.ts b/packages/assemble-release-plan/src/determine-dependents.ts
index ca4d4b7..14417cd 100644
--- a/packages/assemble-release-plan/src/determine-dependents.ts
+++ b/packages/assemble-release-plan/src/determine-dependents.ts
@@ -89,7 +89,8 @@ export default function getDependents({
                   releases.get(dependent)!.type === "none") &&
                 !semver.satisfies(
                   incrementVersion(nextRelease, preInfo),
-                  versionRange
+                  // to deal with a * versionRange that comes from workspace:* dependencies as the wildcard will match anything
+                  versionRange === "*" ? nextRelease.oldVersion : versionRange
                 )
               ) {
                 switch (depType) {
@@ -183,7 +184,7 @@ function getDependencyVersionRanges(
     if (deps[dependencyName]) {
       dependencyVersionRanges.push({
         depType: type,
-        versionRange: deps[dependencyName]
+        versionRange: deps[dependencyName].replace("workspace:", "")
       });
     }
   }


Test patch:
diff --git a/packages/apply-release-plan/src/index.test.ts b/packages/apply-release-plan/src/index.test.ts
index f382dc2..560b3cc 100644
--- a/packages/apply-release-plan/src/index.test.ts
+++ b/packages/apply-release-plan/src/index.test.ts
@@ -10,6 +10,7 @@ import fs from "fs-extra";
 import path from "path";
 import outdent from "outdent";
 import spawn from "spawndamnit";
+import { defaultConfig } from "@changesets/config";
 
 import applyReleasePlan from "./";
 import { getPackages } from "@manypkg/get-packages";
@@ -496,6 +497,88 @@ describe("apply release plan", () => {
         }
       });
     });
+    it("should not update dependent versions when a package has a changeset type of none", async () => {
+      let { changedFiles } = await testSetup(
+        "simple-project-caret-dep",
+        {
+          changesets: [
+            {
+              id: "quick-lions-devour",
+              summary: "Hey, let's have fun with testing!",
+              releases: [{ name: "pkg-b", type: "none" }]
+            }
+          ],
+          releases: [
+            {
+              name: "pkg-b",
+              type: "none",
+              oldVersion: "1.0.0",
+              newVersion: "1.0.0",
+              changesets: ["quick-lions-devour"]
+            }
+          ],
+          preState: undefined
+        },
+        { ...defaultConfig, changelog: false }
+      );
+      let pkgPathA = changedFiles.find(a =>
+        a.endsWith(`pkg-a${path.sep}package.json`)
+      );
+      let pkgPathB = changedFiles.find(b =>
+        b.endsWith(`pkg-b${path.sep}package.json`)
+      );
+
+      expect(pkgPathA).toBeUndefined();
+      if (!pkgPathB) throw new Error(`could not find an updated package json`);
+
+      let pkgJSONB = await fs.readJSON(pkgPathB);
+
+      expect(pkgJSONB).toMatchObject({
+        name: "pkg-b",
+        version: "1.0.0"
+      });
+    });
+    it("should not update workspace dependent versions when a package has a changeset type of none", async () => {
+      let { changedFiles } = await testSetup(
+        "simple-workspace-range-dep",
+        {
+          changesets: [
+            {
+              id: "quick-lions-devour",
+              summary: "Hey, let's have fun with testing!",
+              releases: [{ name: "pkg-b", type: "none" }]
+            }
+          ],
+          releases: [
+            {
+              name: "pkg-b",
+              type: "none",
+              oldVersion: "1.0.0",
+              newVersion: "1.0.0",
+              changesets: ["quick-lions-devour"]
+            }
+          ],
+          preState: undefined
+        },
+        { ...defaultConfig, changelog: false }
+      );
+      let pkgPathA = changedFiles.find(a =>
+        a.endsWith(`pkg-a${path.sep}package.json`)
+      );
+      let pkgPathB = changedFiles.find(b =>
+        b.endsWith(`pkg-b${path.sep}package.json`)
+      );
+
+      expect(pkgPathA).toBeUndefined();
+      if (!pkgPathB) throw new Error(`could not find an updated package json`);
+
+      let pkgJSONB = await fs.readJSON(pkgPathB);
+
+      expect(pkgJSONB).toMatchObject({
+        name: "pkg-b",
+        version: "1.0.0"
+      });
+    });
 
     describe("internal dependency bumping", () => {
       describe("updateInternalDependencies set to patch", () => {
diff --git a/packages/assemble-release-plan/src/index.test.ts b/packages/assemble-release-plan/src/index.test.ts
index 3a6e616..adc68c5 100644
--- a/packages/assemble-release-plan/src/index.test.ts
+++ b/packages/assemble-release-plan/src/index.test.ts
@@ -167,6 +167,26 @@ describe("assemble-release-plan", () => {
     expect(releases[2].oldVersion).toEqual("1.0.0");
     expect(releases[2].newVersion).toEqual("1.0.1");
   });
+  it("should assemble release plan without dependencies when the dependent has a changeset type of none", () => {
+    setup.updateDependency("pkg-c", "pkg-b", "^1.0.0");
+    setup.addChangeset({
+      id: "big-cats-delight",
+      releases: [{ name: "pkg-b", type: "none" }]
+    });
+
+    let { releases } = assembleReleasePlan(
+      setup.changesets,
+      setup.packages,
+      defaultConfig,
+      undefined
+    );
+
+    expect(releases.length).toEqual(2);
+    expect(releases[0].name).toEqual("pkg-a");
+    expect(releases[1].name).toEqual("pkg-b");
+    expect(releases[1].oldVersion).toEqual("1.0.0");
+    expect(releases[1].newVersion).toEqual("1.0.0");
+  });
   it("should assemble release plan without dependent through the link protocol", () => {
     setup.updateDevDependency("pkg-b", "pkg-a", "link:../pkg-a");
     setup.addChangeset({
@@ -597,6 +617,65 @@ Mixed changesets that contain both ignored and not ignored packages are not allo
       expect(releases[0].type).toEqual("minor");
     });
   });
+
+  describe("workspace protocol", () => {
+    it("should assemble release plan without workspace dependencies when the dependent has a changeset type of none", () => {
+      setup.updateDependency("pkg-c", "pkg-b", "workspace:^1.0.0");
+      setup.addChangeset({
+        id: "big-cats-delight",
+        releases: [{ name: "pkg-b", type: "none" }]
+      });
+
+      let { releases } = assembleReleasePlan(
+        setup.changesets,
+        setup.packages,
+        defaultConfig,
+        undefined
+      );
+
+      expect(releases.length).toEqual(2);
+      expect(releases[0].name).toEqual("pkg-a");
+      expect(releases[1].name).toEqual("pkg-b");
+      expect(releases[1].oldVersion).toEqual("1.0.0");
+      expect(releases[1].newVersion).toEqual("1.0.0");
+    });
+    it("should assemble release plan without workspace:* dependencies when the dependent has a changeset type of none", () => {
+      setup.updateDependency("pkg-c", "pkg-b", "workspace:*");
+      setup.addChangeset({
+        id: "big-cats-delight",
+        releases: [{ name: "pkg-b", type: "none" }]
+      });
+
+      let { releases } = assembleReleasePlan(
+        setup.changesets,
+        setup.packages,
+        defaultConfig,
+        undefined
+      );
+
+      expect(releases.length).toEqual(2);
+      expect(releases[0].name).toEqual("pkg-a");
+      expect(releases[1].name).toEqual("pkg-b");
+      expect(releases[1].oldVersion).toEqual("1.0.0");
+      expect(releases[1].newVersion).toEqual("1.0.0");
+    });
+    it("should assemble release plan with workspace:* dependencies", () => {
+      setup.updateDependency("pkg-b", "pkg-a", "workspace:*");
+
+      let { releases } = assembleReleasePlan(
+        setup.changesets,
+        setup.packages,
+        defaultConfig,
+        undefined
+      );
+
+      expect(releases.length).toEqual(2);
+      expect(releases[0].name).toEqual("pkg-a");
+      expect(releases[1].name).toEqual("pkg-b");
+      expect(releases[1].oldVersion).toEqual("1.0.0");
+      expect(releases[1].newVersion).toEqual("1.0.1");
+    });
+  });
 });
 
 describe("version update thoroughness", () => {