Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Make release notes more organized #1020

Merged
merged 1 commit into from
Aug 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,24 +1,17 @@
package flank.scripts.ci.releasenotes

import flank.scripts.utils.markdownH2
import java.io.File

fun File.appendReleaseNotes(messages: List<String>, releaseTag: String) {
fun File.appendReleaseNotes(releaseNotesWithType: ReleaseNotesWithType, releaseTag: String) {
appendToReleaseNotes(
messages = messages,
releaseNotesWithType = releaseNotesWithType,
releaseTag = releaseTag
)
}

private fun File.appendToReleaseNotes(messages: List<String>, releaseTag: String) {
val currentFileLines = readLines()
val newLines = mutableListOf<String>().apply {
add(releaseTag.markdownH2())
addAll(messages)
add("")
}

writeText((newLines + currentFileLines).joinToString(System.lineSeparator()).withNewLineAtTheEnd())
private fun File.appendToReleaseNotes(releaseNotesWithType: ReleaseNotesWithType, releaseTag: String) {
writeText(releaseNotesWithType.asString(releaseTag).withNewLineAtTheEnd() +
readLines().joinToString(System.lineSeparator()).withNewLineAtTheEnd())
}

private fun String.withNewLineAtTheEnd() = plus(System.lineSeparator())
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package flank.scripts.ci.releasenotes

import flank.scripts.utils.markdownBold

fun String.mapPrTitle() = when {
startsWith("feat") -> replaceFirst("feat", "New feature".markdownBold())
startsWith("fix") -> replaceFirst("fix", "Fix".markdownBold())
startsWith("docs") -> replaceFirst("docs", "Documentation".markdownBold())
startsWith("refactor") -> replaceFirst("refactor", "Refactor".markdownBold())
startsWith("ci") -> replaceFirst("ci", "CI changes".markdownBold())
startsWith("test") -> replaceFirst("test", "Tests update".markdownBold())
startsWith("perf") -> replaceFirst("perf", "Performance upgrade".markdownBold())
fun String.mapPrTitleWithType() = when {
startsWith("feat") -> "Features" to skipConventionalCommitPrefix().capitalize()
startsWith("fix") -> "Bug Fixes" to skipConventionalCommitPrefix().capitalize()
startsWith("docs") -> "Documentation" to skipConventionalCommitPrefix().capitalize()
startsWith("refactor") -> "Refactor" to skipConventionalCommitPrefix().capitalize()
startsWith("ci") -> "CI Changes" to skipConventionalCommitPrefix().capitalize()
startsWith("test") -> "Tests update" to skipConventionalCommitPrefix().capitalize()
startsWith("perf") -> "Performance upgrade" to skipConventionalCommitPrefix().capitalize()
else -> null // we do not accept other prefix to have update in release notes
}

private fun String.skipConventionalCommitPrefix() = substring(indexOf(':') + 2)
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ fun generateReleaseNotes(githubToken: String) = runBlocking {
fun generateReleaseNotes(
latestReleaseTag: String,
githubToken: String
) = getCommitsSha(latestReleaseTag).getReleaseNotes(githubToken)
) = getCommitsSha(latestReleaseTag).getNewReleaseNotes(githubToken)

internal fun getCommitsSha(fromTag: String): List<String> {
val outputFile = File.createTempFile("sha", ".log")
Expand All @@ -32,18 +32,27 @@ internal fun getCommitsSha(fromTag: String): List<String> {
return outputFile.readLines()
}

private fun List<String>.getReleaseNotes(githubToken: String) = runBlocking {
private fun List<String>.getNewReleaseNotes(githubToken: String) = runBlocking {
map { sha -> async { getPrDetailsByCommit(sha, githubToken) } }
.awaitAll()
.filterIsInstance<Result.Success<List<GithubPullRequest>>>()
.map { it.value }
.filter { it.isNotEmpty() }
.mapNotNull { it.first().toReleaseNoteMessage() }
.mapNotNull { it.value.firstOrNull()?.toReleaseNoteMessage() }
.fold(mutableMapOf<String, MutableList<String>>()) { grouped, pr ->
grouped.apply {
val (type, message) = pr
appendToType(type, message)
}
}
}

private fun MutableMap<String, MutableList<String>>.appendToType(
type: String,
message: String
) = apply { (getOrPut(type) { mutableListOf() }).add(message) }

private fun GithubPullRequest.toReleaseNoteMessage() =
title.mapPrTitle()?.let { title ->
"- ${markdownLink(number.toString(), htmlUrl)} $title ${assignees.format()}"
title.mapPrTitleWithType()?.let { (type, title) ->
type to "- ${markdownLink("#$number", htmlUrl)} $title ${assignees.format()}"
}

private fun List<GithubUser>.format() = "(${joinToString { (login, url) -> markdownLink(login, url) }})"
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.parameters.options.default
import com.github.ajalt.clikt.parameters.options.option
import com.github.ajalt.clikt.parameters.options.required
import com.github.kittinunf.result.map
import com.github.kittinunf.result.success
import flank.scripts.ci.nexttag.generateNextReleaseTag
import flank.scripts.github.getLatestReleaseTag
import java.io.File
import kotlinx.coroutines.runBlocking
import java.io.File

class GenerateReleaseNotesCommand :
CliktCommand("Command to append item to release notes", name = "generateReleaseNotes") {
Expand All @@ -18,12 +19,14 @@ class GenerateReleaseNotesCommand :

override fun run() {
runBlocking {
getLatestReleaseTag(token).success {
File(releaseNotesFile).appendReleaseNotes(
messages = generateReleaseNotes(it.tag, token),
releaseTag = generateNextReleaseTag(it.tag)
)
}
getLatestReleaseTag(token)
.map { it.tag }
.success { previousTag ->
File(releaseNotesFile).appendReleaseNotes(
releaseNotesWithType = generateReleaseNotes(previousTag, token),
releaseTag = generateNextReleaseTag(previousTag)
)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package flank.scripts.ci.releasenotes

import flank.scripts.utils.markdownH2
import flank.scripts.utils.markdownH3
import java.lang.StringBuilder

typealias ReleaseNotesWithType = Map<String, List<String>>

fun ReleaseNotesWithType.asString(headerTag: String) =
StringBuilder(headerTag.markdownH2())
.appendln()
.apply {
this@asString.forEach { (type, messages) ->
appendln(type.markdownH3())
messages.forEach { appendln(it) }
}
}
.toString()
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package flank.scripts.release.hub

import flank.scripts.ci.releasenotes.ReleaseNotesWithType
import flank.scripts.ci.releasenotes.generateReleaseNotes
import flank.scripts.utils.markdownH2
import flank.scripts.utils.runCommand
Expand Down Expand Up @@ -38,7 +39,7 @@ private fun hubStableReleaseCommand(path: String, gitTag: String, token: String)
gitTag
)

private fun List<String>.asReleaseBody(tag: String) =
private fun ReleaseNotesWithType.asReleaseBody(tag: String) =
StringBuilder(tag.markdownH2())
.appendln()
.apply { this@asReleaseBody.forEach { appendln(it) } }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ fun String.markdownBold() = "**$this**"
fun markdownLink(description: String, url: String) = "[$description]($url)"

fun String.markdownH2() = "## $this"

fun String.markdownH3() = "### $this"
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package flank.scripts.ci.releasenotes

import com.google.common.truth.Truth.assertThat
import flank.scripts.utils.markdownH2
import flank.scripts.utils.markdownH3
import java.io.File
import org.junit.Test

Expand All @@ -13,21 +14,39 @@ class AppendReleaseNotesTest {
val testFile = File.createTempFile("empty", ".md")
val tag = "v20.08.0"
val expectedHeader = tag.markdownH2()
val messages = listOf(
"- [#11](https://github.com/Flank/flank/pull/11) **New feature**: Tests ([test_of](https://github.com/test_of))",
"- [#12](https://github.com/Flank/flank/pull/12) **New feature**: Tests2 ([test_of](https://github.com/test_of))",
"- [#13](https://github.com/Flank/flank/pull/13) **New feature**: Tests3 ([test_of](https://github.com/test_of))"
val messages = mapOf(
"Features" to listOf(
"- [#1](https://github.com/Flank/flank/pull/1) Tests1 ([test_of](https://github.com/test_of))",
"- [#2](https://github.com/Flank/flank/pull/2) Tests2 ([test_of](https://github.com/test_of))",
"- [#3](https://github.com/Flank/flank/pull/3) Tests3 ([test_of](https://github.com/test_of))"
),
"Bug fixes" to listOf(
"- [#11](https://github.com/Flank/flank/pull/11) Tests11 ([test_of](https://github.com/test_of))",
"- [#12](https://github.com/Flank/flank/pull/12) Tests12 ([test_of](https://github.com/test_of))",
"- [#13](https://github.com/Flank/flank/pull/13) Tests13 ([test_of](https://github.com/test_of))"
),
"Documentation" to listOf(
"- [#21](https://github.com/Flank/flank/pull/21) Tests21 ([test_of](https://github.com/test_of))",
"- [#22](https://github.com/Flank/flank/pull/22) Tests22 ([test_of](https://github.com/test_of))",
"- [#23](https://github.com/Flank/flank/pull/23) Tests33 ([test_of](https://github.com/test_of))"
)
)
val expectedLinesCount = testFile.readLines().size + messages.size + 2 // header + newline
val expectedLinesCount = testFile.readLines().size +
12 + // values to append
3 // header + newline + end newline

// when
testFile.appendReleaseNotes(messages, tag)

// verify
val lines = testFile.readLines()
assertThat(lines.first()).isEqualTo(expectedHeader)
messages.forEachIndexed { index, text ->
assertThat(lines[index + 1]).isEqualTo(text)
var currentLine = 1
messages.keys.forEach { type ->
assertThat(lines[currentLine++]).isEqualTo(type.markdownH3())
messages[type]?.forEach { line ->
assertThat(lines[currentLine++]).isEqualTo(line)
}
}
assertThat(lines.last()).isEmpty()
assertThat(lines.size).isEqualTo(expectedLinesCount)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,40 @@ import org.junit.runner.RunWith
import org.junit.runners.Parameterized

@RunWith(Parameterized::class)
class ConventionalCommitFormatterTest(private val mapFrom: String, private val expected: String?) {
class ConventionalCommitFormatterTest(
private val mapFrom: String,
private val expectedType: String?,
private val expectedTitle: String?
) {

companion object {
@JvmStatic
@Parameterized.Parameters(name = "{0} to {1}")
fun data() = listOf(
arrayOf("feat: Sample", "New feature"),
arrayOf("fix: Bug", "Fix"),
arrayOf("docs: New", "Documentation"),
arrayOf("refactor: Eveerything", "Refactor"),
arrayOf("ci(cd): actions", "CI changes"),
arrayOf("test(ios): update", "Tests update"),
arrayOf("perf!: 10%", "Performance upgrade"),
arrayOf("style: dd", null),
arrayOf("build: passed", null),
arrayOf("chore: release", null),
arrayOf("nope: nbd", null)
arrayOf("feat: Sample", "Features", "Sample"),
arrayOf("fix: Bug", "Bug Fixes", "Bug"),
arrayOf("docs: New", "Documentation", "New"),
arrayOf("refactor: Eveerything", "Refactor", "Eveerything"),
arrayOf("ci(cd): actions", "CI Changes", "Actions"),
arrayOf("test(ios): update", "Tests update", "Update"),
arrayOf("perf!: 10%", "Performance upgrade", "10%"),
arrayOf("style: dd", null, null),
arrayOf("build: passed", null, null),
arrayOf("chore: release", null, null),
arrayOf("nope: nbd", null, null)
)
}

@Test
fun `Should properly map`() {
// given
val expected = expected?.let { "**$it**" }

// when
val actual = mapFrom.mapPrTitle()
val actual = mapFrom.mapPrTitleWithType()

// then
if (expected != null) {
assertThat(actual).startsWith(expected)
if (expectedType != null) {
val (type, title) = actual!!
assertThat(type).isEqualTo(expectedType)
assertThat(title).startsWith(expectedTitle)
} else {
assertThat(actual).isNull()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package flank.scripts.ci.releasenotes

import org.junit.Assert.assertEquals
import org.junit.Test

class ReleaseNotesWithTypeTest {

@Test
fun `Should properly format release notes with type`() {
// given
val testTag = "TAG"
val expected = """
## TAG
### Features
- [#1](https://github.com/Flank/flank/pull/1) Tests1 ([test_of](https://github.com/test_of))
- [#2](https://github.com/Flank/flank/pull/2) Tests2 ([test_of](https://github.com/test_of))
- [#3](https://github.com/Flank/flank/pull/3) Tests3 ([test_of](https://github.com/test_of))
### Bug fixes
- [#11](https://github.com/Flank/flank/pull/11) Tests11 ([test_of](https://github.com/test_of))
- [#12](https://github.com/Flank/flank/pull/12) Tests12 ([test_of](https://github.com/test_of))
- [#13](https://github.com/Flank/flank/pull/13) Tests13 ([test_of](https://github.com/test_of))
### Documentation
- [#21](https://github.com/Flank/flank/pull/21) Tests21 ([test_of](https://github.com/test_of))
- [#22](https://github.com/Flank/flank/pull/22) Tests22 ([test_of](https://github.com/test_of))
- [#23](https://github.com/Flank/flank/pull/23) Tests33 ([test_of](https://github.com/test_of))

""".trimIndent()
val releaseNotesWithType = mapOf(
"Features" to listOf(
"- [#1](https://github.com/Flank/flank/pull/1) Tests1 ([test_of](https://github.com/test_of))",
"- [#2](https://github.com/Flank/flank/pull/2) Tests2 ([test_of](https://github.com/test_of))",
"- [#3](https://github.com/Flank/flank/pull/3) Tests3 ([test_of](https://github.com/test_of))"
),
"Bug fixes" to listOf(
"- [#11](https://github.com/Flank/flank/pull/11) Tests11 ([test_of](https://github.com/test_of))",
"- [#12](https://github.com/Flank/flank/pull/12) Tests12 ([test_of](https://github.com/test_of))",
"- [#13](https://github.com/Flank/flank/pull/13) Tests13 ([test_of](https://github.com/test_of))"
),
"Documentation" to listOf(
"- [#21](https://github.com/Flank/flank/pull/21) Tests21 ([test_of](https://github.com/test_of))",
"- [#22](https://github.com/Flank/flank/pull/22) Tests22 ([test_of](https://github.com/test_of))",
"- [#23](https://github.com/Flank/flank/pull/23) Tests33 ([test_of](https://github.com/test_of))"
)
)

// when
val actual = releaseNotesWithType.asString(testTag)

// then
assertEquals(expected, actual)
}
}