Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions get-changed-packages.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// oxlint-disable import/max-dependencies -- This module deliberately coordinates several Changesets packages.
import nodePath from "path";
import { assembleReleasePlan } from "@changesets/assemble-release-plan";
import { validateConfig } from "@changesets/config";
import { parseChangesetFile } from "@changesets/parse";
import { shouldSkipPackage } from "@changesets/should-skip-package";
import type {
NewChangeset,
Package,
Expand Down Expand Up @@ -306,12 +308,17 @@ export const getChangedPackages = async ({

// A root-only project has a single package covering the whole repository,
// so there is no directory to narrow the changed files down to.
const changedPackages =
packages.tool.type === "root"
? packages.packages
: packages.packages.filter((pkg) =>
changedFiles.some((changedFile) => changedFile.startsWith(`${pkg.dir}/`)),
);
const changedPackages = packages.packages.filter(
(pkg) =>
(packages.tool.type === "root" ||
changedFiles.some((changedFile) => changedFile.startsWith(`${pkg.dir}/`))) &&
// Ignored and private (unless opted in) packages cannot be versioned, so
// they must not be suggested in the "add a changeset" link.
!shouldSkipPackage(pkg, {
ignore: configResult.config.ignore,
allowPrivatePackages: configResult.config.privatePackages.version,
}),
);

return {
changedPackages: changedPackages.map((pkg) => pkg.packageJson.name),
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"@changesets/assemble-release-plan": "^7.0.0",
"@changesets/config": "^4.0.0",
"@changesets/parse": "^1.0.0",
"@changesets/should-skip-package": "^1.0.0",
"@changesets/types": "^7.0.0",
"@octokit/webhooks": "^9.8.4",
"@sentry/node": "^6.0.0",
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

148 changes: 148 additions & 0 deletions test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@ const normalizeCommentBody = (body: string) =>
"filename=.changeset/<CHANGESET_FILE>.md",
);

function getCommentBody(requests: Array<RecordedRequest>) {
const commentRequests = requests.filter((request) => request.path.includes("/comments"));
assert.equal(commentRequests.length, 1);
const body = commentRequests[0].body;
assert.ok(body && typeof body === "object" && "body" in body && typeof body.body === "string");
return body.body;
}

type ChangedFile = [
{
status: "added";
Expand Down Expand Up @@ -412,6 +420,7 @@ describe.concurrent("changeset-bot", () => {
".changeset/config.json": JSON.stringify({}),
"package.json": JSON.stringify({
name: "root-package",
version: "1.0.0",
}),
"src/index.ts": [{ status: "added" }, "export {};"],
},
Expand Down Expand Up @@ -537,6 +546,7 @@ thing
}),
"packages/a/package.json": JSON.stringify({
name: "pkg-a",
version: "1.0.0",
}),
"packages/a/index.ts": [{ status: "added" }, "export const a = true;"],
"packages/b/package.json": JSON.stringify({
Expand Down Expand Up @@ -599,6 +609,7 @@ thing
}),
"packages/ab/package.json": JSON.stringify({
name: "pkg-ab",
version: "1.0.0",
}),
"packages/ab/index.ts": [{ status: "added" }, "export const ab = true;"],
},
Expand Down Expand Up @@ -641,6 +652,141 @@ thing
`);
});

it("does not include private packages in the add-changeset link", async ({ expect, task }) => {
const probot = setupProbot(task.id);
const { requests } = usePrState(server, {
files: {
".changeset/config.json": JSON.stringify({}),
"package.json": JSON.stringify({
name: "test",
workspaces: ["packages/*"],
}),
"packages/a/package.json": JSON.stringify({
name: "pkg-a",
version: "1.0.0",
}),
"packages/a/index.ts": [{ status: "added" }, "export const a = true;"],
"packages/private/package.json": JSON.stringify({
name: "pkg-private",
version: "1.0.0",
private: true,
}),
"packages/private/index.ts": [{ status: "added" }, "export const p = true;"],
},
comments: [],
});

await probot.receive({
name: "pull_request",
payload: pullRequestOpen,
} as never);

const commentBody = getCommentBody(requests);
expect(commentBody).toContain("%22pkg-a%22%3A%20patch");
expect(commentBody).not.toContain("pkg-private");
});

it("includes private packages in the add-changeset link when opted in", async ({
expect,
task,
}) => {
const probot = setupProbot(task.id);
const { requests } = usePrState(server, {
files: {
".changeset/config.json": JSON.stringify({
privatePackages: { version: true },
}),
"package.json": JSON.stringify({
name: "test",
workspaces: ["packages/*"],
}),
"packages/private/package.json": JSON.stringify({
name: "pkg-private",
version: "1.0.0",
private: true,
}),
"packages/private/index.ts": [{ status: "added" }, "export const p = true;"],
},
comments: [],
});

await probot.receive({
name: "pull_request",
payload: pullRequestOpen,
} as never);

const commentBody = getCommentBody(requests);
expect(commentBody).toContain("%22pkg-private%22%3A%20patch");
});

it("does not include ignored packages in the add-changeset link", async ({ expect, task }) => {
const probot = setupProbot(task.id);
const { requests } = usePrState(server, {
files: {
".changeset/config.json": JSON.stringify({ ignore: ["pkg-ignored"] }),
"package.json": JSON.stringify({
name: "test",
workspaces: ["packages/*"],
}),
"packages/a/package.json": JSON.stringify({
name: "pkg-a",
version: "1.0.0",
}),
"packages/a/index.ts": [{ status: "added" }, "export const a = true;"],
"packages/ignored/package.json": JSON.stringify({
name: "pkg-ignored",
version: "1.0.0",
}),
"packages/ignored/index.ts": [{ status: "added" }, "export const i = true;"],
},
comments: [],
});

await probot.receive({
name: "pull_request",
payload: pullRequestOpen,
} as never);

const commentBody = getCommentBody(requests);
expect(commentBody).toContain("%22pkg-a%22%3A%20patch");
expect(commentBody).not.toContain("pkg-ignored");
});

it("does not include packages without a version in the add-changeset link", async ({
expect,
task,
}) => {
const probot = setupProbot(task.id);
const { requests } = usePrState(server, {
files: {
".changeset/config.json": JSON.stringify({}),
"package.json": JSON.stringify({
name: "test",
workspaces: ["packages/*"],
}),
"packages/a/package.json": JSON.stringify({
name: "pkg-a",
version: "1.0.0",
}),
"packages/a/index.ts": [{ status: "added" }, "export const a = true;"],
"packages/unversioned/package.json": JSON.stringify({
name: "pkg-unversioned",
}),
"packages/unversioned/index.ts": [{ status: "added" }, "export const u = true;"],
},
comments: [],
});

await probot.receive({
name: "pull_request",
payload: pullRequestOpen,
} as never);

const commentBody = getCommentBody(requests);
expect(commentBody).toContain("%22pkg-a%22%3A%20patch");
expect(commentBody).not.toContain("pkg-unversioned");
});

it("detects pnpm workspaces when building the add-changeset link", async ({ expect, task }) => {
const probot = setupProbot(task.id);
const { requests } = usePrState(server, {
Expand All @@ -652,6 +798,7 @@ thing
"pnpm-workspace.yaml": "packages:\n - packages/*\n",
"packages/a/package.json": JSON.stringify({
name: "pkg-a",
version: "1.0.0",
}),
"packages/a/file.ts": [{ status: "added" }, "export const a = true;"],
},
Expand Down Expand Up @@ -704,6 +851,7 @@ thing
".changeset/config.json": JSON.stringify({}),
"package.json": JSON.stringify({
name: "root-package",
version: "1.0.0",
}),
"pnpm-workspace.yaml": "onlyBuiltDependencies:\n - esbuild\n",
"src/index.ts": [{ status: "added" }, "export {};"],
Expand Down