Last active
April 24, 2020 13:40
-
-
Save ywett02/580c81bf782e2b589b06a4e3848a8227 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.livepenalty.android | |
import com.livepenalty.android.CommitRange.BiDirectional | |
import com.livepenalty.android.CommitRange.UniDirectional | |
import com.livepenalty.android.ConventionalCommit.chore | |
import com.livepenalty.android.ConventionalCommit.docs | |
import com.livepenalty.android.ConventionalCommit.feat | |
import com.livepenalty.android.ConventionalCommit.fix | |
import com.livepenalty.android.ConventionalCommit.other | |
import com.livepenalty.android.ConventionalCommit.refactor | |
import com.livepenalty.android.ConventionalCommit.style | |
import com.livepenalty.android.ConventionalCommit.test | |
import org.gradle.api.DefaultTask | |
import org.gradle.api.tasks.Input | |
import org.gradle.api.tasks.TaskAction | |
import java.io.ByteArrayOutputStream | |
import java.io.File | |
import java.text.SimpleDateFormat | |
import java.util.Date | |
import java.util.Locale | |
fun providerAuthorityForFlavor(prefix: String, suffix: String?): String = | |
if (suffix == null) { | |
"$prefix.fileprovider" | |
} else { | |
"$prefix$suffix.fileprovider" | |
} | |
fun nowFormatted(pattern: String) = SimpleDateFormat(pattern, Locale.getDefault()).format(Date()) | |
fun envOrDefaultValue(propertyName: String, defaultValue: Int): Int { | |
val property = System.getenv(propertyName) | |
return if (property?.trim().isNullOrEmpty()) { | |
defaultValue | |
} else { | |
property.toInt() | |
} | |
} | |
fun generateVersionCode(majorVersion: Int, minorVersion: Int, patchVersion: Int, buildVersion: Int) = | |
majorVersion * 10000000 + minorVersion * 100000 + patchVersion * 1000 + buildVersion | |
fun generateVersionName(majorVersion: Int, minorVersion: Int, patchVersion: Int) = | |
"${majorVersion}.${minorVersion}.${patchVersion}" | |
fun isNonStableVersion(version: String): Boolean { | |
val stableKeyword = listOf("RELEASE", "FINAL", "GA").any { version.toUpperCase().contains(it) } | |
val regex = "^[0-9,.v-]+(-r)?$".toRegex() | |
val isStable = stableKeyword || regex.matches(version) | |
return isStable.not() | |
} | |
enum class ConventionalCommit(val title: String) { | |
feat("Features ⚽"), | |
fix("Fixes \uD83D\uDC1B"), | |
docs("Documentation"), | |
style("Formatting"), | |
refactor("Refactoring"), | |
test("Testing"), | |
chore("Chore"), | |
other("Other"); | |
} | |
inline class GitTag(val name: String) | |
inline class GitCommit(val message: String) | |
sealed class CommitRange { | |
abstract val range: String | |
data class BiDirectional(val start: GitTag, val end: GitTag) : CommitRange() { | |
override val range: String = "${start.name}..${end.name}" | |
} | |
data class UniDirectional(val end: GitTag) : CommitRange() { | |
override val range: String = end.name | |
} | |
} | |
open class Changelog : DefaultTask() { | |
@Input | |
lateinit var flavor: String | |
@TaskAction | |
fun generateChangelog() { | |
val lastTag = lastTag() | |
println("Current version: $lastTag") | |
val lastMajorVersion = lastMajorVersion(flavor) | |
println("Last major Version: $lastMajorVersion") | |
val range = if (lastMajorVersion == null) UniDirectional(lastTag) else BiDirectional(lastMajorVersion, lastTag) | |
println("Range: ${range.range}") | |
val commits = changelogCommits(range) | |
println(commits.joinToString(separator = "\n")) | |
val changelogString = changelogString(commits) | |
println(changelogString) | |
File("app/build/changelog.md").apply { | |
writeText(if (changelogString.isEmpty()) "No changes" else changelogString) | |
} | |
} | |
private fun changelogString(commits: List<GitCommit>): String { | |
val map = hashMapOf<ConventionalCommit, List<String>>() | |
commits.map { commit -> commit.message.split(":") }.forEach { message -> | |
val header = message.first() | |
when { | |
message.size != 2 -> map.addItem(other, message.joinToString(separator = " ")) | |
header.startsWith(feat.name, true) -> map.addItem(feat, message[1]) | |
header.startsWith(fix.name, true) -> map.addItem(fix, message[1]) | |
header.startsWith(docs.name, true) -> map.addItem(docs, message[1]) | |
header.startsWith(style.name, true) -> map.addItem(style, message[1]) | |
header.startsWith(refactor.name, true) -> map.addItem(refactor, message[1]) | |
header.startsWith(test.name, true) -> map.addItem(test, message[1]) | |
header.startsWith(chore.name, true) -> map.addItem(chore, message[1]) | |
else -> map.addItem(other, message[1]) | |
} | |
} | |
return buildString { | |
map.forEach { entry -> | |
append("\n") | |
append("### ${entry.key.title}") | |
append("\n") | |
append(entry.value.map { message -> "- ${message.trim()}" }.joinToString(separator = "\n")) | |
append("\n") | |
} | |
} | |
} | |
private fun changelogCommits(commitRange: CommitRange): List<GitCommit> { | |
val commitsOutput = ByteArrayOutputStream() | |
project.exec { | |
isIgnoreExitValue = true | |
commandLine( | |
"sh", | |
"-c", | |
"git log ${commitRange.range} --first-parent --merges --pretty=format:'%b (%h)' | grep -v \"'master' into\"" | |
) | |
standardOutput = commitsOutput | |
} | |
return if (commitsOutput.toString().isBlank()) emptyList() else commitsOutput.toString().split("\n") | |
.takeWhile { it.isNotBlank() }.map { message -> GitCommit(message) } | |
} | |
private fun lastTag(): GitTag { | |
val tagOutput = ByteArrayOutputStream() | |
project.exec { | |
commandLine("git", "describe", "--abbrev=0", "--tags") | |
standardOutput = tagOutput | |
} | |
return GitTag(tagOutput.toString().trim()) | |
} | |
private fun lastMajorVersion(flavor: String): GitTag? { | |
val tagsOutput = ByteArrayOutputStream() | |
project.exec { | |
commandLine("git", "tag", "-l", "v[0-9]*-$flavor") | |
standardOutput = tagsOutput | |
} | |
val tags = tagsOutput.toString().split("\n").takeWhile { input -> input.isNotEmpty() } | |
return if (tags.size > 1) GitTag(tags[tags.size - 2]) else null | |
} | |
private fun <K, V> HashMap<K, List<V>>.addItem(key: K, item: V) { | |
this[key] = this.getOrDefault(key, listOf()).plus(item) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment