Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1046 storybook3 release #2

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
a47bc01
Support GH_TOKEN authentication
shilman May 27, 2017
b27a02d
Report label groups in the order in which they're defined
shilman May 27, 2017
a1309ec
Added collapsible headings
shilman May 27, 2017
8635d01
Only handle PRs with ID > 500
shilman May 27, 2017
10a5982
"Smart collapse" formatting, skip labels
shilman May 27, 2017
973cfc0
Accept multiple valid labels for a single PR (choose first)
shilman May 27, 2017
f74d747
Update changelog format to match github-release-from-changelog
shilman May 27, 2017
a239dce
Update date format
shilman May 27, 2017
1811103
Update formatting to match Storybook lint settings
shilman May 28, 2017
86cdce0
Use up-to-date github PR title instead of merge-commit title
shilman May 28, 2017
439bf99
CHANGE CI config to just test in node 8
ndelangen Jul 28, 2017
a68e120
Expand dependencies.io batch upgrade PRs
shilman Nov 10, 2017
22d0656
Merge branch 'master' into 1046-storybook3-release
ndelangen Nov 10, 2017
df9d258
Allow prerelease tags to be considered in changelog generation
shilman Jan 19, 2018
5708e4c
Handle multi-line commit bodies
shilman Apr 20, 2018
d99283b
Generate changelog with cherry-picked merges
shilman Nov 6, 2018
839b836
Add prepare script so we can install from a GH repo
shilman Nov 6, 2018
65d1ef2
Try to preinstall
shilman Nov 6, 2018
e312c6d
Fix changelog formatting
shilman Jul 24, 2022
4fbe6a0
Fix updated label format
shilman Jul 24, 2022
bde123b
Add since-prerelease CLI option
shilman Jul 24, 2022
9a0b838
h2 formatting
shilman Jul 25, 2022
66d8333
Support CHANGELOG in parent directory
shilman Jul 27, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
language: node_js
node_js:
- "4"
- "6"
- "7"
- "8"
notifications:
email: false
after_success:
Expand Down
8 changes: 4 additions & 4 deletions bin/pr-log.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import cli from '../cli';
program
.version(config.version)
.option('--sloppy', 'Skip ensuring clean local git state.')
.option('--cherry-pick', 'Use cherry-picks instead of PR merges.')
.option('--since-prerelease', 'Use the latest prerelease as base.')
.usage('<version-number>')
.parse(process.argv);

const options = { sloppy: program.sloppy };
cli
.run(program.args[0], options)
.done();
const options = { sloppy: program.sloppy, cherryPick: program.cherryPick };
cli.run(program.args[0], options).done();
20 changes: 16 additions & 4 deletions lib/cli.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import path from 'path';
import fs from 'fs';
import prepend from 'prepend';
import bluebird from 'bluebird';
import ensureCleanLocalGitState from './ensureCleanLocalGitState';
import getMergedPullRequests from './getMergedPullRequests';
import expandDependencyUpgrades from './expandDependencyUpgrades';
import createChangelog from './createChangelog';
import getGithubRepo from './getGithubRepo';
import defaultValidLabels from './validLabels';
Expand All @@ -17,13 +19,20 @@ function stripTrailingEmptyLine(text) {
return text;
}

function getChangelogPath() {
const changelog = ['./CHANGELOG.md', '../CHANGELOG.md'].find(p => fs.existsSync(p))
return changelog || './CHANGELOG.md';
}

