Skip to content

Commit

Permalink
ignore commits with no author information
Browse files Browse the repository at this point in the history
  • Loading branch information
cmhulbert committed Jan 13, 2021
1 parent 37b825f commit 07f061b
Showing 1 changed file with 174 additions and 169 deletions.
343 changes: 174 additions & 169 deletions create-changelog.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,63 +18,66 @@ import java.net.HttpURLConnection
import java.net.URL

data class Change(
val sha: String,
val author: String,
val message: String,
val date: String) {
constructor(commit: JSONObject) : this(
sha = commit.getString("sha"),
author = (commit["author"] as JSONObject).getString("login"),
message = (commit["commit"] as JSONObject).getString("message"),
date = (((commit["commit"] as JSONObject)["author"] as JSONObject)).getString("date"))
val sha: String,
val author: String,
val message: String,
val date: String
) {
constructor(commit: JSONObject) : this(
sha = commit.getString("sha"),
author = if (commit.isNull("author")) "NULL" else (commit["author"] as JSONObject).getString("login"),
message = (commit["commit"] as JSONObject).getString("message"),
date = if (commit.isNull("author")) "NULL" else (((commit["commit"] as JSONObject)["author"] as JSONObject)).getString("date")
)
}

fun versionFromString(str: String): Version {
return if (str.contains("-")) {
val split = str.split("-")
val Mmp = split[0].split(".").map { it.toInt() }.toIntArray()
Version(Mmp[0], Mmp[1], Mmp[2], split[1])
} else {
val Mmp = str.split(".").map { it.toInt() }.toIntArray()
Version(Mmp[0], Mmp[1], Mmp[2], null)
}
return if (str.contains("-")) {
val split = str.split("-")
val Mmp = split[0].split(".").map { it.toInt() }.toIntArray()
Version(Mmp[0], Mmp[1], Mmp[2], split[1])
} else {
val Mmp = str.split(".").map { it.toInt() }.toIntArray()
Version(Mmp[0], Mmp[1], Mmp[2], null)
}
}

data class Version(
val major: Int,
val minor: Int,
val patch: Int,
val preRelease: String? = null) : Comparable<Version> {

val versionString = preRelease?.let { "$major.$minor.$patch-$preRelease" } ?: "$major.$minor.$patch"

override fun toString() = versionString

override fun compareTo(other: Version): Int {
val majorComp = major.compareTo(other.major)
if (majorComp != 0)
return majorComp
val minorComp = minor.compareTo(other.minor)
if (minorComp != 0)
return minorComp
val patchComp = patch.compareTo(other.patch)
if (patchComp != 0)
return patchComp
if (preRelease === null && other.preRelease != null)
return 1
if (other.preRelease === null && preRelease != null)
return -1
else if (other.preRelease === null && preRelease === null)
return 0
return preRelease!!.compareTo(other.preRelease!!)
}

fun bump(major: Boolean = false, minor: Boolean = false, patch: Boolean = false): Version {
if (major) return Version(this.major + 1, 0, 0, null)
if (minor) return Version(this.major, this.minor + 1, 0, null)
if (patch) return Version(this.major, this.minor, this.patch + 1, null)
return Version(this.major, this.minor, this.patch, this.preRelease)
}
val major: Int,
val minor: Int,
val patch: Int,
val preRelease: String? = null
) : Comparable<Version> {

val versionString = preRelease?.let { "$major.$minor.$patch-$preRelease" } ?: "$major.$minor.$patch"

override fun toString() = versionString

override fun compareTo(other: Version): Int {
val majorComp = major.compareTo(other.major)
if (majorComp != 0)
return majorComp
val minorComp = minor.compareTo(other.minor)
if (minorComp != 0)
return minorComp
val patchComp = patch.compareTo(other.patch)
if (patchComp != 0)
return patchComp
if (preRelease === null && other.preRelease != null)
return 1
if (other.preRelease === null && preRelease != null)
return -1
else if (other.preRelease === null && preRelease === null)
return 0
return preRelease!!.compareTo(other.preRelease!!)
}

fun bump(major: Boolean = false, minor: Boolean = false, patch: Boolean = false): Version {
if (major) return Version(this.major + 1, 0, 0, null)
if (minor) return Version(this.major, this.minor + 1, 0, null)
if (patch) return Version(this.major, this.minor, this.patch + 1, null)
return Version(this.major, this.minor, this.patch, this.preRelease)
}

}

