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
91 changes: 68 additions & 23 deletions get-changed-packages.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import nodePath from "path";
import assembleReleasePlan from "@changesets/assemble-release-plan";
import { parse as parseConfig } from "@changesets/config";
import parseChangeset from "@changesets/parse";
import { assembleReleasePlan } from "@changesets/assemble-release-plan";
import { validateConfig } from "@changesets/config";
import { parseChangesetFile } from "@changesets/parse";
import type {
NewChangeset,
Package,
Packages,
PreState,
WrittenConfig,
PackageJSON as ChangesetPackageJSON,
} from "@changesets/types";
import type { Packages, Tool } from "@manypkg/get-packages";
import jsYaml from "js-yaml";
import micromatch from "micromatch";
import type { ProbotOctokit } from "probot";
Expand All @@ -23,6 +24,14 @@ interface PnpmWorkspace {
packages: ReadonlyArray<string>;
}

type ToolType = Packages["tool"]["type"];

/**
* `@changesets/config` reports validation issues instead of throwing,
* so we wrap them to be able to surface them in the PR comment.
*/
export class ConfigValidationError extends Error {}

// TODO: it might be possible to remove this if improvements to `Array.isArray` ever land
// related thread: github.com/microsoft/TypeScript/issues/36554
function isArray<T>(
Expand Down Expand Up @@ -127,15 +136,15 @@ export const getChangedPackages = async ({

changesetPromises.push(
fetchTextFile(item.path).then((text) => ({
...parseChangeset(text),
...parseChangesetFile(text),
id,
})),
);
}
}
let tool:
| {
tool: Tool;
type: ToolType;
globs: ReadonlyArray<string>;
}
| undefined;
Expand All @@ -146,7 +155,7 @@ export const getChangedPackages = async ({

if (pnpmWorkspace.packages) {
tool = {
tool: "pnpm",
type: "pnpm",
globs: pnpmWorkspace.packages,
};
}
Expand All @@ -156,31 +165,34 @@ export const getChangedPackages = async ({
if (rootPackageJsonContent.workspaces) {
if (isArray(rootPackageJsonContent.workspaces)) {
tool = {
tool: "yarn",
type: "yarn",
globs: rootPackageJsonContent.workspaces,
};
} else {
tool = {
tool: "yarn",
type: "yarn",
globs: rootPackageJsonContent.workspaces.packages,
};
}
} else if (rootPackageJsonContent.bolt && rootPackageJsonContent.bolt.workspaces) {
tool = {
tool: "bolt",
type: "bolt",
globs: rootPackageJsonContent.bolt.workspaces,
};
}
}

const rootPackageJsonContent = await rootPackageJsonContentsPromise;

const rootPackage: Package = {
dir: "/",
packageJson: rootPackageJsonContent,
};

const packages: Packages = {
root: {
dir: "/",
packageJson: rootPackageJsonContent,
},
tool: tool ? tool.tool : "root",
rootDir: "/",
rootPackage,
tool: { type: tool ? tool.type : "root" },
packages: [],
};

Expand All @@ -195,26 +207,59 @@ export const getChangedPackages = async ({

packages.packages = await Promise.all(matches.map((dir) => getPackage(dir)));
} else {
packages.packages.push(packages.root);
packages.packages.push(rootPackage);
}
if (hasErrored) {
throw new Error("an error occurred when fetching files");
}

const rawConfig = await rawConfigPromise;

const configResult = validateConfig(
{
...rawConfig,
// `@changesets/config@4` defaults `privatePackages.version` to `false`,
// while previous versions defaulted it to `true`.
// Repositories that don't opt in explicitly would silently stop seeing their private packages reported,
// so the previous default is restored here.
privatePackages:
typeof rawConfig.privatePackages === "object"
? { version: true, ...rawConfig.privatePackages }
: (rawConfig.privatePackages ?? { version: true }),
},
packages,
);

for (const warning of configResult.warnings) {
console.warn(warning);
}

if (configResult.errors) {
throw new ConfigValidationError(
"Some errors occurred when validating the changesets config:\n" +
configResult.errors.join("\n"),
);
}

const releasePlan = assembleReleasePlan(
await Promise.all(changesetPromises),
packages,
parseConfig(await rawConfigPromise, packages),
configResult.config,
await preStatePromise,
);

return {
changedPackages: (packages.tool === "root"
const containsChangedFile = (pkg: Package) =>
changedFiles.some((changedFile) => changedFile.startsWith(`${pkg.dir}/`));

// 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}/`)),
)
).map((pkg) => pkg.packageJson.name),
: packages.packages.filter(containsChangedFile);

return {
changedPackages: changedPackages.map((pkg) => pkg.packageJson.name),
releasePlan,
};
};
5 changes: 2 additions & 3 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { ValidationError } from "@changesets/errors";
import type { ReleasePlan, ComprehensiveRelease, VersionType } from "@changesets/types";
import type { EmitterWebhookEvent } from "@octokit/webhooks";
import { captureException } from "@sentry/node";
import { humanId } from "human-id";
import markdownTable from "markdown-table";
import type { Probot, Context } from "probot";
import { getChangedPackages } from "./get-changed-packages.ts";
import { ConfigValidationError, getChangedPackages } from "./get-changed-packages.ts";
import { isChangeset } from "./is-changeset.ts";

const getReleasePlanMessage = (releasePlan: ReleasePlan | null) => {
Expand Down Expand Up @@ -163,7 +162,7 @@ export default (app: Probot) => {
})
).data.token,
}).catch((err) => {
if (err instanceof ValidationError) {
if (err instanceof ConfigValidationError) {
errFromFetchingChangedFiles = `<details><summary>💥 An error occurred when fetching the changed packages and changesets in this PR</summary>\n\n\`\`\`\n${err.message}\n\`\`\`\n\n</details>\n`;
} else {
console.error(err);
Expand Down
10 changes: 4 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,10 @@
"test": "vitest"
},
"dependencies": {
"@changesets/assemble-release-plan": "^6.0.2",
"@changesets/config": "^3.0.1",
"@changesets/errors": "^0.2.0",
"@changesets/parse": "^0.4.0",
"@changesets/types": "^6.0.0",
"@manypkg/get-packages": "^1.1.3",
"@changesets/assemble-release-plan": "^7.0.0",
"@changesets/config": "^4.0.0",
"@changesets/parse": "^1.0.0",
"@changesets/types": "^7.0.0",
"@octokit/webhooks": "^9.8.4",
"@sentry/node": "^6.0.0",
"@types/js-yaml": "^3.12.2",
Expand Down
Loading