Home | History | Annotate | Download | only in buildSrc
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 import android.support.LibraryVersions
     18 import com.android.build.gradle.internal.coverage.JacocoPlugin
     19 import com.android.build.gradle.internal.coverage.JacocoReportTask
     20 import com.android.build.gradle.internal.tasks.DeviceProviderInstrumentTestTask
     21 import org.gradle.api.logging.configuration.ShowStacktrace
     22 import android.support.gmaven.GMavenVersionChecker
     23 
     24 def supportRoot = ext.supportRootFolder
     25 if (supportRoot == null) {
     26     throw new RuntimeException("variable supportRootFolder is not set. you must set it before" +
     27             " including this script")
     28 }
     29 def init = new Properties()
     30 ext.init = init
     31 ext.init.debugKeystore = file("${supportRoot}/development/keystore/debug.keystore")
     32 rootProject.ext.versionChecker = new GMavenVersionChecker(rootProject)
     33 ext.runningInBuildServer = System.env.DIST_DIR != null && System.env.OUT_DIR != null
     34 
     35 apply from: "${supportRoot}/buildSrc/dependencies.gradle"
     36 ext.docs = [:]
     37 ext.docs.offline = rootProject.getProperties().containsKey("offlineDocs")
     38 ext.docs.dac = [
     39         libraryroot: "android/support",
     40         dataname: "SUPPORT_DATA"
     41 ]
     42 
     43 def enableDoclavaAndJDiff(p) {
     44     p.configurations {
     45         doclava
     46         jdiff
     47     }
     48 
     49     p.dependencies {
     50         doclava project(':doclava')
     51         jdiff project(':jdiff')
     52         jdiff libs.xml_parser_apis
     53         jdiff libs.xerces_impl
     54     }
     55     apply from: "${ext.supportRootFolder}/buildSrc/diff_and_docs.gradle"
     56 }
     57 
     58 def getFullSdkPath() {
     59     final String osName = System.getProperty("os.name").toLowerCase();
     60     final boolean isMacOsX =
     61             osName.contains("mac os x") || osName.contains("darwin") || osName.contains("osx");
     62     final String platform = isMacOsX ? 'darwin' : 'linux'
     63     return "${repos.prebuiltsRoot}/fullsdk-${platform}"
     64 }
     65 
     66 def setSdkInLocalPropertiesFile() {
     67     ext.buildToolsVersion = '26.0.0'
     68     final String fullSdkPath = getFullSdkPath();
     69     if (file(fullSdkPath).exists()) {
     70         gradle.ext.currentSdk = 26
     71         project.ext.androidJar =
     72                 files("${fullSdkPath}/platforms/android-${gradle.currentSdk}/android.jar")
     73         project.ext.androidSrcJar =
     74                 file("${fullSdkPath}/platforms/android-${gradle.currentSdk}/android-stubs-src.jar")
     75         project.ext.androidApiTxt = null
     76         File props = file("local.properties")
     77         props.write "sdk.dir=${fullSdkPath}"
     78         ext.usingFullSdk = true
     79     } else {
     80         gradle.ext.currentSdk = 'current'
     81         project.ext.androidJar = files("${repos.prebuiltsRoot}/sdk/current/android.jar")
     82         project.ext.androidSrcJar = null
     83         project.ext.androidApiTxt = file("${repos.prebuiltsRoot}/sdk/api/26.txt")
     84         System.setProperty('android.dir', "${supportRootFolder}/../../")
     85         File props = file("local.properties")
     86         props.write "android.dir=../../"
     87         ext.usingFullSdk = false
     88     }
     89 }
     90 
     91 def setupRepoOutAndBuildNumber() {
     92     // common support repo folder which works well for prebuilts.
     93     ext.supportRepoOut = ''
     94     ext.buildNumber = "0"
     95     /*
     96      * With the build server you are given two env variables.
     97      * The OUT_DIR is a temporary directory you can use to put things during the build.
     98      * The DIST_DIR is where you want to save things from the build.
     99      *
    100      * The build server will copy the contents of DIST_DIR to somewhere and make it available.
    101      */
    102     if (ext.runningInBuildServer) {
    103         buildDir = new File(System.env.OUT_DIR + '/gradle/frameworks/support/build')
    104                 .getCanonicalFile()
    105         project.ext.distDir = new File(System.env.DIST_DIR).getCanonicalFile()
    106 
    107         // the build server does not pass the build number so we infer it from the last folder of
    108         // the dist path.
    109         ext.buildNumber = project.ext.distDir.getName()
    110 
    111         // the build server should always print out full stack traces for any failures.
    112         gradle.startParameter.showStacktrace = ShowStacktrace.ALWAYS
    113     } else {
    114         buildDir = file("${ext.supportRootFolder}/../../out/host/gradle/frameworks/support/build")
    115         project.ext.distDir = new File("${ext.supportRootFolder}/../../out/dist")
    116     }
    117     subprojects {
    118         // Change buildDir first so that all plugins pick up the new value.
    119         project.buildDir = new File("$project.parent.buildDir/../$project.name/build")
    120     }
    121     ext.supportRepoOut = new File(buildDir, 'support_repo')
    122     ext.testApkDistOut = ext.distDir
    123     ext.testResultsDistDir = new File(distDir, "host-test-reports")
    124     ext.docsDir = new File(buildDir, 'javadoc')
    125 }
    126 
    127 def configureBuildOnServer() {
    128     def buildOnServerTask = rootProject.tasks.create("buildOnServer")
    129     rootProject.tasks.whenTaskAdded { task ->
    130         if ("createArchive".equals(task.name)) {
    131             buildOnServerTask.dependsOn task
    132         }
    133     }
    134 
    135     subprojects {
    136         project.tasks.whenTaskAdded { task ->
    137             if ("assembleErrorProne".equals(task.name) || "assembleAndroidTest".equals(task.name)) {
    138                 buildOnServerTask.dependsOn task
    139             }
    140         }
    141     }
    142 }
    143 
    144 def configureSubProjects() {
    145     // lint every library
    146     def lintTask = project.tasks.create("lint")
    147     subprojects {
    148         repos.addMavenRepositories(repositories)
    149 
    150         // Only modify Android projects.
    151         if (project.name.equals('doclava')
    152                 || project.name.equals('jdiff')
    153                 || project.name.equals('noto-emoji-compat')
    154                 || project.name.equals('support-media-compat-test-lib')) {
    155             // disable tests and return
    156             project.tasks.whenTaskAdded { task ->
    157                 if (task instanceof org.gradle.api.tasks.testing.Test) {
    158                     task.enabled = false
    159                 }
    160             }
    161             return
    162         }
    163 
    164         project.ext.currentSdk = gradle.ext.currentSdk
    165         apply plugin: 'maven'
    166 
    167         version = LibraryVersions.SUPPORT_LIBRARY.toString();
    168         group = 'com.android.support'
    169 
    170         project.plugins.whenPluginAdded { plugin ->
    171             def isAndroidLibrary = "com.android.build.gradle.LibraryPlugin"
    172                     .equals(plugin.class.name)
    173             def isAndroidApp = "com.android.build.gradle.AppPlugin".equals(plugin.class.name)
    174             def isJavaLibrary = "org.gradle.api.plugins.JavaPlugin".equals(plugin.class.name)
    175 
    176             if (isAndroidLibrary || isAndroidApp) {
    177                 project.android.buildToolsVersion = rootProject.buildToolsVersion
    178 
    179                 // Enable code coverage for debug builds only if we are not running inside the IDE,
    180                 // since enabling coverage reports breaks the method parameter resolution in the IDE
    181                 // debugger.
    182                 project.android.buildTypes.debug.testCoverageEnabled =
    183                         !project.hasProperty('android.injected.invoked.from.ide')
    184 
    185                 // Copy the class files in a jar to be later used to generate code coverage report
    186                 project.android.testVariants.all { v ->
    187                     // check if the variant has any source files
    188                     // and test coverage is enabled
    189                     if (v.buildType.testCoverageEnabled
    190                             && v.sourceSets.any { !it.java.sourceFiles.isEmpty() }) {
    191                         def jarifyTask = project.tasks.create(
    192                                 name: "package${v.name.capitalize()}ClassFilesForCoverageReport",
    193                                 type: Jar) {
    194                             from v.testedVariant.javaCompile.destinationDir
    195                             exclude "**/R.class"
    196                             exclude "**/R\$*.class"
    197                             exclude "**/BuildConfig.class"
    198                             destinationDir file(project.distDir)
    199                             archiveName "${project.name}-${v.baseName}-allclasses.jar"
    200                         }
    201 
    202                         def collectJacocoAntPackages = project.tasks.create(
    203                                 name: "collectJacocoAntPackages",
    204                                 type: Jar) {
    205                             inputs.files project.configurations[JacocoPlugin.ANT_CONFIGURATION_NAME]
    206                             from {
    207                                 project.configurations[JacocoPlugin.ANT_CONFIGURATION_NAME]
    208                                         .resolvedConfiguration
    209                                         .resolvedArtifacts.collect{ zipTree(it.getFile()) }} {
    210                                     // exclude all the signatures the jar might have
    211                                     exclude "META-INF/*.SF"
    212                                     exclude "META-INF/*.DSA"
    213                                     exclude "META-INF/*.RSA"
    214                                 }
    215                             destinationDir file(project.distDir)
    216                             archiveName "jacocoant.jar"
    217                         }
    218 
    219                         jarifyTask.dependsOn v.getJavaCompiler()
    220                         v.assemble.dependsOn jarifyTask , collectJacocoAntPackages
    221                     }
    222                 }
    223 
    224                 // Enforce NewApi lint check as fatal.
    225                 project.android.lintOptions.fatal 'NewApi'
    226                 lintTask.dependsOn {project.lint}
    227             }
    228 
    229             if (isAndroidLibrary || isJavaLibrary) {
    230                 // Add library to the aggregate dependency report.
    231                 task allDeps(type: DependencyReportTask) {}
    232 
    233                 project.afterEvaluate {
    234                     Upload uploadTask = (Upload) project.tasks.uploadArchives;
    235                     uploadTask.repositories.mavenDeployer {
    236                         repository(url: uri("$rootProject.ext.supportRepoOut"))
    237                         setUniqueVersion(true)
    238                     }
    239 
    240                     // Before the upload, make sure the repo is ready.
    241                     uploadTask.dependsOn rootProject.tasks.prepareRepo
    242 
    243                     // Make the mainupload depend on this one.
    244                     mainUpload.dependsOn uploadTask
    245                 }
    246             }
    247         }
    248 
    249         // Copy instrumentation test APKs and app APKs into the dist dir
    250         // For test apks, they are uploaded only if we have java test sources.
    251         // For regular app apks, they are uploaded only if they have java sources.
    252         project.tasks.whenTaskAdded { task ->
    253             if (task.name.startsWith("packageDebug")) {
    254                 def testApk = task.name.contains("AndroidTest")
    255                 task.doLast {
    256                     def source = testApk ? project.android.sourceSets.androidTest
    257                             : project.android.sourceSets.main
    258                     if (task.hasProperty("outputDirectory") && !source.java.sourceFiles.isEmpty()) {
    259                         copy {
    260                             from(task.outputDirectory)
    261                             include '*.apk'
    262                             into(rootProject.ext.testApkDistOut)
    263                             rename { String fileName ->
    264                                 // Exclude media-compat-test-* modules from existing support library
    265                                 // presubmit tests.
    266                                 if (fileName.contains("media-compat-test")) {
    267                                     fileName.replace("-debug-androidTest", "")
    268                                 } else {
    269                                     // multiple modules may have the same name so prefix the name with
    270                                     // the module's path to ensure it is unique.
    271                                     // e.g. palette-v7-debug-androidTest.apk becomes
    272                                     // support-palette-v7_palette-v7-debug-androidTest.apk
    273                                     "${project.getPath().replace(':', '-').substring(1)}_${fileName}"
    274                                 }
    275                             }
    276                         }
    277                     }
    278                 }
    279             }
    280         }
    281 
    282         // copy host side test results to DIST
    283         project.tasks.whenTaskAdded { task ->
    284             if (task instanceof org.gradle.api.tasks.testing.Test) {
    285                 def junitReport = task.reports.junitXml
    286                 if (junitReport.enabled) {
    287                     def zipTask = project.tasks.create(name : "zipResultsOf${task.name.capitalize()}", type : Zip) {
    288                         destinationDir(testResultsDistDir)
    289                         // first one is always :, drop it.
    290                         archiveName("${project.getPath().split(":").join("_").substring(1)}.zip")
    291                     }
    292                     if (project.rootProject.ext.runningInBuildServer) {
    293                         task.ignoreFailures = true
    294                     }
    295                     task.finalizedBy zipTask
    296                     task.doFirst {
    297                         zipTask.from(junitReport.destination)
    298                     }
    299                 }
    300             }
    301         }
    302 
    303         project.afterEvaluate { p ->
    304             // remove dependency on the test so that we still get coverage even if some tests fail
    305             p.tasks.findAll { it instanceof JacocoReportTask }.each { task ->
    306                 def toBeRemoved = new ArrayList()
    307                 def dependencyList = task.taskDependencies.values
    308                 dependencyList.each { dep ->
    309                     if (dep instanceof String) {
    310                         def t = tasks.findByName(dep)
    311                         if (t instanceof DeviceProviderInstrumentTestTask) {
    312                             toBeRemoved.add(dep)
    313                             task.mustRunAfter(t)
    314                         }
    315                     }
    316                 }
    317                 toBeRemoved.each { dep ->
    318                     dependencyList.remove(dep)
    319                 }
    320             }
    321         }
    322     }
    323 }
    324 
    325 def setupRelease() {
    326     apply from: "${ext.supportRootFolder}/buildSrc/release.gradle"
    327 }
    328 
    329 ext.init.enableDoclavaAndJDiff = this.&enableDoclavaAndJDiff
    330 ext.init.setSdkInLocalPropertiesFile = this.&setSdkInLocalPropertiesFile
    331 ext.init.setupRepoOutAndBuildNumber = this.&setupRepoOutAndBuildNumber
    332 ext.init.setupRelease = this.&setupRelease
    333 ext.init.configureSubProjects = this.&configureSubProjects
    334 ext.init.configureBuildOnServer = this.&configureBuildOnServer
    335