Skip to content

Commit c693f4e

Browse files
committed
chore: custom changesets plugin
1 parent 3dcc4ef commit c693f4e

File tree

5 files changed

+390
-2
lines changed

5 files changed

+390
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import { getInfo, getInfoFromPullRequest } from "@changesets/get-github-info";
2+
import { config } from "dotenv";
3+
4+
config();
5+
6+
/**
7+
* @type {import("@changesets/types").ChangelogFunctions}
8+
*/
9+
const changelogFunctions = {
10+
getDependencyReleaseLine: async (
11+
changesets,
12+
dependenciesUpdated,
13+
options,
14+
) => {
15+
if (!options.repo) {
16+
throw new Error(
17+
"Please provide a repo to this changelog generator like this:\n\"changelog\": [\"@changesets/changelog-github\", { \"repo\": \"org/repo\" }]",
18+
);
19+
}
20+
if (dependenciesUpdated.length === 0) return "";
21+
22+
const changesetLink = `Updated dependencies [${(
23+
await Promise.all(
24+
changesets.map(async (cs) => {
25+
if (cs.commit) {
26+
let { links } = await getInfo({
27+
repo: options.repo,
28+
commit: cs.commit,
29+
});
30+
return links.commit;
31+
}
32+
}),
33+
)
34+
)
35+
.filter((_) => _)
36+
.join(", ")}]:`;
37+
38+
const updatedDepenenciesList = dependenciesUpdated.map(
39+
(dependency) => ` - ${dependency.name}@${dependency.newVersion}`,
40+
);
41+
42+
return [changesetLink, ...updatedDepenenciesList].join("\n");
43+
},
44+
getReleaseLine: async (changeset, type, options) => {
45+
if (!options || !options.repo) {
46+
throw new Error(
47+
"Please provide a repo to this changelog generator like this:\n\"changelog\": [\"@changesets/changelog-github\", { \"repo\": \"org/repo\" }]",
48+
);
49+
}
50+
51+
/** @type {number | undefined} */
52+
let prFromSummary;
53+
/** @type {string | undefined} */
54+
let commitFromSummary;
55+
/** @type {string[]} */
56+
let usersFromSummary = [];
57+
58+
const replacedChangelog = changeset.summary
59+
.replace(/^\s*(?:pr|pull|pull\s+request):\s*#?(\d+)/im, (_, pr) => {
60+
let num = Number(pr);
61+
if (!isNaN(num)) prFromSummary = num;
62+
return "";
63+
})
64+
.replace(/^\s*commit:\s*([^\s]+)/im, (_, commit) => {
65+
commitFromSummary = commit;
66+
return "";
67+
})
68+
.replace(/^\s*(?:author|user):\s*@?([^\s]+)/gim, (_, user) => {
69+
usersFromSummary.push(user);
70+
return "";
71+
})
72+
.trim();
73+
74+
const changelogLines = replacedChangelog
75+
.split("\n")
76+
.map((l) => l.trimRight());
77+
78+
const links = await (async () => {
79+
if (prFromSummary !== undefined) {
80+
let { links } = await getInfoFromPullRequest({
81+
repo: options.repo,
82+
pull: prFromSummary,
83+
});
84+
if (commitFromSummary) {
85+
const shortCommitId = commitFromSummary.slice(0, 7);
86+
links = {
87+
...links,
88+
commit: `[\`${shortCommitId}\`](https://github.com/${options.repo}/commit/${commitFromSummary})`,
89+
};
90+
}
91+
return links;
92+
}
93+
const commitToFetchFrom = commitFromSummary || changeset.commit;
94+
if (commitToFetchFrom) {
95+
let { links } = await getInfo({
96+
repo: options.repo,
97+
commit: commitToFetchFrom,
98+
});
99+
return links;
100+
}
101+
return { commit: null, pull: null, user: null };
102+
})();
103+
104+
const users = usersFromSummary.length
105+
? usersFromSummary
106+
.map(
107+
(userFromSummary) =>
108+
`[@${userFromSummary}](https://github.com/${userFromSummary})`,
109+
)
110+
.join(", ")
111+
: links.user;
112+
113+
const prefix = [
114+
links.pull === null ? "" : ` ${links.pull}`,
115+
links.commit === null ? "" : ` ${links.commit}`,
116+
users === null ? "" : ` Thanks ${users}!`,
117+
].join("");
118+
119+
return `\n\n📝 ${prefix ? `${prefix}` : ""}\n\n${changelogLines.join("\n")}`;
120+
},
121+
};
122+
123+
export default changelogFunctions;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"name": "@spectrum-tools/changesets-changelog-github",
3+
"version": "0.0.0",
4+
"description": "A changelog entry generator for GitHub that links to commits, PRs and users",
5+
"license": "Apache-2.0",
6+
"author": "Adobe",
7+
"homepage": "https://opensource.adobe.com/spectrum-css/",
8+
"repository": {
9+
"type": "git",
10+
"url": "https://github.com/adobe/spectrum-css.git",
11+
"directory": "plugins/changesets-changelog-github"
12+
},
13+
"bugs": {
14+
"url": "https://github.com/adobe/spectrum-css/issues"
15+
},
16+
"type": "module",
17+
"module": "index.js",
18+
"dependencies": {
19+
"@changesets/get-github-info": "^0.6.0",
20+
"@changesets/types": "^6.1.0",
21+
"dotenv": "^16.4.7"
22+
},
23+
"devDependencies": {
24+
"@changesets/parse": "^0.4.1",
25+
"ava": "^6.2.0",
26+
"sinon": "^20.0.0"
27+
},
28+
"keywords": [
29+
"design-system",
30+
"spectrum",
31+
"spectrum-css",
32+
"adobe",
33+
"adobe-spectrum"
34+
]
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
3+
"name": "changesets-changelog-github",
4+
"tags": ["tooling", "changesets", "plugin"],
5+
"targets": {
6+
"format": { "defaultConfiguration": "plugins" },
7+
"lint": { "defaultConfiguration": "plugins" },
8+
"test": { "defaultConfiguration": "plugins" }
9+
}
10+
}
+143
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import parse from "@changesets/parse";
2+
import test from "ava";
3+
import sinon from "sinon";
4+
import changelogFunctions from "./index.js";
5+
6+
/** @type {sinon.SinonSandbox} */
7+
let sandbox;
8+
9+
const data = {
10+
commit: "a085003",
11+
user: "Andarist",
12+
pull: 1613,
13+
repo: "emotion-js/emotion",
14+
};
15+
16+
test.beforeEach((t) => {
17+
sandbox = sinon.createSandbox();
18+
const stub = sandbox.stub("@changesets/get-github-info");
19+
stub.getInfo.returns({
20+
pull: data.pull,
21+
user: data.user,
22+
links: {
23+
user: `[@${data.user}](https://github.com/${data.user})`,
24+
pull: `[#${data.pull}](https://github.com/${data.repo}/pull/${data.pull})`,
25+
commit: `[\`${data.commit}\`](https://github.com/${data.repo}/commit/${data.commit})`,
26+
},
27+
});
28+
29+
stub.getInfoFromPullRequest.returns({
30+
commit: data.commit,
31+
user: data.user,
32+
links: {
33+
user: `[@${data.user}](https://github.com/${data.user})`,
34+
pull: `[#${data.pull}](https://github.com/${data.repo}/pull/${data.pull})`,
35+
commit: `[\`${data.commit}\`](https://github.com/${data.repo}/commit/${data.commit})`,
36+
},
37+
});
38+
});
39+
40+
test.afterEach.always(() => {
41+
sandbox.restore();
42+
});
43+
44+
/**
45+
*
46+
* @param {string} content
47+
* @param {string|undefined} commit
48+
* @returns
49+
*/
50+
const getChangeset = (content, commit) => {
51+
return [
52+
{
53+
...parse(
54+
`---
55+
pkg: "minor"
56+
---
57+
58+
something
59+
${content}
60+
`
61+
),
62+
id: "some-id",
63+
commit,
64+
},
65+
"minor",
66+
{ repo: data.repo },
67+
];
68+
};
69+
70+
[data.commit, "wrongcommit", undefined].forEach((commitFromChangeset) => {
71+
["pr", "pull request", "pull"].forEach((keyword) => {
72+
test(`with commit from changeset of ${commitFromChangeset} override pr with ${keyword} keyword with #`, async (t) => {
73+
t.is(
74+
await changelogFunctions.getReleaseLine(
75+
...getChangeset(
76+
`${keyword}: #${data.pull}`,
77+
commitFromChangeset
78+
)
79+
),
80+
"\n\n- [#1613](https://github.com/emotion-js/emotion/pull/1613) [`a085003`](https://github.com/emotion-js/emotion/commit/a085003) Thanks [@Andarist](https://github.com/Andarist)! - something\n"
81+
);
82+
});
83+
84+
test(`with commit from changeset of ${commitFromChangeset} override pr with pr ${keyword} without #`, async (t) => {
85+
t.is(
86+
await changelogFunctions.getReleaseLine(
87+
...getChangeset(
88+
`pr: ${data.pull}`,
89+
commitFromChangeset
90+
)
91+
),
92+
"\n\n- [#1613](https://github.com/emotion-js/emotion/pull/1613) [`a085003`](https://github.com/emotion-js/emotion/commit/a085003) Thanks [@Andarist](https://github.com/Andarist)! - something\n"
93+
);
94+
});
95+
});
96+
97+
test(`override commit ${commitFromChangeset} with commit keyword`, async (t) => {
98+
t.is(
99+
await changelogFunctions.getReleaseLine(
100+
...getChangeset(`commit: ${data.commit}`, commitFromChangeset)
101+
),
102+
"\n\n- [#1613](https://github.com/emotion-js/emotion/pull/1613) [`a085003`](https://github.com/emotion-js/emotion/commit/a085003) Thanks [@Andarist](https://github.com/Andarist)! - something\n"
103+
);
104+
});
105+
});
106+
107+
["author", "user"].forEach((keyword) => {
108+
test(`override author with ${keyword} keyword with @`, async (t) => {
109+
t.is(
110+
await changelogFunctions.getReleaseLine(
111+
...getChangeset(
112+
`${keyword}: @other`,
113+
data.commit
114+
)
115+
),
116+
"\n\n- [#1613](https://github.com/emotion-js/emotion/pull/1613) [`a085003`](https://github.com/emotion-js/emotion/commit/a085003) Thanks [@other](https://github.com/other)!\n\nsomething\n"
117+
);
118+
});
119+
120+
test(`override author with ${keyword} keyword without @`, async (t) => {
121+
t.is(
122+
await changelogFunctions.getReleaseLine(
123+
...getChangeset(
124+
`${keyword}: other`,
125+
data.commit
126+
)
127+
),
128+
"\n\n- [#1613](https://github.com/emotion-js/emotion/pull/1613) [`a085003`](https://github.com/emotion-js/emotion/commit/a085003) Thanks [@other](https://github.com/other)!\n\nsomething\n"
129+
);
130+
});
131+
});
132+
133+
test("with multiple authors", async (t) => {
134+
t.is(
135+
await changelogFunctions.getReleaseLine(
136+
...getChangeset(
137+
["author: @Andarist", "author: @mitchellhamilton"].join("\n"),
138+
data.commit
139+
)
140+
),
141+
`
142+
- [#1613](https://github.com/emotion-js/emotion/pull/1613) [\`a085003\`](https://github.com/emotion-js/emotion/commit/a085003) Thanks [@Andarist](https://github.com/Andarist), [@mitchellhamilton](https://github.com/mitchellhamilton)!\n\nsomething`);
143+
});

0 commit comments

Comments
 (0)