diff --git a/.changeset/chatty-plums-watch.md b/.changeset/chatty-plums-watch.md new file mode 100644 index 000000000..9be3afd01 --- /dev/null +++ b/.changeset/chatty-plums-watch.md @@ -0,0 +1,5 @@ +--- +"@changesets/cli": minor +--- + +`changeset status` command no longer errors when no packages have been changed. diff --git a/packages/cli/src/commands/add/createChangeset.ts b/packages/cli/src/commands/add/createChangeset.ts index e52ebed99..527a8c814 100644 --- a/packages/cli/src/commands/add/createChangeset.ts +++ b/packages/cli/src/commands/add/createChangeset.ts @@ -218,7 +218,6 @@ export default async function createChangeset( )}? (current version is ${pkg.packageJson.version})`, ["patch", "minor", "major"] ); - console.log(type); if (type === "major") { let shouldReleaseAsMajor = await confirmMajorRelease(pkg.packageJson); if (!shouldReleaseAsMajor) { diff --git a/packages/cli/src/commands/publish/__tests__/index.test.ts b/packages/cli/src/commands/publish/__tests__/index.test.ts index bf33cf49c..44a724081 100644 --- a/packages/cli/src/commands/publish/__tests__/index.test.ts +++ b/packages/cli/src/commands/publish/__tests__/index.test.ts @@ -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 = { @@ -18,6 +19,7 @@ jest.mock("../publishPackages.ts"); jest.mock("@changesets/pre"); describe("Publish command", () => { + temporarilySilenceLogs(); let cwd: string; beforeEach(async () => { diff --git a/packages/cli/src/commands/publish/__tests__/publishPackages.test.ts b/packages/cli/src/commands/publish/__tests__/publishPackages.test.ts index ad1533b59..ac3ffe179 100644 --- a/packages/cli/src/commands/publish/__tests__/publishPackages.test.ts +++ b/packages/cli/src/commands/publish/__tests__/publishPackages.test.ts @@ -3,6 +3,7 @@ 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); @@ -10,6 +11,7 @@ jest.mock("is-ci", () => true); const f = fixtures(__dirname); describe("publishPackages", () => { + temporarilySilenceLogs(); let cwd: string; beforeEach(async () => { diff --git a/packages/cli/src/commands/status/__tests__/status.ts b/packages/cli/src/commands/status/__tests__/status.ts index 1a57df630..376f1e04d 100644 --- a/packages/cli/src/commands/status/__tests__/status.ts +++ b/packages/cli/src/commands/status/__tests__/status.ts @@ -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"; @@ -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); @@ -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))); @@ -71,16 +83,61 @@ 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 () => { // @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); @@ -88,6 +145,10 @@ describe("status", () => { 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); diff --git a/packages/cli/src/commands/status/index.ts b/packages/cli/src/commands/status/index.ts index f53eba24b..0dcecae91 100644 --- a/packages/cli/src/commands/status/index.ts +++ b/packages/cli/src/commands/status/index.ts @@ -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 { @@ -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); 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); }