Skip to content

Commit

Permalink
chore: generate changelog based on conventional commits (#5487)
Browse files Browse the repository at this point in the history
* Update known authors

* Generate changelog based on conventional commits

* Rename generate changelog script

* Update PR title checker types based on predefined sections

* Convert generate changelog script to ES module

* Update order of sections

* Update Changelog heading to h1

* Print out ignored commits with reason
  • Loading branch information
nflaig authored May 16, 2023
1 parent f417c35 commit 1602f67
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 18 deletions.
15 changes: 14 additions & 1 deletion .github/workflows/lint-pr-title.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,20 @@ jobs:
with:
# Configure which types are allowed (newline-delimited).
# Default: https://github.com/commitizen/conventional-commit-types
#types: |
# Customized based on sections defined in scripts/generate_changelog.mjs
types: |
feat
fix
perf
refactor
revert
deps
build
ci
test
style
chore
docs
# Configure which scopes are allowed (newline-delimited).
# These are regex patterns auto-wrapped in `^ $`.
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish-rc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ jobs:
# </common-build>

- name: Generate changelog
run: node scripts/generate_changelog_simple.js ${{ needs.tag.outputs.prev_tag }} ${{ needs.tag.outputs.tag }} CHANGELOG.md
run: node scripts/generate_changelog.mjs ${{ needs.tag.outputs.prev_tag }} ${{ needs.tag.outputs.tag }} CHANGELOG.md

- name: Create Release
id: create_release
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish-stable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ jobs:
# </common-build>

- name: Generate changelog
run: node scripts/generate_changelog_simple.js ${{ needs.tag.outputs.prev_tag }} ${{ needs.tag.outputs.tag }} CHANGELOG.md
run: node scripts/generate_changelog.mjs ${{ needs.tag.outputs.prev_tag }} ${{ needs.tag.outputs.tag }} CHANGELOG.md

- name: Create Release
id: create_release
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
// ```

/**
Expand All @@ -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]",
Expand All @@ -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];
Expand All @@ -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 = {
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]+)(?:\((.*)\))?(?:(!))?: (.*)$/;

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`;

// 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);
Expand Down

0 comments on commit 1602f67

Please sign in to comment.