diff --git a/CHANGELOG.md b/CHANGELOG.md index e5c069c..0726eea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,11 +17,12 @@ adhere to https://github.com/olivierlacan/keep-a-changelog. ### Internal - [Issue-#31] Reformat code according to Kotlin coding conventions - [Issue-#33] Move all GitHub API calls to GitHubAPIClient to adhere to the Single Responsibility Principle +- [Issue-#40] Migrate Klaxon to kotlinx.serialization JSON Serializer library ## [1.3.0] - 2021-02-01 ### Added -- [Issue-#14] Github authentication token configurable through app.properties +- [Issue-#14] GitHub's authentication token configurable through app.properties - [Issue-#29] Improve app user experience by using `Clikt` library for command line user interaction ### Changed @@ -85,3 +86,4 @@ adhere to https://github.com/olivierlacan/keep-a-changelog. [Issue-#33]: https://github.com/ClausPolanka/github-pr-factory/issues/33 [Issue-#35]: https://github.com/ClausPolanka/github-pr-factory/issues/35 [Issue-#36]: https://github.com/ClausPolanka/github-pr-factory/issues/36 +[Issue-#40]: https://github.com/ClausPolanka/github-pr-factory/issues/40 diff --git a/README.md b/README.md index c20bda9..9c07e24 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ ## github-pr-factory -George Hiring Github Pull Request Factory +George Hiring GitHub Pull Request Factory The **github-pr-factory** allows creating pull requests via command line. The candidate has to create git branches with the following naming scheme: @@ -83,10 +83,10 @@ Options: ### user.properties - Setting user properties to reduce typing -You can set your Github authentication token in a file called `user.properties`. +You can set your GitHub authentication token in a file called `user.properties`. The `github-pr-factory` app expects the file to be either on the classpath or in the same directory in which the app gets executed. -In case you are using a `user.properties` you can set the Github authentication +In case you are using a `user.properties` you can set the GitHub authentication token by adding a key-value-pair `github-token=TODO` to the file where the `TODO` must be replaced with your token. Therefore, you don't need to pass the token neither to the `open` nor `close` command. diff --git a/pom.xml b/pom.xml index 98f1211..9916e2d 100644 --- a/pom.xml +++ b/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 github-pr-factory @@ -15,7 +16,7 @@ 3.19.0 2.28.0 1.0.0 - 5.5 + 1.2.1 3.0.0-M4 3.2.0 3.3.0 @@ -33,17 +34,16 @@ kotlin-reflect ${kotlin.version} - - - com.beust - klaxon - ${klaxon.version} - khttp khttp ${khttp.version} + + org.jetbrains.kotlinx + kotlinx-serialization-json + ${kotlinx.serialization.version} + com.github.ajalt.clikt clikt-jvm @@ -84,6 +84,12 @@ org.apache.maven.plugins maven-surefire-plugin ${maven-surefire-plugin.version} + + + **/*IT + **/*Test + + org.jetbrains.kotlin @@ -104,8 +110,18 @@ + + kotlinx-serialization + 1.8 + + + org.jetbrains.kotlin + kotlin-maven-serialization + ${kotlin.version} + + org.apache.maven.plugins @@ -150,7 +166,7 @@ - + jcenter https://jcenter.bintray.com/ diff --git a/src/main/kotlin/pullrequestfactory/Main.kt b/src/main/kotlin/pullrequestfactory/Main.kt index 2209e01..83c4982 100644 --- a/src/main/kotlin/pullrequestfactory/Main.kt +++ b/src/main/kotlin/pullrequestfactory/Main.kt @@ -1,22 +1,33 @@ package pullrequestfactory import com.github.ajalt.clikt.core.subcommands +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.json.Json +import kotlinx.serialization.modules.SerializersModule +import kotlinx.serialization.modules.contextual import pullrequestfactory.io.clikt.CloseCommand import pullrequestfactory.io.clikt.CommandArgs import pullrequestfactory.io.clikt.GitHubPrFactoryCommand import pullrequestfactory.io.clikt.OpenCommand import pullrequestfactory.io.programs.impl.FileAppProperties +import pullrequestfactory.io.programs.impl.InstantSerializer import pullrequestfactory.io.uis.ConsoleUI +@ExperimentalSerializationApi fun main(args: Array) { val appProps = FileAppProperties("app.properties") val cmdArgs = CommandArgs( appProps.getGithubBaseUrl(), appProps.getGithubRepositoryPath(), "user.properties", - ConsoleUI() + ConsoleUI(), + jsonSerializer() ) GitHubPrFactoryCommand(appProps.getProjectVersion()) .subcommands(OpenCommand(cmdArgs), CloseCommand(cmdArgs)) .main(args) } + +@ExperimentalSerializationApi +fun jsonSerializer() = + Json { ignoreUnknownKeys = true; serializersModule = SerializersModule { contextual(InstantSerializer) } } diff --git a/src/main/kotlin/pullrequestfactory/domain/PairingPartner.kt b/src/main/kotlin/pullrequestfactory/domain/PairingPartner.kt index 2d43d62..99b4cca 100644 --- a/src/main/kotlin/pullrequestfactory/domain/PairingPartner.kt +++ b/src/main/kotlin/pullrequestfactory/domain/PairingPartner.kt @@ -31,14 +31,14 @@ enum class PairingPartner(vararg val pullRequestNames: String) { MARTON("Marton"), ; - fun contains(branchName: String): Boolean = pullRequestNames.contains(branchName.capitalize()) + fun contains(branchName: String): Boolean = pullRequestNames.contains(branchName.replaceFirstChar { it.titlecase() }) - fun pullRequestName() = name.toLowerCase().capitalize() + fun pullRequestName() = name.lowercase().replaceFirstChar { it.titlecase() } companion object { fun from(value: String) = - values().find { it.pullRequestNames.contains(value.capitalize()) } + values().find { it.pullRequestNames.contains(value.replaceFirstChar { c -> c.titlecase() }) } fun from(ordinal: Int) = try { val pp = values()[ordinal] diff --git a/src/main/kotlin/pullrequestfactory/domain/branches/Branch.kt b/src/main/kotlin/pullrequestfactory/domain/branches/Branch.kt index fc4bc65..5d86e5f 100644 --- a/src/main/kotlin/pullrequestfactory/domain/branches/Branch.kt +++ b/src/main/kotlin/pullrequestfactory/domain/branches/Branch.kt @@ -1,5 +1,8 @@ package pullrequestfactory.domain.branches +import kotlinx.serialization.Serializable + +@Serializable data class Branch(val name: String) { fun iterationNr(): Int = parts().dropLast(1).last().toInt() diff --git a/src/main/kotlin/pullrequestfactory/domain/branches/Branches.kt b/src/main/kotlin/pullrequestfactory/domain/branches/Branches.kt index 015be29..aa33beb 100644 --- a/src/main/kotlin/pullrequestfactory/domain/branches/Branches.kt +++ b/src/main/kotlin/pullrequestfactory/domain/branches/Branches.kt @@ -16,8 +16,8 @@ class Branches( val prs = branches.mapIndexed { idx, branch -> PullRequest( title = getBranchTitles()[idx], - _base = getBaseBranches()[idx].copy(), - _head = branch.copy() + base = getBaseBranches()[idx].copy(), + head = branch.copy() ) } return prMarker.markTitlesOf(prs) @@ -69,8 +69,8 @@ class Branches( private fun getBranchTitles(): List = branches.mapIndexed { idx, br -> val (firstName, lastName, _, iterationNr, pairingPartner) = br.parts() val titleParts = listOf( - firstName.capitalize(), - lastName.capitalize(), + firstName.replaceFirstChar { it.titlecase() }, + lastName.replaceFirstChar { it.titlecase() }, "Iteration", iterationNr, "/", diff --git a/src/main/kotlin/pullrequestfactory/domain/pullrequests/GetPullRequest.kt b/src/main/kotlin/pullrequestfactory/domain/pullrequests/GetPullRequest.kt index 3f9b423..61654ed 100644 --- a/src/main/kotlin/pullrequestfactory/domain/pullrequests/GetPullRequest.kt +++ b/src/main/kotlin/pullrequestfactory/domain/pullrequests/GetPullRequest.kt @@ -1,3 +1,6 @@ package pullrequestfactory.domain.pullrequests +import kotlinx.serialization.Serializable + +@Serializable data class GetPullRequest(val number: Int, val title: String) diff --git a/src/main/kotlin/pullrequestfactory/domain/pullrequests/PullRequest.kt b/src/main/kotlin/pullrequestfactory/domain/pullrequests/PullRequest.kt index 96ba37b..db3bc71 100644 --- a/src/main/kotlin/pullrequestfactory/domain/pullrequests/PullRequest.kt +++ b/src/main/kotlin/pullrequestfactory/domain/pullrequests/PullRequest.kt @@ -4,19 +4,16 @@ import pullrequestfactory.domain.branches.Branch data class PullRequest( val title: String, - private val _base: Branch, - private val _head: Branch + val base: Branch, + val head: Branch, ) { - val base: String = _base.name - val head: String = _head.name - fun markTitleWhenNextHasNewIteration(nextPr: PullRequest) = when { nextPr.hasNewIteration() -> markTitle() else -> this.copy() } - private fun hasNewIteration() = _base.iterationNr() < _head.iterationNr() + private fun hasNewIteration() = base.iterationNr() < head.iterationNr() fun markTitle() = this.copy(title = "$title [PR]") diff --git a/src/main/kotlin/pullrequestfactory/io/clikt/CloseCommand.kt b/src/main/kotlin/pullrequestfactory/io/clikt/CloseCommand.kt index 1583df7..bd5d0c5 100644 --- a/src/main/kotlin/pullrequestfactory/io/clikt/CloseCommand.kt +++ b/src/main/kotlin/pullrequestfactory/io/clikt/CloseCommand.kt @@ -31,7 +31,7 @@ class CloseCommand( val httpClient = KhttpClientStats(KhttpClient(githubToken)) ClosePullRequestsPrograms( args.ui, - GithubAPIClient(httpClient, args.baseUrl, args.repoUrl, args.ui), + GithubAPIClient(httpClient, args.baseUrl, args.repoUrl, args.ui, args.jsonSerizalizer), httpClient, candidate, debug diff --git a/src/main/kotlin/pullrequestfactory/io/clikt/CommandArgs.kt b/src/main/kotlin/pullrequestfactory/io/clikt/CommandArgs.kt index ea8f10f..01ffe72 100644 --- a/src/main/kotlin/pullrequestfactory/io/clikt/CommandArgs.kt +++ b/src/main/kotlin/pullrequestfactory/io/clikt/CommandArgs.kt @@ -1,12 +1,14 @@ package pullrequestfactory.io.clikt +import kotlinx.serialization.json.Json import pullrequestfactory.domain.uis.UI class CommandArgs( val baseUrl: String, repoPath: String, val userPropertiesFile: String, - val ui: UI + val ui: UI, + val jsonSerizalizer: Json ) { val repoUrl = baseUrl + repoPath } diff --git a/src/main/kotlin/pullrequestfactory/io/clikt/OpenCommand.kt b/src/main/kotlin/pullrequestfactory/io/clikt/OpenCommand.kt index 0c9f4c5..4612826 100644 --- a/src/main/kotlin/pullrequestfactory/io/clikt/OpenCommand.kt +++ b/src/main/kotlin/pullrequestfactory/io/clikt/OpenCommand.kt @@ -40,7 +40,7 @@ class OpenCommand( val pps = listOf(pp1, pp2, pp3, pp4, pp5, pp6, pp7) OpenPullRequestsProgram( args.ui, - GithubAPIClient(httpClient, args.baseUrl, args.repoUrl, args.ui), + GithubAPIClient(httpClient, args.baseUrl, args.repoUrl, args.ui, args.jsonSerizalizer), httpClient, isLastFinished, candidate, diff --git a/src/main/kotlin/pullrequestfactory/io/programs/impl/EpochMilliInstantConverter.kt b/src/main/kotlin/pullrequestfactory/io/programs/impl/EpochMilliInstantConverter.kt deleted file mode 100644 index 6ac81e4..0000000 --- a/src/main/kotlin/pullrequestfactory/io/programs/impl/EpochMilliInstantConverter.kt +++ /dev/null @@ -1,17 +0,0 @@ -package pullrequestfactory.io.programs.impl - -import com.beust.klaxon.Converter -import com.beust.klaxon.JsonValue -import java.time.Instant - -class EpochMilliInstantConverter : Converter { - - override fun canConvert(cls: Class<*>) = cls == Instant::class.java - - override fun toJson(value: Any) = throw NotImplementedError() - - override fun fromJson(jv: JsonValue): Instant { - return Instant.ofEpochSecond(jv.longValue ?: 0) - } - -} diff --git a/src/main/kotlin/pullrequestfactory/io/programs/impl/InstantSerializer.kt b/src/main/kotlin/pullrequestfactory/io/programs/impl/InstantSerializer.kt new file mode 100644 index 0000000..19d038f --- /dev/null +++ b/src/main/kotlin/pullrequestfactory/io/programs/impl/InstantSerializer.kt @@ -0,0 +1,28 @@ +package pullrequestfactory.io.programs.impl + +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.KSerializer +import kotlinx.serialization.Serializer +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import java.time.Instant + +@ExperimentalSerializationApi +@Serializer(forClass = Instant::class) +object InstantSerializer : KSerializer { + + override val descriptor: SerialDescriptor = + PrimitiveSerialDescriptor(serialName = "Instant", kind = PrimitiveKind.LONG) + + override fun serialize(encoder: Encoder, value: Instant) { + encoder.encodeString("${value.toEpochMilli()}") + } + + override fun deserialize(decoder: Decoder): Instant { + return Instant.ofEpochSecond(decoder.decodeLong()) + } + +} diff --git a/src/main/kotlin/pullrequestfactory/io/programs/impl/Rate.kt b/src/main/kotlin/pullrequestfactory/io/programs/impl/Rate.kt index f9cdb2e..16fd031 100644 --- a/src/main/kotlin/pullrequestfactory/io/programs/impl/Rate.kt +++ b/src/main/kotlin/pullrequestfactory/io/programs/impl/Rate.kt @@ -1,5 +1,9 @@ package pullrequestfactory.io.programs.impl +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable import java.time.Instant -data class Rate(val limit: Int, val remaining: Int, val reset: Instant, val used: Int) +@Serializable +data class Rate(val limit: Int, val remaining: Int, @Contextual val reset: Instant, val used: Int) + diff --git a/src/main/kotlin/pullrequestfactory/io/programs/impl/RateLimit.kt b/src/main/kotlin/pullrequestfactory/io/programs/impl/RateLimit.kt index 16f9f3c..54aab5f 100644 --- a/src/main/kotlin/pullrequestfactory/io/programs/impl/RateLimit.kt +++ b/src/main/kotlin/pullrequestfactory/io/programs/impl/RateLimit.kt @@ -1,10 +1,12 @@ package pullrequestfactory.io.programs.impl +import kotlinx.serialization.Serializable import java.time.Instant import java.time.LocalDateTime import java.time.ZoneOffset import java.time.format.DateTimeFormatter +@Serializable data class RateLimit(val rate: Rate) { fun localResetDateTime() = toLocalDateTime(rate.reset) diff --git a/src/main/kotlin/pullrequestfactory/io/repositories/GithubAPIClient.kt b/src/main/kotlin/pullrequestfactory/io/repositories/GithubAPIClient.kt index c2ffcf2..b821136 100644 --- a/src/main/kotlin/pullrequestfactory/io/repositories/GithubAPIClient.kt +++ b/src/main/kotlin/pullrequestfactory/io/repositories/GithubAPIClient.kt @@ -1,14 +1,16 @@ package pullrequestfactory.io.repositories -import com.beust.klaxon.Klaxon import khttp.responses.Response +import kotlinx.serialization.Serializable +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json import pullrequestfactory.domain.branches.Branch import pullrequestfactory.domain.branches.GithubBranchesRepo import pullrequestfactory.domain.pullrequests.GetPullRequest import pullrequestfactory.domain.pullrequests.GithubPullRequestsRepo import pullrequestfactory.domain.pullrequests.PullRequest import pullrequestfactory.domain.uis.UI -import pullrequestfactory.io.programs.impl.EpochMilliInstantConverter import pullrequestfactory.io.programs.impl.Rate import pullrequestfactory.io.programs.impl.RateLimit import java.time.Instant @@ -17,7 +19,8 @@ class GithubAPIClient( private val httpClient: HttpClient, baseUrl: String, repoUrl: String, - private val ui: UI + private val ui: UI, + private val jsonSerializer: Json ) : GithubBranchesRepo, GithubPullRequestsRepo { private val urlForGitHubRateLimit = "$baseUrl/rate_limit" private val urlForGitHubBranches = "$repoUrl/branches" @@ -31,7 +34,7 @@ class GithubAPIClient( ui.show("Response: ${response.text}") defaultRateLimit() } - else -> jsonParser().parse(response.text) ?: defaultRateLimit() + else -> jsonSerializer.decodeFromString(response.text) ?: defaultRateLimit() } } @@ -60,7 +63,8 @@ class GithubAPIClient( } override fun openPullRequest(pullRequest: PullRequest) { - val json = jsonParser().toJsonString(pullRequest) + val dto = PullRequestDto(title = pullRequest.title, base = pullRequest.base.name, head = pullRequest.head.name) + val json = jsonSerializer.encodeToString(dto) val response = httpClient.post( url = urlForGitHubPullRequests, data = json @@ -80,7 +84,7 @@ class GithubAPIClient( override fun closePullRequest(number: Int) { val url = "$urlForGitHubPullRequests/$number" - val json = jsonParser().toJsonString(PullRequstPatch(state = "closed")) + val json = jsonSerializer.encodeToString(PullRequstPatch(state = "closed")) val response = httpClient.patch( url = url, data = json @@ -99,10 +103,7 @@ class GithubAPIClient( ui.show("Get Pull Requests Response Code: '${response.statusCode}'") ui.show("Response: ${response.text}") } - else -> { - val json = response.text - list.add((jsonParser().parseArray(json) ?: emptyList())) - } + else -> list.add((jsonSerializer.decodeFromString(response.text) ?: emptyList())) } } return list.flatten() @@ -111,9 +112,10 @@ class GithubAPIClient( private fun defaultRateLimit() = RateLimit((Rate(limit = 0, remaining = 0, Instant.now(), 0))) - private fun jsonParser(): Klaxon = - Klaxon().converter(EpochMilliInstantConverter()) - } +@Serializable +data class PullRequestDto(val title: String, val base: String, val head: String) + +@Serializable data class PullRequstPatch(val state: String) diff --git a/src/test/kotlin/it/pullrequestfactory/io/clikt/CloseCommandIT.kt b/src/test/kotlin/it/pullrequestfactory/io/clikt/CloseCommandIT.kt index a24a36b..880ff0d 100644 --- a/src/test/kotlin/it/pullrequestfactory/io/clikt/CloseCommandIT.kt +++ b/src/test/kotlin/it/pullrequestfactory/io/clikt/CloseCommandIT.kt @@ -2,14 +2,17 @@ package it.pullrequestfactory.io.clikt import com.github.tomakehurst.wiremock.client.WireMock.* import com.github.tomakehurst.wiremock.junit.WireMockRule +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.encodeToString import org.junit.After import org.junit.ClassRule import org.junit.Test import pullrequestfactory.domain.pullrequests.GetPullRequest import pullrequestfactory.domain.uis.QuietUI import pullrequestfactory.io.clikt.CloseCommand -import pullrequestfactory.io.clikt.CommandArgs +import pullrequestfactory.jsonSerializer +@ExperimentalSerializationApi class CloseCommandIT { private val repoPath = "/repos/ClausPolanka/wordcount" @@ -39,7 +42,7 @@ class CloseCommandIT { .willReturn( aResponse() .withStatus(200) - .withBody(toJson(arrayOf(pr1, pr2))) + .withBody(jsonSerializer().encodeToString(arrayOf(pr1, pr2))) ) ) @@ -62,20 +65,13 @@ class CloseCommandIT { ) private fun `github-pr-factory CLOSE pull requests`(args: Array) { - CloseCommand( - CommandArgs( - baseUrl = "http://localhost:8080", - repoPath = repoPath, - userPropertiesFile = "user.properties", - ui = QuietUI() - ) - ).parse(args) + CloseCommand(cmdArgsFor(repoPath, QuietUI())).parse(args) } private fun verifyPatchRequestToCloseOpenPullRequestsFor(prNumber: Int) { verify( patchRequestedFor(urlMatching("$repoPath/pulls/$prNumber")) - .withRequestBody(matching(Regex.escape("""{"state" : "closed"}"""))) + .withRequestBody(equalToJson("""{"state":"closed"}""")) .addCommonHeaders() ) } diff --git a/src/test/kotlin/it/pullrequestfactory/io/clikt/IntegrationTestsHelper.kt b/src/test/kotlin/it/pullrequestfactory/io/clikt/IntegrationTestsHelper.kt index 0b86ba2..24bc0d0 100644 --- a/src/test/kotlin/it/pullrequestfactory/io/clikt/IntegrationTestsHelper.kt +++ b/src/test/kotlin/it/pullrequestfactory/io/clikt/IntegrationTestsHelper.kt @@ -1,20 +1,25 @@ package it.pullrequestfactory.io.clikt -import com.beust.klaxon.Klaxon -import com.github.tomakehurst.wiremock.client.WireMock import com.github.tomakehurst.wiremock.client.WireMock.* import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.encodeToString +import pullrequestfactory.domain.uis.QuietUI +import pullrequestfactory.domain.uis.UI +import pullrequestfactory.io.clikt.CommandArgs import pullrequestfactory.io.programs.impl.Rate import pullrequestfactory.io.programs.impl.RateLimit +import pullrequestfactory.jsonSerializer import java.time.Instant +@ExperimentalSerializationApi fun ensureHighEnoughRateLimit(remaining: Int = 5000, resetInMillisSinceEpoch: Long = 1608411669) { stubFor( get("/rate_limit").willReturn( aResponse() .withStatus(200) .withBody( - Klaxon().toJsonString( + jsonSerializer().encodeToString( RateLimit( Rate( limit = 5000, @@ -29,10 +34,17 @@ fun ensureHighEnoughRateLimit(remaining: Int = 5000, resetInMillisSinceEpoch: Lo ) } -fun toJson(objects: Array) = Klaxon().toJsonString(objects) - fun RequestPatternBuilder.addCommonHeaders(): RequestPatternBuilder? { return this.withHeader("Accept", matching("application/json")) .withHeader("Authorization", matching("token .*")) .withHeader("Content-Type", matching("application/json")) } + +@ExperimentalSerializationApi +fun cmdArgsFor(repoPath: String, ui: UI = QuietUI()) = CommandArgs( + baseUrl = "http://localhost:8080", + repoPath = repoPath, + userPropertiesFile = "user.properties", + ui = ui, + jsonSerizalizer = jsonSerializer() +) diff --git a/src/test/kotlin/it/pullrequestfactory/io/clikt/OpenCommandIT.kt b/src/test/kotlin/it/pullrequestfactory/io/clikt/OpenCommandIT.kt index 624ce79..8cb7781 100644 --- a/src/test/kotlin/it/pullrequestfactory/io/clikt/OpenCommandIT.kt +++ b/src/test/kotlin/it/pullrequestfactory/io/clikt/OpenCommandIT.kt @@ -1,8 +1,9 @@ package it.pullrequestfactory.io.clikt -import com.beust.klaxon.Klaxon import com.github.tomakehurst.wiremock.client.WireMock.* import com.github.tomakehurst.wiremock.junit.WireMockRule +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.encodeToString import org.assertj.core.api.Assertions.assertThat import org.junit.After import org.junit.ClassRule @@ -11,15 +12,15 @@ import pullrequestfactory.domain.PairingPartner import pullrequestfactory.domain.PairingPartner.* import pullrequestfactory.domain.branches.Branch import pullrequestfactory.domain.pullrequests.PullRequest -import pullrequestfactory.domain.uis.QuietUI import pullrequestfactory.domain.uis.UI -import pullrequestfactory.io.clikt.CommandArgs import pullrequestfactory.io.clikt.OpenCommand import pullrequestfactory.io.programs.impl.Rate import pullrequestfactory.io.programs.impl.RateLimit +import pullrequestfactory.jsonSerializer import java.time.LocalDateTime import java.time.ZoneId +@ExperimentalSerializationApi class OpenCommandIT { private val repoPath = "/repos/ClausPolanka/wordcount" @@ -65,7 +66,7 @@ class OpenCommandIT { .willReturn( aResponse() .withStatus(200) - .withBody(toJson(branches)) + .withBody(jsonSerializer().encodeToString(branches)) ) ) @@ -84,13 +85,55 @@ class OpenCommandIT { ) ) - verify(PullRequest("$candidateFirstName $candidateLastName Iteration 1 / Session 1 Markus [PR]", Branch("master"), branches[0])) - verify(PullRequest("$candidateFirstName $candidateLastName Iteration 2 / Session 2 Berni [PR]", branches[0], branches[1])) - verify(PullRequest("$candidateFirstName $candidateLastName Iteration 3 / Session 3 Lukas [PR]", branches[1], branches[2])) - verify(PullRequest("$candidateFirstName $candidateLastName Iteration 4 / Session 4 Jakub [PR]", branches[2], branches[3])) - verify(PullRequest("$candidateFirstName $candidateLastName Iteration 5 / Session 5 Peter [PR]", branches[3], branches[4])) - verify(PullRequest("$candidateFirstName $candidateLastName Iteration 6 / Session 6 Christian [PR]", branches[4], branches[5])) - verify(PullRequest("$candidateFirstName $candidateLastName Iteration 7 / Session 7 Vaclav", branches[5], branches[6])) + verify( + PullRequest( + "$candidateFirstName $candidateLastName Iteration 1 / Session 1 Markus [PR]", + Branch("master"), + branches[0] + ) + ) + verify( + PullRequest( + "$candidateFirstName $candidateLastName Iteration 2 / Session 2 Berni [PR]", + branches[0], + branches[1] + ) + ) + verify( + PullRequest( + "$candidateFirstName $candidateLastName Iteration 3 / Session 3 Lukas [PR]", + branches[1], + branches[2] + ) + ) + verify( + PullRequest( + "$candidateFirstName $candidateLastName Iteration 4 / Session 4 Jakub [PR]", + branches[2], + branches[3] + ) + ) + verify( + PullRequest( + "$candidateFirstName $candidateLastName Iteration 5 / Session 5 Peter [PR]", + branches[3], + branches[4] + ) + ) + verify( + PullRequest( + "$candidateFirstName $candidateLastName Iteration 6 / Session 6 Christian [PR]", + branches[4], + branches[5] + ) + ) + verify( + PullRequest( + "$candidateFirstName $candidateLastName Iteration 7 / Session 7 Vaclav", + branches[5], + branches[6] + ) + ) } @Test @@ -108,7 +151,7 @@ class OpenCommandIT { .willReturn( aResponse() .withStatus(200) - .withBody(toJson(branches)) + .withBody(jsonSerializer().encodeToString(branches)) ) ) @@ -128,13 +171,55 @@ class OpenCommandIT { ) ) - verify(PullRequest("$candidateFirstName $candidateLastName Iteration 1 / Session 1 Markus [PR]", Branch("master"), branches[0])) - verify(PullRequest("$candidateFirstName $candidateLastName Iteration 2 / Session 2 Berni [PR]", branches[0], branches[1])) - verify(PullRequest("$candidateFirstName $candidateLastName Iteration 3 / Session 3 Lukas [PR]", branches[1], branches[2])) - verify(PullRequest("$candidateFirstName $candidateLastName Iteration 4 / Session 4 Jakub [PR]", branches[2], branches[3])) - verify(PullRequest("$candidateFirstName $candidateLastName Iteration 5 / Session 5 Peter [PR]", branches[3], branches[4])) - verify(PullRequest("$candidateFirstName $candidateLastName Iteration 6 / Session 6 Christian [PR]", branches[4], branches[5])) - verify(PullRequest("$candidateFirstName $candidateLastName Iteration 7 / Session 7 Vaclav [PR]", branches[5], branches[6])) + verify( + PullRequest( + "$candidateFirstName $candidateLastName Iteration 1 / Session 1 Markus [PR]", + Branch("master"), + branches[0] + ) + ) + verify( + PullRequest( + "$candidateFirstName $candidateLastName Iteration 2 / Session 2 Berni [PR]", + branches[0], + branches[1] + ) + ) + verify( + PullRequest( + "$candidateFirstName $candidateLastName Iteration 3 / Session 3 Lukas [PR]", + branches[1], + branches[2] + ) + ) + verify( + PullRequest( + "$candidateFirstName $candidateLastName Iteration 4 / Session 4 Jakub [PR]", + branches[2], + branches[3] + ) + ) + verify( + PullRequest( + "$candidateFirstName $candidateLastName Iteration 5 / Session 5 Peter [PR]", + branches[3], + branches[4] + ) + ) + verify( + PullRequest( + "$candidateFirstName $candidateLastName Iteration 6 / Session 6 Christian [PR]", + branches[4], + branches[5] + ) + ) + verify( + PullRequest( + "$candidateFirstName $candidateLastName Iteration 7 / Session 7 Vaclav [PR]", + branches[5], + branches[6] + ) + ) } @Test @@ -144,7 +229,7 @@ class OpenCommandIT { aResponse() .withStatus(403) .withBody( - Klaxon().toJsonString( + jsonSerializer().encodeToString( RateLimit( Rate( limit = 50, @@ -170,26 +255,19 @@ class OpenCommandIT { fn: String, ln: String ) = pairingPartner - .map { it.name.toLowerCase() } + .map { it.name.lowercase() } .mapIndexed { i, pp -> Branch("${fn}_${ln}_iteration_${i.inc()}_$pp") } .toTypedArray() private fun `github-pr-factory OPEN pull requests`(args: Array) { - OpenCommand( - CommandArgs( - baseUrl = "http://localhost:8080", - repoPath = repoPath, - userPropertiesFile = "user.properties", - ui = QuietUI() - ) - ).parse(args) + OpenCommand(cmdArgsFor(repoPath)).parse(args) } private fun verify(pr: PullRequest) { - val json = """{"base" : "${pr.base}", "head" : "${pr.head}", "title" : "${pr.title}"}""" + val json = """{"base" : "${pr.base.name}", "head" : "${pr.head.name}", "title" : "${pr.title}"}""" verify( postRequestedFor(urlMatching("$repoPath/pulls")) - .withRequestBody(matching(Regex.escape(json))) + .withRequestBody(equalToJson(json)) .addCommonHeaders() ) } @@ -197,13 +275,7 @@ class OpenCommandIT { private fun fromNowInOneHour() = LocalDateTime.now().plusHours(1).atZone(ZoneId.systemDefault()).toInstant() - private fun argsWith(ui: UI) = - CommandArgs( - baseUrl = "http://localhost:8080", - repoPath = repoPath, - userPropertiesFile = "user.properties", - ui = ui - ) + private fun argsWith(ui: UI) = cmdArgsFor(repoPath, ui) private fun fakeUI(outputCapture: MutableList) = object : UI { diff --git a/src/test/kotlin/ut/pullrequestfactory/domain/GithubPRFactoryTest.kt b/src/test/kotlin/ut/pullrequestfactory/domain/GithubPRFactoryTest.kt index f934afb..d328ab7 100644 --- a/src/test/kotlin/ut/pullrequestfactory/domain/GithubPRFactoryTest.kt +++ b/src/test/kotlin/ut/pullrequestfactory/domain/GithubPRFactoryTest.kt @@ -39,13 +39,13 @@ class GithubPRFactoryTest { assertThat(pullRequests).containsExactly( PullRequest( title = "Firstname Lastname Iteration 1 / Session 1 ${pairingPartner1.pullRequestName()} [PR]", - _base = Branch("master"), - _head = branch1 + base = Branch("master"), + head = branch1 ), PullRequest( title = "Firstname Lastname Iteration 2 / Session 2 ${pairingPartner2.pullRequestName()}", - _base = branch1, - _head = branch2 + base = branch1, + head = branch2 ) ) } @@ -65,8 +65,8 @@ class GithubPRFactoryTest { assertThat(pullRequests).containsExactly( PullRequest( title = "Firstname Lastname Iteration 1 / Session 1 ${pairingPartner.pullRequestName()}", - _base = Branch("master"), - _head = branch + base = Branch("master"), + head = branch ) ) } @@ -86,8 +86,8 @@ class GithubPRFactoryTest { assertThat(pullRequests).containsExactly( PullRequest( title = "Firstname Lastname Iteration 1 / Session 1 ${pairingPartner.pullRequestName()}", - _base = Branch("master"), - _head = branch + base = Branch("master"), + head = branch ) ) } @@ -139,8 +139,8 @@ class GithubPRFactoryTest { fun `close pull requests for two candidates with same first name`() { val (pullRequestNumbersToBeClosed, sut) = createGithubPrFactoryFor( listOf( - GetPullRequest(1, "Firstname1 Lastname1 Iteration 1 / Session 1 ${pairingPartner.name.toLowerCase()}"), - GetPullRequest(2, "Firstname1 Lastname2 Iteration 1 / Session 1 ${pairingPartner.name.toLowerCase()}") + GetPullRequest(1, "Firstname1 Lastname1 Iteration 1 / Session 1 ${pairingPartner.name.lowercase()}"), + GetPullRequest(2, "Firstname1 Lastname2 Iteration 1 / Session 1 ${pairingPartner.name.lowercase()}") ) ) @@ -155,8 +155,8 @@ class GithubPRFactoryTest { fun `close pull requests for two candidates with same last name`() { val (pullRequestNumbersToBeClosed, sut) = createGithubPrFactoryFor( listOf( - GetPullRequest(1, "Firstname1 Lastname1 Iteration 1 / Session 1 ${pairingPartner.name.toLowerCase()}"), - GetPullRequest(2, "Firstname2 Lastname1 Iteration 1 / Session 1 ${pairingPartner.name.toLowerCase()}") + GetPullRequest(1, "Firstname1 Lastname1 Iteration 1 / Session 1 ${pairingPartner.name.lowercase()}"), + GetPullRequest(2, "Firstname2 Lastname1 Iteration 1 / Session 1 ${pairingPartner.name.lowercase()}") ) ) @@ -171,8 +171,8 @@ class GithubPRFactoryTest { fun `close pull requests for one candidate`() { val (pullRequestNumbersToBeClosed, sut) = createGithubPrFactoryFor( listOf( - GetPullRequest(1, "Firstname1 Lastname1 Iteration 1 / Session 1 ${pairingPartner1.name.toLowerCase()}"), - GetPullRequest(2, "Firstname1 Lastname1 Iteration 1 / Session 2 ${pairingPartner2.name.toLowerCase()}") + GetPullRequest(1, "Firstname1 Lastname1 Iteration 1 / Session 1 ${pairingPartner1.name.lowercase()}"), + GetPullRequest(2, "Firstname1 Lastname1 Iteration 1 / Session 2 ${pairingPartner2.name.lowercase()}") ) ) diff --git a/src/test/kotlin/ut/pullrequestfactory/domain/TestBranchBuilder.kt b/src/test/kotlin/ut/pullrequestfactory/domain/TestBranchBuilder.kt index c5a5641..716d7fb 100644 --- a/src/test/kotlin/ut/pullrequestfactory/domain/TestBranchBuilder.kt +++ b/src/test/kotlin/ut/pullrequestfactory/domain/TestBranchBuilder.kt @@ -39,8 +39,8 @@ class TestBranchBuilder { fun build(): Branch { val name = _branchName ?: listOf( - _candidate.firstName.toLowerCase(), - _candidate.lastName.toLowerCase(), + _candidate.firstName.lowercase(), + _candidate.lastName.lowercase(), "iteration", _iteration, pairing_partner() ?: throwException() @@ -54,7 +54,7 @@ class TestBranchBuilder { } return when (_pairingPartner) { null -> _pairingPartnerBranchName - else -> _pairingPartner?.name?.toLowerCase() + else -> _pairingPartner?.name?.lowercase() } } diff --git a/src/test/kotlin/ut/pullrequestfactory/domain/pullrequests/PullRequestTest.kt b/src/test/kotlin/ut/pullrequestfactory/domain/pullrequests/PullRequestTest.kt index 9a62e56..0f3aa05 100644 --- a/src/test/kotlin/ut/pullrequestfactory/domain/pullrequests/PullRequestTest.kt +++ b/src/test/kotlin/ut/pullrequestfactory/domain/pullrequests/PullRequestTest.kt @@ -10,15 +10,6 @@ class PullRequestTest { private val pullRequestTitle = "Firstname Lastname Iteration 1 / Session 1 pairingpartner" - @Test - fun `base and head return corresponding branch names`() { - val sut = PullRequest(pullRequestTitle, _base = Branch(name = "branch1"), _head = Branch(name = "branch2")) - val base = sut.base - val head = sut.head - assertThat(base).isEqualTo("branch1") - assertThat(head).isEqualTo("branch2") - } - @Test fun `mark title of current pull request when next pull request has new iteration`() { val sut = createPullRequest() @@ -26,8 +17,8 @@ class PullRequestTest { val newPr = sut.markTitleWhenNextHasNewIteration( nextPr = PullRequest( title = "any", - _base = createBranchFor(iterationNr = 1), - _head = createBranchFor(iterationNr = 2) + base = createBranchFor(iterationNr = 1), + head = createBranchFor(iterationNr = 2) ) ) @@ -41,8 +32,8 @@ class PullRequestTest { val newPr = sut.markTitleWhenNextHasNewIteration( nextPr = PullRequest( title = "any", - _base = createBranchFor(iterationNr = 1), - _head = createBranchFor(iterationNr = 1) + base = createBranchFor(iterationNr = 1), + head = createBranchFor(iterationNr = 1) ) ) @@ -50,7 +41,7 @@ class PullRequestTest { } private fun createPullRequest() = - PullRequest(pullRequestTitle, _base = Branch("any"), _head = Branch("any")) + PullRequest(pullRequestTitle, base = Branch("any"), head = Branch("any")) private fun createBranchFor(iterationNr: Int) = Branch("firstname_lastname_iteration_${iterationNr}_pairingpartner")