diff --git a/components/scripts/gradle/gradle-init-scripts/capture-published-build-scan.gradle b/components/scripts/gradle/gradle-init-scripts/capture-published-build-scan.gradle deleted file mode 100644 index e2cfe835..00000000 --- a/components/scripts/gradle/gradle-init-scripts/capture-published-build-scan.gradle +++ /dev/null @@ -1,51 +0,0 @@ -import org.gradle.util.GradleVersion - -// Don't run against the included builds (if the main build has any). -def isTopLevelBuild = gradle.getParent() == null -if (isTopLevelBuild) { - def version = GradleVersion.current().baseVersion - def atLeastGradle5 = version >= GradleVersion.version("5.0") - def atLeastGradle6 = version >= GradleVersion.version("6.0") - - if (atLeastGradle6) { - settingsEvaluated { settings -> - if (!settings.pluginManager.hasPlugin("com.gradle.enterprise")) { - throw new IllegalStateException("The com.gradle.enterprise plugin is missing from the project (see https://docs.gradle.com/enterprise/gradle-plugin/#gradle_6_x_and_later).") - } - registerCallbacks(settings.extensions["gradleEnterprise"]) - } - } else if (atLeastGradle5) { - projectsEvaluated { gradle -> - if (!gradle.rootProject.pluginManager.hasPlugin("com.gradle.build-scan")) { - throw new IllegalStateException("The com.gradle.build-scan plugin is missing from the project (see https://docs.gradle.com/enterprise/gradle-plugin/#gradle_5_x).") - } - registerCallbacks(gradle.rootProject.extensions["gradleEnterprise"]) - } - } else { - throw new IllegalStateException("Build validation not supported for Gradle ${GradleVersion.current()}. Upgrade your project's build to Gradle 5 or newer.") - } -} - -void registerCallbacks(gradleEnterprise) { - gradleEnterprise.with { - buildScan { - def scanFile = new File(experimentDir, "build-scans.csv") - buildScanPublished { buildScan -> - def buildScanUri = buildScan.buildScanUri - def buildScanId = buildScan.buildScanId - def port = (buildScanUri.port != -1) ? ":" + buildScanUri.port : "" - def baseUrl = "${buildScanUri.scheme}://${buildScanUri.host}${port}" - scanFile.append("${baseUrl},${buildScanUri},${buildScanId}\n") - } - def errorFile = new File(experimentDir, "build-scan-publish-error.txt") - onError { error -> - errorFile.text = error - } - } - } -} - -File getExperimentDir() { - def projectProperties = gradle.startParameter.projectProperties - new File(projectProperties.get("com.gradle.enterprise.build_validation.experimentDir")) -} diff --git a/components/scripts/gradle/gradle-init-scripts/configure-gradle-enterprise.gradle b/components/scripts/gradle/gradle-init-scripts/configure-gradle-enterprise.gradle index 6b44b72f..0e197b53 100644 --- a/components/scripts/gradle/gradle-init-scripts/configure-gradle-enterprise.gradle +++ b/components/scripts/gradle/gradle-init-scripts/configure-gradle-enterprise.gradle @@ -1,101 +1,237 @@ import org.gradle.util.GradleVersion -import java.nio.charset.StandardCharsets; +import java.nio.charset.StandardCharsets +// note that there is no mechanism to share code between the initscript{} block and the main script, so some logic is duplicated + +// conditionally apply the GE / Build Scan plugin to the classpath so it can be applied to the build further down in this script initscript { - def gradleEnterprisePluginVersion = "3.12.4" + def isTopLevelBuild = !gradle.parent + if (!isTopLevelBuild) { + return + } - repositories { - gradlePluginPortal() + def getInputParam = { String name -> + def envVarName = name.toUpperCase().replace('.', '_').replace('-', '_') + return System.getProperty(name) ?: System.getenv(envVarName) + } + + def pluginRepositoryUrl = getInputParam('com.gradle.enterprise.build_validation.gradle.plugin-repository.url') + def gePluginVersion = getInputParam('com.gradle.enterprise.build_validation.gradle-enterprise.plugin.version') + def ccudPluginVersion = getInputParam('com.gradle.enterprise.build_validation.ccud.plugin.version') + + def atLeastGradle5 = GradleVersion.current() >= GradleVersion.version('5.0') + def atLeastGradle4 = GradleVersion.current() >= GradleVersion.version('4.0') + + if (gePluginVersion || ccudPluginVersion && atLeastGradle4) { + pluginRepositoryUrl = pluginRepositoryUrl ?: 'https://plugins.gradle.org/m2' + logger.quiet("Gradle Enterprise plugins resolution: $pluginRepositoryUrl") + + repositories { + maven { url pluginRepositoryUrl } + } } dependencies { - classpath("com.gradle:gradle-enterprise-gradle-plugin:${gradleEnterprisePluginVersion}") + if (gePluginVersion) { + classpath atLeastGradle5 ? + "com.gradle:gradle-enterprise-gradle-plugin:$gePluginVersion" : + "com.gradle:build-scan-plugin:1.16" + } + + if (ccudPluginVersion && atLeastGradle4) { + classpath "com.gradle:common-custom-user-data-gradle-plugin:$ccudPluginVersion" + } } } -// Don't run against the included builds (if the main build has any). -def isTopLevelBuild = gradle.getParent() == null -if (isTopLevelBuild) { - def version = GradleVersion.current().baseVersion - def atLeastGradle5 = version >= GradleVersion.version("5.0") - def atLeastGradle6 = version >= GradleVersion.version("6.0") - def isScanDump = System.properties.containsKey("scan.dump") +def BUILD_SCAN_PLUGIN_ID = 'com.gradle.build-scan' +def BUILD_SCAN_PLUGIN_CLASS = 'com.gradle.scan.plugin.BuildScanPlugin' + +def GRADLE_ENTERPRISE_PLUGIN_ID = 'com.gradle.enterprise' +def GRADLE_ENTERPRISE_PLUGIN_CLASS = 'com.gradle.enterprise.gradleplugin.GradleEnterprisePlugin' +def GRADLE_ENTERPRISE_EXTENSION_CLASS = 'com.gradle.enterprise.gradleplugin.GradleEnterpriseExtension' + +def CCUD_PLUGIN_ID = 'com.gradle.common-custom-user-data-gradle-plugin' +def CCUD_PLUGIN_CLASS = 'com.gradle.CommonCustomUserDataGradlePlugin' + +def isTopLevelBuild = !gradle.parent +if (!isTopLevelBuild) { + return +} + +def getInputParam = { String name -> + def envVarName = name.toUpperCase().replace('.', '_').replace('-', '_') + return System.getProperty(name) ?: System.getenv(envVarName) +} + +def geUrl = getInputParam('com.gradle.enterprise.build_validation.gradle-enterprise.url') +def geAllowUntrustedServer = Boolean.parseBoolean(getInputParam('com.gradle.enterprise.build_validation.gradle-enterprise.allow-untrusted-server')) +def gePluginVersion = getInputParam('com.gradle.enterprise.build_validation.gradle-enterprise.plugin.version') +def ccudPluginVersion = getInputParam('com.gradle.enterprise.build_validation.ccud.plugin.version') + +def atLeastGradle4 = GradleVersion.current() >= GradleVersion.version('4.0') + +// finish early if configuration parameters passed in via system properties are not valid/supported +if (ccudPluginVersion && isNotAtLeast(ccudPluginVersion, '1.7')) { + logger.warn("Common Custom User Data Gradle plugin must be at least 1.7. Configured version is $ccudPluginVersion.") + return +} + +// register build scan listeners to capture build scan URL/id and to track publishing errors +def registerBuildScanActions = { def buildScan -> + def scanFile = new File(experimentDir, 'build-scans.csv') + buildScan.buildScanPublished { publishedBuildScan -> + def buildScanUri = publishedBuildScan.buildScanUri + def buildScanId = publishedBuildScan.buildScanId + def port = (buildScanUri.port != -1) ? ':' + buildScanUri.port : '' + def baseUrl = "${buildScanUri.scheme}://${buildScanUri.host}${port}" + scanFile.append("${baseUrl},${buildScanUri},${buildScanId}\n") + } + + def errorFile = new File(experimentDir, 'build-scan-publish-error.txt') + buildScan.onError { error -> + errorFile.text = error + } +} + +// configure build scan publishing behavior +def configureBuildScanPublishing = { def buildScan -> + buildScan.publishAlways() + // buildScan.captureTaskInputFiles = true // too late to be set here for Gradle 5, set via sys prop + if (buildScan.metaClass.respondsTo(buildScan, 'setUploadInBackground', Boolean)) buildScan.uploadInBackground = false // uploadInBackground not available for build-scan-plugin 1.16 +} + +// add custom data identifying the experiment +def addBuildScanCustomData = { def buildScan -> + def projectProperties = gradle.startParameter.projectProperties + + def expId = projectProperties.get("com.gradle.enterprise.build_validation.expId") + addCustomValueAndSearchLink(buildScan, "Experiment id", expId) + buildScan.tag(expId) + + def runId = projectProperties.get("com.gradle.enterprise.build_validation.runId") + addCustomValueAndSearchLink(buildScan, "Experiment run id", runId) +} + +// configure build scan behavior and optionally apply the GE / Build Scan / CCUD plugin +if (GradleVersion.current() < GradleVersion.version('6.0')) { + //noinspection GroovyAssignabilityCheck + rootProject { + buildscript.configurations.getByName("classpath").incoming.afterResolve { ResolvableDependencies incoming -> + def resolutionResult = incoming.resolutionResult - clearWarnings() + def scanPluginComponent = resolutionResult.allComponents.find { + it.moduleVersion.with { group == "com.gradle" && (name == "build-scan-plugin" || name == "gradle-enterprise-gradle-plugin") } + } - if (atLeastGradle6) { - settingsEvaluated { settings -> - if (!settings.pluginManager.hasPlugin("com.gradle.enterprise")) { - throw new IllegalStateException("The com.gradle.enterprise plugin is missing from the project (see https://docs.gradle.com/enterprise/gradle-plugin/#gradle_6_x_and_later).") + if (gePluginVersion) { + if (!scanPluginComponent) { + logger.quiet("Applying $BUILD_SCAN_PLUGIN_CLASS via init script") + logger.quiet("Connection to Gradle Enterprise: $geUrl, allowUntrustedServer: $geAllowUntrustedServer") + pluginManager.apply(initscript.classLoader.loadClass(BUILD_SCAN_PLUGIN_CLASS)) + if (geUrl) buildScan.server = geUrl + if (geAllowUntrustedServer) buildScan.allowUntrustedServer = geAllowUntrustedServer + } + } else { + if (!scanPluginComponent) { + throw new IllegalStateException("The com.gradle.build-scan plugin is missing from the project.\n" + + "Either apply it directly (see https://docs.gradle.com/enterprise/gradle-plugin/#gradle_5_x) to the project,\n" + + "or use `--enable-gradle-enterprise` when running the build validation script.") + } } - if (!settings.pluginManager.hasPlugin("com.gradle.common-custom-user-data-gradle-plugin")) { - logWarningMissingCommonCustomUserDataGradlePlugin() + + def ccudPluginComponent = resolutionResult.allComponents.find { + it.moduleVersion.with { group == "com.gradle" && name == "common-custom-user-data-gradle-plugin" } } - if (!isScanDump) { - configureGradleEnterprise(settings.extensions["gradleEnterprise"]) + + if (ccudPluginVersion && atLeastGradle4) { + if (!ccudPluginComponent) { + logger.quiet("Applying $CCUD_PLUGIN_CLASS via init script") + pluginManager.apply(initscript.classLoader.loadClass(CCUD_PLUGIN_CLASS)) + } + } else { + if (!ccudPluginComponent) { + logWarningMissingCommonCustomUserDataGradlePlugin() + } } } - } else if (atLeastGradle5) { - projectsEvaluated { gradle -> - if (!gradle.rootProject.pluginManager.hasPlugin("com.gradle.build-scan")) { - throw new IllegalStateException("The com.gradle.build-scan plugin is missing from the project (see https://docs.gradle.com/enterprise/gradle-plugin/#gradle_5_x).") + + pluginManager.withPlugin(BUILD_SCAN_PLUGIN_ID) { + afterEvaluate { + if (geUrl) buildScan.server = geUrl + if (geAllowUntrustedServer) buildScan.allowUntrustedServer = geAllowUntrustedServer + + registerBuildScanActions(buildScan) + addBuildScanCustomData(buildScan) + configureBuildScanPublishing(buildScan) } - if (!gradle.rootProject.pluginManager.hasPlugin("com.gradle.common-custom-user-data-gradle-plugin")) { - logWarningMissingCommonCustomUserDataGradlePlugin() + } + } +} else { + gradle.settingsEvaluated { settings -> + if (gePluginVersion) { + if (!settings.pluginManager.hasPlugin(GRADLE_ENTERPRISE_PLUGIN_ID)) { + logger.quiet("Applying $GRADLE_ENTERPRISE_PLUGIN_CLASS via init script") + logger.quiet("Connection to Gradle Enterprise: $geUrl, allowUntrustedServer: $geAllowUntrustedServer") + settings.pluginManager.apply(initscript.classLoader.loadClass(GRADLE_ENTERPRISE_PLUGIN_CLASS)) + extensionsWithPublicType(settings, GRADLE_ENTERPRISE_EXTENSION_CLASS).collect { settings[it.name] }.each { ext -> + if (geUrl) ext.server = geUrl + if (geAllowUntrustedServer) ext.allowUntrustedServer = geAllowUntrustedServer + } } - if (!isScanDump) { - configureGradleEnterprise(gradle.rootProject.extensions["gradleEnterprise"]) + } else { + if (!settings.pluginManager.hasPlugin(GRADLE_ENTERPRISE_PLUGIN_ID)) { + throw new IllegalStateException("The com.gradle.enterprise plugin is missing from the project.\n" + + "Either apply it directly (see https://docs.gradle.com/enterprise/gradle-plugin/#gradle_6_x_and_later),\n" + + "or use `--enable-gradle-enterprise` when running the build validation script.") } } - } else { - throw new IllegalStateException("Build validation not supported for Gradle ${GradleVersion.current()}. Upgrade your project's build to Gradle 5 or newer.") - } -} -void configureGradleEnterprise(gradleEnterprise) { - gradleEnterprise.with { - buildScan { - def projectProperties = gradle.startParameter.projectProperties - if (projectProperties.containsKey("com.gradle.enterprise.build_validation.server")) { - server = projectProperties.get("com.gradle.enterprise.build_validation.server") + if (ccudPluginVersion) { + if (!settings.pluginManager.hasPlugin(CCUD_PLUGIN_ID)) { + logger.quiet("Applying $CCUD_PLUGIN_CLASS via init script") + settings.pluginManager.apply(initscript.classLoader.loadClass(CCUD_PLUGIN_CLASS)) } - - if (!server) { - throw new IllegalStateException("A Gradle Enterprise server URL has not been configured.", null) + } else { + if (!settings.pluginManager.hasPlugin(CCUD_PLUGIN_ID)) { + logWarningMissingCommonCustomUserDataGradlePlugin() } + } + + extensionsWithPublicType(settings, GRADLE_ENTERPRISE_EXTENSION_CLASS).collect { settings[it.name] }.each { ext -> + if (geUrl) ext.server = geUrl + if (geAllowUntrustedServer) ext.allowUntrustedServer = geAllowUntrustedServer - // captureTaskInputFiles = true (too late to be set here for Gradle 5, set via sys prop) - uploadInBackground = false - publishAlways() + registerBuildScanActions(ext.buildScan) + addBuildScanCustomData(ext.buildScan) + configureBuildScanPublishing(ext.buildScan) } - addCustomData(buildScan) } } -void addCustomData(buildScan) { - def projectProperties = gradle.startParameter.projectProperties - - def expId = projectProperties.get("com.gradle.enterprise.build_validation.expId") - addCustomValueAndSearchLink(buildScan, "Experiment id", expId) - buildScan.tag(expId) +static def extensionsWithPublicType(def container, String publicType) { + container.extensions.extensionsSchema.elements.findAll { it.publicType.concreteClass.name == publicType } +} - def runId = projectProperties.get("com.gradle.enterprise.build_validation.runId") - addCustomValueAndSearchLink(buildScan, "Experiment run id", runId) +static boolean isNotAtLeast(String versionUnderTest, String referenceVersion) { + GradleVersion.version(versionUnderTest) < GradleVersion.version(referenceVersion) } -void addCustomValueAndSearchLink(buildScan, String label, String value) { +static void addCustomValueAndSearchLink(buildScan, String label, String value) { buildScan.value(label, value) - String server = buildScan.server - String searchParams = "search.names=" + urlEncode(label) + "&search.values=" + urlEncode(value) - String url = appendIfMissing(server, "/") + "scans?" + searchParams + "#selection.buildScanB=" + urlEncode("{SCAN_ID}") - buildScan.link(label + " build scans", url) + if (buildScan.metaClass.respondsTo(buildScan, 'getServer')) { // required for Gradle 4.x / build-scan-plugin 1.16 + String server = buildScan.server + String searchParams = "search.names=" + urlEncode(label) + "&search.values=" + urlEncode(value) + String url = appendIfMissing(server, "/") + "scans?" + searchParams + "#selection.buildScanB=" + urlEncode("{SCAN_ID}") + buildScan.link(label + " build scans", url) + } } -String appendIfMissing(String str, String suffix) { +static String appendIfMissing(String str, String suffix) { return str.endsWith(suffix) ? str : str + suffix } -String urlEncode(String str) { +static String urlEncode(String str) { return URLEncoder.encode(str, StandardCharsets.UTF_8.name()) } @@ -108,11 +244,6 @@ void logWarning(String warning) { warningFile.append(warning + "\n") } -void clearWarnings() { - def warningFile = new File(experimentDir, "warnings.txt") - warningFile.delete() -} - File getExperimentDir() { def projectProperties = gradle.startParameter.projectProperties new File(projectProperties.get("com.gradle.enterprise.build_validation.experimentDir")) diff --git a/components/scripts/gradle/gradle-init-scripts/enable-gradle-enterprise.gradle b/components/scripts/gradle/gradle-init-scripts/enable-gradle-enterprise.gradle deleted file mode 100644 index 06b4814f..00000000 --- a/components/scripts/gradle/gradle-init-scripts/enable-gradle-enterprise.gradle +++ /dev/null @@ -1,41 +0,0 @@ -import com.gradle.enterprise.gradleplugin.GradleEnterprisePlugin -import com.gradle.scan.plugin.BuildScanPlugin -import com.gradle.CommonCustomUserDataGradlePlugin -import org.gradle.util.GradleVersion - -initscript { - def gradleEnterprisePluginVersion = "3.12.4" - def commonCustomUserDataPluginVersion = "1.9" - - repositories { - gradlePluginPortal() - } - - dependencies { - classpath("com.gradle:gradle-enterprise-gradle-plugin:${gradleEnterprisePluginVersion}") - classpath("com.gradle:common-custom-user-data-gradle-plugin:${commonCustomUserDataPluginVersion}") - } -} - -// Don't run against the included builds (if the main build has any). -def isTopLevelBuild = gradle.getParent() == null -if (isTopLevelBuild) { - def version = GradleVersion.current().baseVersion - def atLeastGradle5 = version >= GradleVersion.version("5.0") - def atLeastGradle6 = version >= GradleVersion.version("6.0") - - if (atLeastGradle6) { - beforeSettings { settings -> - settings.pluginManager.apply(GradleEnterprisePlugin) - settings.pluginManager.apply(CommonCustomUserDataGradlePlugin) - } - } else if (atLeastGradle5) { - rootProject { - pluginManager.apply(BuildScanPlugin) - pluginManager.apply(CommonCustomUserDataGradlePlugin) - } - } else { - throw new IllegalStateException("Build validation not supported for Gradle ${GradleVersion.current()}. Upgrade your project's build to Gradle 5 or newer.") - } -} - diff --git a/components/scripts/lib/gradle.sh b/components/scripts/lib/gradle.sh index a0da73cb..b165a158 100644 --- a/components/scripts/lib/gradle.sh +++ b/components/scripts/lib/gradle.sh @@ -10,20 +10,20 @@ invoke_gradle() { cd "${project_dir}" > /dev/null 2>&1 || die "ERROR: The subdirectory ${project_dir} (set with --project-dir) does not exist in ${project_name}." "${INVALID_INPUT}" fi + args+=(--init-script "${INIT_SCRIPTS_DIR}/configure-gradle-enterprise.gradle") + if [ "$enable_ge" == "on" ]; then - args+=(--init-script "${INIT_SCRIPTS_DIR}/enable-gradle-enterprise.gradle") + args+=("-Dcom.gradle.enterprise.build_validation.gradle.plugin-repository.url=https://plugins.gradle.org/m2") + args+=("-Dcom.gradle.enterprise.build_validation.gradle-enterprise.plugin.version=3.12.4") + args+=("-Dcom.gradle.enterprise.build_validation.ccud.plugin.version=1.9") fi - args+=(--init-script "${INIT_SCRIPTS_DIR}/configure-gradle-enterprise.gradle") - args+=(--init-script "${INIT_SCRIPTS_DIR}/capture-published-build-scan.gradle") - if [ -n "${ge_server}" ]; then - args+=("-Pcom.gradle.enterprise.build_validation.server=${ge_server}") + args+=("-Dcom.gradle.enterprise.build_validation.gradle-enterprise.url=${ge_server}") + args+=("-Dcom.gradle.enterprise.build_validation.gradle-enterprise.allow-untrusted-server=false") fi - if [[ "${build_scan_publishing_mode}" == "on" ]]; then - args+=("--scan") - else + if [[ "${build_scan_publishing_mode}" == "off" ]]; then args+=("-Dscan.dump") fi