-
Notifications
You must be signed in to change notification settings - Fork 330
/
Copy pathnotify.mjs
147 lines (129 loc) · 4.5 KB
/
notify.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
import { fileURLToPath } from 'node:url';
import fs from 'fs-extra';
import { globby as glob } from 'globby';
const { GITHUB_REF = 'main' } = process.env;
const baseUrl = new URL(`https://github.com/clerkinc/javascript/blob/${GITHUB_REF}/`);
/**
* @typedef {Object} PackageData
* @property {string} name
* @property {string} version
* @property {string} changelogUrl
*/
/**
* @typedef {Object} Pusher
* @property {string} username
* @property {string} avatarUrl
* @property {string} profileUrl
*/
/**
* @typedef {Object} ChangelogData
* @property {PackageData[]} packageData
* @property {string} releasePrUrl
* @property {Pusher} pusher
*/
/**
* @typedef {Object} Formatter
* @property {(data: ChangelogData) => string} generateChangelog
*/
/**
* Slack is using their own Markdown format, see:
* https://api.slack.com/reference/surfaces/formatting#basics
* https://app.slack.com/block-kit-builder
* @type {Formatter}
*/
const slackFormatter = {
generateChangelog: ({ packageData, releasePrUrl, pusher }) => {
const markdown = text => ({ type: 'section', text: { type: 'mrkdwn', text } });
const divider = () => ({ type: 'divider' });
const header = text => ({ type: 'header', text: { type: 'plain_text', text } });
const context = (imgUrl, text) => ({
type: 'context',
elements: [
...(imgUrl ? [{ type: 'image', image_url: imgUrl, alt_text: 'avatar' }] : []),
{ type: 'mrkdwn', text },
],
});
const blocks = [];
blocks.push(header(`Javascript SDKs - Stable Release - ${new Date().toLocaleDateString('en-US')}`));
let body = '';
for (const { name, version, changelogUrl } of packageData) {
body += `• <${changelogUrl}|Changelog> - \`${name}@${version}\`\n`;
}
blocks.push(markdown(`All release PRs for this day can be found <${releasePrUrl}|here>.\nReleased packages:\n`));
blocks.push(markdown(body));
// blocks.push(divider());
blocks.push(markdown('\n'));
blocks.push(context(pusher.avatarUrl, `<${pusher.profileUrl}|*${pusher.username}*> triggered this release.`));
return JSON.stringify({ blocks });
},
};
/**
* @type {Record<string, Formatter>}
*/
const formatters = {
slack: slackFormatter,
};
const run = async () => {
const releasedPackages = JSON.parse(process.argv[2]);
const packageToPathMap = await createPackageToPathMap();
const packageData = createPackageData(releasedPackages, packageToPathMap);
const releasePrUrl = createReleasePrUrl();
const pusher = createPusher(process.argv[3]);
const data = { packageData, releasePrUrl, pusher };
// TODO: Add support for more formatters
const formatter = formatters['slack'];
if (!formatter) {
throw new Error('Invalid formatter, supported formatters are: ' + Object.keys(formatters).join(', '));
}
console.log(formatter.generateChangelog(data));
};
run();
/*
* @returns {Pusher}
*/
const createPusher = username => {
return { username, avatarUrl: `https://github.com/${username}.png`, profileUrl: `https://github.com/${username}` };
};
/**
* @returns {Promise<Map<string,string>>}
*/
async function createPackageToPathMap() {
const map = new Map();
const packagesRoot = new URL('../packages/', import.meta.url);
const packages = await glob(['*/package.json', '*/*/package.json'], { cwd: fileURLToPath(packagesRoot) });
await Promise.all(
packages.map(async pkg => {
const packageJsonPath = fileURLToPath(new URL(pkg, packagesRoot));
const packageJson = fs.readJSONSync(packageJsonPath);
if (!packageJson.private && packageJson.version) {
map.set(packageJson.name, `./packages/${pkg.replace('/package.json', '')}`);
}
}),
);
return map;
}
/**
* @returns {PackageData[]}
*/
const createPackageData = (releasedPackages, packageToPathMap) => {
return releasedPackages.map(({ name, version }) => {
const relativePath = packageToPathMap.get(name);
if (!relativePath) {
throw new Error(`Not found: "${relativePath}"!`);
}
const changelogUrl = new URL(`${relativePath}/CHANGELOG.md#${version.replace(/\./g, '')}`, baseUrl).toString();
return { name, version, changelogUrl };
});
};
/**
* @returns {string}
*/
const createReleasePrUrl = () => {
// TODO: Get PR number using the GitHub API
// if (prNumber) {
// message += `\nView <https://github.com/clerkinc/javascript/pull/${prNumber}|release PR>`;
// }
return `https://github.com/clerkinc/javascript/pulls?q=is%3Apr+is%3Aclosed+Version+Packages+in%3Atitle+merged%3A${new Date()
.toISOString()
.slice(0, 10)}`;
};