-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: changelog parser and update tool (#856)
* feat: parse changelog, check version * feat: create changelog * feat: handle other headers * chore: use reduce to handle any heading * feat: return the complete changelog * feat: ensure there are release notes
- Loading branch information
1 parent
22885c8
commit d51a115
Showing
13 changed files
with
948 additions
and
4 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
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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
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,151 @@ | ||
/* eslint-disable import/prefer-default-export */ | ||
|
||
const assert = require('assert'); | ||
const semver = require('semver'); | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
const marked = require('marked'); | ||
const moment = require('moment'); | ||
|
||
// TODO stronger check for version heading? | ||
const getPreviousVersion = (tokens) => | ||
tokens.find((t) => /v\d+/.test(t.text)).tokens.find((t) => t.type === 'text') | ||
.text; | ||
|
||
const releaseHeading = (version) => | ||
`## <sub>${version}</sub> | ||
#### ${moment().format('_MMM. D, YYYY_')}\n\n`; | ||
|
||
const pendingReleaseNotes = (changelog) => { | ||
const tokens = marked.lexer(changelog.toString()); | ||
|
||
const previousFullReleaseIndex = tokens.findIndex( | ||
(t) => t.type === 'heading' && t.depth === 2 && !/alpha/.test(t.text) | ||
); | ||
|
||
return tokens.slice(0, previousFullReleaseIndex); | ||
}; | ||
|
||
const pastReleaseNotes = (changelog) => { | ||
const tokens = marked.lexer(changelog.toString()); | ||
|
||
const previousFullReleaseIndex = tokens.findIndex( | ||
(t) => t.type === 'heading' && t.depth === 2 && !/alpha/.test(t.text) | ||
); | ||
|
||
return tokens.slice(previousFullReleaseIndex); | ||
}; | ||
|
||
const isPendingPreRelease = (tokens) => tokens[0].type !== 'heading'; | ||
|
||
/** | ||
* Given a list of tokens and a heading, find all list items that appear | ||
* under that heading. | ||
*/ | ||
const getItemsFor = (heading, tokens) => { | ||
let items = ''; | ||
|
||
let i = 0; | ||
|
||
while (i < tokens.length) { | ||
const currentToken = tokens[i]; | ||
const regex = new RegExp(heading, 'i'); | ||
|
||
if (currentToken.type === 'paragraph' && regex.test(currentToken.text)) { | ||
// search for list | ||
let j = i + 1; | ||
while (j < tokens.length) { | ||
if (tokens[j].type === 'list') { | ||
items += `${tokens[j].raw.trim()}\n`; | ||
i = j + 1; | ||
break; | ||
} else { | ||
j += 1; | ||
} | ||
} | ||
} else { | ||
i += 1; | ||
} | ||
} | ||
|
||
return items.length ? `${items}\n` : ''; | ||
}; | ||
|
||
const findSubHeadings = (tokens) => { | ||
const headings = new Set(); | ||
const regex = /\*\*([a-zA-Z ]+)\*\*/; | ||
// eslint-disable-next-line no-restricted-syntax | ||
for (const token of tokens) { | ||
if (regex.test(token.raw)) { | ||
headings.add(regex.exec(token.raw)[1].toLowerCase()); | ||
} | ||
} | ||
|
||
return [...headings]; | ||
}; | ||
|
||
const capitalise = (string) => string.charAt(0).toUpperCase() + string.slice(1); | ||
|
||
const preRelease = (version, changelog) => | ||
releaseHeading(version) + changelog.toString(); | ||
|
||
const fullRelease = (version, changelog) => { | ||
const tokens = pendingReleaseNotes(changelog); | ||
const subHeadings = findSubHeadings(tokens); | ||
|
||
const previousChangelog = pastReleaseNotes(changelog).reduce( | ||
(acc, item) => acc + item.raw, | ||
'' | ||
); | ||
|
||
return ( | ||
subHeadings.reduce((result, subHeading) => { | ||
const items = getItemsFor(subHeading, tokens); | ||
const title = capitalise(subHeading); | ||
|
||
return `${result}**${title}**\n\n${items}`; | ||
}, releaseHeading(version)) + previousChangelog | ||
); | ||
}; | ||
|
||
const release = (version, changelogPath) => { | ||
if (!changelogPath) { | ||
// eslint-disable-next-line no-param-reassign | ||
changelogPath = path.join(process.cwd(), 'CHANGELOG.md'); | ||
} | ||
|
||
assert.ok( | ||
semver.valid(version), | ||
`Version must be a valid semver - you entered ${version}` | ||
); | ||
|
||
assert.ok(fs.existsSync(changelogPath), 'failed to load CHANGELOG.md'); | ||
|
||
const changelog = fs.readFileSync(changelogPath).toString(); | ||
const tokens = marked.lexer(changelog); | ||
|
||
const previousVersion = getPreviousVersion(tokens); | ||
|
||
assert.ok( | ||
semver.gt(version, previousVersion), | ||
`The release version must be greater than previous releases. version: ${version} previous: ${previousVersion}` | ||
); | ||
|
||
if (semver.prerelease(version)) { | ||
assert.ok( | ||
isPendingPreRelease(tokens), | ||
'There are no pending release notes. Did you update the change log?' | ||
); | ||
return preRelease(version, changelog); | ||
} | ||
return fullRelease(version, changelog); | ||
}; | ||
|
||
module.exports = { | ||
release, | ||
findSubHeadings, | ||
getItemsFor, | ||
pastReleaseNotes, | ||
pendingReleaseNotes, | ||
}; |
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,12 @@ | ||
module.exports = { | ||
parser: '@typescript-eslint/parser', | ||
plugins: ['@typescript-eslint'], | ||
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'], | ||
env: { | ||
browser: true, | ||
}, | ||
rules: { | ||
'@typescript-eslint/no-unused-vars': 'off', | ||
'@typescript-eslint/no-empty-function': 'warn', | ||
}, | ||
}; |
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,43 @@ | ||
## <sub>v1.2.0-alpha.0</sub> | ||
|
||
#### _Feb. 17, 2021_ | ||
|
||
**New** | ||
|
||
- π : Something new | ||
|
||
**Bugfixes** | ||
|
||
- π: a bugfix | ||
|
||
## <sub>v1.1.0-alpha.1</sub> | ||
|
||
#### _Feb. 12, 2021_ | ||
|
||
**Bugfixes** | ||
|
||
- π― Targeted content: will now scroll back to targeted content on close | ||
|
||
## <sub>v1.1.0-alpha.0</sub> | ||
|
||
#### _Feb. 4, 2021_ | ||
|
||
**New** | ||
|
||
- π― Targeted content: you can now specifiy the heading level of the title element | ||
|
||
**Bugfixes** | ||
|
||
- π₯ Breadcrumbs: Layout adjustments when viewed on small screen | ||
|
||
## <sub>v1.0.0</sub> | ||
|
||
#### _Jan. 21, 2021_ | ||
|
||
**New** | ||
|
||
- π€ Header links: support for no javascript added | ||
|
||
**Bugfixes** | ||
|
||
- π Navigation: More / Close arrow correction |
26 changes: 26 additions & 0 deletions
26
scripts/tests/__fixtures__/pending-release-after-production.md
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,26 @@ | ||
## <sub>v1.1.1</sub> | ||
|
||
#### _Feb. 17, 2021_ | ||
|
||
**New** | ||
|
||
- π : Something new | ||
- π― Targeted content: you can now specifiy the heading level of the title element | ||
|
||
**Bugfixes** | ||
|
||
- π: a bugfix | ||
- π― Targeted content: will now scroll back to targeted content on close | ||
- π₯ Breadcrumbs: Layout adjustments when viewed on small screen | ||
|
||
## <sub>v1.0.0</sub> | ||
|
||
#### _Jan. 21, 2021_ | ||
|
||
**New** | ||
|
||
- π€ Header links: support for no javascript added | ||
|
||
**Bugfixes** | ||
|
||
- π Navigation: More / Close arrow correction |
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,39 @@ | ||
**New** | ||
|
||
- π : Something new | ||
|
||
**Bugfixes** | ||
|
||
- π: a bugfix | ||
|
||
## <sub>v1.1.0-alpha.1</sub> | ||
|
||
#### _Feb. 12, 2021_ | ||
|
||
**Bugfixes** | ||
|
||
- π― Targeted content: will now scroll back to targeted content on close | ||
|
||
## <sub>v1.1.0-alpha.0</sub> | ||
|
||
#### _Feb. 4, 2021_ | ||
|
||
**New** | ||
|
||
- π― Targeted content: you can now specifiy the heading level of the title element | ||
|
||
**Bugfixes** | ||
|
||
- π₯ Breadcrumbs: Layout adjustments when viewed on small screen | ||
|
||
## <sub>v1.0.0</sub> | ||
|
||
#### _Jan. 21, 2021_ | ||
|
||
**New** | ||
|
||
- π€ Header links: support for no javascript added | ||
|
||
**Bugfixes** | ||
|
||
- π Navigation: More / Close arrow correction |
Oops, something went wrong.