-
-
Notifications
You must be signed in to change notification settings - Fork 479
chore: generate changelog based on conventional commits #5487
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
Changes from all commits
8118e38
b8b0f58
7b6f532
2d4bc8f
d5caae9
3a0813e
a9aa98f
dc26df1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,15 +6,15 @@ | |
| no-console | ||
| */ | ||
|
|
||
| const {execSync} = require("node:child_process"); | ||
| const fs = require("node:fs"); | ||
| import {execSync} from "node:child_process"; | ||
| import fs from "node:fs"; | ||
|
|
||
| // Docs | ||
| // [script] <fromTag> <toTag> | ||
| // | ||
| // Exmaple | ||
| // Example | ||
| // ``` | ||
| // node scripts/changelog_simple.js v0.32.0 v0.33.0 | ||
| // node scripts/generate_changelog.mjs v0.32.0 v0.33.0 | ||
| // ``` | ||
|
|
||
| /** | ||
|
|
@@ -23,8 +23,8 @@ const fs = require("node:fs"); | |
| */ | ||
| const knownAuthors = { | ||
| "caymannava@gmail.com": "wemeetagain", | ||
| "76567250+g11tech@users.noreply.github.com": "g11tech", | ||
| "vutuyen2636@gmail.com": "tuyennhv", | ||
| "develop@g11tech.io": "g11tech", | ||
| "tuyen@chainsafe.io": "tuyennhv", | ||
| "35266934+dapplion@users.noreply.github.com": "dapplion", | ||
| "41898282+github-actions[bot]@users.noreply.github.com": "github-actions[bot]", | ||
| "49699333+dependabot[bot]@users.noreply.github.com": "dependabot[bot]", | ||
|
|
@@ -39,6 +39,9 @@ const knownAuthors = { | |
| "ammar1lakho@gmail.com": "ammarlakho", | ||
| "dadepo@gmail.com": "dadepo", | ||
| "hi@enriqueortiz.dev": "Evalir", | ||
| "nflaig@protonmail.com": "nflaig", | ||
| "nazarhussain@gmail.com": "nazarhussain", | ||
| "me@matthewkeil.com": "matthewkeil", | ||
| }; | ||
|
|
||
| const fromTag = process.argv[2]; | ||
|
|
@@ -49,36 +52,96 @@ if (!fromTag) throw Error("No process.argv[2]"); | |
| if (!toTag) throw Error("No process.argv[3]"); | ||
| if (!outpath) throw Error("No process.argv[4]"); | ||
|
|
||
| /** | ||
| * @type {Record<string, {heading: string; commitsByScope: Record<string, string[]>}>} | ||
| */ | ||
| const sections = { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Order and wording LGTM |
||
| feat: {heading: "Features", commitsByScope: {"": []}}, | ||
| fix: {heading: "Bug Fixes", commitsByScope: {"": []}}, | ||
| perf: {heading: "Performance", commitsByScope: {"": []}}, | ||
| refactor: {heading: "Refactoring", commitsByScope: {"": []}}, | ||
| revert: {heading: "Reverts", commitsByScope: {"": []}}, | ||
| deps: {heading: "Dependencies", commitsByScope: {"": []}}, | ||
| build: {heading: "Build System", commitsByScope: {"": []}}, | ||
| ci: {heading: "Continuous Integration", commitsByScope: {"": []}}, | ||
| test: {heading: "Tests", commitsByScope: {"": []}}, | ||
| style: {heading: "Styles", commitsByScope: {"": []}}, | ||
| chore: {heading: "Maintenance", commitsByScope: {"": []}}, | ||
| docs: {heading: "Documentation", commitsByScope: {"": []}}, | ||
| _: {heading: "Miscellaneous", commitsByScope: {"": []}}, | ||
| }; | ||
|
|
||
| const isPrCommitRg = /\(#\d+\)/; | ||
| const conventionalCommitRg = /^([a-z]+)(?:\((.*)\))?(?:(!))?: (.*)$/; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thats pretty a pretty fancy regexp. Did this get pulled from somewhere? Perhaps we can unit test it but that feels silly honestly for a workflow script... Found this thread and it had a a pretty cool one in it to support emojis. Not something I feel strongly about but thought was worth a mention. I put my faith in your trusting hands sir
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not in favor of adding tests for the script. I have verified that the output is correct. As I also do not trust any regex, I created some test cases which I just executed locally.
The regex allows emojis in the commit message itself. It is really not that strict, a more strict format will be enforced by the PR title checker.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added console logs to print out ignored commits (dc26df1), this should be sufficient for now to verify that the regex works and there are no false positives. |
||
|
|
||
| const commitHashes = shell(`git log --pretty=format:"%H" ${fromTag}...${toTag}`); | ||
|
|
||
| let commitListStr = ""; | ||
|
|
||
| for (const commitHash of commitHashes.trim().split("\n")) { | ||
| const subject = shell(`git log --format='%s' ${commitHash}^!`); | ||
| if (!isPrCommitRg.test(subject)) { | ||
| const rawCommit = shell(`git log --format='%s' ${commitHash}^!`); | ||
|
|
||
| if (!isPrCommitRg.test(rawCommit)) { | ||
| console.log(`Ignored commit "${rawCommit}" (missing PR reference)`); | ||
| continue; | ||
| } | ||
|
|
||
| const conventionalCommit = rawCommit.match(conventionalCommitRg); | ||
| if (!conventionalCommit) { | ||
| console.log(`Ignored commit "${rawCommit}" (not conventional commit)`); | ||
| continue; | ||
| } | ||
|
|
||
| const [, type, scope, _breaking, subject] = conventionalCommit; | ||
|
|
||
| const authorEmail = shell(`git log --format='%ae' ${commitHash}^!`); | ||
| const authorName = shell(`git log --format='%an' ${commitHash}^!`); | ||
| const login = getCommitAuthorLogin(commitHash, authorEmail, authorName); | ||
|
|
||
| commitListStr += `- ${subject} (@${login})\n`; | ||
| const formattedCommit = `- ${scope ? `**${scope}:** ` : ""}${subject} (@${login})\n`; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Very nice touch looking up the author login name!! Always great to provide visibility to contributors
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, it is pretty nice, can easily see contributors of a release. That was already there in our initial version and does not seem to be easily supported by any other tools like release-please or semantic-release which is another good reason besides added complexity to not introduce additional tooling (for now). |
||
|
|
||
| // Sort commits by type and scope | ||
| // - assign each commit to section based on type | ||
| // - group commits by scope within each section | ||
| if (sections[type] != null) { | ||
| if (scope) { | ||
| if (sections[type].commitsByScope[scope] == null) { | ||
| sections[type].commitsByScope[scope] = []; | ||
| } | ||
| sections[type].commitsByScope[scope].push(formattedCommit); | ||
| } else { | ||
| sections[type].commitsByScope[""].push(formattedCommit); | ||
| } | ||
| } else { | ||
| // Commits with a type that is not defined in sections | ||
| sections._.commitsByScope[""].push(formattedCommit); | ||
| } | ||
| } | ||
|
|
||
| // Print knownAuthors to update if necessary | ||
| console.log("knownAuthors", knownAuthors); | ||
|
|
||
| const changelog = `# Changelog | ||
| let changelog = `# Changelog | ||
|
|
||
| [Full Changelog](https://github.com/ChainSafe/lodestar/compare/${fromTag}...${toTag}) | ||
| `; | ||
|
|
||
| **Merged pull requests:** | ||
| // Write sections to changelog | ||
| for (const type in sections) { | ||
| const section = sections[type]; | ||
| let hasCommits = false; | ||
| let sectionChangelog = `\n### ${section.heading}\n\n`; | ||
|
|
||
| ${commitListStr} | ||
| `; | ||
| for (const commits of Object.values(section.commitsByScope)) { | ||
| if (commits.length > 0) { | ||
| hasCommits = true; | ||
| sectionChangelog += commits.join(""); | ||
| } | ||
| } | ||
|
|
||
| if (hasCommits) { | ||
| // Only add section if it has at least one commit | ||
| changelog += sectionChangelog; | ||
| } | ||
| } | ||
|
|
||
| // Print to console | ||
| console.log(changelog); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.