Skip to content
5 changes: 5 additions & 0 deletions .changeset/chatty-plums-watch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@changesets/cli": minor
---

`changeset status` command no longer errors when no packages have been changed.
1 change: 0 additions & 1 deletion packages/cli/src/commands/add/createChangeset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,6 @@ export default async function createChangeset(
)}? (current version is ${pkg.packageJson.version})`,
["patch", "minor", "major"]
);
console.log(type);
Comment thread
vitorbal marked this conversation as resolved.
if (type === "major") {
let shouldReleaseAsMajor = await confirmMajorRelease(pkg.packageJson);
if (!shouldReleaseAsMajor) {
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/src/commands/publish/__tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { defaultConfig } from "@changesets/config";
import * as path from "path";
import * as pre from "@changesets/pre";
import { Config } from "@changesets/types";
import { temporarilySilenceLogs } from "@changesets/test-utils";

let changelogPath = path.resolve(__dirname, "../../changelog");
let modifiedDefaultConfig: Config = {
Expand All @@ -18,6 +19,7 @@ jest.mock("../publishPackages.ts");
jest.mock("@changesets/pre");

describe("Publish command", () => {
temporarilySilenceLogs();
let cwd: string;

beforeEach(async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ import fixtures from "fixturez";
import publishPackages from "../publishPackages";
import * as npmUtils from "../npm-utils";
import { getPackages } from "@manypkg/get-packages";
import { temporarilySilenceLogs } from "@changesets/test-utils";

jest.mock("../npm-utils");
jest.mock("is-ci", () => true);

const f = fixtures(__dirname);

describe("publishPackages", () => {
temporarilySilenceLogs();
let cwd: string;

beforeEach(async () => {
Expand Down
69 changes: 65 additions & 4 deletions packages/cli/src/commands/status/__tests__/status.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import fixtures from "fixturez";
import fs from "fs-extra";
import path from "path";
import * as git from "@changesets/git";
import { defaultConfig } from "@changesets/config";
import { temporarilySilenceLogs } from "@changesets/test-utils";
import writeChangeset from "@changesets/write";
Expand All @@ -9,8 +10,10 @@ import status from "..";

import humanId from "human-id";
import { NewChangeset, ReleasePlan } from "@changesets/types";
import { Package } from "@manypkg/get-packages";

jest.mock("human-id");
jest.mock("@changesets/git");

const f = fixtures(__dirname);

Expand Down Expand Up @@ -53,7 +56,16 @@ const simpleReleasePlan: ReleasePlan = {
preState: undefined
};

jest.mock("@changesets/git");
const simpleChangedPackagesList: Package[] = [
{
packageJson: { name: "pkg-a", version: "1.0.0", dependencies: {} },
dir: "/fake/folder/doesnt/matter"
},
{
packageJson: { name: "pkg-b", version: "1.0.0" },
dir: "/fake/folder/doesnt/matter"
}
];

const writeChangesets = (changesets: NewChangeset[], cwd: string) => {
return Promise.all(changesets.map(commit => writeChangeset(commit, cwd)));
Expand All @@ -71,23 +83,72 @@ describe("status", () => {
const changesetID = "ascii";
// @ts-ignore
humanId.mockReturnValueOnce(changesetID);
// @ts-ignore
git.getChangedPackagesSinceRef.mockImplementation(
() => simpleChangedPackagesList
);

await writeChangesets([simpleChangeset], cwd);
const releaseObj = await status(cwd, {}, defaultConfig);
expect(releaseObj).toEqual(simpleReleasePlan);
});
it("should exit with a non-zero error code when there are no changesets", async () => {

it("should exit early with a non-zero error code when there are changed packages but no changesets", async () => {
Comment thread
vitorbal marked this conversation as resolved.
// @ts-ignore
const mockExit = jest.spyOn(process, "exit").mockImplementation(() => {});
jest.spyOn(process, "exit").mockImplementation(() => {});
// @ts-ignore
git.getChangedPackagesSinceRef.mockImplementation(
() => simpleChangedPackagesList
);

await status(cwd, {}, defaultConfig);
expect(mockExit).toHaveBeenCalledWith(1);

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

it("should not exit early with a non-zero error code when there are no changed packages", async () => {
// @ts-ignore
jest.spyOn(process, "exit").mockImplementation(() => {});
// @ts-ignore
git.getChangedPackagesSinceRef.mockImplementation(() => []);

const releaseObj = await status(cwd, {}, defaultConfig);

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

it("should not exit early with a non-zero code when there are changed packages and also a changeset", async () => {
// @ts-ignore
jest.spyOn(process, "exit").mockImplementation(() => {});
// @ts-ignore
git.getChangedPackagesSinceRef.mockImplementation(
() => simpleChangedPackagesList
);
const changesetID = "ascii";
// @ts-ignore
humanId.mockReturnValueOnce(changesetID);

await writeChangesets([simpleChangeset], cwd);
const releaseObj = await status(cwd, {}, defaultConfig);

expect(releaseObj).toEqual(simpleReleasePlan);
expect(process.exit).not.toHaveBeenCalled();
});

it.skip("should respect since master flag", () => false);
it.skip("should respect the verbose flag", () => false);
it("should respect the output flag", async () => {
const output = "nonsense.json";

// @ts-ignore
git.getChangedPackagesSinceRef.mockImplementation(
() => simpleChangedPackagesList
);
const changesetID = "ascii";
// @ts-ignore
humanId.mockReturnValueOnce(changesetID);
Expand Down
24 changes: 16 additions & 8 deletions packages/cli/src/commands/status/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import chalk from "chalk";
import table from "tty-table";
import fs from "fs-extra";
import path from "path";

import * as git from "@changesets/git";
import getReleasePlan from "@changesets/get-release-plan";
import { error, log, info, warn } from "@changesets/logger";
import {
Expand Down Expand Up @@ -32,16 +34,22 @@ export default async function getStatus(
);
warn("Use --since=master instead");
}
const releasePlan = await getReleasePlan(
cwd,
since === undefined ? (sinceMaster ? "master" : undefined) : since,
config
);

const sinceBranch =
since === undefined ? (sinceMaster ? "master" : undefined) : since;
const releasePlan = await getReleasePlan(cwd, sinceBranch, config);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering - do you happen to know why this doesn't account for config.baseBranch? 🤔 I see that it's utilized by @changesets/read but not sure why. Maybe just something you have figured out while working on this PR

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question! I took a look at the original PR that added it and couldn't figure out the intent here, so I decided to follow the same logic. Maybe @mitchellhamilton remembers?

const { changesets, releases } = releasePlan;
const changedPackages = await git.getChangedPackagesSinceRef({
cwd,
ref: sinceBranch || config.baseBranch
});

if (changesets.length < 1) {
error("No changesets present");
if (changedPackages.length > 0 && changesets.length === 0) {
error(
"Some packages have been changed but no changesets were found. Run `changeset add` to resolve this error."
);
error(
"If this change doesn't need a release, run `changeset add --empty`."
);
process.exit(1);
}

Expand Down