-
Notifications
You must be signed in to change notification settings - Fork 979
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: add release notes tooling (#665)
- Loading branch information
Showing
4 changed files
with
122 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
## Requirements | ||
``` | ||
npm install -g git-release-notes | ||
``` | ||
|
||
## Usage | ||
``` | ||
git release-notes -f release-notes.json PREVIOUS..CURRENT release-notes-md.ejs | ||
``` | ||
Where PREVIOUS is the previous release tag, and CURRENT is the current release tag |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<% | ||
const typeGroups = { | ||
feats: { title: 'Features:', types: ['feat'] }, | ||
fixes: { title: 'Fixes:', types: ['fix'] }, | ||
etc: { | ||
title: 'Other changes (not related to library code):', | ||
types: ['docs','style','refactor','perf','test','build','ci','chore'] | ||
}, | ||
unknown: { title: 'Unknown:', types: ['?'] }, | ||
} | ||
const commitTypes = { | ||
feat: '✨', fix: '🐛', docs: '📚', style: '💎', | ||
refactor: '🔨', perf: '🚀', test: '🚨', build: '📦', | ||
ci: '⚙️', chore: '🔧', ['?']: '❓', | ||
} | ||
for(const group of Object.values(typeGroups)){ | ||
const groupCommits = commits.filter(c => group.types.includes(c.type)); | ||
if (groupCommits.length < 1) continue; | ||
%> | ||
## <%=group.title%> | ||
<% for (const {issue, title, authorName, authorUser, scope, type} of groupCommits) { %> | ||
* <%=commitTypes[type]%> | ||
<%=issue ? ` [[#${issue}](https://github.com/icsharpcode/SharpZipLib/pull/${issue})]\n` : ''-%> | ||
<%=scope ? ` \`${scope}\`\n` : ''-%> | ||
__<%=title-%>__ | ||
by <%=authorUser ? `[_${authorName}_](https://github.com/${authorUser})` : `_${authorName}_`%> | ||
<% } %> | ||
<% } %> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
const https = require('https') | ||
|
||
const authorUsers = {} | ||
|
||
/** | ||
* @param {string} email | ||
* @param {string} prId | ||
* @returns {Promise<string | null>} User login if found */ | ||
const getAuthorUser = async (email, prId) => { | ||
const lookupUser = authorUsers[email]; | ||
if (lookupUser) return lookupUser; | ||
|
||
const match = /[0-9]+\+([^@]+)@users\.noreply\.github\.com/.exec(email); | ||
if (match) { | ||
return match[1]; | ||
} | ||
|
||
const pr = await new Promise((resolve, reject) => { | ||
console.warn(`Looking up GitHub user for PR #${prId} (${email})...`) | ||
https.get(`https://api.github.com/repos/icsharpcode/sharpziplib/pulls/${prId}`, { | ||
headers: {Accept: 'application/vnd.github.v3+json', 'User-Agent': 'release-notes-script/0.3.1'} | ||
}, (res) => { | ||
res.setEncoding('utf8'); | ||
let chunks = ''; | ||
res.on('data', (chunk) => chunks += chunk); | ||
res.on('end', () => resolve(JSON.parse(chunks))); | ||
res.on('error', reject); | ||
}).on('error', reject); | ||
}).catch(e => { | ||
console.error(`Could not get GitHub user (${email}): ${e}}`) | ||
return null; | ||
}); | ||
|
||
if (!pr) { | ||
console.error(`Could not get GitHub user (${email})}`) | ||
return null; | ||
} else { | ||
const user = pr.user.login; | ||
console.warn(`Resolved email ${email} to user ${user}`) | ||
authorUsers[email] = user; | ||
return user; | ||
} | ||
} | ||
|
||
/** | ||
* @typedef {{issue?: string, sha1: string, authorEmail: string, title: string, type: string}} Commit | ||
* @param {{commits: Commit[], range: string, dateFnsFormat: ()=>any, debug: (...p[]) => void}} data | ||
* @param {(data: {commits: Commit[], extra: {[key: string]: any}}) => void} callback | ||
* */ | ||
module.exports = (data, callback) => { | ||
// Migrates commits in the old format to conventional commit style, omitting any commits in neither format | ||
const normalizedCommits = data.commits.flatMap(c => { | ||
if (c.type) return [c] | ||
const match = /^(?:Merge )?(?:PR ?)?#(\d+):? (.*)/.exec(c.title) | ||
if (match != null) { | ||
const [, issue, title] = match | ||
return [{...c, title, issue, type: '?'}] | ||
} else { | ||
console.warn(`Skipping commit [${c.sha1.substr(0, 7)}] "${c.title}"!`); | ||
return []; | ||
} | ||
}); | ||
|
||
const commitAuthoredBy = email => commit => commit.authorEmail === email && commit.issue ? [commit.issue] : [] | ||
const authorEmails = new Set(normalizedCommits.map(c => c.authorEmail)); | ||
Promise.all( | ||
Array | ||
.from(authorEmails.values(), e => [e, normalizedCommits.flatMap(commitAuthoredBy(e))]) | ||
.map(async ([email, prs]) => [email, await getAuthorUser(email, ...prs)]) | ||
) | ||
.then(Object.fromEntries) | ||
.then(authorUsers => callback({ | ||
commits: normalizedCommits.map(c => ({...c, authorUser: authorUsers[c.authorEmail]})), | ||
extra: {} | ||
})) | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"title" : "^([a-z]+)(?:\\(([\\w\\$\\.]*)\\))?\\: (.*?)(?: \\(#(\\d+)\\))?$", | ||
"meaning": ["type", "scope", "title", "issue"], | ||
"script": "release-notes.js" | ||
} |