export default {
run: (newVersionNumber, options) => {
const packageConfig = require(path.join(process.cwd(), 'package.json'));
const githubRepo = getGithubRepo(packageConfig.repository.url);
const changelogPath = path.join(process.cwd(), 'CHANGELOG.md');
const changelogPath = getChangelogPath();
const prLogConfig = packageConfig['pr-log'];
const validLabels = prLogConfig && prLogConfig.validLabels || defaultValidLabels;
const validLabels = Object.assign({}, prLogConfig && Object.fromEntries(prLogConfig.validLabels) || defaultValidLabels);
const skipLabels = prLogConfig && prLogConfig.skipLabels || [];
skipLabels.forEach((label) => validLabels[label] = label);

if (!newVersionNumber) {
throw new Error('version-number not specified');
Expand All @@ -33,9 +42,12 @@ export default {
bluebird.resolve(true) :
bluebird.try(ensureCleanLocalGitState.bind(null, githubRepo));

const formatOptions = { validLabels, skipLabels };

return preconditions
.then(getMergedPullRequests.bind(null, githubRepo, validLabels))
.then(createChangelog.bind(null, newVersionNumber, validLabels))
.then(getMergedPullRequests.bind(null, githubRepo, validLabels, options.cherryPick))
.then(expandDependencyUpgrades)
.then(createChangelog.bind(null, newVersionNumber, formatOptions))
.then(stripTrailingEmptyLine)
.then(prependFile.bind(null, changelogPath));
}
Expand Down
35 changes: 22 additions & 13 deletions lib/createChangelog.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,32 @@
import moment from 'moment';
import R from 'ramda';

function createChangelog(newVersionNumber, validLabels, mergedPullRequests) {
const groupedPullRequests = R.groupBy(R.prop('label'), mergedPullRequests);
const date = moment().locale('en').format('MMMM D, YYYY');
const title = `## ${newVersionNumber} (${date})`;

let changelog = `${title}\n\n`;
function formatPR(pr) {
return `- ${pr.title} [#${pr.id}](https://github.com/storybooks/storybook/pull/${pr.id})\n`;
}

Object.keys(groupedPullRequests).forEach(function (label) {
const pullRequests = groupedPullRequests[label];
function formatExpanded(heading, pullRequests, options) {
let formatted = `#### ${heading}\n\n`;
pullRequests.forEach((pullRequest) => {
formatted += formatPR(pullRequest);
});
formatted += '\n';
return formatted;
}

changelog += `### ${validLabels[label]}\n\n`;
function createChangelog(newVersionNumber, formatOptions, mergedPullRequests) {
const { validLabels, skipLabels } = formatOptions;
const groupedPullRequests = R.groupBy(R.prop('label'), mergedPullRequests);
const date = moment().locale('en').format('LL');

pullRequests.forEach(function (pullRequest) {
changelog += `* ${pullRequest.title} (#${pullRequest.id})\n`;
});
let changelog = `## ${newVersionNumber} (${date})\n\n`;

changelog += '\n';
Object.keys(validLabels).forEach(function (label) {
const pullRequests = groupedPullRequests[label];
if (pullRequests && !R.contains(label, skipLabels)) {
const formatter = formatExpanded;
changelog += formatter(validLabels[label], pullRequests, formatOptions);
}
});

return changelog;
Expand Down
33 changes: 33 additions & 0 deletions lib/expandDependencyUpgrades.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import R from 'ramda';

export function parseUpgrades(description) {
if (description.startsWith('## Overview\n\nThe following dependencies have been updated:')) {
const parts = description.split('## Details');
if (parts.length === 2) {
return parts[0]
.trim()
.split('\n')
.filter((line) => line.startsWith('- '))
.map((line) => line.replace(/^- /, ''));
}
}
return null;
}

export function expandUpgradePR(pr) {
const { id, title, label, body } = pr;
const unexpanded = [ pr ];
if (title.match(/^Update \d+ dependencies from npm$/u)) {
const upgrades = parseUpgrades(body);
if (upgrades) {
return upgrades.map((line) => ({
id, label, body, title: `Upgraded ${line}`
}));
}
}
return unexpanded;
}

export default function expandDependencyUpgrades(prs) {
return R.flatten(prs.map(expandUpgradePR));
}
26 changes: 26 additions & 0 deletions lib/getGithubPullRequest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import rest from 'restling';

const accessToken = process.env.GH_TOKEN; // eslint-disable-line
const header = accessToken ? { accessToken } : {};

function getLabel(labels, validLabels) {
const validLabelNames = Object.keys(validLabels);
const listOfLabels = validLabelNames.join(', ');
const filteredLabels = labels.filter((label) => {
return validLabelNames.indexOf(label.name) !== -1;
});
return (filteredLabels.length === 0) ? 'other' : filteredLabels[0].name;
}

function getPullRequestLabel(githubRepo, validLabels, pullRequestId) {
const url = `https://api.github.com/repos/${githubRepo}/issues/${pullRequestId}`;
return rest.get(url, header)
.get('data')
.then((pr) => {
const { title, labels, body } = pr;
const label = getLabel(labels, validLabels);
return { id: pullRequestId, title, label, body };
});
}

export default getPullRequestLabel;
63 changes: 30 additions & 33 deletions lib/getMergedPullRequests.js
Original file line number Diff line number Diff line change
@@ -1,49 +1,46 @@
import git from 'git-promise';
import bluebird from 'bluebird';
import Promise from 'bluebird';
import semver from 'semver';
import getPullRequestLabel from './getPullRequestLabel';

function getLatestVersionTag() {
return git('tag --list')
.then(function (result) {
const tags = result.split('\n');
const versionTags = tags.filter((tag) => semver.valid(tag) && !semver.prerelease(tag));
const orderedVersionTags = versionTags.sort(semver.compare);

return orderedVersionTags[orderedVersionTags.length - 1];
});
import getGithubPullRequest from './getGithubPullRequest';

function getLatestVersionTag(sincePrerelease) {
return git('tag --list').then(function (result) {
const tags = result.split('\n');
const versionTags = tags.filter((tag) =>
semver.valid(tag) && (sincePrerelease ? semver.prerelease(tag) : !semver.prerelease(tag))
);

const orderedVersionTags = versionTags.sort(semver.compare);
return orderedVersionTags[orderedVersionTags.length - 1];
});
}

function getPullRequests(fromTag) {
return git(`log --no-color --pretty=format:"%s (%b)" --merges ${fromTag}..HEAD`)
.then((result) => {
const mergeCommits = result.replace(/[\r\n]+\)/g, ')').split('\n');
function getPullRequests(mergeType, fromTag) {
return git(`log --no-color --pretty=format:"%s (%b)%n%n" --${mergeType} ${fromTag}..HEAD`).then((result) => {
const mergeCommits = result.split('\n\n\n');

return mergeCommits
.map((commit) => commit.match(/^Merge pull request #(\d+) from (.*?) \((.*)\)$/u))
.filter((matches) => matches)
.map((matches) => ({ id: matches[1], title: matches[3] }));
});
const prCommits = mergeCommits
.map((commit) => commit.replace(/[\r\n]+/g, ''))
.map((commit) => commit.match(/^Merge pull request #(\d+) from (.*?) \((.*)\)$/u))
.filter((matches) => matches && parseInt(matches[1], 10) > 500)
.map((matches) => ({ id: matches[1], title: matches[3] }));

return prCommits;
});
}

function extendWithLabel(githubRepo, validLabels, pullRequests) {
const promises = pullRequests.map((pullRequest) => {
return getPullRequestLabel(githubRepo, validLabels, pullRequest.id)
.then((label) => {
return {
id: pullRequest.id,
title: pullRequest.title,
label
};
});
return getGithubPullRequest(githubRepo, validLabels, pullRequest.id);
});

return bluebird.all(promises);
return Promise.all(promises);
}

function getMergedPullRequests(githubRepo, validLabels) {
return getLatestVersionTag()
.then(getPullRequests)
function getMergedPullRequests(githubRepo, validLabels, cherryPick, sincePrerelease) {
const mergeType = cherryPick ? 'cherry-pick' : 'merges';
return getLatestVersionTag(sincePrerelease)
.then(getPullRequests.bind(null, mergeType))
.then(extendWithLabel.bind(null, githubRepo, validLabels));
}

Expand Down
25 changes: 0 additions & 25 deletions lib/getPullRequestLabel.js

This file was deleted.

11 changes: 7 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
"pretest": "eslint .",
"test": "nyc npm run test:unit",
"prepublish": "npm run build",
"test:unit": "mocha test",
"coveralls": "cat ./build/coverage/lcov.info | coveralls"
"test:unit": "mocha --compilers js:babel-core/register test",
"coveralls": "cat ./build/coverage/lcov.info | coveralls",
"preinstall": "npm run build"
},
"author": "Mathias Schreck <schreck.mathias@gmail.com>",
"license": "MIT",
Expand Down Expand Up @@ -57,7 +58,9 @@
"cache": false,
"all": true,
"check-coverage": true,
"require": [ "babel-register" ],
"require": [
"babel-register"
],
"sourceMap": true,
"instrumment": false,
"report-dir": "./build/coverage"
Expand All @@ -77,4 +80,4 @@
"contributors": [
"Alexander Schmidt <alexanderschmidt1@gmail.com>"
]
}
}
45 changes: 45 additions & 0 deletions test/unit/lib/expandDependencyUpgradesSpec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import chai from 'chai';

import sinonChai from 'sinon-chai';

import { expandUpgradePR } from '../../../lib/expandDependencyUpgrades';

const expect = chai.expect;
chai.use(sinonChai);

const validTitle = 'Update 10 dependencies from npm';
const invalidTitle = 'Foo bar baz';

const validBody = `## Overview

The following dependencies have been updated:

- react-textarea-autosize in \`addons/events\` from \`5.1.0\` to \`5.2.0\`
- react-textarea-autosize in \`addons/knobs\` from \`5.1.0\` to \`5.2.0\`

## Details

[Dependencies.io](https://www.dependencies.io) has updated react-textarea-autosize (a npm dependency in \`addons/events\`) from \`5.1.0\` to \`5.2.0\`.
`;
const invalidBody = 'Blah blah blah';

describe('expanding upgrades', () => {
const id = 1;
const label = 'test';
it('should skip prs with invalid titles', () => {
const pr = { id, label, title: invalidTitle, body: validBody };
expect(expandUpgradePR(pr)).to.deep.equal([ pr ]);
});
it('should skip prs with invalid bodies', () => {
const pr = { id, label, title: validTitle, body: invalidBody };
expect(expandUpgradePR(pr)).to.deep.equal([ pr ]);
});
it('should parse valid upgrades', () => {
const body = validBody;
const pr = { id, label, title: validTitle, body };
expect(expandUpgradePR(pr)).to.deep.equal([
{ id, label, body, title: 'Upgraded react-textarea-autosize in `addons/events` from `5.1.0` to `5.2.0`' },
{ id, label, body, title: 'Upgraded react-textarea-autosize in `addons/knobs` from `5.1.0` to `5.2.0`' }
]);
});
});
2 changes: 1 addition & 1 deletion test/unit/lib/getPullRequestLabelSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import sinonChai from 'sinon-chai';
import chaiAsPromised from 'chai-as-promised';
import bluebird from 'bluebird';
import rest from 'restling';
import getPullRequestLabel from '../../../lib/getPullRequestLabel';
import getPullRequestLabel from '../../../lib/getGithubPullRequest';
import defaultValidLabels from '../../../lib/validLabels';

const expect = chai.expect;
Expand Down