beforeApi.
*
* @param refApi the reference API version, ex. 25.0.0-SNAPSHOT
* @return the most recently released API file
*/
File getApiFile(String refApi = supportVersion, boolean previous = false, boolean release = false) {
def refMatcher = refApi =~ /^(\d+)\.(\d+)\.(\d+)(-.+)?$/
def refMajor = refMatcher[0][1] as int
def refMinor = refMatcher[0][2] as int
def refPatch = refMatcher[0][3] as int
def refExtra = refMatcher[0][4]
File apiDir = new File(ext.supportRootFolder, 'api')
if (!previous) {
// If this is a patch or release version, ignore the extra.
return new File(apiDir, "$refMajor.$refMinor.0" +
(refPatch || release ? "" : refExtra) + ".txt")
}
File lastFile = null
def lastMajor
def lastMinor
// Only look at released versions and snapshots thereof, ex. X.Y.0.txt or X.Y.0-SNAPSHOT.txt.
apiDir.eachFileMatch FileType.FILES, ~/(\d+)\.(\d+)\.0(-SNAPSHOT)?\.txt/, { File file ->
def matcher = file.name =~ /(\d+)\.(\d+)\.0(-SNAPSHOT)?\.txt/
def major = matcher[0][1] as int
def minor = matcher[0][2] as int
if (lastFile == null || major > lastMajor || (major == lastMajor && minor > lastMinor)) {
if (refMajor > major || (refMajor == major && refMinor > minor)) {
lastFile = file
lastMajor = major;
lastMinor = minor;
}
}
}
return lastFile
}
String stripExtension(String fileName) {
return fileName[0..fileName.lastIndexOf('.')-1]
}
// Make sure the API surface has not broken since the last release.
def isPatchVersion = supportVersion ==~ /\d+\.\d+.[1-9]\d*(-.+)?/
def isSnapshotVersion = supportVersion ==~ /\d+\.\d+.\d+-SNAPSHOT/
def previousApiFile = getApiFile(project.supportVersion, !isPatchVersion)
def whitelistFile = new File(
previousApiFile.parentFile, stripExtension(previousApiFile.name) + ".ignore")
def checkApiRelease = createCheckApiTask("checkApiRelease", CHECK_API_CONFIG_RELEASE,
previousApiFile, generateApi.apiFile, whitelistFile).dependsOn(generateApi)
// Allow a comma-delimited list of whitelisted errors.
if (project.hasProperty("ignore")) {
checkApiRelease.whitelistErrors = ignore.split(',')
}
// Check whether the development API surface has changed.
def verifyConfig = isPatchVersion != 0 ? CHECK_API_CONFIG_DEVELOP : CHECK_API_CONFIG_PATCH;
def checkApi = createCheckApiTask("checkApi", verifyConfig, getApiFile(), generateApi.apiFile)
.dependsOn(generateApi, checkApiRelease)
checkApi.group JavaBasePlugin.VERIFICATION_GROUP
checkApi.description 'Verify the API surface.'
rootProject.createArchive.dependsOn checkApi
task verifyUpdateApiAllowed() {
// This could be moved to doFirst inside updateApi, but using it as a
// dependency with no inputs forces it to run even when updateApi is a
// no-op.
doLast {
if (isPatchVersion) {
throw new GradleException("Public APIs may not be modified in patch releases.")
} else if (isSnapshotVersion && getApiFile(supportVersion, false, true).exists()) {
throw new GradleException("Inconsistent version. Public API file already exists.")
} else if (!isSnapshotVersion && getApiFile().exists() && !project.hasProperty("force")) {
throw new GradleException("Public APIs may not be modified in finalized releases.")
}
}
}
task updateApi(type: UpdateApiTask, dependsOn: [checkApiRelease, verifyUpdateApiAllowed]) {
group JavaBasePlugin.VERIFICATION_GROUP
description 'Updates the candidate API file to incorporate valid changes.'
newApiFile = checkApiRelease.newApiFile
oldApiFile = getApiFile()
newRemovedApiFile = new File(project.docsDir, 'release/removed.txt')
oldRemovedApiFile = new File(supportRootFolder, 'api/removed.txt')
whitelistErrors = checkApiRelease.whitelistErrors
whitelistErrorsFile = checkApiRelease.whitelistErrorsFile
}
/**
* Converts the toApi.txt file (or current.txt if not explicitly
* defined using -PtoAPi=fromApi.txt file (or the most recently released
* X.Y.Z.txt if not explicitly defined using -PfromAPi=* By default, diffs are generated for the delta between current.txt and the * next most recent X.Y.Z.txt API file. Behavior may be changed by specifying * one or both of -PtoApi and -PfromApi. *
* If both fromApi and toApi are specified, diffs will be generated for
* fromApi -> toApi. For example, 25.0.0 -> 26.0.0 diffs could be generated by
* using:
*
* ./gradlew generateDiffs -PfromApi=25.0.0 -PtoApi=26.0.0
*
*
* If only toApi is specified, it MUST be specified as X.Y.Z and diffs will be
* generated for (release before toApi) -> toApi. For example, 24.2.0 -> 25.0.0
* diffs could be generated by using:
*
* ./gradlew generateDiffs -PtoApi=25.0.0
*
*
* If only fromApi is specified, diffs will be generated for fromApi -> current.
* For example, lastApiReview -> current diffs could be generated by using:
*
* ./gradlew generateDiffs -PfromApi=lastApiReview
*
*
*/ task generateDiffs(type: JDiffTask, dependsOn: [configurations.jdiff, configurations.doclava, oldApiXml, newApiXml, generateDocs]) { // Base classpath is Android SDK, sub-projects add their own. classpath = project.ext.androidJar // JDiff properties. oldApiXmlFile = oldApiXml.outputApiXmlFile newApiXmlFile = newApiXml.outputApiXmlFile newJavadocPrefix = "../../../../reference/" String newApi = newApiXmlFile.name int lastDot = newApi.lastIndexOf('.') newApi = newApi.substring(0, lastDot) // Javadoc properties. docletpath = configurations.jdiff.resolve() destinationDir = new File(project.docsDir, "online/sdk/support_api_diff/$newApi") title = "Support Library API Differences Report" exclude '**/BuildConfig.java' exclude '**/R.java' } // configuration file for setting up api diffs and api docs void registerForDocsTask(Task task, Project subProject, releaseVariant) { task.dependsOn releaseVariant.javaCompile task.source { def buildConfig = fileTree(releaseVariant.getGenerateBuildConfig().sourceOutputDir) return releaseVariant.javaCompile.source.minus(buildConfig) + fileTree(releaseVariant.aidlCompile.sourceOutputDir) + fileTree(releaseVariant.outputs[0].processResources.sourceOutputDir) } task.classpath += files{releaseVariant.javaCompile.classpath.files} + files(releaseVariant.javaCompile.destinationDir) } // configuration file for setting up api diffs and api docs void registerJavaProjectForDocsTask(Task task, Project subProject, javaCompileTask) { task.dependsOn javaCompileTask task.source javaCompileTask.source task.classpath += files(javaCompileTask.classpath) + files(javaCompileTask.destinationDir) } subprojects { subProject -> subProject.afterEvaluate { p -> if (!p.hasProperty("noDocs") || !p.noDocs) { if (p.hasProperty('android') && p.android.hasProperty('libraryVariants')) { p.android.libraryVariants.all { v -> if (v.name == 'release') { registerForDocsTask(rootProject.generateDocs, p, v) registerForDocsTask(rootProject.generateApi, p, v) registerForDocsTask(rootProject.generateDiffs, p, v) } } } else if (p.hasProperty("compileJava")) { registerJavaProjectForDocsTask(rootProject.generateDocs, p, p.compileJava) } } } }