File size: 3,251 Bytes
a03b3ba
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
const { join } = require("path");
const { readFileSync, existsSync, writeFileSync, unlinkSync } = require("fs");
const { getPackagesSync } = require("@manypkg/get-packages");

const RE_PKG_NAME = /^[\w-]+\b/;
const pkg_meta = getPackagesSync(process.cwd());

/**
 * @typedef {{dirs: string[], highlight: {summary: string}[], feat: {summary: string}[], fix: {summary: string}[], current_changelog: string}} ChangesetMeta
 */

/**
 * @typedef {{[key: string]: ChangesetMeta}} ChangesetMetaCollection
 */

function run() {
	if (!existsSync(join(pkg_meta.rootDir, ".changeset", "_changelog.json"))) {
		console.warn("No changesets to process");
		return;
	}

	/**
	 * @type { ChangesetMetaCollection & { _handled: string[] } }}
	 */
	const { _handled, ...packages } = JSON.parse(
		readFileSync(
			join(pkg_meta.rootDir, ".changeset", "_changelog.json"),
			"utf-8"
		)
	);

	/**
	 * @typedef { {packageJson: {name: string, version: string, python: boolean}, dir: string} } PackageMeta
	 */

	/**
	 * @type { {[key:string]: PackageMeta} }
	 */
	const all_packages = pkg_meta.packages.reduce((acc, pkg) => {
		acc[pkg.packageJson.name] = /**@type {PackageMeta} */ (
			/** @type {unknown} */ (pkg)
		);
		return acc;
	}, /** @type {{[key:string] : PackageMeta}} */ ({}));

	for (const pkg_name in packages) {
		const { dirs, highlight, feat, fix, current_changelog } =
			/**@type {ChangesetMeta} */ (packages[pkg_name]);

		const { version, python } = all_packages[pkg_name].packageJson;

		const highlights = highlight.map((h) => `${h.summary}`);
		const features = feat.map((f) => `- ${f.summary}`);
		const fixes = fix.map((f) => `- ${f.summary}`);

		const release_notes = /** @type {[string[], string][]} */ ([
			[highlights, "### Highlights"],
			[features, "### Features"],
			[fixes, "### Fixes"]
		])
			.filter(([s], i) => s.length > 0)
			.map(([lines, title]) => {
				if (title === "### Highlights") {
					return `${title}\n\n${lines.join("\n\n")}`;
				}

				return `${title}\n\n${lines.join("\n")}`;
			})
			.join("\n\n");

		const new_changelog = `# ${pkg_name}

## ${version}

${release_notes}

${current_changelog.replace(`# ${pkg_name}`, "").trim()}
`.trim();

		dirs.forEach((dir) => {
			writeFileSync(join(dir, "CHANGELOG.md"), new_changelog);
		});

		if (python) {
			bump_local_dependents(pkg_name, version);
		}
	}

	unlinkSync(join(pkg_meta.rootDir, ".changeset", "_changelog.json"));

	/**
	 * @param {string} pkg_to_bump The name of the package to bump
	 * @param {string} version The version to bump to
	 * @returns {void}
	 * */
	function bump_local_dependents(pkg_to_bump, version) {
		for (const pkg_name in all_packages) {
			const {
				dir,
				packageJson: { python }
			} = all_packages[pkg_name];

			if (!python) continue;

			const requirements_path = join(dir, "..", "requirements.txt");
			const requirements = readFileSync(requirements_path, "utf-8").split("\n");

			const pkg_index = requirements.findIndex((line) => {
				const m = line.trim().match(RE_PKG_NAME);
				if (!m) return false;
				return m[0] === pkg_to_bump;
			});

			if (pkg_index !== -1) {
				requirements[pkg_index] = `${pkg_to_bump}==${version}`;
				writeFileSync(requirements_path, requirements.join("\n"));
			}
		}
	}
}

run();