forked from thirdweb-dev/js
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathchangeset-explain-major.mjs
161 lines (135 loc) · 4.83 KB
/
changeset-explain-major.mjs
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// @ts-check
import getReleasePlanPkg from "@changesets/get-release-plan";
import parsePkg from "@changesets/parse";
import fs from "node:fs";
import path from "node:path";
/** @typedef { import("@changesets/get-release-plan").default } getReleasePlan */
/** @typedef { import("@changesets/parse").default } parse */
/** @type {getReleasePlan} */
// @ts-ignore
const getReleasePlan = getReleasePlanPkg.default;
/** @type {parse} */
// @ts-ignore
const parse = parsePkg.default;
const releasePlan = await getReleasePlan(".");
// a utility function to load the changeset given a changeset file name (e.g. "changeset-1.md")
const loadChangeset = (/** @type {string} */ changesetName) => {
const changesetPath = path.join(".", ".changeset", changesetName + ".md");
const changesetContents = fs.readFileSync(changesetPath, "utf8");
const parsed = parse(changesetContents);
return parsed;
};
// rename a given changeset file to a .xd extension so that it is ignored by changesets
const ignoreChangeset = (/** @type {string} */ changesetName) => {
const changesetPath = path.join(".", ".changeset", changesetName + ".md");
const ignoredChangesetPath = path.join(
".",
".changeset",
changesetName + ".xd",
);
try {
fs.renameSync(changesetPath, ignoredChangesetPath);
} catch (e) {
// noop
}
};
// rename a given changeset file to a .md extension so that it is no longer ignored by changesets
const unignoreChangeset = (/** @type {string} */ changesetName) => {
const ignoredChangesetPath = path.join(
".",
".changeset",
changesetName + ".xd",
);
const changesetPath = path.join(".", ".changeset", changesetName + ".md");
try {
fs.renameSync(ignoredChangesetPath, changesetPath);
} catch (e) {
// noop
}
};
// function to look at all files in the .changeset directory and rename any files that are .xd files back to .md files
const unignoreAllChangesets = () => {
const changesetDir = path.join(".", ".changeset");
const changesetFiles = fs.readdirSync(changesetDir);
for (const changesetFile of changesetFiles) {
if (changesetFile.endsWith(".xd")) {
unignoreChangeset(changesetFile.replace(".xd", ""));
}
}
};
async function findMajorChangesetForPackage(
/** @type {string} */ pkgName,
/** @type {string[]} */ ignoredChangesets = [],
) {
// load the current release plan
// ignore the changesets that were ignored
for (const changesetName of ignoredChangesets) {
ignoreChangeset(changesetName);
}
const releasePlan = await getReleasePlan(".");
// find the release plan entry for the given package
const releasePlanEntry = releasePlan.releases.find(
(release) => release.name === pkgName,
);
if (!releasePlanEntry) {
unignoreAllChangesets();
throw new Error("could not find release plan entry for " + pkgName);
}
let changesetsToCheck = releasePlan.changesets;
// ignore changesets that are part of the package's release plan first
if (releasePlanEntry) {
changesetsToCheck = changesetsToCheck.filter(
(changeset) => !releasePlanEntry.changesets.includes(changeset.id),
);
}
// if there a re no *other* changesets to check then fall back to trying *all* changesets
if (changesetsToCheck.length === 0) {
// try all (other) changesets
changesetsToCheck = releasePlan.changesets;
}
if (!changesetsToCheck.length) {
// unignore the changesets that were ignored
unignoreAllChangesets();
throw new Error("no changesets to check");
}
// check if the release plan entry is not a major release
if (releasePlanEntry.type === "major") {
// recurse to find the changeset that caused the major release
return await findMajorChangesetForPackage(
pkgName,
ignoredChangesets.concat(changesetsToCheck[0].id),
);
}
// unignore the changesets that were ignored
unignoreAllChangesets();
// otherwise return the changeset that caused the release
// it will have to be the last one in the list of ignored changesets
return ignoredChangesets.at(-1);
}
// find all releases that have major versions
const majorReleases = releasePlan.releases.filter(
(release) => release.type === "major",
);
const majorReleaseNames = majorReleases.map((release) => release.name);
if (!majorReleaseNames.length) {
console.log();
console.log("✅ No major releases found");
console.log();
}
for (const majorReleaseName of majorReleaseNames) {
let changesetName;
console.log("⌛️ Checking:", majorReleaseName);
try {
changesetName = await findMajorChangesetForPackage(majorReleaseName);
console.log(`✅ Changeset causing major version: ${changesetName}`);
console.log();
const changeset = loadChangeset(changesetName);
console.log(changeset.summary);
console.log();
} catch (err) {
console.error(
"❌ failed to find major bump changeset for " + majorReleaseName,
);
}
console.log();
}