Skip to content

Common Develocity injection script is used for Gradle experiments #671

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 1 commit into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
25 changes: 25 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,22 @@ repositories {
includeModule("argbash", "argbash")
}
}
exclusiveContent {
forRepository {
ivy {
url = uri("https://raw.githubusercontent.com/gradle/develocity-ci-injection/")
patternLayout {
artifact("refs/tags/v[revision]/reference/develocity-injection.init.gradle")
}
metadataSources {
artifact()
}
}
}
filter {
includeModule("com.gradle", "develocity-injection")
}
}
exclusiveContent {
forRepository {
maven("https://repo.gradle.org/artifactory/solutions")
Expand All @@ -52,6 +68,10 @@ allprojects {
}

val argbash by configurations.creating
val develocityInjection = configurations.dependencyScope("develocityInjection").get()
val develocityInjectionResolvable = configurations.resolvable("${develocityInjection.name}Resolvable") {
extendsFrom(develocityInjection)
}
val develocityComponents by configurations.creating {
attributes.attribute(
TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE,
Expand All @@ -64,6 +84,7 @@ val develocityMavenComponents by configurations.creating

dependencies {
argbash("argbash:argbash:2.10.0@zip")
develocityInjection("com.gradle:develocity-injection:1.0")
develocityComponents("com.gradle:build-scan-summary:$buildScanSummaryVersion")
develocityMavenComponents("com.gradle:gradle-enterprise-maven-extension:1.18.4")
mavenComponents(project(path = ":configure-gradle-enterprise-maven-extension", configuration = "shadow"))
Expand Down Expand Up @@ -143,6 +164,10 @@ val copyGradleScripts by tasks.registering(Sync::class) {
include("gradle-init-scripts/**")
into("lib/scripts/")
}
from(develocityInjectionResolvable) {
rename { "develocity-injection.gradle" }
into("lib/scripts/gradle-init-scripts")
}
from(layout.projectDirectory.dir("components/scripts")) {
include("README.md")
include("mapping.example")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ execute_build() {
local args
args=(--build-cache --init-script "${INIT_SCRIPTS_DIR}/configure-remote-build-caching.gradle")
if [ -n "${remote_build_cache_url}" ]; then
args+=("-Dcom.gradle.enterprise.build-validation.remoteBuildCacheUrl=${remote_build_cache_url}")
args+=("-Ddevelocity.build-validation.remoteBuildCacheUrl=${remote_build_cache_url}")
fi

# shellcheck disable=SC2206 # we want tasks to expand with word splitting in this case
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
import org.gradle.util.GradleVersion
import java.nio.charset.StandardCharsets

static getInputParam(String name) {
def ENV_VAR_PREFIX = ''
def envVarName = ENV_VAR_PREFIX + name.toUpperCase().replace('.', '_').replace('-', '_')
return System.getProperty(name) ?: System.getenv(envVarName)
}

def isTopLevelBuild = !gradle.parent
if (!isTopLevelBuild) {
return
}

def BUILD_SCAN_PLUGIN_ID = 'com.gradle.build-scan'
def GRADLE_ENTERPRISE_PLUGIN_ID = 'com.gradle.enterprise'
def DEVELOCITY_PLUGIN_ID = 'com.gradle.develocity'
def CCUD_PLUGIN_ID = 'com.gradle.common-custom-user-data-gradle-plugin'

def develocityUrl = getInputParam('develocity.url')

def expDir = getInputParam('develocity.build-validation.expDir')
def expId = getInputParam('develocity.build-validation.expId')
def runId = getInputParam('develocity.build-validation.runId')
def scriptsVersion = getInputParam('develocity.build-validation.scriptsVersion')

def atLeastGradle5 = GradleVersion.current() >= GradleVersion.version('5.0')

// register build scan listeners to capture build scan URL/id and to track publishing errors
def registerBuildScanActions = { def buildScan, def rootProjectName ->
buildScan.buildScanPublished { publishedBuildScan ->
// defer reading the runNum system property until execution time since it does not affect
// the configuration of the build, and given its value changes between consecutive build invocations
// it would always invalidate the configuration cache model from the first build invocation
// in the second build invocation
def getInputParam = { String name ->
def ENV_VAR_PREFIX = ''
def envVarName = ENV_VAR_PREFIX + name.toUpperCase().replace('.', '_').replace('-', '_')
return System.getProperty(name) ?: System.getenv(envVarName)
}
def runNum = getInputParam('develocity.build-validation.runNum')
def buildScanUri = publishedBuildScan.buildScanUri
def buildScanId = publishedBuildScan.buildScanId
def port = (buildScanUri.port != -1) ? ':' + buildScanUri.port : ''
def baseUrl = "${buildScanUri.scheme}://${buildScanUri.host}${port}"

def scanFile = new File(expDir, 'build-scans.csv')
scanFile.append("${runNum},${rootProjectName},${baseUrl},${buildScanUri},${buildScanId}\n")
}

buildScan.onError { error ->
def errorFile = new File(expDir, 'errors.txt')
errorFile.text = 'Build Scan publishing failed.'
}
}

// add custom data identifying the experiment
def addBuildScanCustomData = { def buildScan, def server ->
addCustomValueAndSearchLink(buildScan, server, "Experiment id", expId)
buildScan.tag(expId)

addCustomValueAndSearchLink(buildScan, server, "Experiment run id", runId)

buildScan.value("Build validation scripts", scriptsVersion)
}

// fail if no server is configured
def failMissingDevelocityServerURL = { def docs ->
def errorFile = new File(expDir, 'errors.txt')
errorFile.text = 'The Develocity server URL has not been configured in the project or on the command line.'
throw new IllegalStateException("The Develocity server URL is not configured.\n"
+ "Either configure it directly (see $docs) in the project,\n"
+ "or use --gradle-enterprise-server when running the build validation script.")
}

// fail if a plugin is not applied
def failMissingPlugin = { def plugin, docs ->
def errorFile = new File(expDir, 'errors.txt')
errorFile.text = "The $plugin plugin is missing from the project."
throw new IllegalStateException("The $plugin plugin is missing from the project.\n" +
"Either apply it directly (see $docs),\n" +
"or use --enable-gradle-enterprise when running the build validation script.")
}

// do not fail if the CCUD plugin is not applied but surface a warning
def warnMissingCommonCustomUserDataGradlePlugin = {
def warningFile = new File(expDir, 'warnings.txt')
warningFile.append("The com.gradle.common-custom-user-data-gradle-plugin plugin is missing from " +
"the project (see https://github.com/gradle/common-custom-user-data-gradle-plugin).\n")
}

if (GradleVersion.current() < GradleVersion.version('6.0')) {
//noinspection GroovyAssignabilityCheck
rootProject {
afterEvaluate {
if (!pluginManager.hasPlugin(BUILD_SCAN_PLUGIN_ID) && !pluginManager.hasPlugin(DEVELOCITY_PLUGIN_ID)) {
if (atLeastGradle5) {
failMissingPlugin(DEVELOCITY_PLUGIN_ID, 'https://docs.gradle.com/develocity/gradle-plugin/current/#gradle_5_x')
} else {
failMissingPlugin(BUILD_SCAN_PLUGIN_ID, 'https://docs.gradle.com/develocity/gradle-plugin/legacy/#gradle_2_1_4_10_3')
}
}

if (!pluginManager.hasPlugin(CCUD_PLUGIN_ID)) {
warnMissingCommonCustomUserDataGradlePlugin()
}

pluginManager.withPlugin(BUILD_SCAN_PLUGIN_ID) {
// only execute if Develocity plugin isn't applied
if (pluginManager.hasPlugin(DEVELOCITY_PLUGIN_ID)) return

if (develocityUrl) {
buildScan.server = develocityUrl
}

if (!buildScan.server) {
failMissingDevelocityServerURL('https://docs.gradle.com/develocity/gradle-plugin/legacy#gradle_5_x_2')
}

buildScan.publishAlways()
registerBuildScanActions(buildScan, rootProject.name)
addBuildScanCustomData(buildScan, buildScan.server)
}

pluginManager.withPlugin(DEVELOCITY_PLUGIN_ID) {
if (develocityUrl) {
develocity.server = develocityUrl
}

if (!develocity.server.present) {
develocity.buildScan.publishing.onlyIf { false } // prevent publishing to scans.gradle.com
failMissingDevelocityServerURL('https://docs.gradle.com/develocity/gradle-plugin/current/#connecting_to_develocity')
}

registerBuildScanActions(develocity.buildScan, rootProject.name)
addBuildScanCustomData(develocity.buildScan, develocity.server.get())
}
}
}
} else {
gradle.settingsEvaluated { settings ->
if (!settings.pluginManager.hasPlugin(GRADLE_ENTERPRISE_PLUGIN_ID) && !settings.pluginManager.hasPlugin(DEVELOCITY_PLUGIN_ID)) {
failMissingPlugin(DEVELOCITY_PLUGIN_ID, 'https://docs.gradle.com/develocity/gradle-plugin/current/#gradle_6_x_and_later')
}

if (!settings.pluginManager.hasPlugin(CCUD_PLUGIN_ID)) {
warnMissingCommonCustomUserDataGradlePlugin()
}

settings.pluginManager.withPlugin(GRADLE_ENTERPRISE_PLUGIN_ID) {
// only execute if Develocity plugin isn't applied
if (settings.pluginManager.hasPlugin(DEVELOCITY_PLUGIN_ID)) return

if (develocityUrl) {
settings.gradleEnterprise.server = develocityUrl
}

if (!settings.gradleEnterprise.server) {
failMissingDevelocityServerURL('https://docs.gradle.com/develocity/gradle-plugin/legacy/#gradle_6_x_and_later_2')
}

settings.gradleEnterprise.buildScan.publishAlways()
registerBuildScanActions(settings.gradleEnterprise.buildScan, settings.rootProject.name)
addBuildScanCustomData(settings.gradleEnterprise.buildScan, settings.gradleEnterprise.server)
}

settings.pluginManager.withPlugin(DEVELOCITY_PLUGIN_ID) {
if (develocityUrl) {
settings.develocity.server = develocityUrl
}

if (!settings.develocity.server.present) {
settings.develocity.buildScan.publishing.onlyIf { false } // prevent publishing to scans.gradle.com
failMissingDevelocityServerURL('https://docs.gradle.com/develocity/gradle-plugin/current/#connecting_to_develocity')
}

registerBuildScanActions(settings.develocity.buildScan, settings.rootProject.name)
addBuildScanCustomData(settings.develocity.buildScan, settings.develocity.server.get())
}
}
}

static void addCustomValueAndSearchLink(buildScan, String server, label, String value) {
buildScan.value(label, value)
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)
}

static String appendIfMissing(String str, String suffix) {
return str.endsWith(suffix) ? str : str + suffix
}

static String urlEncode(String str) {
return URLEncoder.encode(str, StandardCharsets.UTF_8.name())
}
Loading