feat: rewrite commit parsing to support revert/reapply and merge commits
This commit is contained in:
parent
6d822fc915
commit
44a820e641
|
@ -4,25 +4,48 @@ enum class CommitType {
|
||||||
FIX, FEAT, BREAKING;
|
FIX, FEAT, BREAKING;
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val pattern: Regex = Regex("([a-zA-Z ]+)(?:\\([a-zA-Z0-9 -]+\\))?(!)?: .+", RegexOption.DOT_MATCHES_ALL)
|
private val conventionalPattern = Regex("^(\\w+)(\\(([\\w\\-.,\\s:]+)\\)?)?(!?)[\\s?]*:(.+)")
|
||||||
|
private val footerPattern = Regex("^(BREAKING[ -]CHANGE|[^ ]+)(((: )|( #))(.+))")
|
||||||
|
|
||||||
fun from(commitMessage: String, warn: (String) -> Unit): CommitType {
|
fun from(commitMessage: String, warn: (String) -> Unit): CommitType {
|
||||||
val match = pattern.matchEntire(commitMessage)
|
val lines = commitMessage.trim().split("\\r?\\n")
|
||||||
if (match != null) {
|
val headerMatch = conventionalPattern.matchEntire(extractHeader(lines[0]))
|
||||||
val m = match.groupValues
|
if (headerMatch == null) {
|
||||||
if (m[2] == "!") return BREAKING
|
warn("Could not parse commit, guessing type is FEAT: $commitMessage")
|
||||||
return when (m[1].lowercase()) {
|
return FEAT
|
||||||
"fix", "build", "chore", "ci", "docs", "style", "refactor", "perf", "test" -> FIX
|
}
|
||||||
"feat" -> FEAT
|
if (headerMatch.groupValues[3] == "!") return BREAKING
|
||||||
"breaking change", "breaking" -> BREAKING
|
for (s in lines.drop(1).filterNot { it.isBlank() }) {
|
||||||
else -> {
|
val footerMatch = footerPattern.matchEntire(s)
|
||||||
warn("Unrecognized commit type: ${m[1]}, guessing FEAT")
|
if (footerMatch != null) {
|
||||||
FEAT
|
val type = footerMatch.groupValues[1].lowercase()
|
||||||
}
|
if (type == "breaking change" || type == "breaking-change") return BREAKING
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
warn("Could not parse commit, guessing type is FEAT: $commitMessage")
|
return when (headerMatch.groupValues[1].lowercase()) {
|
||||||
return FEAT
|
"fix", "build", "chore", "ci", "docs", "style", "refactor", "perf", "test" -> FIX
|
||||||
|
"feat" -> FEAT
|
||||||
|
"breaking change", "breaking" -> BREAKING
|
||||||
|
else -> {
|
||||||
|
warn("Unrecognized commit type: ${headerMatch.groupValues[1]}, guessing FEAT")
|
||||||
|
FEAT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val revertPattern = Regex("^Revert \"(.+)\"", RegexOption.IGNORE_CASE)
|
||||||
|
private val reapplyPattern = Regex("^Reapply \"(.+)\"", RegexOption.IGNORE_CASE)
|
||||||
|
|
||||||
|
private tailrec fun extractHeader(headerLine: String): String {
|
||||||
|
if (headerLine.startsWith("Revert ")) {
|
||||||
|
val revertMatch = revertPattern.matchEntire(headerLine)
|
||||||
|
if (revertMatch != null) return extractHeader(revertMatch.groupValues[1])
|
||||||
|
}
|
||||||
|
if (headerLine.startsWith("Reapply ")) {
|
||||||
|
val reapplyMatch = reapplyPattern.matchEntire(headerLine)
|
||||||
|
if (reapplyMatch != null) return extractHeader(reapplyMatch.groupValues[1])
|
||||||
|
}
|
||||||
|
return headerLine
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -76,7 +76,7 @@ fun RevCommit.resolve(repo: Repository): Commit = Commit(
|
||||||
),
|
),
|
||||||
fullMessage,
|
fullMessage,
|
||||||
shortMessage,
|
shortMessage,
|
||||||
parents.map { ObjectId.toString(it) }
|
parents?.map { ObjectId.toString(it) } ?: emptyList()
|
||||||
)
|
)
|
||||||
|
|
||||||
private val String?.nullable get() = if (this == null || this == "") null else this
|
private val String?.nullable get() = if (this == null || this == "") null else this
|
||||||
|
@ -86,4 +86,6 @@ data class Tag(val id: ObjectId, val original: RevTag?, val fullName: String, va
|
||||||
val peeledId: ObjectId get() = commit.original.id
|
val peeledId: ObjectId get() = commit.original.id
|
||||||
}
|
}
|
||||||
data class Commit(val original: RevCommit, val id: ObjectId, val abbreviatedId: String?, val committer: Person, val author: Person, val dateTime: ZonedDateTime, val fullMessage: String, val shortMessage: String, val parentIds: List<String>)
|
data class Commit(val original: RevCommit, val id: ObjectId, val abbreviatedId: String?, val committer: Person, val author: Person, val dateTime: ZonedDateTime, val fullMessage: String, val shortMessage: String, val parentIds: List<String>)
|
||||||
data class Person(val original: PersonIdent, val name: String, val emailAddress: String)
|
data class Person(val original: PersonIdent, val name: String, val emailAddress: String)
|
||||||
|
|
||||||
|
private val Commit.isMerge get() = parentIds.size > 1
|
|
@ -30,6 +30,7 @@ if (File(projectDir, ".git").exists()) {
|
||||||
val log = git.log(tags[0].peeledId, git.repository.resolve("HEAD")).reversed()
|
val log = git.log(tags[0].peeledId, git.repository.resolve("HEAD")).reversed()
|
||||||
changelog += log.joinToString("\n") { "- ${it.shortMessage}" }
|
changelog += log.joinToString("\n") { "- ${it.shortMessage}" }
|
||||||
val type = log.stream()
|
val type = log.stream()
|
||||||
|
.filter { !it.isMerge }
|
||||||
.map { it.fullMessage }
|
.map { it.fullMessage }
|
||||||
.map { msg -> CommitType.from(msg) { logger.warn(it) } }
|
.map { msg -> CommitType.from(msg) { logger.warn(it) } }
|
||||||
.max { o1, o2 -> o1.compareTo(o2) }
|
.max { o1, o2 -> o1.compareTo(o2) }
|
||||||
|
|
Loading…
Reference in New Issue