Expand All @@ -84,138 +87,140 @@ fun getTags(repo: String) = JSONArray(fromURL(URL("$GITHUB_API_URL/repos/$repo/t

fun getCommitTags(repo: String) = getTags(repo).filter { it.has("commit") }

fun getParentsFromTag(repo: String, tag: JSONObject) = JSONObject(fromURL(URL("$GITHUB_API_URL/repos/$repo/commits/${(tag["commit"] as JSONObject)["sha"]}")))["parents"] as JSONArray
fun getParentsFromTag(repo: String, tag: JSONObject) =
JSONObject(fromURL(URL("$GITHUB_API_URL/repos/$repo/commits/${(tag["commit"] as JSONObject)["sha"]}")))["parents"] as JSONArray

fun getParentFromTag(repo: String, tag: JSONObject) = getParentsFromTag(repo, tag)
.also { require(it.length() == 1) { "Release tags must have exactly one parent but got $it" } }[0] as JSONObject
.also { require(it.length() == 1) { "Release tags must have exactly one parent but got $it" } }[0] as JSONObject

fun compare(repo: String, shaFrom: String, shaTo: String): List<Change> {
val compareUrl = URL("$GITHUB_API_URL/repos/$repo/compare/$shaFrom...$shaTo")
val compareObj = JSONObject(fromURL(compareUrl))
val commits = compareObj["commits"] as JSONArray
return commits.map { Change(it as JSONObject) }
val compareUrl = URL("$GITHUB_API_URL/repos/$repo/compare/$shaFrom...$shaTo")
val compareObj = JSONObject(fromURL(compareUrl))
val commits = compareObj["commits"] as JSONArray
return commits.filter { !((it as JSONObject).isNull("author"))}.map { Change(it as JSONObject) }
}


fun fromURL(url: URL): String {
val conn = url.openConnection() as HttpURLConnection;
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/json");
val conn = url.openConnection() as HttpURLConnection;
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/json");

if (conn.getResponseCode() != 200)
throw RuntimeException("Failed : HTTP error code : ${conn.responseCode}")
if (conn.getResponseCode() != 200)
throw RuntimeException("Failed : HTTP error code : ${conn.responseCode}")

val br = conn.inputStream.bufferedReader();
val text = br.use(BufferedReader::readText)
conn.disconnect()
return text
val br = conn.inputStream.bufferedReader();
val text = br.use(BufferedReader::readText)
conn.disconnect()
return text
}

fun generateChangelog() {

val reader = MavenXpp3Reader()
val model = FileReader("pom.xml").use { reader.read(it) }
val isSnapshot = model.version.contains("-SNAPSHOT")
val version = versionFromString(model.version)

val tags = getCommitTags("saalfeldlab/paintera").filter {
try {
versionFromString(it.getString("name").replace("paintera-", ""))
true
} catch (e: Exception) {
false
}
}

val repo = FileRepositoryBuilder().setGitDir(File(".git")).build()
val head = repo.resolve("HEAD")
val commitTo = if (isSnapshot) {
head.name
} else {
"paintera-${model.version}"
.takeUnless { t -> tags.count { it.getString("name") == t } == 0 }
?: head.name
}

val tagFrom = tags.first { versionFromString(it.getString("name").replace("paintera-", "")) < version }
val commitFrom = getParentFromTag("saalfeldlab/paintera", tagFrom)
val relevantCommits = compare(
repo = "saalfeldlab/paintera",
shaFrom = commitFrom.getString("sha"),
shaTo = commitTo)
val mergeCommits = relevantCommits.filter { it.message.startsWith("Merge pull request #") }

val breaking = mutableListOf<String>()
val features = mutableListOf<String>()
val fixes = mutableListOf<String>()
val unversioned = mutableListOf<String>()
val visitedCommits = mutableSetOf<String>()
val pullRequests = mutableListOf<Pair<Int, String>>()

val regex = "Merge pull request #([0-9]+)".toRegex()

for (commit in mergeCommits) {
if (visitedCommits.contains(commit.sha)) continue
visitedCommits.add(commit.sha)
val lines = commit.message.lines()
val matchResult = regex.find(lines[0])
val pullRequestNumber = if (matchResult === null) {
-1
} else {
matchResult.groupValues[1].toInt()
}
pullRequests += Pair(pullRequestNumber, commit.message)
var isAnything = false
for (line in lines) {
var l = line
val isBreaking = if (l.contains("[BREAKING]")) {
l = l.replace("[BREAKING]", "").trim()
true
} else false
val isFeature = if (l.contains("[FEATURE]")) {
l = l.replace("[FEATURE]", "").trim()
true
} else false
val isBugfix = if (l.contains("[BUGFIX]")) {
l = l.replace("[BUGFIX]", "").trim()
true
} else false
val isUnversioned = if (l.contains("[UNVERSIONED]")) {
l = l.replace("[UNVERSIONED]", "").trim()
true
} else false
isAnything = isBreaking || isFeature || isBugfix || isUnversioned
if (pullRequestNumber > 0) l = "$l (#$pullRequestNumber)"
if (isBreaking) breaking.add(l)
if (isFeature) features.add(l)
if (isBugfix) fixes.add(l)
if (isUnversioned) unversioned.add(l)
}
if (!isAnything) {
unversioned.add(commit.message.replace("\n+".toRegex(), ": "))
}
}

val versionFrom = versionFromString(tagFrom.getString("name").replace("paintera-", ""))
val suggestedVersion = versionFrom.bump(major = !breaking.isEmpty(), minor = !features.isEmpty(), patch = !fixes.isEmpty())

var text = "# Paintera $suggestedVersion\nPrevious release: $versionFrom\n\n\n## Changelog"

if (!breaking.isEmpty())
text = "$text\n\n### Breaking Changes${breaking.map { "\n - $it" }.joinToString("")}"

if (!features.isEmpty())
text = "$text\n\n### New Features${features.map { "\n - $it" }.joinToString("")}"

if (!fixes.isEmpty())
text = "$text\n\n### Bug Fixes${fixes.map { "\n - $it" }.joinToString("")}"

if (!unversioned.isEmpty())
text = "$text\n\n### Other${unversioned.map { "\n - $it" }.joinToString("")}"
val pullRequestStrings = pullRequests.map { "### #${it.first}\n${it.second}" }
text = "$text\n\n\n## Pull Requests\n\n${pullRequestStrings.joinToString("\n\n")}"

println(text)
val reader = MavenXpp3Reader()
val model = FileReader("pom.xml").use { reader.read(it) }
val isSnapshot = model.version.contains("-SNAPSHOT")
val version = versionFromString(model.version)

val tags = getCommitTags("saalfeldlab/paintera").filter {
try {
versionFromString(it.getString("name").replace("paintera-", ""))
true
} catch (e: Exception) {
false
}
}

val repo = FileRepositoryBuilder().setGitDir(File(".git")).build()
val head = repo.resolve("HEAD")
val commitTo = if (isSnapshot) {
head.name
} else {
"paintera-${model.version}"
.takeUnless { t -> tags.count { it.getString("name") == t } == 0 }
?: head.name
}

val tagFrom = tags.first { versionFromString(it.getString("name").replace("paintera-", "")) < version }
val commitFrom = getParentFromTag("saalfeldlab/paintera", tagFrom)
val relevantCommits = compare(
repo = "saalfeldlab/paintera",
shaFrom = commitFrom.getString("sha"),
shaTo = commitTo
)
val mergeCommits = relevantCommits.filter { it.message.startsWith("Merge pull request #") }

val breaking = mutableListOf<String>()
val features = mutableListOf<String>()
val fixes = mutableListOf<String>()
val unversioned = mutableListOf<String>()
val visitedCommits = mutableSetOf<String>()
val pullRequests = mutableListOf<Pair<Int, String>>()

val regex = "Merge pull request #([0-9]+)".toRegex()

for (commit in mergeCommits) {
if (visitedCommits.contains(commit.sha)) continue
visitedCommits.add(commit.sha)
val lines = commit.message.lines()
val matchResult = regex.find(lines[0])
val pullRequestNumber = if (matchResult === null) {
-1
} else {
matchResult.groupValues[1].toInt()
}
pullRequests += Pair(pullRequestNumber, commit.message)
var isAnything = false
for (line in lines) {
var l = line
val isBreaking = if (l.contains("[BREAKING]")) {
l = l.replace("[BREAKING]", "").trim()
true
} else false
val isFeature = if (l.contains("[FEATURE]")) {
l = l.replace("[FEATURE]", "").trim()
true
} else false
val isBugfix = if (l.contains("[BUGFIX]")) {
l = l.replace("[BUGFIX]", "").trim()
true
} else false
val isUnversioned = if (l.contains("[UNVERSIONED]")) {
l = l.replace("[UNVERSIONED]", "").trim()
true
} else false
isAnything = isBreaking || isFeature || isBugfix || isUnversioned
if (pullRequestNumber > 0) l = "$l (#$pullRequestNumber)"
if (isBreaking) breaking.add(l)
if (isFeature) features.add(l)
if (isBugfix) fixes.add(l)
if (isUnversioned) unversioned.add(l)
}
if (!isAnything) {
unversioned.add(commit.message.replace("\n+".toRegex(), ": "))
}
}

val versionFrom = versionFromString(tagFrom.getString("name").replace("paintera-", ""))
val suggestedVersion = versionFrom.bump(major = !breaking.isEmpty(), minor = !features.isEmpty(), patch = !fixes.isEmpty())

var text = "# Paintera $suggestedVersion\nPrevious release: $versionFrom\n\n\n## Changelog"

if (!breaking.isEmpty())
text = "$text\n\n### Breaking Changes${breaking.map { "\n - $it" }.joinToString("")}"

if (!features.isEmpty())
text = "$text\n\n### New Features${features.map { "\n - $it" }.joinToString("")}"

if (!fixes.isEmpty())
text = "$text\n\n### Bug Fixes${fixes.map { "\n - $it" }.joinToString("")}"

if (!unversioned.isEmpty())
text = "$text\n\n### Other${unversioned.map { "\n - $it" }.joinToString("")}"
val pullRequestStrings = pullRequests.map { "### #${it.first}\n${it.second}" }
text = "$text\n\n\n## Pull Requests\n\n${pullRequestStrings.joinToString("\n\n")}"

println(text)
}

generateChangelog()

0 comments on commit 07f061b

Please sign in to comment.