Merge pull request #2786 from thelounge/xpaw/fix-changelog

Update changelog generator script
This commit is contained in:
Jérémie Astori 2018-12-15 23:44:29 -05:00 committed by GitHub
commit 263d2ca133
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -78,7 +78,11 @@ if (!version) {
version = semver.inc(packageJson.version, process.argv[2]);
}
if (!/^[0-9]+\.[0-9]+\.[0-9]+(-(pre|rc)+\.[0-9]+)?$/.test(version)) {
function isValidVersion(str) {
return (/^[0-9]+\.[0-9]+\.[0-9]+(-(pre|rc)+\.[0-9]+)?$/.test(str));
}
if (!isValidVersion(version)) {
log.error(`Argument ${colors.bold("version")} is incorrect It must be either:`);
log.error(`- A keyword among: ${colors.green("major")}, ${colors.green("minor")}, ${colors.green("patch")}, ${colors.green("prerelease")}, ${colors.green("pre")}`);
log.error(`- An explicit version of format ${colors.green("x.y.z")} (stable) or ${colors.green("x.y.z-(pre|rc).n")} (pre-release).`);
@ -151,7 +155,7 @@ ${printList(items.documentation)}`
}
${_.isEmpty(items.websiteDocumentation) ? "" :
`On the [website repository](https://github.com/thelounge/thelounge.chat):
`On the [website repository](https://github.com/thelounge/thelounge.github.io):
${printList(items.websiteDocumentation)}`
}
@ -340,13 +344,25 @@ class RepositoryFetcher {
return data.repository.milestones.nodes.find(({title}) => title === targetVersion);
}
async fetchChunkedPullRequests(numbers) {
const chunks = _.chunk(numbers, 100);
let result = {};
for (const chunk of chunks) {
const data = await this.fetchPullRequests(chunk);
result = _.merge(result, data);
}
return result;
}
// Given a list of PR numbers, retrieve information for all those PRs. They
// are returned as a hash whose keys are `PR<number>`.
// This is a bit wonky (generating a dynamic GraphQL query) but the GitHub API
// does not have a way to retrieve multiple PRs given a list of IDs.
async fetchPullRequests(numbers) {
if (numbers.length === 0) {
return [];
return {};
}
const prQuery = `query fetchPullRequests($repositoryName: String!) {
@ -386,7 +402,7 @@ class RepositoryFetcher {
const taggedCommit = await this.fetchTaggedCommit(tag);
const commits = await this.fetchCommitsSince(taggedCommit);
const pullRequestIds = pullRequestNumbersInCommits(commits);
const pullRequests = await this.fetchPullRequests(pullRequestIds);
const pullRequests = await this.fetchChunkedPullRequests(pullRequestIds);
return combine(commits, pullRequests);
}
}
@ -485,11 +501,12 @@ ${printList(items)}
const dependencies = Object.keys(packageJson.dependencies);
const devDependencies = Object.keys(packageJson.devDependencies);
const optionalDependencies = Object.keys(packageJson.optionalDependencies);
// Returns the package.json section in which that package exists, or undefined
// if that package is not listed there.
function whichDependencyType(packageName) {
if (dependencies.includes(packageName)) {
if (dependencies.includes(packageName) || optionalDependencies.includes(packageName)) {
return "dependencies";
} else if (devDependencies.includes(packageName)) {
return "devDependencies";
@ -508,12 +525,20 @@ function hasLabel(labels, expected) {
function hasAnnotatedComment(comments, expected) {
return comments && comments.nodes.some(({authorAssociation, body}) =>
["OWNER", "MEMBER"].includes(authorAssociation) &&
body.split("\n").includes(`[${expected}]`)
body.split("\r\n").includes(`[${expected}]`)
);
}
function isSkipped(entry) {
return hasLabelOrAnnotatedComment(entry, "Meta: Skip Changelog");
return (
(entry.messageHeadline && (
// Version bump commits created by `yarn version`
isValidVersion(entry.messageHeadline) ||
// Commit message suggested by this script
entry.messageHeadline.startsWith("Add changelog entry for v")
)) ||
hasLabelOrAnnotatedComment(entry, "Meta: Skip Changelog")
);
}
// Dependency update PRs are listed in a special, more concise way in the changelog.
@ -550,8 +575,20 @@ function isFeature({labels}) {
// Update `stylelint` to v1.2.3
// Update `express` and `ua-parser-js` to latest versions
// Update `express`, `chai`, and `ua-parser-js` to ...
function extractPackages(title) {
return /^Update ([\w-,`. ]+) to /.exec(title)[1]
// Update @fortawesome/fontawesome-free-webfonts to the latest version
// Update dependency request to v2.87.0
// chore(deps): update dependency mini-css-extract-plugin to v0.4.3
// fix(deps): update dependency web-push to v3.3.3
// chore(deps): update babel monorepo to v7.1.0
function extractPackages({title, url}) {
const extracted = /(?:U|u)pdate(?: dependency)? ([\w-,` ./@]+?) (?:monorepo )?to /.exec(title);
if (!extracted) {
log.warn(`Failed to extract package from: ${title} ${colors.gray(url)}`);
return [];
}
return extracted[1]
.replace(/`/g, "")
.split(/, and |, | and /);
}
@ -560,10 +597,12 @@ function extractPackages(title) {
// based on different information that describes them.
function parse(entries) {
return entries.reduce((result, entry) => {
let deps;
if (isSkipped(entry)) {
result.skipped.push(entry);
} else if (isDependency(entry)) {
extractPackages(entry.title).forEach((packageName) => {
} else if (isDependency(entry) && (deps = extractPackages(entry))) {
deps.forEach((packageName) => {
const dependencyType = whichDependencyType(packageName);
if (dependencyType) {
@ -573,7 +612,7 @@ function parse(entries) {
result[dependencyType][packageName].push(entry);
} else {
log.info(`${colors.bold(packageName)} was updated in ${colors.green("#" + entry.number)} then removed since last release. Skipping.`);
log.info(`${colors.bold(packageName)} was updated in ${colors.green("#" + entry.number)} then removed since last release. Skipping. ${colors.gray(entry.url)}`);
}
});
} else if (isDocumentation(entry)) {
@ -654,8 +693,9 @@ async function generateChangelogEntry(targetVersion) {
items.milestone = await codeRepo.fetchMilestone(targetVersion);
contributors = extractContributors(codeCommitsAndPullRequests);
const websiteRepo = new RepositoryFetcher(client, "thelounge.chat");
items.websiteDocumentation = await websiteRepo.fetchCommitsAndPullRequestsSince("v" + previousVersion);
const websiteRepo = new RepositoryFetcher(client, "thelounge.github.io");
const previousWebsiteVersion = await websiteRepo.fetchPreviousVersion(targetVersion);
items.websiteDocumentation = await websiteRepo.fetchCommitsAndPullRequestsSince("v" + previousWebsiteVersion);
}
items.version = targetVersion;