commit 4ea6a8ad46e69cc6f57b3061e377ffce95550c1f Author: Charles7c Date: Wed Feb 25 14:07:37 2026 +0800 init repo diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..29d0410 --- /dev/null +++ b/.gitignore @@ -0,0 +1,45 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +!.idea/icon.png +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +# Maven ignore +.flattened-pom.xml + +### Temp ### +*.log +*.logs +*.cache +*.diff +*.patch +*.tmp \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..3596706 --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +# CHANGELOG 生成器 + +将提交信息转换成 CHANGELOG Markdown。 + +## 快速开始 + +- `BASIC_PATH`:项目基础路径 +- `PROJECT_NAME`:项目名称 +- `LAST_TAG_NAME`:上一个版本名称 +- `SHOW_MODULE_NAME`:是否显示模块名称 + +## 示例 + +```text +feat(core): ServletUtils 新增 isMultipart、isForm、isStream 方法 +``` + +转换如下: + +```text +新特性: +- 【core】ServletUtils 新增 isMultipart、isForm、isStream 方法 ([580aa00a](https://github.com/continew-org/continew-starter/commit/580aa00af920acb3f66fbd835378a802741d18d6)) +``` \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..54a5b90 --- /dev/null +++ b/pom.xml @@ -0,0 +1,30 @@ + + + 4.0.0 + + top.charles7c + changelog-generator + 1.0.0 + + + 17 + 17 + UTF-8 + + + + + org.eclipse.jgit + org.eclipse.jgit + 7.2.1.202505142326-r + + + + cn.hutool + hutool-all + 5.8.40 + + + \ No newline at end of file diff --git a/src/main/java/top/charles7c/app/App.java b/src/main/java/top/charles7c/app/App.java new file mode 100644 index 0000000..59baf1d --- /dev/null +++ b/src/main/java/top/charles7c/app/App.java @@ -0,0 +1,143 @@ +package top.charles7c.app; + +import cn.hutool.core.util.StrUtil; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.storage.file.FileRepositoryBuilder; + +import java.io.File; +import java.io.IOException; +import java.util.*; + +/** + * Git Changelog 生成器 + * + * @author Charles7c + */ +public class App { + + private static final String BASIC_PATH = "D:\\Projects\\charles7c\\"; + + private static final String PROJECT_NAME = "continew-starter"; + // private static final String PROJECT_NAME = "continew-admin"; +// private static final String PROJECT_NAME = "continew-admin-ui"; + // + private static final String LAST_TAG_NAME = "release: v2.15.0"; +// private static final String LAST_TAG_NAME = "release: v4.1.0"; + + private static final boolean SHOW_MODULE_NAME = true; + + public static void main(String[] args) throws IOException, GitAPIException { + FileRepositoryBuilder builder = new FileRepositoryBuilder(); + Repository repository = builder.setGitDir(new File(BASIC_PATH + PROJECT_NAME + "\\.git")) + .readEnvironment() + .findGitDir() + .build(); + + Map> commitListMap = new LinkedHashMap<>(); + // 根据类型汇总提交记录 + try (Git git = new Git(repository)) { + // 倒序遍历所有提交记录 + Iterable logs = git.log().call(); + for (RevCommit commit : logs) { + // 直到上次发布标签,停止遍历 + if (LAST_TAG_NAME.equals(commit.getShortMessage())) { + break; + } + logChangeCommit(commit, commitListMap); + } + } finally { + repository.close(); + } + + // 转换为 CHANGELOG Markdown + Set>> entrySet = commitListMap.entrySet(); + for (Map.Entry> entry : entrySet) { + String changeType = entry.getKey(); + System.out.printf("%n%n%s:%n", changeType); + printChangelog(entry.getValue()); + } + } + + /** + * 添加变更记录 + * + * @param commit 提交记录 + * @param commitListMap 提交记录列表 + */ + private static void logChangeCommit(RevCommit commit, Map> commitListMap) { + String shortMessage = commit.getShortMessage(); + // 忽略合并 + if (shortMessage.startsWith("Merge ")) { + return; + } + // e.g. feat(core): ServletUtils 新增 isMultipart、isForm、isStream 方法 + String changeType = getChangeType(shortMessage); + String changeTypeName = getChangeTypeName(changeType); + List commitList = commitListMap.get(changeTypeName); + if (null == commitList) { + commitList = new ArrayList<>(); + } + // 正序添加 + commitList.add(0, commit); + commitListMap.put(changeTypeName, commitList); + } + + /** + * 转换为 CHANGELOG Markdown + * + * @param commitList 提交记录列表 + */ + private static void printChangelog(List commitList) { + for (RevCommit commit : commitList) { + String shortMessage = commit.getShortMessage(); + String commitId = commit.getId().getName(); + String moduleName = getModuleName(shortMessage); + List changelogTemplateVarList = new ArrayList<>(List.of(StrUtil.subAfter(shortMessage, ": ", false), StrUtil.subPre(commitId, 8), PROJECT_NAME, commitId)); + String changelogTemplate = "- "; + if (SHOW_MODULE_NAME && StrUtil.isNotBlank(moduleName)) { + changelogTemplate += "【%s】"; + changelogTemplateVarList.add(0, moduleName); + } + changelogTemplate += "%s ([%s](https://github.com/continew-org/%s/commit/%s))%n"; + System.out.printf(changelogTemplate, changelogTemplateVarList.toArray()); + } + } + + /** + * 获取变更类型 + * + * @param shortMessage {@link RevCommit#getShortMessage()} + * @return 变更类型 + */ + private static String getChangeType(String shortMessage) { + return StrUtil.subBefore(StrUtil.subBefore(shortMessage, ":", false), "(", false); + } + + /** + * 获取变更类型名称 + * + * @param changeType 变更类型 + * @return 变更类型名称 + */ + private static String getChangeTypeName(String changeType) { + return switch (changeType) { + case "feat" -> "新特性"; + case "fix" -> "问题修复"; + case "style", "refactor", "perf", "chore" -> "功能优化"; + default -> "其他"; + }; + } + + /** + * 获取模块名称 + * + * @param shortMessage {@link RevCommit#getShortMessage()} + * @return 模块名称 + */ + private static String getModuleName(String shortMessage) { + return StrUtil.subBetween(StrUtil.subBefore(shortMessage, ":", false), "(", ")"); + } +} \ No newline at end of file