nemerosa/versioning

Support Gradle configuration cache

Opened this issue · 7 comments

$ mkdir /tmp/test && cd "$_"
$ gradle init --type java-library --java-version 21 --project-name test --dsl groovy --test-framework junit-jupiter --no-comments --no-incubating --quiet
$ perl -i -l -p -e "print \"    id 'net.nemerosa.versioning' version '2.8.2'\" if $. == 4" lib/build.gradle
$ printf '\nversioning {}\nversion = versioning.info.full\n' >> lib/build.gradle
$ git init --quiet
$ git add -A
$ git commit --quiet -m "initial"
$ ./gradlew --configuration-cache --quiet clean

FAILURE: Build failed with an exception.

* Where:
Build file '/private/tmp/test/lib/build.gradle' line: 32

* What went wrong:
Configuration cache problems found in this build.

2 problems were found storing the configuration cache.
- Build file 'lib/build.gradle': external process started 'git --version'
  See https://docs.gradle.org/8.7/userguide/configuration_cache.html#config_cache:requirements:external_processes
- Build file 'lib/build.gradle': external process started 'git config --system --edit'
  See https://docs.gradle.org/8.7/userguide/configuration_cache.html#config_cache:requirements:external_processes

See the complete report at file:///private/tmp/test/build/reports/configuration-cache/2cvh062oate61b7yhx8pzmmbf/3h3vaqnt0bpkufj7xky7uxoi0/configuration-cache-report.html
> Starting an external process 'git --version' during configuration time is unsupported.
> Starting an external process 'git config --system --edit' during configuration time is unsupported.

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
> Get more help at https://help.gradle.org.

BUILD FAILED in 2s
$ gradle --version

------------------------------------------------------------
Gradle 8.7
------------------------------------------------------------

Build time:   2024-03-22 15:52:46 UTC
Revision:     650af14d7653aa949fce5e886e685efc9cf97c10

Kotlin:       1.9.22
Groovy:       3.0.17
Ant:          Apache Ant(TM) version 1.10.13 compiled on January 4 2023
JVM:          21.0.2 (Eclipse Adoptium 21.0.2+13-LTS)
OS:           Mac OS X 12.7.4 x86_64
$ cat lib/build.gradle

plugins {
    id 'java-library'
    id 'net.nemerosa.versioning' version '2.8.2'
}

repositories {
    mavenCentral()
}

dependencies {
    testImplementation libs.junit.jupiter

    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

    api libs.commons.math3

    implementation libs.guava
}

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(21)
    }
}

tasks.named('test') {
    useJUnitPlatform()
}

versioning {}
version = versioning.info.full

configuration-cache-report.html

	at net.nemerosa.versioning.git.GitInfoService.getInfo(GitInfoService.groovy:37)
	at net.nemerosa.versioning.SCMInfoService$getInfo.call(Unknown Source)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:148)(3 internal lines hidden)
	at net.nemerosa.versioning.VersioningExtension.computeInfo(VersioningExtension.groovy:195)
	at net.nemerosa.versioning.VersioningExtension.getInfo(VersioningExtension.groovy:182)
	at net.nemerosa.versioning.VersioningExtension_Decorated.getInfo(Unknown Source)

https://docs.gradle.org/8.7/userguide/configuration_cache.html#config_cache:requirements:external_processes

Interim solution?

It is possible to declare that a particular task is not compatible with the configuration cache via the Task.notCompatibleWithConfigurationCache() method.

Configuration cache problems found in tasks marked incompatible will no longer cause the build to fail.

https://docs.gradle.org/current/userguide/configuration_cache.html#config_cache:task_opt_out

Hi,

I see in the first snippet that you're using the version 2.8.2? Is that possible to try with version 3.1.0.

As for the cache configuration issue, I don't know how the call to the external command (git) could be cached and if it even makes sense. So I agree with you that the least bad approach would maybe to mark it as not compatible with the cache.

What do you think?

$ mkdir /tmp/test && cd "$_"
$ gradle init --type java-library --java-version 21 --project-name test --dsl groovy --test-framework junit-jupiter --no-comments --no-incubating --quiet
$ perl -i -l -p -e "print \"    id 'net.nemerosa.versioning' version '3.1.0'\" if $. == 4" lib/build.gradle
$ printf '\nversioning {}\nversion = versioning.info.full\n' >> lib/build.gradle
$ git init --quiet
$ git add -A
$ git commit --quiet -m "initial"
$ ./gradlew --configuration-cache --quiet clean

FAILURE: Build failed with an exception.

* Where:
Build file '/private/tmp/test/lib/build.gradle' line: 32

* What went wrong:
Configuration cache problems found in this build.

2 problems were found storing the configuration cache.
- Build file 'lib/build.gradle': external process started '/usr/local/bin/git --version'
  See https://docs.gradle.org/8.7/userguide/configuration_cache.html#config_cache:requirements:external_processes
- Build file 'lib/build.gradle': external process started '/usr/local/bin/git config --system --show-origin --list -z'
  See https://docs.gradle.org/8.7/userguide/configuration_cache.html#config_cache:requirements:external_processes

See the complete report at file:///private/tmp/test/build/reports/configuration-cache/2cvh062oate61b7yhx8pzmmbf/ebyxie6m7vpbm2q7bw5v4bf88/configuration-cache-report.html
> Starting an external process '/usr/local/bin/git --version' during configuration time is unsupported.
> Starting an external process '/usr/local/bin/git config --system --show-origin --list -z' during configuration time is unsupported.

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
> Get more help at https://help.gradle.org.

BUILD FAILED in 5s

The example provided by the Gradle team wraps the git call inside providers.exec:

def gitVersion = providers.exec {
    commandLine("git", "--version")
}.standardOutput.asText.get()

Maybe calls to SCMInfoService should be wrapped in providers.exec or calls to Grgit and SVNClientManager should be wrapped.

There is Gradle Roadmap item this issue might be added to ...

https://blog.gradle.org/road-to-gradle-9#configuration-cache-improvements

In Gradle 9.0, the Configuration Cache will be the preferred mode of execution, and turning it off will be deprecated.

Here is what another project using Grgit did:

n0mer/gradle-git-properties#164

I was able to work around this by wrapping my calls to versioning.info in a provider:

val provider = project.provider {
    // Intentionally skip cache (not sure if necessary though)
    val info = versioning.computeInfo()
    runCatching { info.tag ?: info.full }.getOrDefault("0.0.0")
}

project.version = provider.get()