Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add since option to version CLI #1206

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/cyan-moles-walk.md
@@ -0,0 +1,5 @@
---
"@changesets/cli": minor
---

feat: Add since option to version CLI
11 changes: 9 additions & 2 deletions docs/command-line-options.md
Expand Up @@ -4,7 +4,7 @@ The command line for changesets is the main way of interacting with it. There ar

- init
- add [--empty][--open]
- version [--ignore, --snapshot]
- version [--since=master, --ignore, --snapshot]
- publish [--otp=code, --tag]
- status [--since=master --verbose --output=JSON_FILE.json]
- pre [exit|enter {tag}]
Expand Down Expand Up @@ -76,7 +76,14 @@ This is one of two commands responsible for releasing packages. The version comm

> We recommend making sure changes made from this command are merged back into the base branch before you run publish.

Version has two options, `ignore` and `snapshot`:
Version has three options, `since`, `ignore` and `snapshot`:

```
changeset version --since={baseBranch}
```

Since option used to preform version of changesets since a specific branch or git tag (such as `main`, or the git hash of latest).
Usefully when you want to publish pull request prerelease versions.

```
changeset version --ignore PACKAGE_NAME
Expand Down
131 changes: 131 additions & 0 deletions packages/cli/src/commands/version/git-version.test.ts
@@ -0,0 +1,131 @@
import fs from "fs-extra";
import path from "path";
import * as git from "@changesets/git";
import { warn } from "@changesets/logger";
import { gitdir } from "@changesets/test-utils";
import writeChangeset from "@changesets/write";
import { Config } from "@changesets/types";
import { defaultConfig } from "@changesets/config";
import version from "./index";
import spawn from "spawndamnit";

let changelogPath = path.resolve(__dirname, "../../changelog");
let modifiedDefaultConfig: Config = {
...defaultConfig,
changelog: [changelogPath, null],
};

jest.mock("../../utils/cli-utilities");
jest.mock("human-id");
jest.mock("@changesets/logger");

const getFile = (pkgName: string, fileName: string, calls: any) => {
let castCalls: [string, string][] = calls;
const foundCall = castCalls.find((call) =>
call[0].endsWith(`${pkgName}${path.sep}${fileName}`)
);
if (!foundCall)
throw new Error(`could not find writing of ${fileName} for: ${pkgName}`);

// return written content
return foundCall[1];
};

const getPkgJSON = (pkgName: string, calls: any) => {
return JSON.parse(getFile(pkgName, "package.json", calls));
};

describe("version since option", () => {
it("should not detect version since the given ref", 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",
dependencies: {
"pkg-b": "1.0.0",
},
}),
"packages/pkg-b/package.json": JSON.stringify({
name: "pkg-b",
version: "1.0.0",
}),
".changeset/changesets-are-beautiful.md": `---
"pkg-a": minor
---

Nice simple summary, much wow
`,
".changeset/.ignored-temporarily.md": `---
"pkg-b": minor
---

Awesome feature, hidden behind a feature flag
`,
});

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

await fs.outputFile(
path.join(cwd, "packages/pkg-a/a.js"),
'export default "updated a"'
);

await git.add(".", cwd);
await git.commit("updated a", cwd);

const spy = jest.spyOn(fs, "writeFile");

await version(cwd, { since: "main" }, modifiedDefaultConfig);

expect(spy).not.toHaveBeenCalled();
// @ts-ignore
const loggerWarnCalls = warn.mock.calls;
expect(loggerWarnCalls.length).toEqual(1);
expect(loggerWarnCalls[0][0]).toEqual(
"No unreleased changesets found, exiting."
);
});

it("should only bump packages that have changed since the given ref", 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",
}),
"packages/pkg-a/src/a.js": 'export default "a"',
".changeset/config.json": JSON.stringify({}),
});

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

await fs.outputFile(
path.join(cwd, "packages/pkg-a/a.js"),
'export default "updated a"'
);
await writeChangeset(
{
summary: "This is a summary",
releases: [{ name: "pkg-a", type: "minor" }],
},
cwd
);
await git.add(".", cwd);
await git.commit("updated a", cwd);

const spy = jest.spyOn(fs, "writeFile");

await version(cwd, { since: "main" }, modifiedDefaultConfig);

expect(getPkgJSON("pkg-a", spy.mock.calls)).toEqual(
expect.objectContaining({ name: "pkg-a", version: "1.1.0" })
);
});
});
3 changes: 2 additions & 1 deletion packages/cli/src/commands/version/index.ts
Expand Up @@ -26,6 +26,7 @@ export default async function version(
cwd: string,
options: {
snapshot?: string | boolean;
since?: string;
},
config: Config
) {
Expand All @@ -35,7 +36,7 @@ export default async function version(
commit: options.snapshot ? false : config.commit,
};
const [changesets, preState] = await Promise.all([
readChangesets(cwd),
readChangesets(cwd, options.since),
readPreState(cwd),
removeEmptyFolders(path.resolve(cwd, ".changeset")),
]);
Expand Down