From 5203a0b09d7c67a0ee383607c6062e04fe6fbbad Mon Sep 17 00:00:00 2001 From: Daz DeBoer Date: Sat, 4 Jun 2022 22:53:36 -0600 Subject: [PATCH] Capture build results when config-cache is enabled When enabled, the configuration-cache will cause the build to fail when a `buildFinished` listener is added. Instead, use a BuildService to listen for task failures and to write the results on build completion. --- .github/workflows/demo-job-summary.yml | 4 +- src/cache-base.ts | 1 + ...build-result-capture-service.plugin.groovy | 44 +++++++++++++++++++ .../build-result-capture.init.gradle | 10 ++++- ....groovy => TestBuildResultRecorder.groovy} | 4 +- 5 files changed, 56 insertions(+), 7 deletions(-) create mode 100644 src/resources/build-result-capture-service.plugin.groovy rename test/test-init-scripts/src/test/groovy/com/gradle/gradlebuildaction/{TestBuildResultOutput.groovy => TestBuildResultRecorder.groovy} (97%) diff --git a/.github/workflows/demo-job-summary.yml b/.github/workflows/demo-job-summary.yml index facff59..85dfbf1 100644 --- a/.github/workflows/demo-job-summary.yml +++ b/.github/workflows/demo-job-summary.yml @@ -23,13 +23,13 @@ jobs: - name: Build kotlin-dsl project working-directory: .github/workflow-samples/kotlin-dsl run: ./gradlew assemble - - name: Build kotlin-dsl project + - name: Build kotlin-dsl project without build scan working-directory: .github/workflow-samples/kotlin-dsl run: ./gradlew check --no-scan - name: Build groovy-dsl project working-directory: .github/workflow-samples/groovy-dsl run: ./gradlew assemble - - name: Build kotlin-dsl project again + - name: Build kotlin-dsl project with multiple gradle invocations working-directory: .github/workflow-samples/kotlin-dsl run: | ./gradlew tasks --no-daemon diff --git a/src/cache-base.ts b/src/cache-base.ts index 9c037b8..43ba3a0 100644 --- a/src/cache-base.ts +++ b/src/cache-base.ts @@ -172,6 +172,7 @@ export class GradleStateCache { const initScriptFilenames = [ 'build-result-capture.init.gradle', + 'build-result-capture-service.plugin.groovy', 'project-root-capture.init.gradle', 'project-root-capture.plugin.groovy' ] diff --git a/src/resources/build-result-capture-service.plugin.groovy b/src/resources/build-result-capture-service.plugin.groovy new file mode 100644 index 0000000..2942529 --- /dev/null +++ b/src/resources/build-result-capture-service.plugin.groovy @@ -0,0 +1,44 @@ +import org.gradle.tooling.events.* +import org.gradle.tooling.events.task.* +import org.gradle.util.GradleVersion + +// Can't use settingsEvaluated since this script is applied inside a settingsEvaluated handler +// But projectsEvaluated is good enough, since the build service won't catch configuration failures anyway +projectsEvaluated { + def projectTracker = gradle.sharedServices.registerIfAbsent("gradle-build-action-buildResultsRecorder", BuildResultsRecorder, { spec -> + spec.getParameters().getRootProject().set(gradle.rootProject.name); + spec.getParameters().getRequestedTasks().set(gradle.startParameter.taskNames.join(" ")); + }) + + gradle.services.get(BuildEventsListenerRegistry).onTaskCompletion(projectTracker) +} + +abstract class BuildResultsRecorder implements BuildService, OperationCompletionListener, AutoCloseable { + private boolean buildFailed = false + interface Params extends BuildServiceParameters { + Property getRootProject(); + Property getRequestedTasks(); + } + + public void onFinish(FinishEvent finishEvent) { + if (finishEvent instanceof TaskFinishEvent && finishEvent.result instanceof TaskFailureResult) { + buildFailed = true + } + } + + @Override + public void close() { + def buildResults = [ + rootProject: getParameters().getRootProject().get(), + requestedTasks: getParameters().getRequestedTasks().get(), + gradleVersion: GradleVersion.current().version, + buildFailed: buildFailed, + buildScanUri: null + ] + + def buildResultsDir = new File(System.getenv("RUNNER_TEMP"), ".build-results") + buildResultsDir.mkdirs() + def buildResultsFile = new File(buildResultsDir, System.getenv("GITHUB_ACTION") + System.currentTimeMillis() + ".json") + buildResultsFile << groovy.json.JsonOutput.toJson(buildResults) + } +} \ No newline at end of file diff --git a/src/resources/build-result-capture.init.gradle b/src/resources/build-result-capture.init.gradle index a6ecbb1..7063028 100644 --- a/src/resources/build-result-capture.init.gradle +++ b/src/resources/build-result-capture.init.gradle @@ -12,9 +12,12 @@ if (isTopLevelBuild) { def atLeastGradle6 = version >= GradleVersion.version("6.0") if (atLeastGradle6) { + def useBuildService = version >= GradleVersion.version("6.6") settingsEvaluated { settings -> if (settings.pluginManager.hasPlugin("com.gradle.enterprise")) { captureUsingBuildScanPublished(settings.extensions["gradleEnterprise"].buildScan, settings.rootProject.name) + } else if (useBuildService) { + captureUsingBuildService(settings) } else { captureUsingBuildFinished(gradle) } @@ -30,7 +33,6 @@ if (isTopLevelBuild) { } } - def captureUsingBuildScanPublished(buildScanExtension, rootProjectName) { buildScanExtension.with { def requestedTasks = gradle.startParameter.taskNames.join(" ") @@ -77,4 +79,8 @@ def captureUsingBuildFinished(gradle) { def buildResultsFile = new File(buildResultsDir, System.getenv("GITHUB_ACTION") + System.currentTimeMillis() + ".json") buildResultsFile << groovy.json.JsonOutput.toJson(buildResults) } -} \ No newline at end of file +} + +def captureUsingBuildService(settings) { + apply from: 'build-result-capture-service.plugin.groovy' +} diff --git a/test/test-init-scripts/src/test/groovy/com/gradle/gradlebuildaction/TestBuildResultOutput.groovy b/test/test-init-scripts/src/test/groovy/com/gradle/gradlebuildaction/TestBuildResultRecorder.groovy similarity index 97% rename from test/test-init-scripts/src/test/groovy/com/gradle/gradlebuildaction/TestBuildResultOutput.groovy rename to test/test-init-scripts/src/test/groovy/com/gradle/gradlebuildaction/TestBuildResultRecorder.groovy index eab1703..cadec01 100644 --- a/test/test-init-scripts/src/test/groovy/com/gradle/gradlebuildaction/TestBuildResultOutput.groovy +++ b/test/test-init-scripts/src/test/groovy/com/gradle/gradlebuildaction/TestBuildResultRecorder.groovy @@ -1,11 +1,10 @@ package com.gradle.gradlebuildaction import groovy.json.JsonSlurper -import spock.lang.Ignore import static org.junit.Assume.assumeTrue -class TestBuildResultOutput extends BaseInitScriptTest { +class TestBuildResultRecorder extends BaseInitScriptTest { def initScript = 'build-result-capture.init.gradle' def "produces build results file for build with #testGradleVersion"() { @@ -35,7 +34,6 @@ class TestBuildResultOutput extends BaseInitScriptTest { testGradleVersion << ALL_VERSIONS } - @Ignore def "produces build results file for build with --configuration-cache on #testGradleVersion"() { assumeTrue testGradleVersion.compatibleWithCurrentJvm