Skip to content

Commit

Permalink
Add a script to generate GitHub release notes (#3199)
Browse files Browse the repository at this point in the history
* Add a script to generate GitHub release notes

* Link to comparison in release notes template

* Add total feature count to release notes template

* Fix spelling mistake in release notes template

* Default prerelease setting to true

* Remove inquirer dependency

* Document release notes script
  • Loading branch information
ddbeck authored and Elchi3 committed Jan 11, 2019
1 parent b9328e2 commit 2d8f8cf
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 14 deletions.
15 changes: 1 addition & 14 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,20 +50,7 @@ Regularly, a new release of [mdn-browser-compat-data](https://www.npmjs.com/pack
This step will trigger Travis to publish to npm automatically (see our [.travis.yml file](https://github.com/mdn/browser-compat-data/blob/master/.travis.yml)).
6. Check [Travis CI](https://travis-ci.org/mdn/browser-compat-data) again for the v0.0.43 build and also check [mdn-browser-compat-data on npm](https://www.npmjs.com/package/mdn-browser-compat-data) to see if `0.0.43` shows up correctly once Travis has finished its work.
7. Notify the [#mdndev](irc://irc.mozilla.org/mdndev) IRC channel on irc.mozilla.org about the new release and coordinate with jwhitlock or rjohnson a deployment of the new package to the MDN site.
8. Create a [new release on GitHub](https://github.com/mdn/browser-compat-data/releases) and write down release notes. Mention notable changes if non-data updates happened (schema, test, or infrastructure changes). Also record current statistics such as total number of contributors and stargazers, as well as the total number of features by running this node command in the main dir:
`node -p "bcd=require('.');i=0;JSON.parse(JSON.stringify(bcd),function(k,v){if(k==='__compat'){i++;}return i;})"`

Release notes template:
```
Notable changes:
- [TK text]
Statistics:
- [TK number] contributors have changed [TK number] files with [TK number] additions and [TK number] deletions in [TK number] commits [TK link to diff between version tags]
- [TK number] total contributors
- [TK number] total stargazers
- [TK number] total features
```
8. Create a new [release on GitHub](https://github.com/mdn/browser-compat-data/releases) by running `npm run release-notes -- v0.0.43`).

## Licensing

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"scripts": {
"confluence": "node ./node_modules/mdn-confluence/main/generate.es6.js --output-dir=. --bcd-module=./index.js",
"lint": "node test/lint",
"release-notes": "node test/release-notes",
"render": "node test/render",
"show-errors": "npm test 1> /dev/null",
"test": "npm run lint"
Expand Down
144 changes: 144 additions & 0 deletions test/release-notes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
const { execSync } = require('child_process');
const http = require('https');
const readline = require('readline');

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',
});
});

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 = async () => {
const { result } = await prompt([
{
name: 'result',
message: 'Does this release contain any schema, test, or infrastructure changes?',
type: confirm,
},
]);

if (!result) {
return 'None';
}
return 'REPLACE ME WITH ACTUAL RELEASE NOTES';
};

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}&prerelease=true&body=${encodedBody}`;
};

const main = async () => {
const version = argv.versionTag;
const previousVersion = execSync(`git describe --abbrev=0 ${version}^`, { encoding: 'utf8' }).trim();

const { commits, changed, insertions, deletions } = stats(version, previousVersion);

const { releaseContributors, totalContributors } = await contributors(version, previousVersion);
const changeMessage = await notableChanges();
const stars = await stargazers();
const features = countFeatures();

const body = `\
**Notable changes**
- ${changeMessage}
**Statistics**
- ${features} total features
- ${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})
- ${totalContributors} total contributors
- ${stars} total stargazers`;

console.log('\n\x1b[1mOpen this URL in a browser:\x1b[0m');
console.log(makeURL(version, body));
};

main();

0 comments on commit 2d8f8cf

Please sign in to comment.