/*
 * Capture information for each executed Gradle build to display in the job summary.
 */
import org.gradle.util.GradleVersion

// Only run against root build. Do not run against included builds.
def isTopLevelBuild = gradle.getParent() == null
if (isTopLevelBuild) {
    def version = GradleVersion.current().baseVersion

    def atLeastGradle3 = version >= GradleVersion.version("3.0")
    def atLeastGradle6 = version >= GradleVersion.version("6.0")

    def invocationId = "-${System.currentTimeMillis()}"

    if (atLeastGradle6) {
        def useBuildService = version >= GradleVersion.version("6.6")
        settingsEvaluated { settings ->
            // The `buildScanPublished` hook is the only way to capture the build scan URI.
            if (settings.pluginManager.hasPlugin("com.gradle.enterprise")) {
                captureUsingBuildScanPublished(settings.extensions["gradleEnterprise"].buildScan, settings.rootProject, invocationId)
            }
            // We also need to add hooks in case the plugin is applied but no build scan is published
            if (useBuildService) {
                captureUsingBuildService(settings, invocationId)
            } else {
                captureUsingBuildFinished(gradle, invocationId)
            }
        }
    } else if (atLeastGradle3) {
        projectsEvaluated { gradle ->
            if (gradle.rootProject.pluginManager.hasPlugin("com.gradle.build-scan")) {
                captureUsingBuildScanPublished(gradle.rootProject.extensions["buildScan"], gradle.rootProject, invocationId)
            }
            // We  need to capture in buildFinished in case the plugin is applied but no build scan is published
            captureUsingBuildFinished(gradle, invocationId)
        }
    }
}

def captureUsingBuildScanPublished(buildScanExtension, rootProject, invocationId) {
    buildScanExtension.with {
        def buildResults = new BuildResults(invocationId, gradle, rootProject)

        buildFinished { result ->
            buildResults.setBuildResult(result)
        }

        buildScanPublished { buildScan ->
            buildResults.setBuildScanUri(buildScan.buildScanUri.toASCIIString())
            buildResults.writeToResultsFile(true)

            println("::set-output name=build-scan-url::${buildScan.buildScanUri}")
        }

        onError { error ->
            buildResults.setBuildScanFailed()
            buildResults.writeToResultsFile(true)
        }
    }
}

def captureUsingBuildFinished(gradle, invocationId) {
    gradle.buildFinished { result ->
        def buildResults = new BuildResults(invocationId, gradle, gradle.rootProject)
        buildResults.setBuildResult(result)

        buildResults.writeToResultsFile(false)

    }
}

def captureUsingBuildService(settings, invocationId) {
    gradle.ext.invocationId = invocationId
    apply from: '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) {
        buildResults['buildFailed'] = result.failure != null
    }

    def setBuildScanUri(def buildScanUrl) {
        buildResults['buildScanUri'] = buildScanUrl
    }

    def setBuildScanFailed() {
        buildResults['buildScanFailed'] = true
    }

    def writeToResultsFile(boolean overwrite) {
        def buildResultsDir = new File(System.getenv("RUNNER_TEMP"), ".build-results")
        buildResultsDir.mkdirs()
        def buildResultsFile = new File(buildResultsDir, System.getenv("GITHUB_ACTION") + 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)
        }
    }
}
