blob: 6380687fd4ddb70f16c906fa971542ad4ca6911f [file] [log] [blame]
/**
* This Gradle script captures data about the OS, IDE, CI, and Git and stores it in build scans via custom tags, custom links, and custom values.
*
* Proceed as following to benefit from this script in your Gradle build:
*
* - Copy this script to the root folder of your Gradle project, renaming it to 'build-scan-user-data.gradle'
* - Apply the Gradle Build Scan plugin
* - Point to your Gradle Enterprise server
* - Include this script in the root project's build.gradle(.kts) file via `apply from: 'build-scan-user-data.gradle'`
* - Further customize this script to your needs
*/
tagOs()
tagIde()
tagCiOrLocal()
addCiMetadata()
addGitMetadata()
addTestParallelization()
// Add here other scripts, if needed
//apply from:"${rootProject.projectDir}/<<other-script.gradle>>"
void tagOs() {
buildScan.tag System.getProperty('os.name')
}
void tagIde() {
if (project.hasProperty('android.injected.invoked.from.ide')) {
buildScan.tag 'Android Studio'
} else if (System.getProperty('idea.version')) {
buildScan.tag 'IntelliJ IDEA'
} else if (System.getProperty('eclipse.buildId')) {
buildScan.tag 'Eclipse'
} else if (!isCi()) {
buildScan.tag 'Cmd Line'
}
}
void tagCiOrLocal() {
buildScan.tag(isCi() ? 'CI' : 'LOCAL')
}
void addCiMetadata() {
if (isJenkins()) {
if (System.getenv('BUILD_URL')) {
buildScan.link 'Jenkins build', System.getenv('BUILD_URL')
}
if (System.getenv('BUILD_NUMBER')) {
buildScan.value 'CI build number', System.getenv('BUILD_NUMBER')
}
if (System.getenv('NODE_NAME')) {
def agentName = System.getenv('NODE_NAME') == 'master' ? 'master-node' : System.getenv('NODE_NAME')
buildScan.tag agentName
buildScan.value 'CI node name', agentName
}
if (System.getenv('JOB_NAME')) {
def jobNameLabel = 'CI job'
def jobName = System.getenv('JOB_NAME')
buildScan.value jobNameLabel, jobName
addCustomValueSearchLink 'CI job build scans', [(jobNameLabel): jobName]
}
if (System.getenv('STAGE_NAME')) {
def stageNameLabel = 'CI stage'
def stageName = System.getenv('STAGE_NAME')
buildScan.value stageNameLabel, stageName
addCustomValueSearchLink 'CI stage build scans', [(stageNameLabel): stageName]
}
}
if (isTeamCity()) {
def teamCityConfigurationFileProp = 'teamcity.configuration.properties.file'
if (project.hasProperty(teamCityConfigurationFileProp)) {
def properties = new Properties()
properties.load(new FileInputStream("${project.property(teamCityConfigurationFileProp)}"))
def teamCityServerUrl = properties.getProperty("teamcity.serverUrl")
if (teamCityServerUrl && project.hasProperty('build.number') && project.hasProperty('teamcity.buildType.id')) {
def teamCityBuildNumber = project.property('build.number')
def teamCityBuildTypeId = project.property('teamcity.buildType.id')
buildScan.link 'TeamCity build', "${appendIfMissing(teamCityServerUrl, '/')}viewLog.html?buildNumber=${URLEncoder.encode(teamCityBuildNumber, 'UTF-8')}&buildTypeId=${teamCityBuildTypeId}"
}
}
if (project.hasProperty('build.number')) {
buildScan.value 'CI build number', project.property('build.number')
}
if (project.hasProperty('agent.name')) {
def agentName = project.property('agent.name')
buildScan.tag agentName
buildScan.value 'CI agent name', agentName
}
}
if (isCircleCI()) {
if (System.getenv('CIRCLE_BUILD_URL')) {
buildScan.link 'CircleCI build', System.getenv('CIRCLE_BUILD_URL')
}
if (System.getenv('CIRCLE_BUILD_NUM')) {
buildScan.value 'CI build number', System.getenv('CIRCLE_BUILD_NUM')
}
if (System.getenv('CIRCLE_JOB')) {
def jobLabel = 'CI job'
def job = System.getenv('CIRCLE_JOB')
buildScan.value jobLabel, job
addCustomValueSearchLink 'CI job build scans', [(jobLabel): job]
}
if (System.getenv('CIRCLE_WORKFLOW_ID')) {
def workflowIdLabel = 'CI workflow'
def workflowId = System.getenv('CIRCLE_WORKFLOW_ID')
buildScan.value workflowIdLabel, workflowId
addCustomValueSearchLink 'CI workflow build scans', [(workflowIdLabel): workflowId]
}
}
if (isBamboo()) {
if (System.getenv('bamboo_resultsUrl')) {
buildScan.link 'Bamboo build', System.getenv('bamboo_resultsUrl')
}
if (System.getenv('bamboo_buildNumber')) {
buildScan.value 'CI build number', System.getenv('bamboo_buildNumber')
}
if (System.getenv('bamboo_planName')) {
def planNameLabel = 'CI plan'
def planName = System.getenv('bamboo_planName')
buildScan.value planNameLabel, planName
addCustomValueSearchLink 'CI plan build scans', [(planNameLabel): planName]
}
if (System.getenv('bamboo_buildPlanName')) {
def jobNameLabel = 'CI job'
def jobName = System.getenv('bamboo_buildPlanName')
buildScan.value jobNameLabel, jobName
addCustomValueSearchLink 'CI job build scans', [(jobNameLabel): jobName]
}
if (System.getenv('bamboo_agentId')) {
def agentId = System.getenv('bamboo_agentId')
buildScan.tag agentId
buildScan.value 'CI agent ID', agentId
}
}
}
void addGitMetadata() {
buildScan.background {
if (!isGitInstalled()) {
return
}
def gitCommitId = execAndGetStdout('git', 'rev-parse', '--short=8', '--verify', 'HEAD')
def gitBranchName = execAndGetStdout('git', 'rev-parse', '--abbrev-ref', 'HEAD')
def gitStatus = execAndGetStdout('git', 'status', '--porcelain')
if (gitCommitId) {
def commitIdLabel = 'Git commit id'
value commitIdLabel, gitCommitId
addCustomValueSearchLink 'Git commit id build scans', [(commitIdLabel): gitCommitId]
def originUrl = execAndGetStdout('git', 'config', '--get', 'remote.origin.url')
if (originUrl.contains('github.com')) { // only for GitHub
def repoPath = (originUrl =~ /(.*)github\.com[\/|:](.*)/)[0][2]
if (repoPath.endsWith('.git')) {
repoPath = repoPath.substring(0, repoPath.length() - 4)
}
link 'Github Source', "https://github.com/$repoPath/tree/" + gitCommitId
}
}
if (gitBranchName) {
tag gitBranchName
value 'Git branch', gitBranchName
}
if (gitStatus) {
tag 'Dirty'
value 'Git status', gitStatus
}
}
}
void addTestParallelization() {
allprojects { p ->
p.tasks.withType(Test).configureEach { t -> doFirst { buildScan.value "${t.identityPath}#maxParallelForks", t.maxParallelForks.toString() } }
}
}
static boolean isCi() {
isJenkins() || isTeamCity() || isCircleCI() || isBamboo()
}
static boolean isJenkins() {
System.getenv('JENKINS_URL')
}
static boolean isTeamCity() {
System.getenv('TEAMCITY_VERSION')
}
static boolean isCircleCI() {
System.getenv('CIRCLECI')
}
static boolean isBamboo() {
System.getenv('bamboo_resultsUrl')
}
String execAndGetStdout(String... args) {
def stdout = new ByteArrayOutputStream()
exec {
commandLine(args)
standardOutput = stdout
}
trimAtEnd(stdout.toString())
}
void addCustomValueSearchLink(String title, Map<String, String> search) {
if (buildScan.server) {
buildScan.link title, customValueSearchUrl(search)
}
}
String customValueSearchUrl(Map<String, String> search) {
def query = search.collect { name, value ->
"search.names=${encodeURL(name)}&search.values=${encodeURL(value)}"
}.join('&')
"${appendIfMissing(buildScan.server, '/')}scans?$query"
}
static String encodeURL(String url) {
URLEncoder.encode(url, 'UTF-8')
}
static boolean isGitInstalled() {
try {
"git --version".execute().waitFor() == 0
} catch (IOException ignored) {
false
}
}
static String appendIfMissing(String str, String suffix) {
str.endsWith(suffix) ? str : str + suffix
}
static String trimAtEnd(String str) {
('x' + str).trim().substring(1)
}