Skip to content

Commit 44f2f0a

Browse files
authored
Merge pull request #495 from ELIXIR-NO/feat/better-changelogs
2 parents 9bfd680 + 0678c21 commit 44f2f0a

File tree

3 files changed

+160
-7
lines changed

3 files changed

+160
-7
lines changed

.github/workflows/publish-and-release.yml

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,23 +31,24 @@ jobs:
3131
TAG_PREFIX: ${{matrix.component}}-
3232
DRY_RUN: true
3333
DEFAULT_BUMP: patch
34-
MAJOR_STRING_TOKEN: '#major_${{ matrix.component }}'
35-
MINOR_STRING_TOKEN: '#minor_${{ matrix.component }}'
36-
PATCH_STRING_TOKEN: '#patch_${{ matrix.component }}'
34+
MAJOR_STRING_TOKEN: "#major_${{ matrix.component }}"
35+
MINOR_STRING_TOKEN: "#minor_${{ matrix.component }}"
36+
PATCH_STRING_TOKEN: "#patch_${{ matrix.component }}"
3737
- name: Extract New Version
3838
id: new-tag
3939
run: |
4040
full_version="${{ steps.generate-new-tag.outputs.new_tag }}"
4141
component="${{ matrix.component }}"
4242
version="${full_version#"$component"-}"
4343
echo "version=$version" >> "$GITHUB_OUTPUT"
44-
44+
4545
- name: Setup Java
4646
if: ${{ matrix.component == 'clearinghouse' || matrix.component == 'crypt4gh' || matrix.component == 'tsd-file-api-client' }}
4747
uses: actions/setup-java@v4
4848
with:
49-
java-version: '21'
50-
distribution: 'temurin'
49+
java-version: "21"
50+
distribution: "temurin"
51+
5152
- name: Publish Jar Files
5253
if: ${{ matrix.component == 'clearinghouse' || matrix.component == 'crypt4gh' || matrix.component == 'tsd-file-api-client' }}
5354
run: |
@@ -61,13 +62,47 @@ jobs:
6162
run: |
6263
REPO_NAME=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]')
6364
echo "repo_name=$REPO_NAME" >> $GITHUB_ENV
65+
66+
- name: Set component path
67+
id: set_path
68+
run: |
69+
declare -A component_paths=(
70+
[lega-commander]="cli/lega-commander"
71+
[e2eTests]="e2eTests"
72+
[clearinghouse]="lib/clearinghouse"
73+
[crypt4gh]="lib/crypt4gh"
74+
[tsd-file-api-client]="lib/tsd-file-api-client"
75+
[cega-mock]="services/cega-mock"
76+
[localega-tsd-proxy]="services/localega-tsd-proxy"
77+
[mq-interceptor]="services/mq-interceptor"
78+
[tsd-api-mock]="services/tsd-api-mock"
79+
)
80+
path="${component_paths[${{ matrix.component }}]:-.}"
81+
echo "changelog_path=$path" >> $GITHUB_ENV
82+
echo "component_path=${component_paths[${{ matrix.component }}]}" >> $GITHUB_ENV
83+
84+
- name: Set PR title
85+
id: set_pr_title
86+
env:
87+
TITLE: ${{ github.event.pull_request.title }}
88+
run: |
89+
CLEAN_TITLE="${TITLE//[\"\'\`]/ }"
90+
echo "pr_title=$CLEAN_TITLE" >> $GITHUB_ENV
91+
92+
- name: Generate Fancy Changelog
93+
run: |
94+
./gradlew ${{ env.component_path }}:generateChangelog \
95+
-Pversion=${{ steps.new-tag.outputs.version }} \
96+
-PprTitle="${{ env.pr_title }}"
97+
6498
- name: Log in to the Github Container registry
6599
if: ${{ matrix.component == 'localega-tsd-proxy' || matrix.component == 'tsd-api-mock' || matrix.component == 'cega-mock' || matrix.component == 'mq-interceptor' }}
66100
uses: docker/login-action@v3
67101
with:
68102
registry: ghcr.io
69103
username: ${{ github.actor }}
70104
password: ${{ secrets.GITHUB_TOKEN }}
105+
71106
- name: Retag and Push Docker Image
72107
if: ${{ matrix.component == 'localega-tsd-proxy' || matrix.component == 'tsd-api-mock' || matrix.component == 'cega-mock' || matrix.component == 'mq-interceptor' }}
73108
run: |
@@ -84,7 +119,7 @@ jobs:
84119
if: ${{matrix.component == 'lega-commander'}}
85120
uses: goreleaser/goreleaser-action@v6
86121
with:
87-
version: '~> v2'
122+
version: "~> v2"
88123
args: release --clean
89124
workdir: cli/lega-commander
90125
env:
@@ -98,3 +133,4 @@ jobs:
98133
token: "${{ secrets.GITHUB_TOKEN }}"
99134
tag_name: "${{matrix.component}}-${{ steps.new-tag.outputs.version }}"
100135
prerelease: false
136+
body_path: ${{ env.changelog_path }}/CHANGELOG.md

build.gradle.kts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
plugins {
22
id("java")
33
id("formatting-conventions")
4+
id("changelog")
45
}
56

67
group = "no.elixir"
@@ -14,6 +15,10 @@ dependencies {
1415

1516
tasks.test { useJUnitPlatform() }
1617

18+
subprojects {
19+
plugins.apply("changelog")
20+
}
21+
1722
tasks.wrapper {
1823
gradleVersion = "8.10"
1924
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
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

Comments
 (0)