From 59310d1e048a7e3f9da41956b0b4f74d782a8ebd Mon Sep 17 00:00:00 2001 From: Michael Sims Date: Sat, 27 Dec 2025 08:54:53 -0600 Subject: [PATCH 1/9] Configure functional tests to run serially In commit 43379f I configured junit to run tests in parallel to speed up verifications, but this unfortunately breaks assumptions that the functional tests make and additionally increases the odds that I'll hit GitHub's API rate limits, so I'm configuring the functional tests to run serially while leaving the global default to parallel. commit-id: I22786ee4 --- .../michael/gitjaspr/GitJasprFunctionalExternalProcessTest.kt | 3 +++ .../kotlin/sims/michael/gitjaspr/GitJasprFunctionalTest.kt | 3 +++ .../gitjaspr/githubtests/GitHubTestHarnessFunctionalTest.kt | 3 +++ 3 files changed, 9 insertions(+) diff --git a/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprFunctionalExternalProcessTest.kt b/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprFunctionalExternalProcessTest.kt index 5fff92c..2b413e6 100644 --- a/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprFunctionalExternalProcessTest.kt +++ b/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprFunctionalExternalProcessTest.kt @@ -7,6 +7,8 @@ import kotlinx.coroutines.async import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.withTimeout +import org.junit.jupiter.api.parallel.Execution +import org.junit.jupiter.api.parallel.ExecutionMode import org.slf4j.Logger import org.slf4j.LoggerFactory import sims.michael.gitjaspr.ExecuteCli.executeCli @@ -21,6 +23,7 @@ import sims.michael.gitjaspr.testing.FunctionalTest * [GitJasprFunctionalTest] should be the one used to verify behavior. */ @FunctionalTest +@Execution(ExecutionMode.SAME_THREAD) class GitJasprFunctionalExternalProcessTest : GitJasprTest { override val logger: Logger = LoggerFactory.getLogger(GitJasprDefaultTest::class.java) override val useFakeRemote: Boolean = false diff --git a/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprFunctionalTest.kt b/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprFunctionalTest.kt index 053f060..395fb2f 100644 --- a/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprFunctionalTest.kt +++ b/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprFunctionalTest.kt @@ -5,12 +5,15 @@ import kotlinx.coroutines.async import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.withTimeout +import org.junit.jupiter.api.parallel.Execution +import org.junit.jupiter.api.parallel.ExecutionMode import org.slf4j.Logger import org.slf4j.LoggerFactory import sims.michael.gitjaspr.githubtests.GitHubTestHarness import sims.michael.gitjaspr.testing.FunctionalTest @FunctionalTest +@Execution(ExecutionMode.SAME_THREAD) class GitJasprFunctionalTest : GitJasprTest { override val logger: Logger = LoggerFactory.getLogger(GitJasprDefaultTest::class.java) override val useFakeRemote: Boolean = false diff --git a/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/githubtests/GitHubTestHarnessFunctionalTest.kt b/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/githubtests/GitHubTestHarnessFunctionalTest.kt index 0875459..534dbff 100644 --- a/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/githubtests/GitHubTestHarnessFunctionalTest.kt +++ b/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/githubtests/GitHubTestHarnessFunctionalTest.kt @@ -3,6 +3,8 @@ package sims.michael.gitjaspr.githubtests import kotlin.test.assertEquals import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestInfo +import org.junit.jupiter.api.parallel.Execution +import org.junit.jupiter.api.parallel.ExecutionMode import sims.michael.gitjaspr.DEFAULT_TARGET_REF import sims.michael.gitjaspr.JGitClient import sims.michael.gitjaspr.githubtests.GitHubTestHarness.Companion.withTestSetup @@ -11,6 +13,7 @@ import sims.michael.gitjaspr.githubtests.generatedtestdsl.testCase import sims.michael.gitjaspr.testing.FunctionalTest @FunctionalTest +@Execution(ExecutionMode.SAME_THREAD) class GitHubTestHarnessFunctionalTest { @Test From de45488ad86921bd2ac84113b695ce2548f396f8 Mon Sep 17 00:00:00 2001 From: Michael Sims Date: Sat, 27 Dec 2025 10:23:47 -0600 Subject: [PATCH 2/9] Add a configurable delay after each functional test This is to help with avoiding hitting API rate limits commit-id: Ie7089fdb --- .../GitJasprFunctionalExternalProcessTest.kt | 5 ++++ .../gitjaspr/GitJasprFunctionalTest.kt | 5 ++++ .../GitHubTestHarnessFunctionalTest.kt | 5 ++++ .../gitjaspr/testing/DelayAfterTestMillis.kt | 9 +++++++ .../testing/DelayAfterTestsExtension.kt | 27 +++++++++++++++++++ 5 files changed, 51 insertions(+) create mode 100644 git-jaspr/src/test/kotlin/sims/michael/gitjaspr/testing/DelayAfterTestMillis.kt create mode 100644 git-jaspr/src/test/kotlin/sims/michael/gitjaspr/testing/DelayAfterTestsExtension.kt diff --git a/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprFunctionalExternalProcessTest.kt b/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprFunctionalExternalProcessTest.kt index 2b413e6..215c423 100644 --- a/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprFunctionalExternalProcessTest.kt +++ b/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprFunctionalExternalProcessTest.kt @@ -7,12 +7,15 @@ import kotlinx.coroutines.async import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.withTimeout +import org.junit.jupiter.api.extension.ExtendWith import org.junit.jupiter.api.parallel.Execution import org.junit.jupiter.api.parallel.ExecutionMode import org.slf4j.Logger import org.slf4j.LoggerFactory import sims.michael.gitjaspr.ExecuteCli.executeCli import sims.michael.gitjaspr.githubtests.GitHubTestHarness +import sims.michael.gitjaspr.testing.DelayAfterTestMillis +import sims.michael.gitjaspr.testing.DelayAfterTestsExtension import sims.michael.gitjaspr.testing.FunctionalTest /** @@ -24,6 +27,8 @@ import sims.michael.gitjaspr.testing.FunctionalTest */ @FunctionalTest @Execution(ExecutionMode.SAME_THREAD) +@ExtendWith(DelayAfterTestsExtension::class) +@DelayAfterTestMillis(2_000) class GitJasprFunctionalExternalProcessTest : GitJasprTest { override val logger: Logger = LoggerFactory.getLogger(GitJasprDefaultTest::class.java) override val useFakeRemote: Boolean = false diff --git a/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprFunctionalTest.kt b/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprFunctionalTest.kt index 395fb2f..38b6f87 100644 --- a/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprFunctionalTest.kt +++ b/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprFunctionalTest.kt @@ -5,15 +5,20 @@ import kotlinx.coroutines.async import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.withTimeout +import org.junit.jupiter.api.extension.ExtendWith import org.junit.jupiter.api.parallel.Execution import org.junit.jupiter.api.parallel.ExecutionMode import org.slf4j.Logger import org.slf4j.LoggerFactory import sims.michael.gitjaspr.githubtests.GitHubTestHarness +import sims.michael.gitjaspr.testing.DelayAfterTestMillis +import sims.michael.gitjaspr.testing.DelayAfterTestsExtension import sims.michael.gitjaspr.testing.FunctionalTest @FunctionalTest @Execution(ExecutionMode.SAME_THREAD) +@ExtendWith(DelayAfterTestsExtension::class) +@DelayAfterTestMillis(2_000) class GitJasprFunctionalTest : GitJasprTest { override val logger: Logger = LoggerFactory.getLogger(GitJasprDefaultTest::class.java) override val useFakeRemote: Boolean = false diff --git a/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/githubtests/GitHubTestHarnessFunctionalTest.kt b/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/githubtests/GitHubTestHarnessFunctionalTest.kt index 534dbff..8f1e00e 100644 --- a/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/githubtests/GitHubTestHarnessFunctionalTest.kt +++ b/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/githubtests/GitHubTestHarnessFunctionalTest.kt @@ -3,6 +3,7 @@ package sims.michael.gitjaspr.githubtests import kotlin.test.assertEquals import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestInfo +import org.junit.jupiter.api.extension.ExtendWith import org.junit.jupiter.api.parallel.Execution import org.junit.jupiter.api.parallel.ExecutionMode import sims.michael.gitjaspr.DEFAULT_TARGET_REF @@ -10,10 +11,14 @@ import sims.michael.gitjaspr.JGitClient import sims.michael.gitjaspr.githubtests.GitHubTestHarness.Companion.withTestSetup import sims.michael.gitjaspr.githubtests.generatedtestdsl.ident import sims.michael.gitjaspr.githubtests.generatedtestdsl.testCase +import sims.michael.gitjaspr.testing.DelayAfterTestMillis +import sims.michael.gitjaspr.testing.DelayAfterTestsExtension import sims.michael.gitjaspr.testing.FunctionalTest @FunctionalTest @Execution(ExecutionMode.SAME_THREAD) +@ExtendWith(DelayAfterTestsExtension::class) +@DelayAfterTestMillis(2_000) class GitHubTestHarnessFunctionalTest { @Test diff --git a/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/testing/DelayAfterTestMillis.kt b/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/testing/DelayAfterTestMillis.kt new file mode 100644 index 0000000..af36c12 --- /dev/null +++ b/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/testing/DelayAfterTestMillis.kt @@ -0,0 +1,9 @@ +package sims.michael.gitjaspr.testing + +/** + * Specifies a custom delay (in milliseconds) to wait after each test in a class completes. Used in + * conjunction with [DelayAfterTestsExtension]. + */ +@Target(AnnotationTarget.CLASS) +@Retention(AnnotationRetention.RUNTIME) +annotation class DelayAfterTestMillis(val millis: Long) diff --git a/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/testing/DelayAfterTestsExtension.kt b/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/testing/DelayAfterTestsExtension.kt new file mode 100644 index 0000000..d4b3c69 --- /dev/null +++ b/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/testing/DelayAfterTestsExtension.kt @@ -0,0 +1,27 @@ +package sims.michael.gitjaspr.testing + +import org.junit.jupiter.api.extension.AfterEachCallback +import org.junit.jupiter.api.extension.ExtensionContext +import org.slf4j.LoggerFactory + +/** + * JUnit extension that introduces a delay after each test (useful to avoid hitting API rate + * limits). The default delay is 1000 ms, but it can be customized per-class using the + * [DelayAfterTestMillis] annotation. + */ +class DelayAfterTestsExtension : AfterEachCallback { + private val logger = LoggerFactory.getLogger(DelayAfterTestsExtension::class.java) + + override fun afterEach(context: ExtensionContext) { + val delayMillis = + context.requiredTestClass.getAnnotation(DelayAfterTestMillis::class.java)?.millis + ?: DEFAULT_DELAY_MILLIS + logger.debug("Delaying for {} ms after test...", delayMillis) + Thread.sleep(delayMillis) + logger.debug("Delay complete") + } + + companion object { + const val DEFAULT_DELAY_MILLIS: Long = 1000L + } +} From 9454bc7a15cb9ce5f997c6da1cf75ccc4ee8c0ad Mon Sep 17 00:00:00 2001 From: Michael Sims Date: Sat, 27 Dec 2025 12:29:35 -0600 Subject: [PATCH 3/9] Remove unnecessary exclusion from spotless config commit-id: Ie907364d --- build.gradle.kts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index f34801d..1430299 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -27,9 +27,4 @@ subprojects { } } -spotless { - kotlinGradle { - ktfmt(libs.versions.ktfmt.get()).kotlinlangStyle() - targetExclude("build/generated/") - } -} +spotless { kotlinGradle { ktfmt(libs.versions.ktfmt.get()).kotlinlangStyle() } } From b5dea992d374d2ac349057a14cdd423f6feca517 Mon Sep 17 00:00:00 2001 From: Michael Sims Date: Sat, 27 Dec 2025 12:29:53 -0600 Subject: [PATCH 4/9] Clean up .editorconfig commit-id: I48126df2 --- .editorconfig | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.editorconfig b/.editorconfig index 62435d0..cd5157d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,6 +1,9 @@ [*.{kt,kts}] -ktlint_code_style = intellij_idea -ktlint_standard_no-wildcard-imports = disabled ij_kotlin_continuation_indent_size = 4 ij_kotlin_allow_trailing_comma = true ij_kotlin_allow_trailing_comma_on_call_site = true +ij_kotlin_import_nested_classes = true +ij_kotlin_packages_to_use_import_on_demand = +ij_kotlin_imports_layout = * +ij_kotlin_name_count_to_use_star_import = 2147483647 +ij_kotlin_name_count_to_use_star_import_for_members = 2147483647 From 8dc65e535115b7250fefeff8a611cd770ae907c4 Mon Sep 17 00:00:00 2001 From: Michael Sims Date: Sat, 27 Dec 2025 13:21:50 -0600 Subject: [PATCH 5/9] Format repo with latest ktfmt (0.60) commit-id: I956198cc --- .../sims/michael/gitjaspr/CliGitClientTest.kt | 2 +- .../michael/gitjaspr/CommitParsersTest.kt | 192 +++++++++--------- .../sims/michael/gitjaspr/GitJasprTest.kt | 88 ++++---- libs.versions.toml | 2 +- 4 files changed, 151 insertions(+), 133 deletions(-) diff --git a/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/CliGitClientTest.kt b/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/CliGitClientTest.kt index a3c7bf1..27ad8d7 100644 --- a/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/CliGitClientTest.kt +++ b/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/CliGitClientTest.kt @@ -733,7 +733,7 @@ class CliGitClientTest { This is a commit body - """ + """ .trimIndent(), mapOf("Co-authored-by" to "Michael Sims"), DEFAULT_COMMITTER, diff --git a/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/CommitParsersTest.kt b/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/CommitParsersTest.kt index b170a96..f771b5c 100644 --- a/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/CommitParsersTest.kt +++ b/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/CommitParsersTest.kt @@ -30,10 +30,10 @@ class CommitParsersTest { fun `getSubjectAndBodyFromFullMessage - subject and body`() { val message = """ - This is a subject - - This is a body - + This is a subject + + This is a body + """ .trimIndent() @@ -47,12 +47,12 @@ class CommitParsersTest { fun `getSubjectAndBodyFromFullMessage - multiline subject`() { val message = """ - This is a subject - with three lines - but still a subject - - This is a body - + This is a subject + with three lines + but still a subject + + This is a body + """ .trimIndent() @@ -79,9 +79,9 @@ class CommitParsersTest { fun `getFooters - subject and body only`() { val message = """ - This is a subject + This is a subject - This is a body + This is a body """ .trimIndent() @@ -93,12 +93,12 @@ class CommitParsersTest { fun `getFooters - subject, body with footer-like lines`() { val message = """ - This is a subject + This is a subject - This is a body. - The following are still part of the body: - key-one: value-one - key-two: value-two + This is a body. + The following are still part of the body: + key-one: value-one + key-two: value-two """ .trimIndent() @@ -110,10 +110,10 @@ class CommitParsersTest { fun `getFooters - subject, body url that could look like a footer line if your code was bad`() { val message = """ - This is a subject + This is a subject - See this Slack thread: - https://trillianthealth.slack.com/archives/C04J6Q655GR/p1702918943374039?thread_ts=1702918322.439999&cid=C04J6Q655GR + See this Slack thread: + https://trillianthealth.slack.com/archives/C04J6Q655GR/p1702918943374039?thread_ts=1702918322.439999&cid=C04J6Q655GR """ .trimIndent() @@ -125,15 +125,15 @@ class CommitParsersTest { fun `getFooters - subject, body, existing footer lines`() { val message = """ - This is a subject + This is a subject + + This is a body. + The following are still part of the body: + key-one: value-one + key-two: value-two - This is a body. - The following are still part of the body: - key-one: value-one - key-two: value-two - - key-one: value-three - key-two: value-four + key-one: value-three + key-two: value-four """ .trimIndent() @@ -148,15 +148,15 @@ class CommitParsersTest { fun `getFooters - subject, body, existing footer lines with multiples - last one wins`() { val message = """ - This is a subject + This is a subject + + This is a body. + The following are still part of the body: + key-one: value-one + key-two: value-two - This is a body. - The following are still part of the body: - key-one: value-one - key-two: value-two - - key-one: value-three - key-one: value-four + key-one: value-three + key-one: value-four """ .trimIndent() @@ -172,7 +172,7 @@ class CommitParsersTest { Co-authored-by: John Carmack commit-id: I0e9e0b26 - """ + """ .trimIndent() assertEquals( @@ -191,7 +191,7 @@ class CommitParsersTest { This is a commit subject keys with spaces are not allowed: value - """ + """ .trimIndent() assertEquals(emptyMap(), getFooters(message)) @@ -201,9 +201,9 @@ class CommitParsersTest { fun `addFooters - subject only`() { assertEquals( """ - This is a subject - - key1: value1 + This is a subject + + key1: value1 """ .trimIndent(), @@ -215,9 +215,9 @@ class CommitParsersTest { fun `addFooters - subject with newline`() { assertEquals( """ - This is a subject - - key1: value1 + This is a subject + + key1: value1 """ .trimIndent(), @@ -229,9 +229,9 @@ class CommitParsersTest { fun `addFooters - subject and body only`() { val message = """ - This is a subject + This is a subject - This is a body + This is a body """ .trimIndent() @@ -241,7 +241,7 @@ class CommitParsersTest { This is a subject This is a body - + key1: value1 """ @@ -254,12 +254,12 @@ class CommitParsersTest { fun `addFooters - subject, body with footer-like lines`() { val message = """ - This is a subject + This is a subject - This is a body. - The following are still part of the body: - key-one: value-one - key-two: value-two + This is a body. + The following are still part of the body: + key-one: value-one + key-two: value-two """ .trimIndent() @@ -272,7 +272,7 @@ class CommitParsersTest { The following are still part of the body: key-one: value-one key-two: value-two - + key1: value1 """ @@ -285,15 +285,15 @@ class CommitParsersTest { fun `addFooters - subject, body, existing footer lines`() { val message = """ - This is a subject + This is a subject - This is a body. - The following are still part of the body: - key-one: value-one - key-two: value-two - - key-one: value-three - key-two: value-four + This is a body. + The following are still part of the body: + key-one: value-one + key-two: value-two + + key-one: value-three + key-two: value-four """ .trimIndent() @@ -306,7 +306,7 @@ class CommitParsersTest { The following are still part of the body: key-one: value-one key-two: value-two - + key-one: value-three key-two: value-four key1: value1 @@ -321,15 +321,15 @@ class CommitParsersTest { fun `addFooters - subject, body, existing footer lines with multiples - last one wins`() { val message = """ - This is a subject + This is a subject + + This is a body. + The following are still part of the body: + key-one: value-one + key-two: value-two - This is a body. - The following are still part of the body: - key-one: value-one - key-two: value-two - - key-one: value-three - key-one: value-four + key-one: value-three + key-one: value-four """ .trimIndent() @@ -357,7 +357,7 @@ class CommitParsersTest { fun `addFooters - subject that looks like a footer line`() { val message = """ - Market Explorer: Remove unused code + Market Explorer: Remove unused code """ .trimIndent() @@ -381,7 +381,7 @@ class CommitParsersTest { trimFooters( """ This is a subject - + key1: value1 """ @@ -397,7 +397,7 @@ class CommitParsersTest { trimFooters( """ This is a subject - + key1: value1 """ @@ -410,9 +410,9 @@ class CommitParsersTest { fun `trimFooters - subject and body only`() { val message = """ - This is a subject + This is a subject - This is a body + This is a body """ .trimIndent() @@ -433,12 +433,12 @@ class CommitParsersTest { fun `trimFooters - subject, body with footer-like lines`() { val message = """ - This is a subject + This is a subject - This is a body. - The following are still part of the body: - key-one: value-one - key-two: value-two + This is a body. + The following are still part of the body: + key-one: value-one + key-two: value-two """ .trimIndent() @@ -462,15 +462,15 @@ class CommitParsersTest { fun `trimFooters - subject, body, existing footer lines`() { val message = """ - This is a subject + This is a subject - This is a body. - The following are still part of the body: - key-one: value-one - key-two: value-two - - key-one: value-three - key-two: value-four + This is a body. + The following are still part of the body: + key-one: value-one + key-two: value-two + + key-one: value-three + key-two: value-four """ .trimIndent() @@ -494,15 +494,15 @@ class CommitParsersTest { fun `trimFooters - subject, body, existing footer lines with multiples - last one wins`() { val message = """ - This is a subject + This is a subject - This is a body. - The following are still part of the body: - key-one: value-one - key-two: value-two - - key-one: value-three - key-one: value-four + This is a body. + The following are still part of the body: + key-one: value-one + key-two: value-two + + key-one: value-three + key-one: value-four """ .trimIndent() diff --git a/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprTest.kt b/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprTest.kt index 11d7919..84834db 100644 --- a/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprTest.kt +++ b/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprTest.kt @@ -137,7 +137,8 @@ interface GitJasprTest { """ |[ㄧㄧㄧㄧㄧㄧ] %s : three |[ㄧㄧㄧㄧㄧㄧ] %s : two - |[ㄧㄧㄧㄧㄧㄧ] %s : one""" + |[ㄧㄧㄧㄧㄧㄧ] %s : one + """ .trimMargin() .toStatusString(actual), actual, @@ -169,7 +170,8 @@ interface GitJasprTest { """ |[ㄧㄧㄧㄧㄧㄧ] %s : three |[ㄧㄧㄧㄧㄧㄧ] %s : two - |[✅ㄧㄧㄧㄧㄧ] %s : one""" + |[✅ㄧㄧㄧㄧㄧ] %s : one + """ .trimMargin() .toStatusString(actual), actual, @@ -206,7 +208,8 @@ interface GitJasprTest { """ |[ㄧㄧㄧㄧㄧㄧ] %s : three |[ㄧㄧㄧㄧㄧㄧ] %s : two - |[✅✅⌛✅ㄧㄧ] %s : %s : one""" + |[✅✅⌛✅ㄧㄧ] %s : %s : one + """ .trimMargin() .toStatusString(actual), actual, @@ -246,7 +249,8 @@ interface GitJasprTest { """ |[ㄧㄧㄧㄧㄧㄧ] %s : three |[ㄧㄧㄧㄧㄧㄧ] %s : two - |[✅✅✅✅ㄧㄧ] %s : %s : one""" + |[✅✅✅✅ㄧㄧ] %s : %s : one + """ .trimMargin() .toStatusString(actual), actual, @@ -303,7 +307,8 @@ interface GitJasprTest { """ |[✅✅✅✅ㄧㄧ] %s : %s : three |[✅✅✅✅ㄧㄧ] %s : %s : two - |[✅✅✅✅✅✅] %s : %s : one""" + |[✅✅✅✅✅✅] %s : %s : one + """ .trimMargin() .toStatusString(actual), actual, @@ -507,7 +512,8 @@ interface GitJasprTest { """ |[✅✅✅✅✅✅] %s : %s : three |[✅✅✅✅✅✅] %s : %s : two - |[✅✅✅✅✅✅] %s : %s : one""" + |[✅✅✅✅✅✅] %s : %s : one + """ .trimMargin() .toStatusString(actual), actual, @@ -569,7 +575,8 @@ interface GitJasprTest { """ |[✅✅✅ㄧ✅ㄧ] %s : %s : draft: three |[✅✅✅✅✅✅] %s : %s : two - |[✅✅✅✅✅✅] %s : %s : one""" + |[✅✅✅✅✅✅] %s : %s : one + """ .trimMargin() .toStatusString(actual), actual, @@ -628,7 +635,8 @@ interface GitJasprTest { """ |[✅✅✅✅ㄧㄧ] %s : %s : three |[✅✅✅✅✅ㄧ] %s : %s : two - |[✅✅✅✅ㄧㄧ] %s : %s : one""" + |[✅✅✅✅ㄧㄧ] %s : %s : one + """ .trimMargin() .toStatusString(actual), getActual = { actual }, @@ -686,7 +694,8 @@ interface GitJasprTest { """ |[✅✅✅✅ㄧㄧ] %s : %s : three |[✅✅❌✅ㄧㄧ] %s : %s : two - |[✅✅✅✅ㄧㄧ] %s : %s : one""" + |[✅✅✅✅ㄧㄧ] %s : %s : one + """ .trimMargin() .toStatusString(actual), actual, @@ -730,7 +739,8 @@ interface GitJasprTest { val actual = getAndPrintStatusString(RefSpec("development", "development")) assertEquals( """ - |[✅✅✅✅✅✅] %s : %s : three""" + |[✅✅✅✅✅✅] %s : %s : three + """ .trimMargin() .toStatusString(actual), actual, @@ -820,7 +830,8 @@ interface GitJasprTest { """ |[❗✅✅✅✅ㄧ] %s : %s : four |[❗✅✅✅✅ㄧ] %s : %s : three - |[✅✅✅✅✅✅] %s : %s : one""" + |[✅✅✅✅✅✅] %s : %s : one + """ .trimMargin() .toStatusString(actual), actual, @@ -861,7 +872,8 @@ interface GitJasprTest { |Some commits in your local stack have duplicate IDs: |- a: (one, two) |This is likely because you've based new commit messages off of those from other commits. - |Please correct this by amending the commits and deleting the commit-id lines, then retry your operation.""" + |Please correct this by amending the commits and deleting the commit-id lines, then retry your operation. + """ .trimMargin() .toStatusString(actual), actual, @@ -984,7 +996,8 @@ interface GitJasprTest { |[✅✅✅✅✅✅] %s : %s : four |[✅✅✅✅✅✅] %s : %s : three |[✅✅✅✅✅✅] %s : %s : two - |[✅✅✅✅✅✅] %s : %s : one""" + |[✅✅✅✅✅✅] %s : %s : one + """ .trimMargin() .toStatusString(actual), actual, @@ -1036,7 +1049,8 @@ interface GitJasprTest { assertEquals( """ |[✅✅✅✅✅✅] %s : %s : two - |[✅✅✅✅✅✅] %s : %s : one""" + |[✅✅✅✅✅✅] %s : %s : one + """ .trimMargin() .toStatusString(actual, NamedStackInfo(stackName, 0, 0, remoteName)), actual, @@ -1093,7 +1107,8 @@ interface GitJasprTest { assertEquals( """ - |[✅✅✅✅✅✅] %s : %s : one""" + |[✅✅✅✅✅✅] %s : %s : one + """ .trimMargin() .toStatusString( actual, @@ -1167,7 +1182,8 @@ interface GitJasprTest { assertEquals( """ |[✅ㄧㄧㄧㄧㄧ] %s : two - |[✅✅✅✅✅✅] %s : %s : one""" + |[✅✅✅✅✅✅] %s : %s : one + """ .trimMargin() .toStatusString( actual, @@ -1252,7 +1268,8 @@ interface GitJasprTest { assertEquals( """ |[✅ㄧㄧㄧㄧㄧ] %s : three - |[✅✅✅✅✅✅] %s : %s : one""" + |[✅✅✅✅✅✅] %s : %s : one + """ .trimMargin() .toStatusString( actual, @@ -1326,7 +1343,8 @@ interface GitJasprTest { | update-type: version-update:semver-minor |... | - |Signed-off-by: dependabot[bot] """ + |Signed-off-by: dependabot[bot] + """ .trimMargin() id = "" localRefs += "main" @@ -1372,7 +1390,7 @@ interface GitJasprTest { commit-id: 0 - """ + """ .trimIndent(), localGit.log("HEAD", maxCount = 1).single().fullMessage.withCommitIdZero(), ) @@ -1402,7 +1420,7 @@ interface GitJasprTest { commit-id: 0 - """ + """ .trimIndent(), localGit.log("HEAD", maxCount = 1).single().fullMessage.withCommitIdZero(), ) @@ -1984,7 +2002,7 @@ interface GitJasprTest { - %s - %s ⬅ - """ + """ .trimIndent() .toPrBodyString(actualIterator.next()), """ @@ -1996,7 +2014,7 @@ interface GitJasprTest { - %s ⬅ - %s - """ + """ .trimIndent() .toPrBodyString(actualIterator.next()), """ @@ -2010,7 +2028,7 @@ interface GitJasprTest { - %s - %s - """ + """ .trimIndent() .toPrBodyString(actualIterator.next()), ), @@ -2077,7 +2095,7 @@ interface GitJasprTest { - %s - [01..Current](https://%s/%s/%s/compare/jaspr/main/E_01..jaspr/main/E) - """ + """ .trimIndent() .toPrBodyString(actualIterator.next()), """ @@ -2096,7 +2114,7 @@ interface GitJasprTest { - %s - [01..Current](https://%s/%s/%s/compare/jaspr/main/E_01..jaspr/main/E) - """ + """ .trimIndent() .toPrBodyString(actualIterator.next()), """ @@ -2115,7 +2133,7 @@ interface GitJasprTest { - %s - [01..Current](https://%s/%s/%s/compare/jaspr/main/E_01..jaspr/main/E) - """ + """ .trimIndent() .toPrBodyString(actualIterator.next()), """ @@ -2129,7 +2147,7 @@ interface GitJasprTest { - %s - %s - """ + """ .trimIndent() .toPrBodyString(actualIterator.next()), """ @@ -2148,7 +2166,7 @@ interface GitJasprTest { - %s ⬅ - [01..Current](https://%s/%s/%s/compare/jaspr/main/E_01..jaspr/main/E) - """ + """ .trimIndent() .toPrBodyString(actualIterator.next()), """ @@ -2167,7 +2185,7 @@ interface GitJasprTest { - %s - [01..Current](https://%s/%s/%s/compare/jaspr/main/E_01..jaspr/main/E) - """ + """ .trimIndent() .toPrBodyString(actualIterator.next()), """ @@ -2186,7 +2204,7 @@ interface GitJasprTest { - %s - [01..Current](https://%s/%s/%s/compare/jaspr/main/E_01..jaspr/main/E) - """ + """ .trimIndent() .toPrBodyString(actualIterator.next()), ), @@ -2256,7 +2274,7 @@ interface GitJasprTest { - %s - %s ⬅ - """ + """ .trimIndent() .toPrBodyString(actualIterator.next()), """ @@ -2268,7 +2286,7 @@ interface GitJasprTest { - %s ⬅ - %s - """ + """ .trimIndent() .toPrBodyString(actualIterator.next()), """ @@ -2280,7 +2298,7 @@ interface GitJasprTest { - %s - %s - """ + """ .trimIndent() .toPrBodyString(actualIterator.next()), """ @@ -2292,7 +2310,7 @@ interface GitJasprTest { - %s - %s - """ + """ .trimIndent() .toPrBodyString(actualIterator.next()), """ @@ -2304,7 +2322,7 @@ interface GitJasprTest { - %s - %s - """ + """ .trimIndent() .toPrBodyString(actualIterator.next()), ), diff --git a/libs.versions.toml b/libs.versions.toml index d128f5c..f99aba3 100644 --- a/libs.versions.toml +++ b/libs.versions.toml @@ -4,7 +4,7 @@ kotlin = "2.3.0" kotlinpoet = "2.2.0" ksp = "2.3.4" jgit = "7.4.0.202509020913-r" -ktfmt = "0.58" +ktfmt = "0.60" [plugins] kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } From 0b776f63761e2ce439af3282b3a4128ce5e9be79 Mon Sep 17 00:00:00 2001 From: Michael Sims Date: Sat, 27 Dec 2025 13:34:38 -0600 Subject: [PATCH 6/9] Fix `getOrphanedBranches prunes stale tracking branches` functional test This was failing during the functional test because it assumed there was a "fake remote" (local git repo acting as the "remote" for the test) . The functional test was using a real remote, so we need to make sure branches are deleted properly based on which mode we're in. commit-id: I740f8375 --- .../kotlin/sims/michael/gitjaspr/GitJasprTest.kt | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprTest.kt b/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprTest.kt index 84834db..4439797 100644 --- a/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprTest.kt +++ b/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprTest.kt @@ -3419,10 +3419,18 @@ interface GitJasprTest { } ) - remoteGit.deleteBranches( - listOf(buildRemoteRef("c"), buildRemoteRef("c_01")), - force = true, - ) + // This could be cleaner. We need the remote branches gone so we can verify that + // getOrphanedBranches does a fetch w/prune before returning results. The mechanism to + // remove the remote branches depends on whether we're using a fake remote. + val remoteBranchesToRemove = listOf(buildRemoteRef("c"), buildRemoteRef("c_01")) + if (useFakeRemote) { + remoteGit.deleteBranches(remoteBranchesToRemove, force = true) + } else { + localGit.push( + remoteBranchesToRemove.map { name -> RefSpec(FORCE_PUSH_PREFIX, name) }, + remoteName, + ) + } assertEquals( listOf(buildRemoteRef("b"), buildRemoteRef("b_01")), From 7e2011899090130793b25956ff32b37993863520 Mon Sep 17 00:00:00 2001 From: Michael Sims Date: Sat, 27 Dec 2025 13:37:03 -0600 Subject: [PATCH 7/9] Fix comment formatting commit-id: Ib9d4f25e --- .../src/test/kotlin/sims/michael/gitjaspr/GitJasprTest.kt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprTest.kt b/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprTest.kt index 4439797..6e616d5 100644 --- a/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprTest.kt +++ b/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprTest.kt @@ -3449,11 +3449,9 @@ interface GitJasprTest { ) // It may seem silly to repeat what is already defined in GitJaspr.HEADER, but if a dev changes - // the header I want - // these tests to break so that any such changes are very deliberate. This is a compromise - // between referencing the - // same value from both tests and prod and the other extreme of repeating this header text - // manually in every test. + // the header, I want these tests to break so that any such changes are very deliberate. This is + // a compromise between referencing the same value from both tests and prod and the other + // extreme of repeating this header text manually in every test. private fun String.toStatusString( actual: String, namedStackInfo: NamedStackInfo? = null, From 159cd1fd1259a5c6349ca1913e2a829626e57c7b Mon Sep 17 00:00:00 2001 From: Michael Sims Date: Sat, 27 Dec 2025 13:37:29 -0600 Subject: [PATCH 8/9] Address inspection warnings in GitJasprTest.kt commit-id: I8be43d76 --- .../src/test/kotlin/sims/michael/gitjaspr/GitJasprTest.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprTest.kt b/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprTest.kt index 6e616d5..79b6c98 100644 --- a/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprTest.kt +++ b/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprTest.kt @@ -3470,9 +3470,9 @@ interface GitJasprTest { val formattedString = try { format(*extracts.toTypedArray()) - } catch (e: MissingFormatArgumentException) { + } catch (_: MissingFormatArgumentException) { logger.error( - "Format string doesn't have enough arguments, should have {}", + "toStatusString: format string doesn't have enough arguments, should have {}", extracts.size, ) this @@ -3542,9 +3542,9 @@ interface GitJasprTest { val formattedString = try { format(*list.toTypedArray()) - } catch (e: MissingFormatArgumentException) { + } catch (_: MissingFormatArgumentException) { logger.error( - "Format string doesn't have enough arguments, should have {}", + "toPrBodyString: format string doesn't have enough arguments, should have {}", list.size, ) this From 75c01f9ae6a95d3e98ed38d02daf75f6b9ee88c6 Mon Sep 17 00:00:00 2001 From: Michael Sims Date: Sat, 27 Dec 2025 18:43:23 -0600 Subject: [PATCH 9/9] Mitigate "push adds commit IDs" test flakiness I noticed the last dynamic test in this function titled "only commits in the middle missing IDs" was failing fairly consistently during functional test runs. It seems there's a delay in GitHub closing test PRs created by the previous dynamic test. Since this test reused the same titles and the titles are used as keys, it was causing a "leak" from one test into the next. I'm fixing this by ensuring the titles are unique, but I could also mitigate it by adding a delay after "remote rollback" commit-id: Ia649cdf8 --- .../sims/michael/gitjaspr/GitJasprTest.kt | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprTest.kt b/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprTest.kt index 79b6c98..dc2550b 100644 --- a/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprTest.kt +++ b/git-jaspr/src/test/kotlin/sims/michael/gitjaspr/GitJasprTest.kt @@ -1458,15 +1458,15 @@ interface GitJasprTest { commit { title = "A" } commit { title = "B" } commit { - title = "0" + title = "3" id = "" } commit { - title = "1" + title = "4" id = "" } commit { - title = "2" + title = "5" id = "" localRefs += "main" } @@ -1477,23 +1477,23 @@ interface GitJasprTest { "only commits in the middle missing IDs", testCase { repository { - commit { title = "A" } - commit { title = "B" } + commit { title = "C" } + commit { title = "D" } commit { - title = "0" + title = "6" id = "" } commit { - title = "1" + title = "7" id = "" } commit { - title = "2" + title = "8" id = "" } - commit { title = "C" } + commit { title = "E" } commit { - title = "D" + title = "F" localRefs += "main" } }