Allow custom publish scripts to complete without a Changesets output file (#697)

This commit is contained in:
Mateusz Burzyński
2026-07-22 06:31:15 +00:00
committed by GitHub
parent c6cc0d84cb
commit 84d78c68f9
3 changed files with 83 additions and 6 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"@changesets/action": patch
---
Allow custom publish scripts to complete without a Changesets output file, warning that GitHub releases and git tags cannot be created when that file is missing.
+60 -2
View File
@@ -1,10 +1,11 @@
import path from "node:path";
import * as core from "@actions/core";
import type { Changeset } from "@changesets/types";
import { writeChangeset } from "@changesets/write";
import { createFixture } from "fs-fixture";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { GitHub } from "./github.ts";
import { runVersion } from "./run.ts";
import { runPublish, runVersion } from "./run.ts";
vi.mock("@actions/github", () => ({
context: {
@@ -20,6 +21,10 @@ vi.mock("@actions/github", () => ({
graphql: mockedGraphql,
}),
}));
vi.mock("@actions/core", async (importOriginal) => ({
...(await importOriginal<typeof import("@actions/core")>()),
warning: vi.fn(),
}));
vi.mock("@changesets/ghcommit");
let mockedGithubMethods = {
@@ -102,6 +107,59 @@ beforeEach(() => {
vi.clearAllMocks();
});
afterEach(() => {
vi.unstubAllEnvs();
});
describe("publish", () => {
it("warns when a custom publish script does not create the output file", async () => {
await using fixture = await createSimpleProjectFixture();
const cwd = fixture.path;
vi.stubEnv("RUNNER_TEMP", cwd);
const result = await runPublish({
script: 'node -e "void 0"',
github: createGithub(cwd),
createGithubReleases: true,
pushGitTags: true,
cwd,
});
expect(result).toEqual({ published: false, exitCode: 0 });
expect(core.warning).toHaveBeenCalledWith(
expect.stringContaining(
"GitHub releases and git tags cannot be created without this output",
),
);
});
it("throws when the built-in publish command does not create the output file", async () => {
await using fixture = await createFixture({
"node_modules/@changesets/cli/package.json": JSON.stringify({
name: "@changesets/cli",
type: "module",
}),
"node_modules/@changesets/cli/bin.js": "",
"package.json": JSON.stringify({
name: "simple-project",
version: "1.0.0",
}),
"package-lock.json": "",
});
const cwd = fixture.path;
vi.stubEnv("RUNNER_TEMP", cwd);
await expect(
runPublish({
github: createGithub(cwd),
createGithubReleases: true,
pushGitTags: true,
cwd,
}),
).rejects.toThrow("Failed to read changesets output at");
});
});
describe("version", () => {
it("creates simple PR", async () => {
await using fixture = await createSimpleProjectFixture();
+18 -4
View File
@@ -79,6 +79,8 @@ type ChangesetsOutputEvent = {
packageName: string;
};
class ChangesetsOutputReadError extends Error {}
type PublishResult =
| {
published: true;
@@ -113,9 +115,10 @@ async function readChangesetsOutput(outputPath: string) {
try {
rawOutput = await fs.readFile(outputPath, "utf8");
} catch (err) {
throw new Error(`Failed to read changesets output at ${outputPath}`, {
cause: err,
});
throw new ChangesetsOutputReadError(
`Failed to read changesets output at ${outputPath}`,
{ cause: err },
);
}
const events: ChangesetsOutputEvent[] = [];
@@ -195,7 +198,18 @@ export async function runPublish({
let { packages, tool } = await getPackages(cwd);
let packagesByName = new Map(packages.map((x) => [x.packageJson.name, x]));
let output = await readChangesetsOutput(outputFile);
let output: ChangesetsOutputEvent[];
try {
output = await readChangesetsOutput(outputFile);
} catch (err) {
if (!script || !(err instanceof ChangesetsOutputReadError)) {
throw err;
}
core.warning(
`${err.message}. GitHub releases and git tags cannot be created without this output. Ensure the custom publish script passes CHANGESETS_OUTPUT to the Changesets CLI.`,
);
output = [];
}
let releases = output.map((event) => {
let pkg = packagesByName.get(event.packageName);
if (pkg === undefined) {