From d083d4e12729850529a6ff42896eabc54e5d3531 Mon Sep 17 00:00:00 2001 From: Steve Ramage Date: Sat, 20 Jun 2026 08:30:46 -0700 Subject: [PATCH 1/3] ci: bake a usable dependency cache into the build-environment image Pin GRADLE_USER_HOME to /home/builduser/.gradle so the dependency cache warmed at image-build time - including the ~1 GiB IntelliJ Platform SDK - is reused at runtime instead of being re-downloaded on every CI build. The build scan showed the IDE re-downloaded every run because the runtime GRADLE_USER_HOME did not match where the image warm-up had written it. This stays hermetic: each pod gets its own copy-on-write view of the baked cache from the immutable image, distributed via the registry, with no shared mutable host state. A stale baked cache simply falls back to downloading, so it is never incorrect. Also warm compileTestKotlin so the test-framework dependencies are baked too, and bump the base image to Ubuntu 24.04 - removing the default 'ubuntu' user that now occupies UID 1000 so builduser can keep it. Refs #461 Co-Authored-By: Claude Opus 4.8 (1M context) --- ci/Build-Environment.Dockerfile | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/ci/Build-Environment.Dockerfile b/ci/Build-Environment.Dockerfile index b5e12f80..73745da1 100644 --- a/ci/Build-Environment.Dockerfile +++ b/ci/Build-Environment.Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 RUN apt-get update @@ -6,15 +6,27 @@ RUN apt-get install -y git openjdk-21-jdk-headless WORKDIR /tmp +# Ubuntu 24.04 ships a default 'ubuntu' user occupying UID 1000, which collides with the +# builduser we create below. Remove it so builduser can keep UID 1000 (matching the pod's +# runAsUser: 1000). +RUN userdel -r ubuntu || true + RUN useradd -m builduser -u 1000 +# Pin GRADLE_USER_HOME to a path baked into the image rather than letting it default to a +# location under the ephemeral CI workspace. This ensures the dependency cache warmed below +# (including the ~1 GiB IntelliJ Platform SDK) is actually reused at runtime instead of being +# re-downloaded on every build. It stays hermetic: each pod gets its own copy-on-write view +# of this directory from the immutable image, with no shared mutable host state. +ENV GRADLE_USER_HOME=/home/builduser/.gradle + USER 1000 ARG BRANCH=242.x RUN git clone --depth 1 -b ${BRANCH} https://github.com/SJrX/systemdUnitFilePlugin.git && \ cd /tmp/systemdUnitFilePlugin && \ - /tmp/systemdUnitFilePlugin/gradlew --no-daemon --build-cache dependencies compileKotlin && \ + /tmp/systemdUnitFilePlugin/gradlew --no-daemon --build-cache dependencies compileKotlin compileTestKotlin && \ rm -rf /tmp/systemdUnitFilePlugin/ -WORKDIR / +WORKDIR / \ No newline at end of file From dfd1adc3d9428b17a1df61d06451b543cda77728 Mon Sep 17 00:00:00 2001 From: Steve Ramage Date: Sat, 20 Jun 2026 08:30:46 -0700 Subject: [PATCH 2/3] build: stop accessing Task.project at execution time Two task actions resolved paths through Project at execution time, which Gradle has deprecated and which blocks the configuration cache: - mergePodmanDocumentation called file() inside its doLast; hoist the undocumentedJsonFile path to configuration time. - GenerateDataFromManPages read project.layout.buildDirectory in its action; inject it via a new renderedXIncludesDir property set when the task is registered. Refs #461 Co-Authored-By: Claude Opus 4.8 (1M context) --- build.gradle.kts | 3 ++- buildSrc/src/main/groovy/GenerateDataFromManPages.groovy | 9 ++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index ede7420d..b43f36cf 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -163,6 +163,7 @@ tasks.register("generateDataFromManPages") { systemdSourceCodeRoot = file("./systemd-build/build/") generatedJsonFileLocation = file(sourceSets["main"].output.resourcesDir?.getAbsolutePath() + "/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata") + renderedXIncludesDir = project.layout.buildDirectory.dir("tmp/rendered-xincludes").get().asFile } /* * Lexing / Parsing and Grammar Tasks @@ -226,6 +227,7 @@ tasks.register("mergePodmanDocumentation") { val semanticDataDir = file("${sourceSets["main"].output.resourcesDir?.getAbsolutePath()}/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata") val podmanJsonFile = file("./src/main/resources/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/podman/podman-sectionToKeywordMapFromDoc.json") val targetJsonFile = file("${semanticDataDir}/sectionToKeywordMapFromDoc.json") + val undocumentedJsonFile = file("${semanticDataDir}/undocumentedSectionToKeywordMap.json") inputs.file(podmanJsonFile) @@ -261,7 +263,6 @@ tasks.register("mergePodmanDocumentation") { targetJsonFile.writeText(output) // Merge undocumented keywords (deprecated/moved options) - val undocumentedJsonFile = file("${semanticDataDir}/undocumentedSectionToKeywordMap.json") @Suppress("UNCHECKED_CAST") val undocData = slurper.parse(undocumentedJsonFile) as MutableMap @Suppress("UNCHECKED_CAST") diff --git a/buildSrc/src/main/groovy/GenerateDataFromManPages.groovy b/buildSrc/src/main/groovy/GenerateDataFromManPages.groovy index af78b0c7..e10e86a3 100644 --- a/buildSrc/src/main/groovy/GenerateDataFromManPages.groovy +++ b/buildSrc/src/main/groovy/GenerateDataFromManPages.groovy @@ -56,6 +56,13 @@ class GenerateDataFromManPages extends DefaultTask { @OutputDirectory File generatedJsonFileLocation + /** + * Scratch directory for XInclude-rendered XML. Supplied at configuration time so the task + * does not access Task.project at execution time (deprecated and configuration-cache hostile). + */ + @Internal + File renderedXIncludesDir + /** * Map that stores for each file name, the name of an option attribute */ @@ -455,7 +462,7 @@ class GenerateDataFromManPages extends DefaultTask { xmlContent = processXIncludesWithRegex(xmlContent, sourceFile.parentFile) - File outputDir = project.layout.buildDirectory.dir("tmp/rendered-xincludes").get().asFile + File outputDir = renderedXIncludesDir if (!outputDir.exists()) { outputDir.mkdirs() } From f6d58bea862b323719e97014090f6558302a4664 Mon Sep 17 00:00:00 2001 From: Steve Ramage Date: Sat, 20 Jun 2026 08:41:19 -0700 Subject: [PATCH 3/3] ci: drop compileTestKotlin from build-environment warm-up Warming compileTestKotlin pulled the docker-compose metadata task (composeBuild) into the task graph, which fails during the kaniko image build because no Docker daemon is available: Task :composeBuild FAILED > A problem occurred starting process 'command 'docker'' The IntelliJ Platform SDK (the ~1 GiB cache we actually want baked) is already pulled by compileKotlin, so revert to the proven 'dependencies compileKotlin' warm-up. Refs #461 Co-Authored-By: Claude Opus 4.8 (1M context) --- ci/Build-Environment.Dockerfile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ci/Build-Environment.Dockerfile b/ci/Build-Environment.Dockerfile index 73745da1..1dc9265c 100644 --- a/ci/Build-Environment.Dockerfile +++ b/ci/Build-Environment.Dockerfile @@ -24,9 +24,13 @@ USER 1000 ARG BRANCH=242.x +# Warm the dependency cache. 'dependencies' resolves every configuration and 'compileKotlin' +# pulls the IntelliJ Platform SDK onto the compile classpath, so the ~1 GiB SDK gets baked in. +# Do NOT add compileTestKotlin here: it drags the docker-compose metadata task (composeBuild) +# into the graph, which needs a Docker daemon that isn't available during the image build. RUN git clone --depth 1 -b ${BRANCH} https://github.com/SJrX/systemdUnitFilePlugin.git && \ cd /tmp/systemdUnitFilePlugin && \ - /tmp/systemdUnitFilePlugin/gradlew --no-daemon --build-cache dependencies compileKotlin compileTestKotlin && \ + /tmp/systemdUnitFilePlugin/gradlew --no-daemon --build-cache dependencies compileKotlin && \ rm -rf /tmp/systemdUnitFilePlugin/ WORKDIR / \ No newline at end of file