Repository: atlassian/changesets
Pull request #292 (2020-03-11 00:56:12)

feat: add new @changesets/write package to separate writing changesets
This PR adds a new package `@changesets/write` which does the inverse of `@changesets/parse`.

It basically just extracts the `writeChangesets` function used in `@changesets/cli` so it can be re-used.

changeset-bot[bot]: ###  💥  No Changeset

Latest commit: 25c43999fb196f506d1c838a8bed7774b9f3d428

Merging this PR will not cause any packages to be released. If these changes should not cause updates to packages in this repo, this is fine 🙂

**If these changes should be published to npm, you need to add a changeset.**

[Click here to learn what changesets are, and how to add one](https://github.com/changesets/changesets/blob/master/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add a changeset to this PR](https://github.com/atlassian/changesets/new/feat/export-write-changesets?filename=.changeset/green-rocks-heal.md&value=---%0A%22%40fake-scope%2Ffake-pkg%22%3A%20patch%0A---%0A%0AUpdate%20the%20package%20info%20above%20to%20the%20changes%20you%20want%2C%20and%20write%20your%20description%20here.%20You%20can%20add%20more%20packages%20on%20new%20lines.%0A)


codecov[bot]: # [Codecov](https://codecov.io/gh/atlassian/changesets/pull/292?src=pr&el=h1) Report
> Merging [#292](https://codecov.io/gh/atlassian/changesets/pull/292?src=pr&el=desc) into [master](https://codecov.io/gh/atlassian/changesets/commit/80ab966329bb086f858c2c5def742a0c06f499ab?src=pr&el=desc) will **not change** coverage.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/atlassian/changesets/pull/292/graphs/tree.svg?width=650&token=j0W25zrXm2&height=150&src=pr)](https://codecov.io/gh/atlassian/changesets/pull/292?src=pr&el=tree)

```diff
@@          Coverage Diff          @@
##           master   #292   +/-   ##
=====================================
  Coverage      80%    80%           
=====================================
  Files          45     45           
  Lines        1220   1220           
  Branches      280    284    +4     
=====================================
  Hits          976    976           
  Misses        233    233           
  Partials       11     11
```


| [Impacted Files](https://codecov.io/gh/atlassian/changesets/pull/292?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [packages/cli/src/commands/add/index.ts](https://codecov.io/gh/atlassian/changesets/pull/292/diff?src=pr&el=tree#diff-cGFja2FnZXMvY2xpL3NyYy9jb21tYW5kcy9hZGQvaW5kZXgudHM=) | `79.31% <ø> (ø)` | :arrow_up: |
| [packages/write/src/index.ts](https://codecov.io/gh/atlassian/changesets/pull/292/diff?src=pr&el=tree#diff-cGFja2FnZXMvd3JpdGUvc3JjL2luZGV4LnRz) | `100% <ø> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/atlassian/changesets/pull/292?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/atlassian/changesets/pull/292?src=pr&el=footer). Last update [80ab966...25c4399](https://codecov.io/gh/atlassian/changesets/pull/292?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

Noviny: Hey! Thanks for this.

We initially didn't do this because writing a changeset is simple enough that reimplementing it isn't really a cost, and having it as a library implies it's doing something fancier than it is.

What's the reason for wanting this as a package as opposed to just using the code yourself?
Noviny: PR otherwise looks fine, so happy to merge + release
acheronfail: > We initially didn't do this because writing a changeset is simple enough that reimplementing it isn't really a cost, and having it as a library implies it's doing something fancier than it is.

Makes sense. I guess since we already have the `@changesets/parse` we've abstracted reading the changesets, why not abstract writing them too?

> What's the reason for wanting this as a package as opposed to just using the code yourself?

We need a way to programmatically create a changeset (our use case is to integrate the renovate bot into our monorepo, and there needs to be a way to generate a changeset for the diff that the renovate bot creates).

It seemed odd that we had to duplicate the same logic that `@changesets/cli` itself was doing. Plus we wanted to have the nice things that it already does automatically, like `human-id`, integration with `prettier`, etc.

Patch:
diff --git a/.changeset/brave-bikes-guess.md b/.changeset/brave-bikes-guess.md
new file mode 100644
index 0000000..7c7ed98
--- /dev/null
+++ b/.changeset/brave-bikes-guess.md
@@ -0,0 +1,5 @@
+---
+"@changesets/types": minor
+---
+
+Add new `Changeset` type
diff --git a/.changeset/hot-rocks-reply.md b/.changeset/hot-rocks-reply.md
new file mode 100644
index 0000000..7d26753
--- /dev/null
+++ b/.changeset/hot-rocks-reply.md
@@ -0,0 +1,5 @@
+---
+"@changesets/cli": patch
+---
+
+Use `@changesets/write` for writing changesets internally
diff --git a/.changeset/stale-cobras-begin.md b/.changeset/stale-cobras-begin.md
new file mode 100644
index 0000000..01e3d9c
--- /dev/null
+++ b/.changeset/stale-cobras-begin.md
@@ -0,0 +1,5 @@
+---
+"@changesets/parse": patch
+---
+
+Fix `repository` field in package.json
diff --git a/.changeset/thick-foxes-care.md b/.changeset/thick-foxes-care.md
new file mode 100644
index 0000000..40223f0
--- /dev/null
+++ b/.changeset/thick-foxes-care.md
@@ -0,0 +1,5 @@
+---
+"@changesets/write": minor
+---
+
+Initial release
diff --git a/packages/cli/package.json b/packages/cli/package.json
index 30f8808..b8dc287 100644
--- a/packages/cli/package.json
+++ b/packages/cli/package.json
@@ -34,6 +34,7 @@
     "@changesets/pre": "^0.2.0",
     "@changesets/read": "^0.4.1",
     "@changesets/types": "^0.4.0",
+    "@changesets/write": "^0.0.0",
     "@types/semver": "^6.0.0",
     "boxen": "^1.3.0",
     "chalk": "^2.1.0",
@@ -46,7 +47,6 @@
     "meow": "^5.0.0",
     "outdent": "^0.5.0",
     "p-limit": "^2.2.0",
-    "prettier": "^1.18.2",
     "semver": "^5.4.1",
     "spawndamnit": "^2.0.0",
     "term-size": "^2.1.0",
diff --git a/packages/cli/src/commands/add/index.ts b/packages/cli/src/commands/add/index.ts
index f38589b..a742496 100644
--- a/packages/cli/src/commands/add/index.ts
+++ b/packages/cli/src/commands/add/index.ts
@@ -5,8 +5,8 @@ import * as cli from "../../utils/cli-utilities";
 import * as git from "@changesets/git";
 import { info, log, warn } from "@changesets/logger";
 import { Config } from "@changesets/types";
+import writeChangeset from "@changesets/write";
 
-import writeChangeset from "./writeChangeset";
 import createChangeset from "./createChangeset";
 import printConfirmationMessage from "./messages";
 import getWorkspaces from "../../utils/getWorkspaces";
diff --git a/packages/parse/package.json b/packages/parse/package.json
index 0f606c3..65036fc 100644
--- a/packages/parse/package.json
+++ b/packages/parse/package.json
@@ -5,7 +5,7 @@
   "main": "dist/parse.cjs.js",
   "module": "dist/parse.esm.js",
   "license": "MIT",
-  "repository": "https://github.com/changesets/changesets/tree/master/packages/read",
+  "repository": "https://github.com/changesets/changesets/tree/master/packages/parse",
   "dependencies": {
     "@changesets/types": "^0.4.0",
     "js-yaml": "^3.13.1"
diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts
index 85724cb..b35c307 100644
--- a/packages/types/src/index.ts
+++ b/packages/types/src/index.ts
@@ -25,12 +25,15 @@ export type ComprehensiveRelease = {
   changesets: string[];
 };
 
-export type NewChangeset = {
-  id: string;
+export type Changeset = {
   summary: string;
   releases: Array<Release>;
 };
 
+export type NewChangeset = Changeset & {
+  id: string;
+};
+
 export type ReleasePlan = {
   changesets: NewChangeset[];
   releases: ComprehensiveRelease[];
diff --git a/packages/write/README.md b/packages/write/README.md
new file mode 100644
index 0000000..a22513e
--- /dev/null
+++ b/packages/write/README.md
@@ -0,0 +1,43 @@
+# @changesets/write
+
+Writes a changeset to a file.
+
+```js
+import write from "@changesets/write";
+
+const changeset = {
+  "summary": "A description of a minor change",
+  "releases": [
+    { "name": "@changesets/something", "type": "minor" },
+    { "name": "@changesets/something-else", "type": "patch" }
+  ]
+};
+
+const uniqueId = await write(changeset, cwd);
+console.log(uniqueId); // orange-foxes-waggle
+```
+
+For example, it can convert:
+
+```json
+{
+  "summary": "A description of a minor change",
+  "releases": [
+    { "name": "@changesets/something", "type": "minor" },
+    { "name": "@changesets/something-else", "type": "patch" }
+  ]
+}
+```
+
+to
+
+```markdown
+---
+"@changesets/something": minor
+"@changesets/something-else": patch
+---
+
+A description of a minor change
+```
+
+This package will take care of generating a unique id for the changeset.
diff --git a/packages/write/package.json b/packages/write/package.json
new file mode 100644
index 0000000..20d4ba0
--- /dev/null
+++ b/packages/write/package.json
@@ -0,0 +1,20 @@
+{
+  "name": "@changesets/write",
+  "version": "0.0.0",
+  "description": "Writes a changeset to a file",
+  "main": "dist/write.cjs.js",
+  "module": "dist/write.esm.js",
+  "license": "MIT",
+  "repository": "https://github.com/changesets/changesets/tree/master/packages/write",
+  "dependencies": {
+    "@babel/runtime": "^7.4.4",
+    "@changesets/types": "^0.4.0",
+    "fs-extra": "^7.0.1",
+    "human-id": "^1.0.2",
+    "prettier": "^1.18.2"
+  },
+  "devDependencies": {
+    "@changesets/parse": "*",
+    "jest-fixtures": "^0.5.0"
+  }
+}
diff --git a/packages/cli/src/commands/add/writeChangeset.ts b/packages/write/src/index.ts
similarity index 91%
rename from packages/cli/src/commands/add/writeChangeset.ts
rename to packages/write/src/index.ts
index 6339b41..8945b76 100644
--- a/packages/cli/src/commands/add/writeChangeset.ts
+++ b/packages/write/src/index.ts
@@ -2,12 +2,12 @@ import fs from "fs-extra";
 import path from "path";
 import prettier from "prettier";
 import humanId from "human-id";
-import { Release } from "@changesets/types";
+import { Changeset } from "@changesets/types";
 
 async function writeChangeset(
-  changeset: { summary: string; releases: Array<Release> },
+  changeset: Changeset,
   cwd: string
-) {
+): Promise<string> {
   const { summary, releases } = changeset;
 
   const changesetBase = path.resolve(cwd, ".changeset");


Test patch:
diff --git a/packages/cli/src/commands/add/__tests__/add.ts b/packages/cli/src/commands/add/__tests__/add.ts
index 96c9372..f5adf67 100644
--- a/packages/cli/src/commands/add/__tests__/add.ts
+++ b/packages/cli/src/commands/add/__tests__/add.ts
@@ -3,6 +3,7 @@ import stripAnsi from "strip-ansi";
 import * as git from "@changesets/git";
 import { defaultConfig } from "@changesets/config";
 import { temporarilySilenceLogs } from "@changesets/test-utils";
+import writeChangeset from "@changesets/write";
 
 import {
   askCheckboxPlus,
@@ -11,11 +12,10 @@ import {
   askList
 } from "../../../utils/cli-utilities";
 import addChangeset from "..";
-import writeChangeset from "../writeChangeset";
 
 jest.mock("../../../utils/cli-utilities");
 jest.mock("@changesets/git");
-jest.mock("../writeChangeset");
+jest.mock("@changesets/write");
 // @ts-ignore
 writeChangeset.mockImplementation(() => Promise.resolve("abcdefg"));
 // @ts-ignore
diff --git a/packages/cli/src/commands/status/__tests__/status.ts b/packages/cli/src/commands/status/__tests__/status.ts
index e29cea7..4d7f7d4 100644
--- a/packages/cli/src/commands/status/__tests__/status.ts
+++ b/packages/cli/src/commands/status/__tests__/status.ts
@@ -3,8 +3,8 @@ import fs from "fs-extra";
 import path from "path";
 import { defaultConfig } from "@changesets/config";
 import { temporarilySilenceLogs } from "@changesets/test-utils";
+import writeChangeset from "@changesets/write";
 
-import writeChangeset from "../../add/writeChangeset";
 import status from "..";
 
 import humanId from "human-id";
diff --git a/packages/cli/src/commands/version/version.test.ts b/packages/cli/src/commands/version/version.test.ts
index 885a14d..72f8e6d 100644
--- a/packages/cli/src/commands/version/version.test.ts
+++ b/packages/cli/src/commands/version/version.test.ts
@@ -7,7 +7,7 @@ import versionCommand from "./index";
 import * as git from "@changesets/git";
 import { warn } from "@changesets/logger";
 import { temporarilySilenceLogs } from "@changesets/test-utils";
-import writeChangeset from "../add/writeChangeset";
+import writeChangeset from "@changesets/write";
 import { NewChangeset, Config } from "@changesets/types";
 import { defaultConfig } from "@changesets/config";
 import pre from "../pre";
diff --git a/packages/cli/src/commands/add/__tests__/writeChangeset.ts b/packages/write/src/index.test.ts
similarity index 96%
rename from packages/cli/src/commands/add/__tests__/writeChangeset.ts
rename to packages/write/src/index.test.ts
index 1a41b96..cb197b7 100644
--- a/packages/cli/src/commands/add/__tests__/writeChangeset.ts
+++ b/packages/write/src/index.test.ts
@@ -4,7 +4,7 @@ import fs from "fs-extra";
 import path from "path";
 import parse from "@changesets/parse";
 import { Release } from "@changesets/types";
-import writeChangeset from "../writeChangeset";
+import writeChangeset from "./";
 
 import humanId from "human-id";