@shiplane/changesets 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -51,6 +51,21 @@ It fills a flow port, so unit files take no key from it. Its factory takes:
51
51
 
52
52
  Source: `ChangesetsOptions` in `src/changesets-versioning.adapter.ts`.
53
53
 
54
+ ## Release from commits
55
+
56
+ `commitsVersioning()` takes the same options and needs no changeset written: the commits since each
57
+ package's version become the release's changesets, and the changesets CLI does the rest. `feat` is a
58
+ minor, a subject marked `!` a major (a minor below 1.0), and anything else a patch.
59
+ [How-to](../../docs/shiplane/how-to.md#release-from-commits). Source:
60
+ `src/commits-versioning.adapter.ts`.
61
+
62
+ ## Force another version
63
+
64
+ When a person [picks another version](../../docs/shiplane/how-to.md#force-another-version), shiplane
65
+ adds a changeset at that level and hands both adapters a `ceiling`: no line ships above it. A plan
66
+ puts the files back when it ends; a release consumes them on its branch, and puts them back if
67
+ `changeset version` fails.
68
+
54
69
  ## Example
55
70
 
56
71
  [`examples/`](./examples) holds one pending changeset,
@@ -67,7 +82,7 @@ The seed script skips rows it already wrote.
67
82
  `pnpm shiplane status` in that repository counts it:
68
83
 
69
84
  ```text
70
- Release status · preview
85
+ Release status · live
71
86
 
72
87
  Unit Version Target Where it stands
73
88
  scripts 1.0.0 release-only ↑ 1 changeset
package/dist/index.d.ts CHANGED
@@ -9,5 +9,14 @@ type ChangesetsVersioningAdapter = ServiceAdapter<VersioningPort>;
9
9
  /** Versioning from `.changeset` files, through the changesets CLI. */
10
10
  declare const changesetsVersioning: (options?: ChangesetsOptions) => ChangesetsVersioningAdapter;
11
11
  //#endregion
12
- export { type ChangesetsOptions, type ChangesetsVersioningAdapter, changesetsVersioning };
12
+ //#region src/commits-versioning.adapter.d.ts
13
+ type CommitsVersioningAdapter = ServiceAdapter<VersioningPort>;
14
+ /**
15
+ * Versioning from Conventional Commits, with no changeset to write: the commits since each
16
+ * package's version become the changesets of the release, and changesets does the rest. A pending
17
+ * changeset naming a package still takes over from its commits.
18
+ */
19
+ declare const commitsVersioning: (options?: ChangesetsOptions) => CommitsVersioningAdapter;
20
+ //#endregion
21
+ export { type ChangesetsOptions, type ChangesetsVersioningAdapter, type CommitsVersioningAdapter, changesetsVersioning, commitsVersioning };
13
22
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import fs from "node:fs";
2
2
  import os from "node:os";
3
3
  import path from "node:path";
4
- import { expandPatterns, workspacePatterns, z } from "shiplane/plugin";
4
+ import { expandPatterns, isReleaseSubject, workspacePatterns, z } from "shiplane/plugin";
5
5
  //#region src/changesets-versioning.adapter.ts
6
6
  const BumpSchema = z.enum([
7
7
  "major",
@@ -32,6 +32,21 @@ const PackageSchema = z.object({
32
32
  peerDependencies: z.record(z.string(), z.string()).optional()
33
33
  });
34
34
  const LINE = /^"([^"]+)":\s*(\w+)\s*$/;
35
+ const BUMP_AT_LINE_END = /(major|minor|patch)(\s*)$/;
36
+ const SMALLEST_FIRST = [
37
+ "patch",
38
+ "minor",
39
+ "major"
40
+ ];
41
+ /** A changeset's text with no line above `ceiling`; its summary stays as it was written. */
42
+ const cappedText = (text, ceiling) => {
43
+ const [before = "", frontmatter = "", ...rest] = text.split("---");
44
+ return [
45
+ before,
46
+ frontmatter.split("\n").map((line) => line.replace(BUMP_AT_LINE_END, (bump, level, end) => SMALLEST_FIRST.indexOf(level) > SMALLEST_FIRST.indexOf(ceiling) ? `${ceiling}${end}` : bump)).join("\n"),
47
+ ...rest
48
+ ].join("---");
49
+ };
35
50
  const changesetsFiles = (root, shell, options) => {
36
51
  const dir = path.join(root, ".changeset");
37
52
  const fileOf = (id) => path.join(dir, `${id}.md`);
@@ -61,15 +76,23 @@ const changesetsFiles = (root, shell, options) => {
61
76
  });
62
77
  return () => originals.forEach((text, id) => fs.writeFileSync(fileOf(id), text));
63
78
  };
79
+ /** Rewrites what ships to `ceiling` at most; the returned function puts the files back. */
80
+ const capAt = (ceiling) => {
81
+ if (!ceiling) return () => void 0;
82
+ const originals = new Map(pendingIds().map((id) => [id, fs.readFileSync(fileOf(id), "utf8")]));
83
+ originals.forEach((text, id) => fs.writeFileSync(fileOf(id), cappedText(text, ceiling)));
84
+ return () => originals.forEach((text, id) => fs.writeFileSync(fileOf(id), text));
85
+ };
64
86
  return {
65
87
  pending: () => Promise.resolve(pendingIds().map((id) => ({
66
88
  id,
67
89
  text: fs.readFileSync(fileOf(id), "utf8")
68
90
  }))),
69
- plan: async (added, held) => {
91
+ plan: async (added, held, ceiling) => {
70
92
  const output = path.join(os.tmpdir(), `release-status-${process.pid}.json`);
71
93
  added.forEach(write);
72
94
  const restore = holdBack(held);
95
+ const uncap = capAt(ceiling);
73
96
  try {
74
97
  if (pendingIds().length === 0) return {
75
98
  changesets: [],
@@ -83,14 +106,16 @@ const changesetsFiles = (root, shell, options) => {
83
106
  ], { cwd: root });
84
107
  return StatusPlanSchema.parse(JSON.parse(fs.readFileSync(output, "utf8")));
85
108
  } finally {
109
+ uncap();
86
110
  restore();
87
111
  added.forEach(({ id }) => fs.rmSync(fileOf(id), { force: true }));
88
112
  fs.rmSync(output, { force: true });
89
113
  }
90
114
  },
91
- apply: async (added, held) => {
115
+ apply: async (added, held, ceiling) => {
92
116
  added.forEach(write);
93
117
  const restore = holdBack(held);
118
+ const uncap = capAt(ceiling);
94
119
  try {
95
120
  const [command = "pnpm", ...args] = options.version ?? [
96
121
  "pnpm",
@@ -104,6 +129,10 @@ const changesetsFiles = (root, shell, options) => {
104
129
  ...token ? { env: { GITHUB_TOKEN: token } } : {}
105
130
  });
106
131
  if (status !== 0) throw new Error(`${command} ${args.join(" ")} exited with ${status}`);
132
+ } catch (error) {
133
+ uncap();
134
+ added.forEach(({ id }) => fs.rmSync(fileOf(id), { force: true }));
135
+ throw error;
107
136
  } finally {
108
137
  restore();
109
138
  }
@@ -122,6 +151,7 @@ const changesetsFiles = (root, shell, options) => {
122
151
  }).filter((dep) => names.has(dep))])));
123
152
  },
124
153
  folders: () => Promise.resolve(Object.fromEntries(workspacePackages().map(({ folder, pkg }) => [pkg.name, folder]))),
154
+ nextChange: "pnpm changeset",
125
155
  changesetFile: (id) => path.posix.join(".changeset", `${id}.md`),
126
156
  changelogFile: (folder) => path.posix.join(folder, "CHANGELOG.md")
127
157
  };
@@ -132,6 +162,111 @@ const changesetsVersioning = (options = {}) => ({
132
162
  create: ({ root, shell }) => changesetsFiles(root, shell, options)
133
163
  });
134
164
  //#endregion
135
- export { changesetsVersioning };
165
+ //#region src/commits-versioning.adapter.ts
166
+ const BREAKING = /^\w+(\(.+?\))?!:/;
167
+ const FEATURE = /^feat(\(.+?\))?:/;
168
+ const USER_FACING = /^(feat|fix|perf)(\(.+?\))?:/;
169
+ const UNIT_FILES = ["shiplane.unit.yml", "release.unit.yml"];
170
+ const Manifest = z.object({ version: z.string() });
171
+ const Config = z.object({ ignore: z.array(z.string()).optional() });
172
+ /** The Conventional Commits bump: `!` a major (a minor below 1.0), `feat` a minor, else a patch. */
173
+ const bumpOf = (subject, version) => {
174
+ if (BREAKING.test(subject)) return version.startsWith("0.") ? "minor" : "major";
175
+ return FEATURE.test(subject) ? "minor" : "patch";
176
+ };
177
+ const asSentence = (subject) => {
178
+ const text = subject.replace(/^\w+(\(.+?\))?!?:\s*/, "").replace(/\s*\(#\d+\)$/, "").trim();
179
+ const sentence = `${text.charAt(0).toUpperCase()}${text.slice(1)}`;
180
+ return /[.!?]$/.test(sentence) ? sentence : `${sentence}.`;
181
+ };
182
+ /**
183
+ * One changeset per feature, fix or breaking commit, or the latest commit when there are none: a
184
+ * commit in a package changed what it ships, whatever its type says.
185
+ */
186
+ const changesetsFrom = (name, version, subjects) => {
187
+ const told = subjects.filter((subject) => USER_FACING.test(subject) || BREAKING.test(subject));
188
+ const slug = name.replace(/[^a-z0-9]+/gi, "-").replace(/^-|-$/g, "");
189
+ return (told.length > 0 ? told : subjects.slice(0, 1)).map((subject, index) => ({
190
+ id: `commits-${slug}-${index + 1}`,
191
+ releases: [{
192
+ name,
193
+ type: bumpOf(subject, version)
194
+ }],
195
+ summary: asSentence(subject)
196
+ }));
197
+ };
198
+ const textOf = ({ releases, summary }) => `---\n${releases.map(({ name, type }) => `"${name}": ${type}`).join("\n")}\n---\n\n${summary}\n`;
199
+ const readJson = (file) => fs.existsSync(file) ? JSON.parse(fs.readFileSync(file, "utf8")) : {};
200
+ /** Changesets versioning fed by commits: what a person would write is written from the history. */
201
+ const commitsFiles = (root, shell, options) => {
202
+ const files = changesetsVersioning(options).create({
203
+ root,
204
+ shell
205
+ });
206
+ const git = async (args) => {
207
+ const { status, stdout } = await shell.capture("git", args, { cwd: root });
208
+ return status === 0 ? stdout.trim() : "";
209
+ };
210
+ /** The subjects since the commit that brought a version, a release's own aside. */
211
+ const subjectsSince = async (folder, version) => {
212
+ const since = await git([
213
+ "log",
214
+ "-1",
215
+ "--format=%H",
216
+ "-S",
217
+ `"version": "${version}"`,
218
+ "--",
219
+ path.posix.join(folder, "package.json")
220
+ ]);
221
+ if (!since) return [];
222
+ return (await git([
223
+ "log",
224
+ "--format=%s",
225
+ `${since}..HEAD`,
226
+ "--",
227
+ folder,
228
+ ...UNIT_FILES.map((file) => `:(exclude)${path.posix.join(folder, file)}`)
229
+ ])).split("\n").filter((subject) => subject && !isReleaseSubject(subject));
230
+ };
231
+ /** A pending changeset naming a package takes over from its commits. */
232
+ const fromCommits = async () => {
233
+ const [folders, written] = await Promise.all([files.folders(), files.pending()]);
234
+ const config = Config.safeParse(readJson(path.join(root, ".changeset", "config.json")));
235
+ const ignored = new Set(config.success ? config.data.ignore : []);
236
+ const packages = Object.entries(folders);
237
+ const moving = packages.filter(([name, folder]) => !(folder === "." && packages.length > 1) && !ignored.has(name) && !written.some(({ text }) => text.includes(`"${name}":`)));
238
+ return (await Promise.all(moving.map(async ([name, folder]) => {
239
+ const manifest = Manifest.safeParse(readJson(path.join(root, folder, "package.json")));
240
+ if (!manifest.success) return [];
241
+ const { version } = manifest.data;
242
+ return changesetsFrom(name, version, await subjectsSince(folder, version));
243
+ }))).flat();
244
+ };
245
+ return {
246
+ ...files,
247
+ nextChange: "a commit in the package",
248
+ pending: async () => [...await files.pending(), ...(await fromCommits()).map((changeset) => ({
249
+ id: changeset.id,
250
+ text: textOf(changeset)
251
+ }))],
252
+ plan: async (added, held, ceiling) => files.plan([...await fromCommits(), ...added], held, ceiling),
253
+ apply: async (added, held, ceiling) => {
254
+ const commits = await fromCommits();
255
+ await files.apply([...commits, ...added], held, ceiling);
256
+ commits.forEach(({ id }) => fs.rmSync(path.join(root, files.changesetFile(id)), { force: true }));
257
+ }
258
+ };
259
+ };
260
+ /**
261
+ * Versioning from Conventional Commits, with no changeset to write: the commits since each
262
+ * package's version become the changesets of the release, and changesets does the rest. A pending
263
+ * changeset naming a package still takes over from its commits.
264
+ */
265
+ const commitsVersioning = (options = {}) => ({
266
+ name: "commits",
267
+ create: ({ root, shell }) => commitsFiles(root, shell, options)
268
+ });
269
+ //#endregion
270
+ export { changesetsVersioning, commitsVersioning };
136
271
 
137
272
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/changesets-versioning.adapter.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport type { PlannedChangeset, ServiceAdapter, Shell, VersioningPort } from \"shiplane/plugin\";\nimport { expandPatterns, workspacePatterns, z } from \"shiplane/plugin\";\n\nexport interface ChangesetsOptions {\n /** What versions the repository: `changeset version` by default. */\n version?: string[];\n}\n\nconst BumpSchema = z.enum([\"major\", \"minor\", \"patch\", \"none\"]);\nconst StatusPlanSchema = z.object({\n changesets: z.array(\n z.object({\n id: z.string(),\n summary: z.string(),\n releases: z.array(z.object({ name: z.string(), type: BumpSchema })),\n }),\n ),\n releases: z.array(\n z.object({\n name: z.string(),\n type: BumpSchema,\n oldVersion: z.string(),\n newVersion: z.string(),\n changesets: z.array(z.string()),\n }),\n ),\n});\nconst PackageSchema = z.object({\n name: z.string(),\n dependencies: z.record(z.string(), z.string()).optional(),\n peerDependencies: z.record(z.string(), z.string()).optional(),\n});\n\nconst LINE = /^\"([^\"]+)\":\\s*(\\w+)\\s*$/;\n\nconst changesetsFiles = (\n root: string,\n shell: Shell,\n options: ChangesetsOptions,\n): VersioningPort => {\n const dir = path.join(root, \".changeset\");\n const fileOf = (id: string) => path.join(dir, `${id}.md`);\n const write = ({ id, releases, summary }: PlannedChangeset) =>\n fs.writeFileSync(\n fileOf(id),\n `---\\n${releases.map(({ name, type }) => `\"${name}\": ${type}`).join(\"\\n\")}\\n---\\n\\n${summary}\\n`,\n );\n const workspacePackages = () =>\n expandPatterns(root, workspacePatterns(root)).flatMap((folder) => {\n const file = path.join(root, folder, \"package.json\");\n if (!fs.existsSync(file)) return [];\n const parsed = PackageSchema.safeParse(JSON.parse(fs.readFileSync(file, \"utf8\")));\n return parsed.success ? [{ folder, pkg: parsed.data }] : [];\n });\n const pendingIds = () =>\n fs.existsSync(dir)\n ? fs\n .readdirSync(dir)\n .filter((file) => file.endsWith(\".md\") && file !== \"README.md\")\n .map((file) => file.slice(0, -3))\n : [];\n\n /** Leaves only what ships in `.changeset`; the returned function puts the held files back. */\n const holdBack = (held: readonly PlannedChangeset[]) => {\n const originals = new Map(held.map(({ id }) => [id, fs.readFileSync(fileOf(id), \"utf8\")]));\n held.forEach(({ id, releases }) => {\n const original = originals.get(id) ?? \"\";\n const [, frontmatter = \"\", ...rest] = original.split(\"---\");\n const waiting = new Set(releases.map(({ name }) => name));\n const shipping = frontmatter.split(\"\\n\").filter((line) => {\n const match = LINE.exec(line.trim());\n return match && !waiting.has(match[1] ?? \"\");\n });\n if (shipping.length === 0) fs.rmSync(fileOf(id));\n else fs.writeFileSync(fileOf(id), `---\\n${shipping.join(\"\\n\")}\\n---${rest.join(\"---\")}`);\n });\n return () => originals.forEach((text, id) => fs.writeFileSync(fileOf(id), text));\n };\n\n return {\n pending: () =>\n Promise.resolve(\n pendingIds().map((id) => ({ id, text: fs.readFileSync(fileOf(id), \"utf8\") })),\n ),\n // changeset status computes every move, dependents included, without writing anything. What\n // the release adds and holds back lasts only for the time of the call.\n plan: async (added, held) => {\n const output = path.join(os.tmpdir(), `release-status-${process.pid}.json`);\n added.forEach(write);\n const restore = holdBack(held);\n try {\n // changeset status writes nothing and exits 1 when no changeset is left.\n if (pendingIds().length === 0) return { changesets: [], releases: [] };\n await shell.capture(\"pnpm\", [\"exec\", \"changeset\", \"status\", `--output=${output}`], {\n cwd: root,\n });\n return StatusPlanSchema.parse(JSON.parse(fs.readFileSync(output, \"utf8\")));\n } finally {\n restore();\n added.forEach(({ id }) => fs.rmSync(fileOf(id), { force: true }));\n fs.rmSync(output, { force: true });\n }\n },\n apply: async (added, held) => {\n added.forEach(write);\n const restore = holdBack(held);\n try {\n const [command = \"pnpm\", ...args] = options.version ?? [\n \"pnpm\",\n \"exec\",\n \"changeset\",\n \"version\",\n ];\n // A GitHub changelog asks GitHub who wrote each change: gh's sign-in answers it.\n const token = shell.env(\"GITHUB_TOKEN\")\n ? undefined\n : (await shell.capture(\"gh\", [\"auth\", \"token\"])).stdout.trim();\n const status = await shell.attach(command, args, {\n cwd: root,\n ...(token ? { env: { GITHUB_TOKEN: token } } : {}),\n });\n if (status !== 0) throw new Error(`${command} ${args.join(\" \")} exited with ${status}`);\n } finally {\n restore();\n }\n // A held changeset that also named a released unit keeps only its waiting lines.\n held.forEach(write);\n },\n write: (changeset) => {\n write(changeset);\n return Promise.resolve();\n },\n dependencies: () => {\n const packages = workspacePackages().map(({ pkg }) => pkg);\n const names = new Set(packages.map(({ name }) => name));\n // Only runtime dependencies move a dependent's version.\n return Promise.resolve(\n Object.fromEntries(\n packages.map((pkg) => [\n pkg.name,\n Object.keys({ ...pkg.dependencies, ...pkg.peerDependencies }).filter((dep) =>\n names.has(dep),\n ),\n ]),\n ),\n );\n },\n folders: () =>\n Promise.resolve(\n Object.fromEntries(workspacePackages().map(({ folder, pkg }) => [pkg.name, folder])),\n ),\n changesetFile: (id) => path.posix.join(\".changeset\", `${id}.md`),\n changelogFile: (folder) => path.posix.join(folder, \"CHANGELOG.md\"),\n };\n};\n\nexport type ChangesetsVersioningAdapter = ServiceAdapter<VersioningPort>;\n\n/** Versioning from `.changeset` files, through the changesets CLI. */\nexport const changesetsVersioning = (\n options: ChangesetsOptions = {},\n): ChangesetsVersioningAdapter => ({\n name: \"changesets\",\n create: ({ root, shell }) => changesetsFiles(root, shell, options),\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/changesets-versioning.adapter.ts","../src/commits-versioning.adapter.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport type {\n BumpLevel,\n PlannedChangeset,\n ServiceAdapter,\n Shell,\n VersioningPort,\n} from \"shiplane/plugin\";\nimport { expandPatterns, workspacePatterns, z } from \"shiplane/plugin\";\n\nexport interface ChangesetsOptions {\n /** What versions the repository: `changeset version` by default. */\n version?: string[];\n}\n\nconst BumpSchema = z.enum([\"major\", \"minor\", \"patch\", \"none\"]);\nconst StatusPlanSchema = z.object({\n changesets: z.array(\n z.object({\n id: z.string(),\n summary: z.string(),\n releases: z.array(z.object({ name: z.string(), type: BumpSchema })),\n }),\n ),\n releases: z.array(\n z.object({\n name: z.string(),\n type: BumpSchema,\n oldVersion: z.string(),\n newVersion: z.string(),\n changesets: z.array(z.string()),\n }),\n ),\n});\nconst PackageSchema = z.object({\n name: z.string(),\n dependencies: z.record(z.string(), z.string()).optional(),\n peerDependencies: z.record(z.string(), z.string()).optional(),\n});\n\nconst LINE = /^\"([^\"]+)\":\\s*(\\w+)\\s*$/;\nconst BUMP_AT_LINE_END = /(major|minor|patch)(\\s*)$/;\nconst SMALLEST_FIRST: readonly string[] = [\"patch\", \"minor\", \"major\"];\n\n/** A changeset's text with no line above `ceiling`; its summary stays as it was written. */\nconst cappedText = (text: string, ceiling: BumpLevel) => {\n const [before = \"\", frontmatter = \"\", ...rest] = text.split(\"---\");\n const lines = frontmatter\n .split(\"\\n\")\n .map((line) =>\n line.replace(BUMP_AT_LINE_END, (bump: string, level: string, end: string) =>\n SMALLEST_FIRST.indexOf(level) > SMALLEST_FIRST.indexOf(ceiling) ? `${ceiling}${end}` : bump,\n ),\n );\n return [before, lines.join(\"\\n\"), ...rest].join(\"---\");\n};\n\nconst changesetsFiles = (\n root: string,\n shell: Shell,\n options: ChangesetsOptions,\n): VersioningPort => {\n const dir = path.join(root, \".changeset\");\n const fileOf = (id: string) => path.join(dir, `${id}.md`);\n const write = ({ id, releases, summary }: PlannedChangeset) =>\n fs.writeFileSync(\n fileOf(id),\n `---\\n${releases.map(({ name, type }) => `\"${name}\": ${type}`).join(\"\\n\")}\\n---\\n\\n${summary}\\n`,\n );\n const workspacePackages = () =>\n expandPatterns(root, workspacePatterns(root)).flatMap((folder) => {\n const file = path.join(root, folder, \"package.json\");\n if (!fs.existsSync(file)) return [];\n const parsed = PackageSchema.safeParse(JSON.parse(fs.readFileSync(file, \"utf8\")));\n return parsed.success ? [{ folder, pkg: parsed.data }] : [];\n });\n const pendingIds = () =>\n fs.existsSync(dir)\n ? fs\n .readdirSync(dir)\n .filter((file) => file.endsWith(\".md\") && file !== \"README.md\")\n .map((file) => file.slice(0, -3))\n : [];\n\n /** Leaves only what ships in `.changeset`; the returned function puts the held files back. */\n const holdBack = (held: readonly PlannedChangeset[]) => {\n const originals = new Map(held.map(({ id }) => [id, fs.readFileSync(fileOf(id), \"utf8\")]));\n held.forEach(({ id, releases }) => {\n const original = originals.get(id) ?? \"\";\n const [, frontmatter = \"\", ...rest] = original.split(\"---\");\n const waiting = new Set(releases.map(({ name }) => name));\n const shipping = frontmatter.split(\"\\n\").filter((line) => {\n const match = LINE.exec(line.trim());\n return match && !waiting.has(match[1] ?? \"\");\n });\n if (shipping.length === 0) fs.rmSync(fileOf(id));\n else fs.writeFileSync(fileOf(id), `---\\n${shipping.join(\"\\n\")}\\n---${rest.join(\"---\")}`);\n });\n return () => originals.forEach((text, id) => fs.writeFileSync(fileOf(id), text));\n };\n\n /** Rewrites what ships to `ceiling` at most; the returned function puts the files back. */\n const capAt = (ceiling: BumpLevel | undefined) => {\n if (!ceiling) return () => undefined;\n const originals = new Map(pendingIds().map((id) => [id, fs.readFileSync(fileOf(id), \"utf8\")]));\n originals.forEach((text, id) => fs.writeFileSync(fileOf(id), cappedText(text, ceiling)));\n return () => originals.forEach((text, id) => fs.writeFileSync(fileOf(id), text));\n };\n\n return {\n pending: () =>\n Promise.resolve(\n pendingIds().map((id) => ({ id, text: fs.readFileSync(fileOf(id), \"utf8\") })),\n ),\n // changeset status computes every move, dependents included, without writing anything. What\n // the release adds, holds back and caps lasts only for the time of the call.\n plan: async (added, held, ceiling) => {\n const output = path.join(os.tmpdir(), `release-status-${process.pid}.json`);\n added.forEach(write);\n const restore = holdBack(held);\n const uncap = capAt(ceiling);\n try {\n // changeset status writes nothing and exits 1 when no changeset is left.\n if (pendingIds().length === 0) return { changesets: [], releases: [] };\n await shell.capture(\"pnpm\", [\"exec\", \"changeset\", \"status\", `--output=${output}`], {\n cwd: root,\n });\n return StatusPlanSchema.parse(JSON.parse(fs.readFileSync(output, \"utf8\")));\n } finally {\n uncap();\n restore();\n added.forEach(({ id }) => fs.rmSync(fileOf(id), { force: true }));\n fs.rmSync(output, { force: true });\n }\n },\n apply: async (added, held, ceiling) => {\n added.forEach(write);\n const restore = holdBack(held);\n const uncap = capAt(ceiling);\n try {\n const [command = \"pnpm\", ...args] = options.version ?? [\n \"pnpm\",\n \"exec\",\n \"changeset\",\n \"version\",\n ];\n // A GitHub changelog asks GitHub who wrote each change: gh's sign-in answers it.\n const token = shell.env(\"GITHUB_TOKEN\")\n ? undefined\n : (await shell.capture(\"gh\", [\"auth\", \"token\"])).stdout.trim();\n const status = await shell.attach(command, args, {\n cwd: root,\n ...(token ? { env: { GITHUB_TOKEN: token } } : {}),\n });\n if (status !== 0) throw new Error(`${command} ${args.join(\" \")} exited with ${status}`);\n } catch (error) {\n // Versioning consumes what it caps; had it failed, the undo goes back to main with these.\n uncap();\n added.forEach(({ id }) => fs.rmSync(fileOf(id), { force: true }));\n throw error;\n } finally {\n restore();\n }\n // A held changeset that also named a released unit keeps only its waiting lines.\n held.forEach(write);\n },\n write: (changeset) => {\n write(changeset);\n return Promise.resolve();\n },\n dependencies: () => {\n const packages = workspacePackages().map(({ pkg }) => pkg);\n const names = new Set(packages.map(({ name }) => name));\n // Only runtime dependencies move a dependent's version.\n return Promise.resolve(\n Object.fromEntries(\n packages.map((pkg) => [\n pkg.name,\n Object.keys({ ...pkg.dependencies, ...pkg.peerDependencies }).filter((dep) =>\n names.has(dep),\n ),\n ]),\n ),\n );\n },\n folders: () =>\n Promise.resolve(\n Object.fromEntries(workspacePackages().map(({ folder, pkg }) => [pkg.name, folder])),\n ),\n nextChange: \"pnpm changeset\",\n changesetFile: (id) => path.posix.join(\".changeset\", `${id}.md`),\n changelogFile: (folder) => path.posix.join(folder, \"CHANGELOG.md\"),\n };\n};\n\nexport type ChangesetsVersioningAdapter = ServiceAdapter<VersioningPort>;\n\n/** Versioning from `.changeset` files, through the changesets CLI. */\nexport const changesetsVersioning = (\n options: ChangesetsOptions = {},\n): ChangesetsVersioningAdapter => ({\n name: \"changesets\",\n create: ({ root, shell }) => changesetsFiles(root, shell, options),\n});\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { PlannedChangeset, ServiceAdapter, Shell, VersioningPort } from \"shiplane/plugin\";\nimport { isReleaseSubject, z } from \"shiplane/plugin\";\n\nimport type { ChangesetsOptions } from \"./changesets-versioning.adapter\";\nimport { changesetsVersioning } from \"./changesets-versioning.adapter\";\n\nconst BREAKING = /^\\w+(\\(.+?\\))?!:/;\nconst FEATURE = /^feat(\\(.+?\\))?:/;\nconst USER_FACING = /^(feat|fix|perf)(\\(.+?\\))?:/;\nconst UNIT_FILES = [\"shiplane.unit.yml\", \"release.unit.yml\"];\n\nconst Manifest = z.object({ version: z.string() });\nconst Config = z.object({ ignore: z.array(z.string()).optional() });\n\n/** The Conventional Commits bump: `!` a major (a minor below 1.0), `feat` a minor, else a patch. */\nconst bumpOf = (subject: string, version: string): PlannedChangeset[\"releases\"][number][\"type\"] => {\n if (BREAKING.test(subject)) return version.startsWith(\"0.\") ? \"minor\" : \"major\";\n return FEATURE.test(subject) ? \"minor\" : \"patch\";\n};\n\n// Subjects are written as user value already: drop the type, scope and PR number.\nconst asSentence = (subject: string) => {\n const text = subject\n .replace(/^\\w+(\\(.+?\\))?!?:\\s*/, \"\")\n .replace(/\\s*\\(#\\d+\\)$/, \"\")\n .trim();\n const sentence = `${text.charAt(0).toUpperCase()}${text.slice(1)}`;\n return /[.!?]$/.test(sentence) ? sentence : `${sentence}.`;\n};\n\n/**\n * One changeset per feature, fix or breaking commit, or the latest commit when there are none: a\n * commit in a package changed what it ships, whatever its type says.\n */\nconst changesetsFrom = (\n name: string,\n version: string,\n subjects: readonly string[],\n): PlannedChangeset[] => {\n const told = subjects.filter((subject) => USER_FACING.test(subject) || BREAKING.test(subject));\n const slug = name.replace(/[^a-z0-9]+/gi, \"-\").replace(/^-|-$/g, \"\");\n return (told.length > 0 ? told : subjects.slice(0, 1)).map((subject, index) => ({\n id: `commits-${slug}-${index + 1}`,\n releases: [{ name, type: bumpOf(subject, version) }],\n summary: asSentence(subject),\n }));\n};\n\nconst textOf = ({ releases, summary }: PlannedChangeset) =>\n `---\\n${releases.map(({ name, type }) => `\"${name}\": ${type}`).join(\"\\n\")}\\n---\\n\\n${summary}\\n`;\n\nconst readJson = (file: string) =>\n fs.existsSync(file) ? (JSON.parse(fs.readFileSync(file, \"utf8\")) as unknown) : {};\n\n/** Changesets versioning fed by commits: what a person would write is written from the history. */\nconst commitsFiles = (root: string, shell: Shell, options: ChangesetsOptions): VersioningPort => {\n const files = changesetsVersioning(options).create({ root, shell });\n const git = async (args: string[]) => {\n const { status, stdout } = await shell.capture(\"git\", args, { cwd: root });\n return status === 0 ? stdout.trim() : \"\";\n };\n\n /** The subjects since the commit that brought a version, a release's own aside. */\n const subjectsSince = async (folder: string, version: string) => {\n const since = await git([\n \"log\",\n \"-1\",\n \"--format=%H\",\n \"-S\",\n `\"version\": \"${version}\"`,\n \"--\",\n path.posix.join(folder, \"package.json\"),\n ]);\n if (!since) return [];\n const log = await git([\n \"log\",\n \"--format=%s\",\n `${since}..HEAD`,\n \"--\",\n folder,\n ...UNIT_FILES.map((file) => `:(exclude)${path.posix.join(folder, file)}`),\n ]);\n return log.split(\"\\n\").filter((subject) => subject && !isReleaseSubject(subject));\n };\n\n /** A pending changeset naming a package takes over from its commits. */\n const fromCommits = async () => {\n const [folders, written] = await Promise.all([files.folders(), files.pending()]);\n const config = Config.safeParse(readJson(path.join(root, \".changeset\", \"config.json\")));\n const ignored = new Set(config.success ? config.data.ignore : []);\n const packages = Object.entries(folders);\n // The root's folder holds every commit: beside other packages, it is not one of them.\n const moving = packages.filter(\n ([name, folder]) =>\n !(folder === \".\" && packages.length > 1) &&\n !ignored.has(name) &&\n !written.some(({ text }) => text.includes(`\"${name}\":`)),\n );\n const found = await Promise.all(\n moving.map(async ([name, folder]) => {\n const manifest = Manifest.safeParse(readJson(path.join(root, folder, \"package.json\")));\n if (!manifest.success) return [];\n const { version } = manifest.data;\n return changesetsFrom(name, version, await subjectsSince(folder, version));\n }),\n );\n return found.flat();\n };\n\n return {\n ...files,\n nextChange: \"a commit in the package\",\n pending: async () => [\n ...(await files.pending()),\n ...(await fromCommits()).map((changeset) => ({\n id: changeset.id,\n text: textOf(changeset),\n })),\n ],\n plan: async (added, held, ceiling) =>\n files.plan([...(await fromCommits()), ...added], held, ceiling),\n apply: async (added, held, ceiling) => {\n const commits = await fromCommits();\n await files.apply([...commits, ...added], held, ceiling);\n // A held unit's commits are still there next time: no file keeps them.\n commits.forEach(({ id }) =>\n fs.rmSync(path.join(root, files.changesetFile(id)), { force: true }),\n );\n },\n };\n};\n\nexport type CommitsVersioningAdapter = ServiceAdapter<VersioningPort>;\n\n/**\n * Versioning from Conventional Commits, with no changeset to write: the commits since each\n * package's version become the changesets of the release, and changesets does the rest. A pending\n * changeset naming a package still takes over from its commits.\n */\nexport const commitsVersioning = (options: ChangesetsOptions = {}): CommitsVersioningAdapter => ({\n name: \"commits\",\n create: ({ root, shell }) => commitsFiles(root, shell, options),\n});\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shiplane/changesets",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Versioning for shiplane: versions and changelogs from changesets.",
5
5
  "homepage": "https://github.com/arnaud-zg/packages/tree/main/packages/shiplane-changesets#readme",
6
6
  "bugs": {
@@ -32,10 +32,10 @@
32
32
  "prettier": "^3.8.3",
33
33
  "typescript": "6.0.3",
34
34
  "vitest": "^4.1.11",
35
- "shiplane": "0.4.0"
35
+ "shiplane": "0.4.1"
36
36
  },
37
37
  "peerDependencies": {
38
- "shiplane": "0.4.0"
38
+ "shiplane": "0.4.1"
39
39
  },
40
40
  "scripts": {
41
41
  "build": "tsdown",