Repository: atlassian/changesets (ts)

Issue:
Ignore directory dependencies (the file: and link: protocols)
## Affected Packages

<!-- Because monorepos, it's super helpful if you tell us which packages are affected, so it's easy to find the change points. Adding a tag pf `pkg:package-name` would be the best 🙏 -->

## Problem

The CLI currently fails if there are local dependencies. Local or directory dependencies are those that use the `file:<relative path>` or `link:<relative path>` spec (the link protocol is supported by Yarn and pnpm).

<!-- Write the problem you are encountering here. If it is a bug, or process problem, please provide reproduction steps. If you have a repository we can look at that would be great. 😁 -->

## Proposed solution

If a dev dependency is using a `link:` or `file:` protocol, just ignore that dependency. It will not require any update because the package's location is not changed when the versions are bumped.

<!-- If you have an idea of how to solve it, otherwise that's fine as well. We may edit this desciption to add details later -->


Pull request description:
fix: ignore file/link deps in dev deps
close #322

Patch:
diff --git a/.changeset/slow-hounds-lie.md b/.changeset/slow-hounds-lie.md
new file mode 100644
index 0000000..3ac4e90
--- /dev/null
+++ b/.changeset/slow-hounds-lie.md
@@ -0,0 +1,6 @@
+---
+"@changesets/get-dependents-graph": patch
+"@changesets/assemble-release-plan": patch
+---
+
+Dev dependencies that are installed via the link or file protocol are ignored.
diff --git a/packages/get-dependents-graph/src/get-dependency-graph.ts b/packages/get-dependents-graph/src/get-dependency-graph.ts
index f1c2066..dd20ea3 100644
--- a/packages/get-dependents-graph/src/get-dependency-graph.ts
+++ b/packages/get-dependents-graph/src/get-dependency-graph.ts
@@ -19,7 +19,15 @@ const getAllDependencies = (config: PackageJSON) => {
     if (!deps) continue;
 
     for (const name of Object.keys(deps)) {
-      allDependencies.set(name, deps[name]);
+      const depVersion = deps[name];
+      if (
+        (depVersion.startsWith("link:") || depVersion.startsWith("file:")) &&
+        type === "devDependencies"
+      ) {
+        continue;
+      }
+
+      allDependencies.set(name, depVersion);
     }
   }
 


Test patch:
diff --git a/packages/assemble-release-plan/src/index.test.ts b/packages/assemble-release-plan/src/index.test.ts
index ad20c16..f20dc57 100644
--- a/packages/assemble-release-plan/src/index.test.ts
+++ b/packages/assemble-release-plan/src/index.test.ts
@@ -115,6 +115,42 @@ describe("assemble-release-plan", () => {
     expect(releases[1].name).toEqual("pkg-b");
     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({
+      id: "big-cats-delight",
+      releases: [{ name: "pkg-a", type: "major" }]
+    });
+
+    let { releases } = assembleReleasePlan(
+      setup.changesets,
+      setup.packages,
+      defaultConfig,
+      undefined
+    );
+
+    expect(releases.length).toEqual(1);
+    expect(releases[0].name).toEqual("pkg-a");
+    expect(releases[0].newVersion).toEqual("2.0.0");
+  });
+  it("should assemble release plan without dependent through the file protocol", () => {
+    setup.updateDevDependency("pkg-b", "pkg-a", "file:../pkg-a");
+    setup.addChangeset({
+      id: "big-cats-delight",
+      releases: [{ name: "pkg-a", type: "major" }]
+    });
+
+    let { releases } = assembleReleasePlan(
+      setup.changesets,
+      setup.packages,
+      defaultConfig,
+      undefined
+    );
+
+    expect(releases.length).toEqual(1);
+    expect(releases[0].name).toEqual("pkg-a");
+    expect(releases[0].newVersion).toEqual("2.0.0");
+  });
   it("should assemble release plan for linked packages", () => {
     setup.addChangeset({
       id: "just-some-umbrellas",
diff --git a/packages/get-dependents-graph/src/get-dependency-graph.test.ts b/packages/get-dependents-graph/src/get-dependency-graph.test.ts
new file mode 100644
index 0000000..4b8c5cb
--- /dev/null
+++ b/packages/get-dependents-graph/src/get-dependency-graph.test.ts
@@ -0,0 +1,63 @@
+import getDependencyGraph from "./get-dependency-graph";
+
+describe("getting the dependency graph", function() {
+  it("should skip dependencies specified through the link protocol", function() {
+    const { graph, valid } = getDependencyGraph({
+      root: {
+        dir: ".",
+        packageJson: { name: "root", version: "1.0.0" }
+      },
+      packages: [
+        {
+          dir: "foo",
+          packageJson: {
+            name: "foo",
+            version: "1.0.0",
+            devDependencies: {
+              bar: "link:../bar"
+            }
+          }
+        },
+        {
+          dir: "bar",
+          packageJson: {
+            name: "bar",
+            version: "1.0.0"
+          }
+        }
+      ],
+      tool: "pnpm"
+    });
+    expect(graph.get("foo")!.dependencies).toStrictEqual([]);
+    expect(valid).toBeTruthy();
+  });
+  it("should set valid to false if the link protocol is used in a non-dev dep", function() {
+    const { valid } = getDependencyGraph({
+      root: {
+        dir: ".",
+        packageJson: { name: "root", version: "1.0.0" }
+      },
+      packages: [
+        {
+          dir: "foo",
+          packageJson: {
+            name: "foo",
+            version: "1.0.0",
+            dependencies: {
+              bar: "link:../bar"
+            }
+          }
+        },
+        {
+          dir: "bar",
+          packageJson: {
+            name: "bar",
+            version: "1.0.0"
+          }
+        }
+      ],
+      tool: "pnpm"
+    });
+    expect(valid).toBeFalsy();
+  });
+});