Skip to content

Commit

Permalink
fix: Improved change log
Browse files Browse the repository at this point in the history
  • Loading branch information
jmongard committed Sep 13, 2023
1 parent 18d7a12 commit b04623d
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 57 deletions.
106 changes: 56 additions & 50 deletions src/main/kotlin/git/semver/plugin/gradle/ChangeLogFormatter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,86 +5,92 @@ import git.semver.plugin.semver.SemverSettings

class ChangeLogFormatter(private val settings: SemverSettings) {
companion object {
const val HEADING = "#"
const val OTHER = "*"
const val NO_TYPE = "-"
const val BREAKING = "!"
const val HEADER = "#"
const val FOOTER = "~"
const val OTHER_TYPE = "*"
const val MISSING_TYPE = "-"
const val BREAKING_CHANGE = "!"
const val CHANGE_PREFIX = ">"
const val CHANGE_POSTFIX = "<"
const val CHANGE_LINE_SEPARATOR = "\\"
}

private val prefix = settings.changeLogTexts[CHANGE_PREFIX].orEmpty()
private val separator = settings.changeLogTexts[CHANGE_LINE_SEPARATOR].orEmpty()
private val postfix = settings.changeLogTexts[CHANGE_POSTFIX].orEmpty()
private val breakingChange = settings.changeLogTexts[BREAKING_CHANGE]
private val missingType = settings.changeLogTexts[MISSING_TYPE]
private val otherType = settings.changeLogTexts[OTHER_TYPE]

internal fun formatLog(changeLog: List<String>): String {

val builder = StringBuilder()
settings.changeLogHeadings[HEADING]?.let {
builder.appendLine(it)
}
addText(builder, HEADER)

val groupedByHeading = mutableMapOf<String, MutableSet<String>>()
changeLog.forEach { addChange(it, groupedByHeading) }
groupedByHeading.toSortedMap().forEach { (prefix, items) ->
formatLogItems(builder, prefix, items)
}

return builder.toString()
addText(builder, FOOTER)
return builder.trim().toString()
}

private fun addChange(
it: String,
groupedByHeading: MutableMap<String, MutableSet<String>>
) {
if (settings.majorRegex.containsMatchIn(it)) {
add(groupedByHeading, settings.changeLogHeadings[BREAKING], it)
return
private fun addText(builder: StringBuilder, text: String) {
settings.changeLogTexts[text]?.let {
builder.appendLine(it).appendLine()
}
}

val match = settings.changeLogRegex.find(it);
if (match != null) {
val scope = matchValue(match, "Scope")?.let { settings.changeLogHeadings[it] }
if (scope != null) {
add(groupedByHeading, scope, it)
return
}

val type = matchValue(match, "Type")?.let { settings.changeLogHeadings[it] }
if (type != null) {
add(groupedByHeading, type,
(matchValue(match, "Scope")?.let { s -> "$s: " } ?: "") +
(matchValue(match, "Message")?.trim() ?: it))
return
private fun addChange(
text: String,
resultMap: MutableMap<String, MutableSet<String>>
) {
fun getValue(match: MatchResult, id: String) = match.groups[id]?.value
fun add(category: String?, message: String) {
category?.let {
resultMap.computeIfAbsent(it) { mutableSetOf() }.add(message)
}
}

add(groupedByHeading, settings.changeLogHeadings[OTHER], it)
if (settings.majorRegex.containsMatchIn(text)) {
add(breakingChange, text)
return
}

add(groupedByHeading, settings.changeLogHeadings[NO_TYPE], it)
}
val match = settings.changeLogRegex.find(text);
if (match == null) {
add(missingType, text)
return
}

private fun matchValue(match: MatchResult, id: String) = match.groups[id]?.value
val scope = getValue(match, "Scope")
val scopeHeading = scope?.let { settings.changeLogTexts[it] }
if (scopeHeading != null) {
add(scopeHeading, text)
return
}

private fun add(
groupedByHeading: MutableMap<String, MutableSet<String>>,
category: String?,
message: String
) {
category?.let {
groupedByHeading.computeIfAbsent(it) { mutableSetOf() }.add(message)
val typeHeading = getValue(match, "Type")?.let { settings.changeLogTexts[it] }
if (typeHeading != null) {
val messageText = getValue(match, "Message")
val scopeText = scope?.let { s -> "$s: " }.orEmpty()
add(typeHeading, scopeText + (messageText ?: text).trim())
return
}

add(otherType, text)
}

private fun formatLogItems(
sb: StringBuilder,
heading: String,
changeLog: Set<String>
) {
private fun formatLogItems(sb: StringBuilder, heading: String, changeLog: Set<String>) {
if (heading.isEmpty()) {
return;
}
sb.appendLine().appendLine(heading)
sb.appendLine(heading)
changeLog.sorted().forEach { item ->
sb.appendLine(
item.trim().lines()
.joinToString("\n ", " - ")
)
sb.appendLine(item.trim().lines().joinToString(separator, prefix, postfix))
}
sb.appendLine()
}
}
17 changes: 10 additions & 7 deletions src/main/kotlin/git/semver/plugin/semver/SemverSettings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,16 @@ open class SemverSettings {
var patchPattern: String = "\\Afix(?:\\([^()]+\\))?:"
var minorPattern: String = "\\Afeat(?:\\([^()]+\\))?:"
var majorPattern: String = "\\A\\w+(?:\\([^()]+\\))?!:|^BREAKING[ -]CHANGE:"

var changeLogPattern: String = "\\A(?<Type>\\w+)(?:\\((?<Scope>[^()]+)\\))?:(?<Message>(?:.|\n)*)"
var changeLogHeadings: Map<String, String> = mutableMapOf(
var changeLogTexts: Map<String, String> = mutableMapOf(
ChangeLogFormatter.OTHER_TYPE to "## Other Changes \uD83D\uDCA1",
ChangeLogFormatter.MISSING_TYPE to "## Other Changes \uD83D\uDCA1",
ChangeLogFormatter.BREAKING_CHANGE to "## Breaking Changes \uD83D\uDEE0",
ChangeLogFormatter.HEADER to "# What's Changed",
ChangeLogFormatter.CHANGE_PREFIX to " - ",
ChangeLogFormatter.CHANGE_LINE_SEPARATOR to "\n ",
ChangeLogFormatter.CHANGE_POSTFIX to "",
"fix" to "## Bug Fixes \uD83D\uDC1E",
"feat" to "## New Features \uD83C\uDF89",
"test" to "## Tests ✅",
Expand All @@ -21,12 +29,7 @@ open class SemverSettings {
"chore" to "## Chores",
"perf" to "## Performance Enhancements",
"refactor" to "## Refactorings",
"release" to "",
ChangeLogFormatter.OTHER to "## Other Changes \uD83D\uDCA1",
ChangeLogFormatter.NO_TYPE to "## Other Changes \uD83D\uDCA1",
ChangeLogFormatter.BREAKING to "## Breaking Changes \uD83D\uDEE0",
ChangeLogFormatter.HEADING to "# What's Changed"
)
"release" to "")

var releaseCommitTextFormat = "release: v%s\n\n%s"
var releaseTagNameFormat = "%s"
Expand Down

0 comments on commit b04623d

Please sign in to comment.