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;
|
||||
|
||||
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 {
|
||||
val match = pattern.matchEntire(commitMessage)
|
||||
if (match != null) {
|
||||
val m = match.groupValues
|
||||
if (m[2] == "!") return BREAKING
|
||||
return when (m[1].lowercase()) {
|
||||
"fix", "build", "chore", "ci", "docs", "style", "refactor", "perf", "test" -> FIX
|
||||
"feat" -> FEAT
|
||||
"breaking change", "breaking" -> BREAKING
|
||||
else -> {
|
||||
warn("Unrecognized commit type: ${m[1]}, guessing FEAT")
|
||||
FEAT
|
||||
}
|
||||
val lines = commitMessage.trim().split("\\r?\\n")
|
||||
val headerMatch = conventionalPattern.matchEntire(extractHeader(lines[0]))
|
||||
if (headerMatch == null) {
|
||||
warn("Could not parse commit, guessing type is FEAT: $commitMessage")
|
||||
return FEAT
|
||||
}
|
||||
if (headerMatch.groupValues[3] == "!") return BREAKING
|
||||
for (s in lines.drop(1).filterNot { it.isBlank() }) {
|
||||
val footerMatch = footerPattern.matchEntire(s)
|
||||
if (footerMatch != null) {
|
||||
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 FEAT
|
||||
return when (headerMatch.groupValues[1].lowercase()) {
|
||||
"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,
|
||||
shortMessage,
|
||||
parents.map { ObjectId.toString(it) }
|
||||
parents?.map { ObjectId.toString(it) } ?: emptyList()
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
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()
|
||||
changelog += log.joinToString("\n") { "- ${it.shortMessage}" }
|
||||
val type = log.stream()
|
||||
.filter { !it.isMerge }
|
||||
.map { it.fullMessage }
|
||||
.map { msg -> CommitType.from(msg) { logger.warn(it) } }
|
||||
.max { o1, o2 -> o1.compareTo(o2) }
|
||||
|
|
Loading…
Reference in New Issue