Skip to content

Commit

Permalink
Merge pull request #963 from primer/generate-changelog
Browse files Browse the repository at this point in the history
Generate changelog with semantic-release
  • Loading branch information
shawnbot authored Nov 5, 2019
2 parents 2e687a8 + 828e3dc commit 0cde1c4
Show file tree
Hide file tree
Showing 6 changed files with 13,724 additions and 7,796 deletions.
18 changes: 18 additions & 0 deletions .github/workflows/changelog.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: changelog
on:
push:
branches:
- 'release-*'
- '*changelog*'
jobs:
all:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions/setup-node@master
with:
node-version: 11
- name: install
run: npm install
- name: changelog
run: script/changelog.js
134 changes: 134 additions & 0 deletions lib/semantic-release-plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
const Octokit = require('@octokit/rest')

const commitMetadata = new Map()

const noteGroups = {
breaking: {title: ':boom: Breaking changes'},
enhancement: {title: ':rocket: Enhancements'},
fix: {title: ':bug: Bug fixes'},
docs: {title: ':memo: Documentation'},
internal: {title: ':house: Internal'},
polish: {title: ':nail_care: Polish'}
}

const releaseLabels = {
'Tag: Breaking Change': {releaseType: 'major', group: 'breaking'},
'Tag: Enhancement': {releaseType: 'minor', group: 'enhancement'},
'Tag: Bug Fix': {releaseType: 'patch', group: 'fix'},
'Tag: Documentation': {releaseType: 'patch', group: 'docs'},
'Tag: Internal': {releaseType: 'patch', group: 'internal'},
'Tag: Polish': {releaseType: 'patch', group: 'polish'}
}

const repoContext = {owner: 'primer', repo: 'css'}
const githubOptions = {
userAgent: '@primer/css changelog'
}
const {GITHUB_TOKEN} = process.env
if (GITHUB_TOKEN) {
githubOptions.auth = GITHUB_TOKEN
}

const github = new Octokit(githubOptions)

module.exports = {analyzeCommits, generateNotes}

async function analyzeCommits(options, context) {
const {commits, logger} = context

const releaseTypes = new Map()

for (const commit of commits) {
const match = commit.message.match(/Merge pull request #(\d+)/)
if (match) {
const [, pullNumber] = match
logger.log(`Fetching PR #${pullNumber}...`)
// eslint-disable-next-line camelcase
const {data: pull} = await github.pulls.get(Object.assign({pull_number: pullNumber}, repoContext))

const labels = pull.labels.map(label => label.name)
if (labels.length) {
logger.log(`Got labels: "${labels.join('", "')}"`)
for (const label of labels) {
const {releaseType, group} = releaseLabels[label] || {}
if (releaseType) {
logger.info(`Label "${label}" matches release type: ${releaseType}`)

if (!releaseTypes.has(releaseType)) {
releaseTypes.set(releaseType, [])
}
releaseTypes.get(releaseType).push({pull, label})

commitMetadata.set(commit.hash, {pull, group})
}
}
}
} else {
logger.log(`No PR number found in commit: "${commit.message}"`)
}
}

let returnReleaseType

for (const releaseType of ['major', 'minor', 'patch']) {
if (releaseTypes.has(releaseType)) {
const pulls = releaseTypes.get(releaseType)
logger.info(`Found ${pulls.length} pulls for release type: ${releaseType}`)
for (const {pull, label} of pulls) {
logger.info(`- PR #${pull.number} labeled "${label}"`)
if (!returnReleaseType) {
returnReleaseType = releaseType
}
}
}
}

return returnReleaseType
}

async function generateNotes(options, context) {
const {
commits,
logger,
nextRelease: {version}
} = context

logger.info(`Finding metadata for ${commitMetadata.size} commits...`)
const releaseCommits = commits.map(commit => commitMetadata.get(commit.hash)).filter(Boolean)

if (releaseCommits.length) {
logger.info(`Got ${releaseCommits.length} release commits!`)

const groupItems = new Map()
const committers = new Set()
const {owner, repo} = repoContext
const baseURL = `https://github.com/${owner}/${repo}`
for (const {pull, group} of releaseCommits) {
if (!groupItems.has(group)) {
groupItems.set(group, [])
}
const {
number,
title,
user: {login}
} = pull
groupItems.get(group).push(`- [#${number}](${baseURL}/${number}) ${title}`)
committers.add(login)
}

return [
`## ${version}`,
...Object.entries(noteGroups)
.filter(([group]) => groupItems.has(group))
.map(([group, {title}]) => `\n### ${title}\n${groupItems.get(group).join('\n')}`),
'',
`### Committers`,
...Array.from(committers)
.sort()
.map(login => `- [@${login}](https://github.com/${login})`),
''
].join('\n')
} else {
logger.info(`No release commits. :(`)
}
}
Loading

0 comments on commit 0cde1c4

Please sign in to comment.