import { type ParsedCommitData, prCategories } from "../commit"; import { entitiesConfig } from "../intershell-config/intershell-config"; import { ChangelogTemplate } from "./template"; const DEFAULT_BADGE_COLOR = "6B7280"; const validTypes = entitiesConfig.getConfig().commit.conventional.type?.list ?? []; export class DefaultChangelogTemplate extends ChangelogTemplate { protected generateChangelogHeader(): string { return [ `## Changelog (${this.packageName})`, "", "[![Keep a Changelog](https://img.shields.io/badge/changelog-Keep%20a%20Changelog%20v1.0.0-$E05735)](https://keepachangelog.com)", "[![Semantic Versioning](https://img.shields.io/badge/semver-semantic%20versioning%20v2.0.0-%23E05735)](https://semver.org)", "", "All notable changes to this project will be documented in this file.", "The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),", "and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).", "", ].join("\n"); } protected generateChangelogVersionHeader(version: string): string { return ["", `## ${version === "[Unreleased]" ? "" : this.prefix}${version}`, ""].join("\n"); } protected generateCommitSection(commit: ParsedCommitData, repoUrl: string): string { if (commit.pr?.prNumber) { return this.generatePrSection(commit, commit.pr.prCommits || [commit], repoUrl); } return `###### ${this.generateCommitLine(commit, repoUrl)}`; } private generatePrSection( mainCommit: ParsedCommitData, allCommits: ParsedCommitData[], repoUrl: string, ): string { const { pr: { prNumber, prCategory = "other", prBranchName } = {} } = mainCommit; const commitCount = allCommits.length; const categoryEmoji = prCategories[prCategory]?.emoji; const categoryTitle = prCategories[prCategory]?.label; const prCategoryBadge = `${categoryTitle}`; const prNumberBadge = !!prNumber && `#${prNumber}`; const commitCountBadge = `${commitCount} commits`; const prNumberLink = !!prNumberBadge && `${prNumberBadge}`; const prMessages = mainCommit.message.isMerge ? [ // mainCommit.message.bodyLines[0], // We don't want the first line: "Merge pull request #154 from feature/custom-version-management" // "", // Empty line for separation, if you added the first line above, uncomment this line as well ...mainCommit.message.bodyLines.slice(1), // Rest of the lines: "Refactors the version management system..." ] : [mainCommit.message.description, "", ...mainCommit.message.bodyLines]; return [ // Format: emoji branch-name category-title #PR-number commit-count // Example: 🔄 refactor/test-versioning Code Quality & Refactoring #144 9 commits "", `### ${categoryEmoji} ${typeof prBranchName === "object" && prBranchName?.name ? prBranchName.name : typeof prBranchName === "string" ? prBranchName : "unknown-branch"} ${prCategoryBadge} ${prNumberLink} ${commitCountBadge}`, "", ...prMessages, "", "
📝 Commits (Click to expand)", "", ...allCommits.map((commit) => `- ${this.generateCommitLine(commit, repoUrl)}`), "", "
", "", ].join("\n"); } private generateCommitLine(commit: ParsedCommitData, repoUrl: string): string { const { info: { hash, author = "Unknown" } = {}, message: { type, description, scopes = [] }, } = commit; const hashKey = hash?.substring(0, 7) || "unknown"; const hashUrl = hash ? `${repoUrl}/commit/${hash}` : undefined; const scopeSection = scopes && scopes.length > 0 ? scopes.map((s: string) => s.toLowerCase().replace("-", "%20")).join(",") : ""; const badgeText = `${type}-(${scopeSection || "noscope"})`; const badgeColor = validTypes.find((t) => t.type === type)?.badgeColor || DEFAULT_BADGE_COLOR; const badge = `${type}`; const badgeUrl = hashUrl ? `${badge}` : badge; const hashLink = hashUrl ? `([${hashKey}](${hashUrl}))` : `[${hashKey}]`; return [ badgeUrl, description, hashLink, author && (author.includes("@") ? `by [${author}](mailto:${author})` : `by **${author}**`), ] .filter(Boolean) .join(" ") .trim(); } }