Skip to content

Gradle init script improvements #264

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 23 commits into from
Mar 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
77403cb
Remove unnecessary initscript block
bigdaz Jul 25, 2022
d3a13cf
Consolidate init-scripts used to configure GE
bigdaz Jul 25, 2022
0dd801f
Improve error message when GE plugin is not applied
bigdaz Jul 26, 2022
d02452f
Avoid duplicate plugin application with `-e`
bigdaz Jul 26, 2022
347630d
Use System property instead of Project property for server override
bigdaz Jul 26, 2022
e7eae5c
Merge enable- and configure- init scripts
bigdaz Jul 26, 2022
d6fc207
Refactor init-script to be more similar to gold standard
bigdaz Jul 27, 2022
654dc90
Fix comment
bigdaz Jul 29, 2022
d902539
Remove empty files leftover from merge
erichaagdev Dec 29, 2022
00c7829
Create isScanDump variable
erichaagdev Dec 29, 2022
cda7906
Do not pass --scan on command line
erichaagdev Dec 29, 2022
cae969f
Remove logger calls in init script
erichaagdev Dec 29, 2022
7e0594d
Update Gradle version exception message
erichaagdev Jan 9, 2023
366df54
Bump build classpath dependencies in initialization scripts to latest
erichaagdev Mar 6, 2023
1332ea1
Merge branch 'main' into erichaagdev/init-script-cleanup
erichaagdev Mar 6, 2023
9872189
Bring init script more in line with the init script for the TC BS plugin
etiennestuder Mar 6, 2023
5d66447
Consolidate GE and BS configuration
etiennestuder Mar 6, 2023
2a93b40
Update sys props passed from shell script to init script
etiennestuder Mar 7, 2023
a8bf91d
Fix Groovy syntax
etiennestuder Mar 7, 2023
fd81fd9
Remove setting of file input capture from init script
erichaagdev Mar 7, 2023
1ad2263
Add Build Scan link only if server is readable
erichaagdev Mar 7, 2023
b2f4c18
Add clarifying comment
etiennestuder Mar 7, 2023
687a9c3
Make some methods static
etiennestuder Mar 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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())
}

Expand All @@ -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"))
Expand Down
Loading