| /** |
| * 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) |
| } |