mdn-browser-compat-data
Version:
Browser compatibility data provided by MDN Web Docs
184 lines (159 loc) • 5.07 kB
JavaScript
const { execSync } = require('child_process');
const http = require('https');
const readline = require('readline');
const chalk = require('chalk');
const bcd = require('..');
const { argv } = require('yargs').command(
'$0 <version-tag>',
'Initiate a release of this package on GitHub',
yargs => {
yargs.positional('version-tag', {
describe: 'the version tag to generate release notes for',
type: 'string',
});
yargs.option('p', {
alias: 'previous',
requiresArg: true,
describe: 'the previous version tag',
type: 'string',
});
},
);
const getJSON = url =>
new Promise((resolve, reject) =>
http.get(
url,
{ headers: { 'User-Agent': 'bcd-release-script' } },
response => {
let body = '';
response.on('data', data => {
body += data;
});
response.on('error', error => reject(error));
response.on('end', () => {
resolve(JSON.parse(body));
});
},
),
);
const question = query => {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
return new Promise(resolve => rl.question(query, resolve)).then(response => {
rl.close();
return response;
});
};
const confirm = str => !['n', 'no'].includes(str.toLowerCase());
const prompt = async questions => {
const results = {};
for (const q of questions) {
const options = q.type === confirm ? '(Y/n) ' : '';
results[q.name] = await question(`${q.message} ${options}`).then(q.type);
}
return results;
};
const stargazers = () =>
getJSON('https://api.github.com/repos/mdn/browser-compat-data').then(
json => json.stargazers_count,
);
const stats = (version, previousVersion) => {
// Get just the diff stats summary
const diff = execSync(
`git diff --shortstat ${previousVersion}...${version}`,
{ encoding: 'utf8' },
).trim();
// Extract the numbers from a line like this:
// 50 files changed, 1988 insertions(+), 2056 deletions(-)
const [, changed, insertions, deletions] = diff.match(
/(\d+) files* changed, (\d+) insertions*\(\+\), (\d+) deletions*/,
);
// Get the number of commits
const commits = execSync(
`git rev-list --count ${previousVersion}...${version}`,
{ encoding: 'utf8' },
).trim();
return {
commits,
changed,
insertions,
deletions,
};
};
const contributors = (version, previousVersion) =>
prompt([
{
name: 'releaseContributors',
type: Number,
message: `Find "contributors" at https://github.com/mdn/browser-compat-data/compare/${previousVersion}...${version}\nHow many people have contributed to this release?`,
},
{
name: 'totalContributors',
type: Number,
message:
'Find "contributors" at https://github.com/mdn/browser-compat-data/\nHow many people have contributed to browser-compat-data overall?',
},
]);
const notableChanges = previousReleaseDate => {
const searchUrl = new URL('https://github.com/mdn/browser-compat-data/pulls');
const querySafeDate = previousReleaseDate.replace('+', '%2B');
searchUrl.search = `q=is:pr merged:>=${querySafeDate} label:"needs-release-note :newspaper:"`;
return `SUMMARIZE THESE PRs: ${searchUrl.href}`;
};
const countFeatures = () => {
let count = 0;
JSON.parse(JSON.stringify(bcd), k => {
if (k === '__compat') {
count++;
}
return count;
});
return count;
};
const makeURL = (version, body) => {
const baseURL = 'https://github.com/mdn/browser-compat-data/releases/new';
// Adhering to RFC 3986 makes the full link clickable in Terminal.app
const encodedBody = encodeURIComponent(body).replace(
/[!'()*]/g,
c => `%${c.charCodeAt(0).toString(16)}`,
);
return `${baseURL}?title=${version}&tag=${version}&body=${encodedBody}`;
};
const main = async () => {
const version = argv.versionTag;
const previousVersion =
argv.previous ||
execSync(`git describe --abbrev=0 ${version}^`, {
encoding: 'utf8',
}).trim();
const previousReleaseDate = execSync(
`git log -1 --format=%aI ${previousVersion}`,
{
encoding: 'utf8',
},
).trim();
const { commits, changed, insertions, deletions } = stats(
version,
previousVersion,
);
const { releaseContributors, totalContributors } = await contributors(
version,
previousVersion,
);
const changeMessage = notableChanges(previousReleaseDate);
const stars = await stargazers();
const features = countFeatures();
const body = `\
**Notable changes**
- ${changeMessage}
**Statistics**
- ${releaseContributors} contributors have changed ${changed} files with ${insertions} additions and ${deletions} deletions in ${commits} commits (https://github.com/mdn/browser-compat-data/compare/${previousVersion}...${version})
- ${features} total features
- ${totalContributors} total contributors
- ${stars} total stargazers`;
console.log(chalk.bold('\nOpen this URL in a browser:'));
console.log(makeURL(version, body));
};
main();