1+ import java.text.SimpleDateFormat
2+ import java.util.*
3+
4+ val repoUrl = " https://github.com/ELIXIR-NO/FEGA-Norway"
5+
6+ tasks.register(" generateChangelog" ) {
7+ group = " changelog"
8+ doLast {
9+ // 1. Get module name from project directory
10+ val moduleName = project.name
11+
12+ // 2. Get latest tag for this module
13+ val tagPattern = " $moduleName -*"
14+ val tagProcess = ProcessBuilder (
15+ " bash" , " -c" , " git tag --list '$tagPattern ' --sort=-creatordate | head -n 1"
16+ )
17+ .directory(project.rootDir)
18+ .redirectErrorStream(true )
19+ .start()
20+ val latestTag = tagProcess.inputStream.bufferedReader().readText().trim()
21+ tagProcess.waitFor()
22+
23+ // 3. Get commits since the latest tag (or all if no tag)
24+ val logRange = if (latestTag.isNotEmpty()) " $latestTag ..HEAD" else " "
25+ val logCommand = if (logRange.isNotEmpty())
26+ listOf (" git" , " log" , " --pretty=format:%h|%s" , logRange, " --" , project.projectDir.toString())
27+ else
28+ listOf (" git" , " log" , " --pretty=format:%h|%s" , " --" , project.projectDir.toString())
29+
30+ val process = ProcessBuilder (logCommand)
31+ .directory(project.rootDir)
32+ .redirectErrorStream(true )
33+ .start()
34+ val output = process.inputStream.bufferedReader().readText()
35+ process.waitFor()
36+
37+ // Emojis for each group
38+ val groupEmojis = mapOf (
39+ " Features" to " 🚀" ,
40+ " Bug Fixes" to " 🐛" ,
41+ " Chores" to " 🧹" ,
42+ " Documentation" to " 📚" ,
43+ " Other" to " 🔧"
44+ )
45+
46+ // Group commits
47+ val commitGroups = mutableMapOf (
48+ " Features" to mutableListOf (),
49+ " Bug Fixes" to mutableListOf (),
50+ " Chores" to mutableListOf (),
51+ " Documentation" to mutableListOf (),
52+ " Other" to mutableListOf<String >()
53+ )
54+
55+ // Helper to link PRs/issues
56+ fun linkRefs (message : String ): String {
57+ val prLinked = message.replace(
58+ Regex (""" \(#(\d+)\)""" ),
59+ " ([#$1]($repoUrl /pull/$1))"
60+ )
61+ return prLinked.replace(
62+ Regex (""" (?<!\()#(\d+)\b""" ),
63+ " ([#$1]($repoUrl /issues/$1))"
64+ )
65+ }
66+
67+ output.lines().forEach { line ->
68+ if (line.isNotBlank()) {
69+ val (hash, message) = line.split(" |" , limit = 2 )
70+ val linkedHash = " [`${hash} `]($repoUrl /commit/$hash )"
71+ val linkedMessage = linkRefs(message)
72+ when {
73+ message.startsWith(" feat" ) -> commitGroups[" Features" ]?.add(" $linkedHash $linkedMessage " )
74+ message.startsWith(" fix" ) -> commitGroups[" Bug Fixes" ]?.add(" $linkedHash $linkedMessage " )
75+ message.startsWith(" chore" ) -> commitGroups[" Chores" ]?.add(" $linkedHash $linkedMessage " )
76+ message.startsWith(" docs" ) -> commitGroups[" Documentation" ]?.add(" $linkedHash $linkedMessage " )
77+ else -> commitGroups[" Other" ]?.add(" $linkedHash $linkedMessage " )
78+ }
79+ }
80+ }
81+
82+ // Get current date
83+ val date = SimpleDateFormat (" yyyy-MM-dd" ).format(Date ())
84+ val version = project.findProperty(" version" )?.toString()
85+ ? : latestTag.ifEmpty { " Unreleased" }
86+
87+ // Get PR title if provided
88+ val prTitle = project.findProperty(" prTitle" )?.toString()
89+
90+ val changelogFile = file(" CHANGELOG.md" )
91+ changelogFile.writeText(" # Changelog\n\n " )
92+ changelogFile.appendText(" ## [$version ] - $date \n\n " )
93+
94+ // Add PR title at the top if present
95+ if (! prTitle.isNullOrBlank()) {
96+ changelogFile.appendText(" > **$prTitle **\n\n " )
97+ }
98+
99+ commitGroups.forEach { (group, commits) ->
100+ if (commits.isNotEmpty()) {
101+ val emoji = groupEmojis[group] ? : " "
102+ changelogFile.appendText(" ### $emoji $group \n " )
103+ commits.forEach { commit ->
104+ changelogFile.appendText(" - $commit \n " )
105+ }
106+ changelogFile.appendText(" \n " )
107+ }
108+ }
109+
110+ println (" ✨ Fancy changelog generated at ${changelogFile.absolutePath} " )
111+ }
112+ }
0 commit comments