diff --git a/sources/src/resources/init-scripts/gradle-actions.build-result-capture-service.plugin.groovy b/sources/src/resources/init-scripts/gradle-actions.build-result-capture-service.plugin.groovy index 6ea2c5a..7f6d9da 100644 --- a/sources/src/resources/init-scripts/gradle-actions.build-result-capture-service.plugin.groovy +++ b/sources/src/resources/init-scripts/gradle-actions.build-result-capture-service.plugin.groovy @@ -38,9 +38,7 @@ abstract class BuildResultsRecorder implements BuildService= GradleVersion.version("3.0") @@ -26,7 +27,7 @@ if (isTopLevelBuild) { if (useBuildService) { captureUsingBuildService(invocationId) } else { - captureUsingBuildFinished(gradle, invocationId) + captureUsingBuildFinished(gradle, invocationId, resultsWriter) } // Use the Develocity plugin to also capture build scan links, when available @@ -34,46 +35,63 @@ if (isTopLevelBuild) { settings.pluginManager.withPlugin(GE_PLUGIN_ID) { // Only execute if develocity plugin isn't applied. if (!settings.extensions.findByName(DEVELOCITY_EXTENSION)) { - captureUsingBuildScanPublished(settings.extensions[GE_EXTENSION].buildScan, settings.rootProject, invocationId) + captureUsingBuildScanPublished(settings.extensions[GE_EXTENSION].buildScan, invocationId, resultsWriter) } } settings.pluginManager.withPlugin(DEVELOCITY_PLUGIN_ID) { - captureUsingBuildScanPublished(settings.extensions[DEVELOCITY_EXTENSION].buildScan, settings.rootProject, invocationId) + captureUsingBuildScanPublished(settings.extensions[DEVELOCITY_EXTENSION].buildScan, invocationId, resultsWriter) } } } else if (atLeastGradle3) { projectsEvaluated { gradle -> // By default, use 'buildFinished' to capture build results - captureUsingBuildFinished(gradle, invocationId) + captureUsingBuildFinished(gradle, invocationId, resultsWriter) gradle.rootProject.pluginManager.withPlugin(BUILD_SCAN_PLUGIN_ID) { // Only execute if develocity plugin isn't applied. if (!gradle.rootProject.extensions.findByName(DEVELOCITY_EXTENSION)) { - captureUsingBuildScanPublished(gradle.rootProject.extensions[BUILD_SCAN_EXTENSION], gradle.rootProject, invocationId) + captureUsingBuildScanPublished(gradle.rootProject.extensions[BUILD_SCAN_EXTENSION], invocationId, resultsWriter) } } gradle.rootProject.pluginManager.withPlugin(DEVELOCITY_PLUGIN_ID) { - captureUsingBuildScanPublished(gradle.rootProject.extensions[DEVELOCITY_EXTENSION].buildScan, gradle.rootProject, invocationId) + captureUsingBuildScanPublished(gradle.rootProject.extensions[DEVELOCITY_EXTENSION].buildScan, invocationId, resultsWriter) } } } } +def captureUsingBuildService(invocationId) { + gradle.ext.invocationId = invocationId + apply from: 'gradle-actions.build-result-capture-service.plugin.groovy' +} + +void captureUsingBuildFinished(gradle, String invocationId, ResultsWriter resultsWriter) { + gradle.buildFinished { result -> + println "Got buildFinished: ${result}" + def buildResults = [ + rootProjectName: rootProject.name, + rootProjectDir: rootProject.projectDir.absolutePath, + requestedTasks: gradle.startParameter.taskNames.join(" "), + gradleVersion: GradleVersion.current().version, + gradleHomeDir: gradle.gradleHomeDir.absolutePath, + buildFailed: result.failure != null + ] + resultsWriter.writeToResultsFile("build-results", invocationId, buildResults) + } +} + // The `buildScanPublished` hook allows the capture of the Build Scan URI. // Results captured this way will overwrite any results from 'buildFinished'. -def captureUsingBuildScanPublished(buildScanExtension, rootProject, invocationId) { +void captureUsingBuildScanPublished(buildScanExtension, String invocationId, ResultsWriter resultsWriter) { buildScanExtension.with { - def buildResults = new BuildResults(invocationId, gradle, rootProject) - - buildFinished { result -> - buildResults.setBuildResult(result) - } - buildScanPublished { buildScan -> - buildResults.setBuildScanUri(buildScan.buildScanUri.toASCIIString()) - buildResults.writeToResultsFile(true) + def scanResults = [ + buildScanUri: buildScan.buildScanUri.toASCIIString(), + buildScanFailed: false + ] + resultsWriter.writeToResultsFile("build-scans", invocationId, scanResults) def githubOutput = System.getenv("GITHUB_OUTPUT") if (githubOutput) { @@ -85,63 +103,17 @@ def captureUsingBuildScanPublished(buildScanExtension, rootProject, invocationId } onError { error -> - buildResults.setBuildScanFailed() - buildResults.writeToResultsFile(true) + def scanResults = [ + buildScanUri: null, + buildScanFailed: true + ] + resultsWriter.writeToResultsFile("build-scans", invocationId, scanResults) } } } -def captureUsingBuildFinished(gradle, invocationId) { - gradle.buildFinished { result -> - println "Got buildFinished: ${result}" - def buildResults = new BuildResults(invocationId, gradle, gradle.rootProject) - buildResults.setBuildResult(result) - buildResults.writeToResultsFile(false) - } -} - -def captureUsingBuildService(invocationId) { - gradle.ext.invocationId = invocationId - apply from: 'gradle-actions.build-result-capture-service.plugin.groovy' -} - -class BuildResults { - def invocationId - def buildResults - - BuildResults(String invocationId, def gradle, def rootProject) { - this.invocationId = invocationId - buildResults = [ - rootProjectName: rootProject.name, - rootProjectDir: rootProject.projectDir.absolutePath, - requestedTasks: gradle.startParameter.taskNames.join(" "), - gradleVersion: GradleVersion.current().version, - gradleHomeDir: gradle.gradleHomeDir.absolutePath, - buildFailed: false, - buildScanUri: null, - buildScanFailed: false - ] - } - - def setBuildResult(def result) { - try { - // Gradle and old Build Scan/Gradle Enterprise plugins report a single optional failure in the build result - buildResults['buildFailed'] = result.failure != null - } catch (Exception e) { - // Develocity plugin unwraps all build failures and reports them as a mandatory array - buildResults['buildFailed'] = !result.failures.empty - } - } - - def setBuildScanUri(def buildScanUrl) { - buildResults['buildScanUri'] = buildScanUrl - } - - def setBuildScanFailed() { - buildResults['buildScanFailed'] = true - } - - def writeToResultsFile(boolean overwrite) { +class ResultsWriter { + void writeToResultsFile(String subDir, String invocationId, def content) { def runnerTempDir = System.getProperty("RUNNER_TEMP") ?: System.getenv("RUNNER_TEMP") def githubActionStep = System.getProperty("GITHUB_ACTION") ?: System.getenv("GITHUB_ACTION") if (!runnerTempDir || !githubActionStep) { @@ -149,19 +121,12 @@ class BuildResults { } try { - def buildResultsDir = new File(runnerTempDir, ".build-results") + def buildResultsDir = new File(runnerTempDir, ".gradle-actions/${subDir}") buildResultsDir.mkdirs() def buildResultsFile = new File(buildResultsDir, githubActionStep + invocationId + ".json") - - // Overwrite any contents written by buildFinished or build service, since this result is a superset. - if (buildResultsFile.exists()) { - if (overwrite) { - buildResultsFile.text = groovy.json.JsonOutput.toJson(buildResults) - } - } else { - buildResultsFile << groovy.json.JsonOutput.toJson(buildResults) + if (!buildResultsFile.exists()) { + buildResultsFile << groovy.json.JsonOutput.toJson(content) } - } catch (Exception e) { println "\ngradle action failed to write build-results file. Will continue.\n> ${e.getLocalizedMessage()}" } diff --git a/sources/test/init-scripts/src/test/groovy/com/gradle/gradlebuildaction/TestBuildResultRecorder.groovy b/sources/test/init-scripts/src/test/groovy/com/gradle/gradlebuildaction/TestBuildResultRecorder.groovy index a73ad4d..a8f163f 100644 --- a/sources/test/init-scripts/src/test/groovy/com/gradle/gradlebuildaction/TestBuildResultRecorder.groovy +++ b/sources/test/init-scripts/src/test/groovy/com/gradle/gradlebuildaction/TestBuildResultRecorder.groovy @@ -122,6 +122,7 @@ class TestBuildResultRecorder extends BaseInitScriptTest { then: assertResults('help', testGradleVersion, false, true) assert buildResultFile.delete() + assert scanResultFile.delete() when: run(['help', '--configuration-cache'], testGradleVersion.gradleVersion) @@ -240,12 +241,16 @@ class TestBuildResultRecorder extends BaseInitScriptTest { assert results['gradleVersion'] == testGradleVersion.gradleVersion.version assert results['gradleHomeDir'] != null assert results['buildFailed'] == hasFailure - assert results['buildScanUri'] == (hasBuildScan ? "${mockScansServer.address}s/${PUBLIC_BUILD_SCAN_ID}" : null) - assert results['buildScanFailed'] == scanUploadFailed + + if (hasBuildScan || scanUploadFailed) { + def scanResults = new JsonSlurper().parse(scanResultFile) + assert scanResults['buildScanUri'] == (hasBuildScan ? "${mockScansServer.address}s/${PUBLIC_BUILD_SCAN_ID}" : null) + assert scanResults['buildScanFailed'] == scanUploadFailed + } } private File getBuildResultFile() { - def buildResultsDir = new File(testProjectDir, '.build-results') + def buildResultsDir = new File(testProjectDir, '.gradle-actions/build-results') assert buildResultsDir.directory assert buildResultsDir.listFiles().size() == 1 def resultsFile = buildResultsDir.listFiles()[0] @@ -253,4 +258,14 @@ class TestBuildResultRecorder extends BaseInitScriptTest { assert resultsFile.text.count('rootProjectName') == 1 return resultsFile } + + private File getScanResultFile() { + def buildResultsDir = new File(testProjectDir, '.gradle-actions/build-scans') + assert buildResultsDir.directory + assert buildResultsDir.listFiles().size() == 1 + def resultsFile = buildResultsDir.listFiles()[0] + assert resultsFile.name.startsWith('github-step-id') + assert resultsFile.text.count('buildScanUri') == 1 + return resultsFile + } }