From a1fe173460768528f0f23dd6dcfb14776311bb25 Mon Sep 17 00:00:00 2001 From: Jonathan Zollinger Date: Thu, 5 Feb 2026 20:57:21 -0700 Subject: [PATCH 01/16] chore: ignore .env file --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 5a03bc3..9e19835 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ out/ .settings .classpath .factorypath +.env \ No newline at end of file From 63d6c62cd17b95ce9c16445e9ad3449128538184 Mon Sep 17 00:00:00 2001 From: Jonathan Zollinger Date: Thu, 5 Feb 2026 22:21:34 -0700 Subject: [PATCH 02/16] ci: add compile and sonar test workflow --- .github/workflows/TestAndCompile.yml | 34 ++++++++++++++++++++++++++++ build.gradle.kts | 12 ++++------ gradle.properties | 6 +++++ 3 files changed, 45 insertions(+), 7 deletions(-) create mode 100644 .github/workflows/TestAndCompile.yml diff --git a/.github/workflows/TestAndCompile.yml b/.github/workflows/TestAndCompile.yml new file mode 100644 index 0000000..6666f90 --- /dev/null +++ b/.github/workflows/TestAndCompile.yml @@ -0,0 +1,34 @@ +name: GraalVM Native Image Test run and build tests +on: [pull_request, workflow_dispatch] +jobs: + build: + name: test and compile on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-latest, windows-latest, ubuntu-latest] + env: + ZCMI_SANDBOX_URL: ${{ secrets.ZCMI_SANDBOX_URL }} + ZCMI_ADMIN_EMAIL: ${{ secrets.ZCMI_ADMIN_EMAIL }} + ZCMI_ADMIN_TOKEN: ${{ secrets.ZCMI_ADMIN_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - uses: graalvm/setup-graalvm@54b4f5a65c1a84b2fdfdc2078fe43df32819e4b1 # v1.4.5 + with: + java-version: '21' + distribution: 'graalvm' + github-token: ${{ secrets.GITHUB_TOKEN }} + native-image-job-reports: 'true' + native-image-pr-reports: 'true' + - name: call gradle to run tests and then compile + if: matrix.os == 'ubuntu-latest' + run: ./gradlew test sonar nativeCompile + - name: call gradle to run tests and then compile + if: matrix.os != 'ubuntu-latest' + run: ./gradlew test nativeCompile + - name: upload binary + uses: actions/upload-artifact@v4 + with: + name: zcmi-${{ matrix.os }} + path: build/native/nativeCompile/zcmi* diff --git a/build.gradle.kts b/build.gradle.kts index bed81d9..3df8d10 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -71,9 +71,9 @@ kotlin { } } -sonarqube { - properties { - property("sonar.tests", "src/test/groovy") +tasks.jacocoTestReport { + reports { + xml.required.set(true) } } @@ -104,9 +104,7 @@ graalvmNative.binaries { named("main") { imageName.set("zcmi") buildArgs.add("--color=always") - buildArgs.add("-march=native") -// buildArgs.add("-0b") +// buildArgs.add("-march=native") + buildArgs.add("-0b") } } - - diff --git a/gradle.properties b/gradle.properties index d572275..f1b5bb0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,3 +17,9 @@ org.gradle.console=rich picoJlineVersion=4.7.6 jlineVersion=3.30.5 zcmiVersion=0.0.1 +sonar.projectKey=PeanutButter-Unicorn_zcmi +sonar.organization=peanutbutter-unicorn +sonar.sources=src/main/kotlin +sonar.tests=src/test/groovy +sonar.junit.reportPaths=build/reports/jacoco/test/ +sonar.coverage.jacoco.xmlReportPaths=build/reports/jacoco/test/jacocoTestReport.xml From 8bec6153b8af35f33167e65b24bd46bf34debf00 Mon Sep 17 00:00:00 2001 From: Jonathan Zollinger Date: Thu, 5 Feb 2026 23:02:44 -0700 Subject: [PATCH 03/16] build: use native cpu build option --- build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 3df8d10..04ba3da 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -104,7 +104,7 @@ graalvmNative.binaries { named("main") { imageName.set("zcmi") buildArgs.add("--color=always") -// buildArgs.add("-march=native") - buildArgs.add("-0b") + buildArgs.add("-march=native") +// buildArgs.add("-Ob") } } From ead200a0fee48d6aa95a5aee0fd5f8d69a3925eb Mon Sep 17 00:00:00 2001 From: Jonathan Zollinger Date: Fri, 6 Feb 2026 21:00:53 -0700 Subject: [PATCH 04/16] fix: see if this works --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 04ba3da..71c76a6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -58,7 +58,7 @@ tasks.withType { } application { - mainClass = "lol.pbu.ZcmiCommand" + mainClass = "lol.pbu.ZcmiCommandk" } java { From 20d0f6f30a079e61a6b02f7fdd5fc8639f68b1a6 Mon Sep 17 00:00:00 2001 From: Jonathan Zollinger Date: Fri, 6 Feb 2026 23:09:20 -0700 Subject: [PATCH 05/16] feat: swap base language to java --- build.gradle.kts | 60 ++++++++++--------------- gradle.properties | 16 ++----- micronaut-cli.yml | 4 +- src/main/java/lol/pbu/BaseCommand.java | 43 ++++++++++++++++++ src/main/java/lol/pbu/ZcmiCommand.java | 32 +++++++++++++ src/main/kotlin/lol/pbu/BaseCommand.kt | 29 ------------ src/main/kotlin/lol/pbu/ZcmiCommand.kt | 35 --------------- src/test/groovy/lol/pbu/ZcmiSpec.groovy | 9 +++- 8 files changed, 111 insertions(+), 117 deletions(-) create mode 100644 src/main/java/lol/pbu/BaseCommand.java create mode 100644 src/main/java/lol/pbu/ZcmiCommand.java delete mode 100644 src/main/kotlin/lol/pbu/BaseCommand.kt delete mode 100644 src/main/kotlin/lol/pbu/ZcmiCommand.kt diff --git a/build.gradle.kts b/build.gradle.kts index 71c76a6..4939a72 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,18 +8,13 @@ plugins { id("it.nicolasfarabegoli.conventional-commits") version "3.1.3" id("org.sonarqube") version "latest.release" id("jacoco") - id("org.jetbrains.kotlin.jvm") version "1.9.25" - id("org.jetbrains.kotlin.kapt") version "1.9.25" - id("org.jetbrains.kotlin.plugin.allopen") version "1.9.25" - id("groovy") + id("groovy") id("io.micronaut.application") version "4.6.1" id("com.gradleup.shadow") version "8.3.9" } version = project.properties["zcmiVersion"]!! group = "lol.pbu" - -val kotlinVersion = project.properties["kotlinVersion"]!! val z4jVersion = project.properties["z4jVersion"]!! val jansiGraalVersion = project.properties["jansiGraalVersion"]!! val jansiVersion = project.properties["jansiVersion"]!! @@ -31,43 +26,46 @@ repositories { } dependencies { - kapt("info.picocli:picocli-codegen") - kapt("io.micronaut.serde:micronaut-serde-processor") + annotationProcessor("info.picocli:picocli-codegen") + annotationProcessor("io.micronaut.serde:micronaut-serde-processor") implementation("info.picocli:picocli") implementation("lol.pbu:z4j:${z4jVersion}") - implementation("io.micronaut.kotlin:micronaut-kotlin-runtime") implementation("io.micronaut.picocli:micronaut-picocli") implementation("info.picocli:picocli-jansi-graalvm:${jansiGraalVersion}") implementation("org.fusesource.jansi:jansi:${jansiVersion}") implementation("info.picocli:picocli-shell-jline3:${picoJlineVersion}") implementation("org.jline:jline:${jlineVersion}") implementation("io.micronaut.serde:micronaut-serde-jackson") - implementation("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}") - implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:${kotlinVersion}") runtimeOnly("ch.qos.logback:logback-classic") - runtimeOnly("com.fasterxml.jackson.module:jackson-module-kotlin") runtimeOnly("org.yaml:snakeyaml") } -tasks.withType { - val props = Properties() - file("gradle.properties").inputStream().use { props.load(it) } - filesMatching("**/application.yml") { - filter(mapOf("tokens" to props), ReplaceTokens::class.java) - } -} application { - mainClass = "lol.pbu.ZcmiCommandk" + mainClass = "lol.pbu.ZcmiCommand" } - java { sourceCompatibility = JavaVersion.toVersion("21") + targetCompatibility = JavaVersion.toVersion("21") } -kotlin { - jvmToolchain { - languageVersion.set(JavaLanguageVersion.of(21)) +micronaut { + testRuntime("spock2") + processing { + incremental(true) + annotations("lol.pbu.*") + } +} + +tasks.named("dockerfileNative") { + jdkVersion = "21" +} + +tasks.withType { + val props = Properties() + file("gradle.properties").inputStream().use { props.load(it) } + filesMatching("**/application.yml") { + filter(mapOf("tokens" to props), ReplaceTokens::class.java) } } @@ -88,18 +86,6 @@ tasks.test { finalizedBy(tasks.jacocoTestReport) } -micronaut { - testRuntime("spock2") - processing { - incremental(true) - annotations("lol.pbu.*") - } -} - -tasks.named("dockerfileNative") { - jdkVersion = "21" -} - graalvmNative.binaries { named("main") { imageName.set("zcmi") @@ -107,4 +93,4 @@ graalvmNative.binaries { buildArgs.add("-march=native") // buildArgs.add("-Ob") } -} +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index f1b5bb0..22e670f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,22 +1,12 @@ +org.gradle.console=rich + micronautVersion=4.10.7 -kotlin.daemon.jvmargs=--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ - --add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED \ - --add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED \ - --add-opens=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \ - --add-opens=jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED \ - --add-opens=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED \ - --add-opens=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \ - --add-opens=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED \ - --add-opens=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \ - --add-opens=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED -kotlinVersion=1.9.25 +zcmiVersion=0.0.1 z4jVersion=0.0.8 jansiGraalVersion=1.2.0 jansiVersion=2.4.2 -org.gradle.console=rich picoJlineVersion=4.7.6 jlineVersion=3.30.5 -zcmiVersion=0.0.1 sonar.projectKey=PeanutButter-Unicorn_zcmi sonar.organization=peanutbutter-unicorn sonar.sources=src/main/kotlin diff --git a/micronaut-cli.yml b/micronaut-cli.yml index 8bab671..615c6fe 100644 --- a/micronaut-cli.yml +++ b/micronaut-cli.yml @@ -1,6 +1,6 @@ applicationType: cli defaultPackage: lol.pbu testFramework: spock -sourceLanguage: kotlin +sourceLanguage: java buildTool: gradle_kotlin -features: [app-name, graalvm, gradle, http-client-test, kapt, kotlin, logback, micronaut-build, picocli, picocli-kotlin-application, picocli-spock, readme, serialization-jackson, shade, spock, yaml, yaml-build] +features: [app-name, gradle, http-client-test, java, logback, micronaut-build, picocli, picocli-java-application, picocli-spock, readme, serialization-jackson, shade, spock, yaml, yaml-build] diff --git a/src/main/java/lol/pbu/BaseCommand.java b/src/main/java/lol/pbu/BaseCommand.java new file mode 100644 index 0000000..ed5d029 --- /dev/null +++ b/src/main/java/lol/pbu/BaseCommand.java @@ -0,0 +1,43 @@ +package lol.pbu; + +import io.micronaut.core.annotation.NonNull; +import io.micronaut.core.annotation.ReflectiveAccess; +import picocli.CommandLine.Command; +import picocli.CommandLine.Model.CommandSpec; +import picocli.CommandLine.Spec; + +import java.io.PrintWriter; +import java.util.Optional; + +import static picocli.CommandLine.Help.Ansi.AUTO; + +@Command +public class BaseCommand { + + @Spec + @ReflectiveAccess + protected CommandSpec spec; + + + public void out(String message) { + outWriter().ifPresent(writer -> writer.println(AUTO.string(message))); + } + + public void err(String message) { + red(String.format("Error: %s", message)); + } + + public void red(String message) { + outWriter().ifPresent(writer -> writer.println(AUTO.string("@|bold,red " + message + "|@"))); + } + + @NonNull + public Optional outWriter() { + return getSpec().map(commandSpec -> commandSpec.commandLine().getOut()); + } + + @NonNull + public Optional getSpec() { + return Optional.ofNullable(spec); + } +} diff --git a/src/main/java/lol/pbu/ZcmiCommand.java b/src/main/java/lol/pbu/ZcmiCommand.java new file mode 100644 index 0000000..a9cd0ae --- /dev/null +++ b/src/main/java/lol/pbu/ZcmiCommand.java @@ -0,0 +1,32 @@ +package lol.pbu; + +import io.micronaut.configuration.picocli.PicocliRunner; + +import io.micronaut.context.annotation.Value; +import picocli.CommandLine; +import picocli.CommandLine.Command; +import picocli.jansi.graalvm.AnsiConsole; + +@Command(name = "zcmi", description = "...", versionProvider = ZcmiCommand.ZcmiVersionProvider.class, mixinStandardHelpOptions = true) +public class ZcmiCommand extends BaseCommand implements Runnable { + + public static void main(String[] args) { + try (AnsiConsole ignored = AnsiConsole.windowsInstall()) { + PicocliRunner.run(ZcmiCommand.class, args); + } + } + + public void run() { + err("No Command Given"); + } + + static class ZcmiVersionProvider implements CommandLine.IVersionProvider { + @Value("${micronaut.application.version}") + String version; + + @Override + public String[] getVersion() { + return new String[]{version}; + } + } +} diff --git a/src/main/kotlin/lol/pbu/BaseCommand.kt b/src/main/kotlin/lol/pbu/BaseCommand.kt deleted file mode 100644 index ac16c4c..0000000 --- a/src/main/kotlin/lol/pbu/BaseCommand.kt +++ /dev/null @@ -1,29 +0,0 @@ -package lol.pbu - -import io.micronaut.core.annotation.ReflectiveAccess -import picocli.CommandLine.Command -import picocli.CommandLine.Help.Ansi.AUTO -import picocli.CommandLine.Model.CommandSpec -import picocli.CommandLine.Spec -import java.io.PrintWriter - -@Command -open class BaseCommand { - @Spec - @ReflectiveAccess - protected var spec: CommandSpec? = null - - - fun out(message: String) { - outWriter()?.println(AUTO.string(message)) - } - - fun err(message: String?) { - errWriter()?.println(AUTO.string("@|bold,red | Error|@ $message")) - } - - fun outWriter(): PrintWriter? = spec?.commandLine()?.getOut() - - fun errWriter(): PrintWriter? = spec?.commandLine()?.getErr() - -} \ No newline at end of file diff --git a/src/main/kotlin/lol/pbu/ZcmiCommand.kt b/src/main/kotlin/lol/pbu/ZcmiCommand.kt deleted file mode 100644 index 3b1cc4f..0000000 --- a/src/main/kotlin/lol/pbu/ZcmiCommand.kt +++ /dev/null @@ -1,35 +0,0 @@ -package lol.pbu - -import io.micronaut.configuration.picocli.PicocliRunner -import io.micronaut.context.annotation.Value -import lol.pbu.ZcmiCommand.ZcmiVersionProvider -import picocli.CommandLine -import picocli.CommandLine.Command -import picocli.jansi.graalvm.AnsiConsole - -@Command( - subcommands = [HelpCenterCommand::class], - mixinStandardHelpOptions = true, - name = "Zendesk CLI Management Interface", - versionProvider = ZcmiVersionProvider::class, - description = ["Work seamlessly with Zendesk from the command line."] -) -class ZcmiCommand : BaseCommand(), Runnable { - class ZcmiVersionProvider : CommandLine.IVersionProvider { - @Value("\${micronaut.application.version}") - var zcmiVersionProvider: String? = null - override fun getVersion(): Array { - return arrayOf(zcmiVersionProvider); } - } - - override fun run() { - err("No command specified.") - } - - companion object { - @JvmStatic - fun main(args: Array) { - AnsiConsole.windowsInstall().use { _ -> PicocliRunner.run(ZcmiCommand::class.java, *args) } - } - } -} \ No newline at end of file diff --git a/src/test/groovy/lol/pbu/ZcmiSpec.groovy b/src/test/groovy/lol/pbu/ZcmiSpec.groovy index e7461c3..84eb5f5 100644 --- a/src/test/groovy/lol/pbu/ZcmiSpec.groovy +++ b/src/test/groovy/lol/pbu/ZcmiSpec.groovy @@ -21,6 +21,9 @@ class ZcmiSpec extends Specification { @Shared def gradleProperties + @Shared + String ansi + def setupSpec() { testContext = new ZcmiTestContext( createContext(), @@ -32,7 +35,7 @@ class ZcmiSpec extends Specification { new File('gradle.properties').withInputStream { stream -> gradleProperties.load(stream) } - String ansi = "\\u001B\\[[;\\d]*m" + ansi = "\\u001B\\[[;\\d]*m" blank = Pattern.compile "^\\s*\$" success = Pattern.compile("^${ansi}\\w+${ansi}\\s*\$") } @@ -41,6 +44,10 @@ class ZcmiSpec extends Specification { testContext.close() } + def errorPattern = { String errorMessage -> + return Pattern.quote("$ansi$errorMessage$ansi") + } + /** * Executes a command with the given arguments and a specific application context, * capturing stdout and stderr. From 4a4f5b55e7d60dfbb640775651a3dfcf91cbb346 Mon Sep 17 00:00:00 2001 From: Jonathan Zollinger Date: Fri, 6 Feb 2026 23:19:36 -0700 Subject: [PATCH 06/16] ci: run sonar only on ubuntu --- .github/workflows/TestAndCompile.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/TestAndCompile.yml b/.github/workflows/TestAndCompile.yml index 6666f90..732647a 100644 --- a/.github/workflows/TestAndCompile.yml +++ b/.github/workflows/TestAndCompile.yml @@ -23,9 +23,8 @@ jobs: native-image-pr-reports: 'true' - name: call gradle to run tests and then compile if: matrix.os == 'ubuntu-latest' - run: ./gradlew test sonar nativeCompile + run: ./gradlew build sonar - name: call gradle to run tests and then compile - if: matrix.os != 'ubuntu-latest' run: ./gradlew test nativeCompile - name: upload binary uses: actions/upload-artifact@v4 From c4894b3217d6e4f2ea12b19909f54906bce73048 Mon Sep 17 00:00:00 2001 From: Jonathan Zollinger Date: Sat, 7 Feb 2026 16:11:03 -0700 Subject: [PATCH 07/16] refactor: cleanup whitespace --- gradle.properties | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index 22e670f..0734c78 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,4 @@ org.gradle.console=rich - micronautVersion=4.10.7 zcmiVersion=0.0.1 z4jVersion=0.0.8 @@ -12,4 +11,4 @@ sonar.organization=peanutbutter-unicorn sonar.sources=src/main/kotlin sonar.tests=src/test/groovy sonar.junit.reportPaths=build/reports/jacoco/test/ -sonar.coverage.jacoco.xmlReportPaths=build/reports/jacoco/test/jacocoTestReport.xml +sonar.coverage.jacoco.xmlReportPaths=build/reports/jacoco/test/jacocoTestReport.xml \ No newline at end of file From 37d338f872cf5bc1c765bf4511aa33638fcbf59e Mon Sep 17 00:00:00 2001 From: Jonathan Zollinger Date: Sat, 7 Feb 2026 16:12:18 -0700 Subject: [PATCH 08/16] fix(ci): put sonar scan in own wf --- .github/workflows/Sonar.yml | 19 +++++++++++++++++++ .github/workflows/TestAndCompile.yml | 7 ++----- 2 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/Sonar.yml diff --git a/.github/workflows/Sonar.yml b/.github/workflows/Sonar.yml new file mode 100644 index 0000000..08a483a --- /dev/null +++ b/.github/workflows/Sonar.yml @@ -0,0 +1,19 @@ +name: Sonar +on: [pull_request, workflow_dispatch] +jobs: + build: + name: Run Sonar Scan + runs-on: ubuntu-latest + env: + ZCMI_SANDBOX_URL: ${{ secrets.ZCMI_SANDBOX_URL }} + ZCMI_ADMIN_EMAIL: ${{ secrets.ZCMI_ADMIN_EMAIL }} + ZCMI_ADMIN_TOKEN: ${{ secrets.ZCMI_ADMIN_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - uses: graalvm/setup-graalvm@54b4f5a65c1a84b2fdfdc2078fe43df32819e4b1 # v1.4.5 + with: + java-version: '21' + distribution: 'graalvm' + - name: call gradle to run tests and then compile native image + run: ./gradlew test sonar diff --git a/.github/workflows/TestAndCompile.yml b/.github/workflows/TestAndCompile.yml index 732647a..6f0eca0 100644 --- a/.github/workflows/TestAndCompile.yml +++ b/.github/workflows/TestAndCompile.yml @@ -1,4 +1,4 @@ -name: GraalVM Native Image Test run and build tests +name: Compile to Native Image on: [pull_request, workflow_dispatch] jobs: build: @@ -21,10 +21,7 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} native-image-job-reports: 'true' native-image-pr-reports: 'true' - - name: call gradle to run tests and then compile - if: matrix.os == 'ubuntu-latest' - run: ./gradlew build sonar - - name: call gradle to run tests and then compile + - name: call gradle to run tests and then compile native image run: ./gradlew test nativeCompile - name: upload binary uses: actions/upload-artifact@v4 From 203ebbdbd267dd73456766bb3ad533a761c34a71 Mon Sep 17 00:00:00 2001 From: Jonathan Zollinger Date: Sat, 7 Feb 2026 16:22:25 -0700 Subject: [PATCH 09/16] ci: set sonar properties --- .github/workflows/TestAndCompile.yml | 1 - sonar-project.properties | 6 ++++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 sonar-project.properties diff --git a/.github/workflows/TestAndCompile.yml b/.github/workflows/TestAndCompile.yml index 6f0eca0..28e7ef0 100644 --- a/.github/workflows/TestAndCompile.yml +++ b/.github/workflows/TestAndCompile.yml @@ -11,7 +11,6 @@ jobs: ZCMI_SANDBOX_URL: ${{ secrets.ZCMI_SANDBOX_URL }} ZCMI_ADMIN_EMAIL: ${{ secrets.ZCMI_ADMIN_EMAIL }} ZCMI_ADMIN_TOKEN: ${{ secrets.ZCMI_ADMIN_TOKEN }} - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - uses: graalvm/setup-graalvm@54b4f5a65c1a84b2fdfdc2078fe43df32819e4b1 # v1.4.5 diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 0000000..41a8b35 --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,6 @@ +sonar.projectKey=PeanutButter-Unicorn_zcmi +sonar.organization=peanutbutter-unicorn +sonar.sources=src/main/kotlin +sonar.tests=src/test/groovy +sonar.junit.reportPaths=build/reports/jacoco/test/ +sonar.coverage.jacoco.xmlReportPaths=build/reports/jacoco/test/jacocoTestReport.xml From b6c57eed66969e37f1c8745440fcdbf09966aa81 Mon Sep 17 00:00:00 2001 From: Jonathan Zollinger Date: Sat, 7 Feb 2026 16:47:17 -0700 Subject: [PATCH 10/16] fix(ci): work around windows CI bug graalvm/native-build-tools/issues/754 --- .github/workflows/TestAndCompile.yml | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/.github/workflows/TestAndCompile.yml b/.github/workflows/TestAndCompile.yml index 28e7ef0..ccc9a0e 100644 --- a/.github/workflows/TestAndCompile.yml +++ b/.github/workflows/TestAndCompile.yml @@ -1,4 +1,4 @@ -name: Compile to Native Image +name: GraalVM Native Image Test run and build tests on: [pull_request, workflow_dispatch] jobs: build: @@ -11,6 +11,7 @@ jobs: ZCMI_SANDBOX_URL: ${{ secrets.ZCMI_SANDBOX_URL }} ZCMI_ADMIN_EMAIL: ${{ secrets.ZCMI_ADMIN_EMAIL }} ZCMI_ADMIN_TOKEN: ${{ secrets.ZCMI_ADMIN_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - uses: graalvm/setup-graalvm@54b4f5a65c1a84b2fdfdc2078fe43df32819e4b1 # v1.4.5 @@ -20,7 +21,20 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} native-image-job-reports: 'true' native-image-pr-reports: 'true' - - name: call gradle to run tests and then compile native image + - name: call gradle to run tests and then compile (WINDOWS) + if: matrix.os == 'windows-latest' + env: + # This solution found at https://github.com/graalvm/native-build-tools/issues/754#issuecomment-3450913085 + # Needed for Windows; to resolve issue with temp folder during native image build, due to relativization + # problem when different drives are used, such as in GHA runners. + # https://github.com/graalvm/native-build-tools/issues/754 + GRADLE_OPTS: -Djava.io.tmpdir=${{ runner.temp }} + run: ./gradlew test nativeCompile + - name: call gradle to run tests and then compile (NOT WINDOWS) + if: matrix.os != 'windows-latest' + run: ./gradlew test nativeCompile + - name: call gradle to run tests and then compile + if: matrix.os != 'ubuntu-latest' run: ./gradlew test nativeCompile - name: upload binary uses: actions/upload-artifact@v4 From 854a3756c528a066eb5c3d96a9f4bafec373e11b Mon Sep 17 00:00:00 2001 From: Jonathan Zollinger Date: Sat, 7 Feb 2026 19:51:01 -0700 Subject: [PATCH 11/16] fix(ci): set sonar properties --- build.gradle.kts | 14 +++++++++++++- gradle.properties | 8 +------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 4939a72..0f61404 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -93,4 +93,16 @@ graalvmNative.binaries { buildArgs.add("-march=native") // buildArgs.add("-Ob") } -} \ No newline at end of file +} + +sonar { + properties { + property("sonar.projectKey", "PeanutButter-Unicorn_zcmi") + property("sonar.organization", "peanutbutter-unicorn") + property("sonar.host.url", "https://sonarcloud.io") + property("sonar.coverage.jacoco.xmlReportPaths", "build/reports/jacoco/test/jacocoTestReport.xml") + property("sonar.tests", "src/test/groovy") + property("sonar.junit.reportPaths", "build/reports/jacoco/test") + property("sonar.coverage.jacoco.xmlReportPaths", "build/reports/jacoco/test/jacocoTestReport.xml") + } +} diff --git a/gradle.properties b/gradle.properties index 0734c78..820deb0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,10 +5,4 @@ z4jVersion=0.0.8 jansiGraalVersion=1.2.0 jansiVersion=2.4.2 picoJlineVersion=4.7.6 -jlineVersion=3.30.5 -sonar.projectKey=PeanutButter-Unicorn_zcmi -sonar.organization=peanutbutter-unicorn -sonar.sources=src/main/kotlin -sonar.tests=src/test/groovy -sonar.junit.reportPaths=build/reports/jacoco/test/ -sonar.coverage.jacoco.xmlReportPaths=build/reports/jacoco/test/jacocoTestReport.xml \ No newline at end of file +jlineVersion=3.30.5 \ No newline at end of file From 485e0879de5f20b0d5c3438df71cb2cfd740f631 Mon Sep 17 00:00:00 2001 From: Jonathan Zollinger Date: Sat, 7 Feb 2026 20:44:17 -0700 Subject: [PATCH 12/16] test: validate no org behavior --- src/test/groovy/lol/pbu/ZcmiCommandSpec.groovy | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/test/groovy/lol/pbu/ZcmiCommandSpec.groovy b/src/test/groovy/lol/pbu/ZcmiCommandSpec.groovy index 87713a6..7d3af9b 100644 --- a/src/test/groovy/lol/pbu/ZcmiCommandSpec.groovy +++ b/src/test/groovy/lol/pbu/ZcmiCommandSpec.groovy @@ -19,5 +19,17 @@ class ZcmiCommandSpec extends ZcmiSpec { where: [args, context] << [[['-V'], ['--version']], testContext.getAllContexts()].combinations() } -} + void "invoking with no arguments prints error"(ApplicationContext context) { + when: + String[] out = executeCommand(context) + + then: + verifyAll { + out.first().contains("No Command Given") + } + + where: + context << testContext.getAllContexts() + } +} From 3169bb8a764d1537ee88b3664a6029c270b5d1a5 Mon Sep 17 00:00:00 2001 From: Jonathan Zollinger Date: Sat, 7 Feb 2026 20:44:51 -0700 Subject: [PATCH 13/16] ci: allow WF to add PR comments --- .github/workflows/Sonar.yml | 2 ++ .github/workflows/TestAndCompile.yml | 6 ++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/Sonar.yml b/.github/workflows/Sonar.yml index 08a483a..9d90b56 100644 --- a/.github/workflows/Sonar.yml +++ b/.github/workflows/Sonar.yml @@ -4,6 +4,8 @@ jobs: build: name: Run Sonar Scan runs-on: ubuntu-latest + permissions: + pull-requests: write env: ZCMI_SANDBOX_URL: ${{ secrets.ZCMI_SANDBOX_URL }} ZCMI_ADMIN_EMAIL: ${{ secrets.ZCMI_ADMIN_EMAIL }} diff --git a/.github/workflows/TestAndCompile.yml b/.github/workflows/TestAndCompile.yml index ccc9a0e..b8ae694 100644 --- a/.github/workflows/TestAndCompile.yml +++ b/.github/workflows/TestAndCompile.yml @@ -4,6 +4,8 @@ jobs: build: name: test and compile on ${{ matrix.os }} runs-on: ${{ matrix.os }} + permissions: + pull-requests: write strategy: matrix: os: [macos-latest, windows-latest, ubuntu-latest] @@ -30,11 +32,7 @@ jobs: # https://github.com/graalvm/native-build-tools/issues/754 GRADLE_OPTS: -Djava.io.tmpdir=${{ runner.temp }} run: ./gradlew test nativeCompile - - name: call gradle to run tests and then compile (NOT WINDOWS) - if: matrix.os != 'windows-latest' - run: ./gradlew test nativeCompile - name: call gradle to run tests and then compile - if: matrix.os != 'ubuntu-latest' run: ./gradlew test nativeCompile - name: upload binary uses: actions/upload-artifact@v4 From 2add54f513a2182b947756befcee584bb6e1c563 Mon Sep 17 00:00:00 2001 From: Jonathan Zollinger Date: Sat, 7 Feb 2026 20:45:02 -0700 Subject: [PATCH 14/16] refactor: remove sonar properties file --- sonar-project.properties | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 sonar-project.properties diff --git a/sonar-project.properties b/sonar-project.properties deleted file mode 100644 index 41a8b35..0000000 --- a/sonar-project.properties +++ /dev/null @@ -1,6 +0,0 @@ -sonar.projectKey=PeanutButter-Unicorn_zcmi -sonar.organization=peanutbutter-unicorn -sonar.sources=src/main/kotlin -sonar.tests=src/test/groovy -sonar.junit.reportPaths=build/reports/jacoco/test/ -sonar.coverage.jacoco.xmlReportPaths=build/reports/jacoco/test/jacocoTestReport.xml From 2dd71c2b958bac0f184634ec11bf7c6cc751328e Mon Sep 17 00:00:00 2001 From: Jonathan Zollinger Date: Sat, 7 Feb 2026 20:58:50 -0700 Subject: [PATCH 15/16] fix: correct err printing to stderr --- src/main/java/lol/pbu/BaseCommand.java | 15 +++------------ src/test/groovy/lol/pbu/ZcmiCommandSpec.groovy | 5 +++-- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/main/java/lol/pbu/BaseCommand.java b/src/main/java/lol/pbu/BaseCommand.java index ed5d029..9da7613 100644 --- a/src/main/java/lol/pbu/BaseCommand.java +++ b/src/main/java/lol/pbu/BaseCommand.java @@ -18,22 +18,13 @@ public class BaseCommand { @ReflectiveAccess protected CommandSpec spec; - - public void out(String message) { - outWriter().ifPresent(writer -> writer.println(AUTO.string(message))); - } - public void err(String message) { - red(String.format("Error: %s", message)); - } - - public void red(String message) { - outWriter().ifPresent(writer -> writer.println(AUTO.string("@|bold,red " + message + "|@"))); + errWriter().ifPresent(writer -> writer.println(AUTO.string("@|bold,red " + message + "|@"))); } @NonNull - public Optional outWriter() { - return getSpec().map(commandSpec -> commandSpec.commandLine().getOut()); + public Optional errWriter() { + return getSpec().map(commandSpec -> commandSpec.commandLine().getErr()); } @NonNull diff --git a/src/test/groovy/lol/pbu/ZcmiCommandSpec.groovy b/src/test/groovy/lol/pbu/ZcmiCommandSpec.groovy index 7d3af9b..b78a63c 100644 --- a/src/test/groovy/lol/pbu/ZcmiCommandSpec.groovy +++ b/src/test/groovy/lol/pbu/ZcmiCommandSpec.groovy @@ -22,11 +22,12 @@ class ZcmiCommandSpec extends ZcmiSpec { void "invoking with no arguments prints error"(ApplicationContext context) { when: - String[] out = executeCommand(context) + def (out, err) = executeCommand(context) then: verifyAll { - out.first().contains("No Command Given") + out.matches(blank) + err.contains("No Command Given") } where: From 0d31b19f435ecb942ccfb73b364ee0aefd5e4953 Mon Sep 17 00:00:00 2001 From: Jonathan Zollinger Date: Sat, 7 Feb 2026 21:30:21 -0700 Subject: [PATCH 16/16] ci: correct coverage inclusions --- src/main/java/lol/pbu/Generated.java | 16 ++++++++++++++++ src/main/java/lol/pbu/ZcmiCommand.java | 1 + 2 files changed, 17 insertions(+) create mode 100644 src/main/java/lol/pbu/Generated.java diff --git a/src/main/java/lol/pbu/Generated.java b/src/main/java/lol/pbu/Generated.java new file mode 100644 index 0000000..bb6f7fe --- /dev/null +++ b/src/main/java/lol/pbu/Generated.java @@ -0,0 +1,16 @@ +package lol.pbu; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.CONSTRUCTOR; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Documented +@Retention(RUNTIME) +@Target({TYPE, METHOD, CONSTRUCTOR}) +public @interface Generated { +} diff --git a/src/main/java/lol/pbu/ZcmiCommand.java b/src/main/java/lol/pbu/ZcmiCommand.java index a9cd0ae..35d2c3f 100644 --- a/src/main/java/lol/pbu/ZcmiCommand.java +++ b/src/main/java/lol/pbu/ZcmiCommand.java @@ -10,6 +10,7 @@ @Command(name = "zcmi", description = "...", versionProvider = ZcmiCommand.ZcmiVersionProvider.class, mixinStandardHelpOptions = true) public class ZcmiCommand extends BaseCommand implements Runnable { + @Generated public static void main(String[] args) { try (AnsiConsole ignored = AnsiConsole.windowsInstall()) { PicocliRunner.run(ZcmiCommand.class, args);