Skip to content

Commit

Permalink
add failOnNoChanges flag to status cli command
Browse files Browse the repository at this point in the history
  • Loading branch information
runningrandall committed Apr 26, 2024
1 parent 0bf89b3 commit 5afba60
Show file tree
Hide file tree
Showing 8 changed files with 66 additions and 9 deletions.
5 changes: 5 additions & 0 deletions .changeset/empty-ladybugs-perform.md
@@ -0,0 +1,5 @@
---
"@changesets/cli": patch
---

Add failOnNoChanges flag to the changeset status command in the cli. This flag will still force an exit code 1 even if no uncommitted changes exist in one of your packages. The existing behavior will still be the default.
2 changes: 2 additions & 0 deletions docs/checking-for-changesets.md
Expand Up @@ -9,3 +9,5 @@ alert users of missing changesets.

If you want to cause a failure in CI on missing changesets (not recommended), you can run `changeset status --since=main`,
which will exit with a status code of 1 if there are no new changesets.

> [!CAUTION] > **This will still pass with an exit code 0 in CI unless an uncommitted change exists in one of your packages. If you need this to fail in CI without an uncommitted change use the `--failOnNoChanges` flag **
4 changes: 3 additions & 1 deletion packages/cli/README.md
Expand Up @@ -170,7 +170,7 @@ git push --follow-tags
### status

```
status [--verbose] [--output={filePath}] [--since={gitTag}]
status [--verbose] [--output={filePath}] [--since={gitTag}][--failOnNoChanges]
```

The status command provides information about the changesets that currently exist. If there are changes to packages but no changesets are present, it exits with error status code `1`.
Expand All @@ -183,6 +183,8 @@ The status command provides information about the changesets that currently exis
used to add a CI check for changesets, we recommend not doing this. We instead recommend using the [changeset bot](https://github.com/apps/changeset-bot)
to detect pull requests missing changesets, as not all pull requests need one.

- `--failOnNoChanges` - to cause a failure in CI even if there are no uncommitted changes in any of your repo packages.

### pre

```
Expand Down
43 changes: 38 additions & 5 deletions packages/cli/src/commands/status/__tests__/status.ts
Expand Up @@ -116,7 +116,7 @@ describe("status", () => {
});

// @ts-ignore
jest.spyOn(process, "exit").mockImplementation(() => {});
jest.spyOn(process, "exit").mockImplementation(() => { });

await spawn("git", ["checkout", "-b", "new-branch"], { cwd });

Expand All @@ -133,6 +133,39 @@ describe("status", () => {
expect(process.exit).toHaveBeenCalledWith(1);
});

it("should exit early with a non-zero error code when there are no changed packages but no changesets", async () => {
const cwd = await gitdir({
"package.json": JSON.stringify({
private: true,
workspaces: ["packages/*"],
}),
"packages/pkg-a/package.json": JSON.stringify({
name: "pkg-a",
version: "1.0.0",
}),
".changeset/config.json": JSON.stringify({}),
});

// @ts-ignore
jest.spyOn(process, "exit").mockImplementation(() => { });

await spawn("git", ["checkout", "-b", "new-branch"], { cwd });

const releaseObj = await status(
cwd,
{ since: "main", failOnNoChanges: true },
defaultConfig
);

expect(releaseObj).toEqual({
changesets: [],
releases: [],
preState: undefined,
});

expect(process.exit).toHaveBeenCalledWith(1);
});

it("should not exit early with a non-zero error code when there are no changed packages", async () => {
const cwd = await gitdir({
"package.json": JSON.stringify({
Expand All @@ -147,7 +180,7 @@ describe("status", () => {
});

// @ts-ignore
jest.spyOn(process, "exit").mockImplementation(() => {});
jest.spyOn(process, "exit").mockImplementation(() => { });

await spawn("git", ["checkout", "-b", "new-branch"], { cwd });

Expand Down Expand Up @@ -175,7 +208,7 @@ describe("status", () => {
});

// @ts-ignore
jest.spyOn(process, "exit").mockImplementation(() => {});
jest.spyOn(process, "exit").mockImplementation(() => { });

await spawn("git", ["checkout", "-b", "new-branch"], { cwd });

Expand Down Expand Up @@ -286,7 +319,7 @@ describe("status", () => {
});

// @ts-ignore
jest.spyOn(process, "exit").mockImplementation(() => {});
jest.spyOn(process, "exit").mockImplementation(() => { });

await spawn("git", ["checkout", "-b", "new-branch"], { cwd });

Expand Down Expand Up @@ -327,7 +360,7 @@ describe("status", () => {
});

// @ts-ignore
jest.spyOn(process, "exit").mockImplementation(() => {});
jest.spyOn(process, "exit").mockImplementation(() => { });

await spawn("git", ["checkout", "-b", "new-branch"], { cwd });

Expand Down
7 changes: 6 additions & 1 deletion packages/cli/src/commands/status/index.ts
Expand Up @@ -20,11 +20,13 @@ export default async function getStatus(
since,
verbose,
output,
failOnNoChanges,
}: {
sinceMaster?: boolean;
since?: string;
verbose?: boolean;
output?: string;
failOnNoChanges?: boolean;
},
config: Config
) {
Expand All @@ -44,7 +46,10 @@ export default async function getStatus(
changedFilePatterns: config.changedFilePatterns,
});

if (changedPackages.length > 0 && changesets.length === 0) {
if (
(failOnNoChanges || changedPackages.length > 0) &&
changesets.length === 0
) {
error(
"Some packages have been changed but no changesets were found. Run `changeset add` to resolve this error."
);
Expand Down
6 changes: 5 additions & 1 deletion packages/cli/src/index.ts
Expand Up @@ -13,7 +13,7 @@ const { input, flags } = meow(
add [--empty] [--open]
version [--ignore] [--snapshot <?name>] [--snapshot-prerelease-template <template>]
publish [--tag <name>] [--otp <code>] [--no-git-tag]
status [--since <branch>] [--verbose] [--output JSON_FILE.json]
status [--since <branch>] [--verbose] [--output JSON_FILE.json] [--failOnNoChanges]
pre <enter|exit> <tag>
tag
`,
Expand Down Expand Up @@ -56,6 +56,10 @@ const { input, flags } = meow(
snapshotPrereleaseTemplate: {
type: "string",
},
failOnNoChanges: {
type: "boolean",
default: false,
},
// mixed type like this is not supported by `meow`
// if it gets passed explicitly then it's still available on the flags with an inferred type though
// snapshot: { type: "boolean" | "string" },
Expand Down
7 changes: 6 additions & 1 deletion packages/cli/src/run.ts
Expand Up @@ -85,6 +85,7 @@ export async function run(
tag,
open,
gitTag,
failOnNoChanges,
}: CliOptions = flags;
const deadFlags = ["updateChangelog", "isPublic", "skipCI", "commit"];

Expand Down Expand Up @@ -175,7 +176,11 @@ export async function run(
return;
}
case "status": {
await status(cwd, { sinceMaster, since, verbose, output }, config);
await status(
cwd,
{ sinceMaster, since, verbose, output, failOnNoChanges },
config
);
return;
}
case "tag": {
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/types.ts
Expand Up @@ -11,6 +11,7 @@ export type CliOptions = {
tag?: string;
gitTag?: boolean;
open?: boolean;
failOnNoChanges?: boolean;
};

export type CommandOptions = CliOptions & {
Expand Down

0 comments on commit 5afba60

Please sign in to comment.