Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Commit

Permalink
Improve changelog script (#1543)
Browse files Browse the repository at this point in the history
The changelog script now has the following:

- constructed more modularly for easier maintenance.
- removed coupling to blocks repository so it can be used in more contexts (potentially publishing as it's own package).
- switched to use github v4 api (graphql) to reduce number of requests (reducing the likelihood of hitting api limits)
- added support for zenhub releases instead of github milestones for what pulls to derive changelog from.
  • Loading branch information
nerrad authored Jan 13, 2020
1 parent 6ae5eb9 commit 1c44e3b
Show file tree
Hide file tree
Showing 14 changed files with 532 additions and 235 deletions.
176 changes: 0 additions & 176 deletions bin/changelog.js

This file was deleted.

80 changes: 80 additions & 0 deletions bin/changelog/common/get-entry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
'use strict';

const requestPromise = require( 'request-promise' );
const { graphql } = require( '@octokit/graphql' );
const { pkg, REPO } = require( '../config' );

/* eslint no-console: 0 */

const headers = {
authorization: `token ${ process.env.GH_API_TOKEN }`,
'user-agent': 'changelog-tool',
};

const authedGraphql = graphql.defaults( { headers } );

const getPullRequestType = ( labels ) => {
const typeLabel = labels.find( ( label ) =>
label.name.includes( pkg.changelog.labelPrefix )
);
if ( ! typeLabel ) {
return pkg.changelog.defaultPrefix;
}
return typeLabel.name.replace( `${ pkg.changelog.labelPrefix } `, '' );
};

const isCollaborator = async ( username ) => {
return requestPromise( {
url: `https://api.github.com/orgs/${
REPO.split( '/' )[ 0 ]
}/members/${ username }`,
headers,
resolveWithFullResponse: true,
} )
.then( ( response ) => {
return response.statusCode === 204;
} )
.catch( ( err ) => {
if ( err.statusCode !== 404 ) {
console.log( '🤯' );
console.log( err.message );
}
} );
};

const getEntry = async ( pullRequest ) => {
if (
pullRequest.labels.nodes.some(
( label ) => label.name === pkg.changelog.skipLabel
)
) {
return;
}

const collaborator = await isCollaborator( pullRequest.author.login );
const type = getPullRequestType( pullRequest.labels.nodes );
const authorTag = collaborator ? '' : `👏 @${ pullRequest.author.login }`;
let title;
if ( /### Changelog\r\n\r\n> /.test( pullRequest.body ) ) {
const bodyParts = pullRequest.body.split( '### Changelog\r\n\r\n> ' );
const note = bodyParts[ bodyParts.length - 1 ];
title = note
// Remove comment prompt
.replace( /<!---(.*)--->/gm, '' )
// Remove new lines and whitespace
.trim();
if ( ! title.length ) {
title = `${ type }: ${ pullRequest.title }`;
} else {
title = `${ type }: ${ title }`;
}
} else {
title = `${ type }: ${ pullRequest.title }`;
}
return `- ${ title } [#${ pullRequest.number }](${ pullRequest.url }) ${ authorTag }`;
};

module.exports = {
authedGraphql,
getEntry,
};
4 changes: 4 additions & 0 deletions bin/changelog/common/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const { authedGraphql } = require( './get-entry' );
const { make } = require( './make' );

module.exports = { authedGraphql, make };
34 changes: 34 additions & 0 deletions bin/changelog/common/make.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
'use strict';

const chalk = require( 'chalk' );
const { getEntry } = require( './get-entry' );

/* eslint no-console: 0*/

const make = async ( pullRequestFetcher, version ) => {
const pullRequests = await pullRequestFetcher( version );
let entries = await Promise.all(
pullRequests.map( async ( pr ) => await getEntry( pr ) )
);
if ( ! entries || ! entries.length ) {
console.log(
chalk.yellow( "This version doesn't have any associated PR." )
);
return;
}

entries = entries.filter( Boolean );

if ( ! entries || ! entries.length ) {
console.log(
chalk.yellow(
'None of the PRs of this version are eligible for the changelog.'
)
);
return;
}
entries.sort();
console.log( entries.join( '\n' ) );
};

module.exports = { make };
23 changes: 23 additions & 0 deletions bin/changelog/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
'use strict';

const pkg = require( '../../package.json' );

const REPO = pkg.repository.url
// remove https://github.com:
.split( ':' )[ 2 ]
// remove the .git ending.
.slice( 0, -4 );

if ( pkg.changelog === undefined ) {
pkg.changelog = {
labelPrefix: 'type:',
skipLabel: 'no-changelog',
defaultPrefix: 'dev',
zenhub: false,
};
}

module.exports = {
pkg,
REPO,
};
7 changes: 7 additions & 0 deletions bin/changelog/github/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
'use-strict';

const { makeChangeLog } = require( './make-change-log' );

module.exports = {
makeChangeLog,
};
64 changes: 64 additions & 0 deletions bin/changelog/github/make-change-log.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
'use strict';
const chalk = require( 'chalk' );
const promptly = require( 'promptly' );
const { REPO, pkg } = require( '../config' );
const { make } = require( '../common' );
const { fetchAllPullRequests } = require( './requests' );

/* eslint no-console: 0 */

const makeChangeLog = async () => {
console.log(
chalk.yellow(
'This program requires an api token. You can create one here: '
) + 'https://github.com/settings/tokens'
);
console.log( '' );
console.log(
chalk.yellow(
'Token scope will require read permissions on public_repo, admin:org, and user.'
)
);
console.log( '' );
console.log(
chalk.yellow(
'Export the token as variable called GH_API_TOKEN from your bash profile.'
)
);
console.log( '' );

const ready = await promptly.confirm( 'Are you ready to continue? ' );

if ( ready ) {
console.log( '' );
console.log(
chalk.yellow(
'In order to generate the changelog, you will have to provide a version number to retrieve the PRs from.'
)
);
console.log( '' );
console.log(
chalk.yellow( 'Write it as it appears in the milestones page: ' ) +
`https://github.com/${ REPO }/milestones`
);
console.log( '' );
const version = await promptly.prompt( 'Version number: ' );
console.log( '' );
console.log(
chalk.green(
'Here is the generated changelog. Be sure to remove entries ' +
`not intended for a ${ pkg.title } release.`
)
);
console.log( '' );
make( fetchAllPullRequests, version );
} else {
console.log( '' );
console.log( chalk.yellow( 'Ok, see you soon.' ) );
console.log( '' );
}
};

module.exports = {
makeChangeLog,
};
Loading

0 comments on commit 1c44e3b

Please sign in to comment.