/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* .
*
*/
apply plugin: MvnWrapperPlugin
apply plugin: 'signing'
/////////////////////////// Release current state /////////////////////////////
Console console = System.console()
if (!console) {
throw new IllegalStateException("Console not available")
}
/////////////////////////// Repositories //////////////////////////////////////
// Only local Maven repo
repositories {
mavenLocal()
}
/////////////////////////// Release tasks /////////////////////////////////////
if (!HC_DEV) {
throw InvalidUserDataException("HC_DEV not set")
}
task checkoutSnapshot(type: SvnGet) {
group = 'Repository'
description = "Checks out development snapshot from '${HC_DEV}'."
repo = new URI(HC_DEV)
}
task updateSnapshot(type: SvnUpdate, dependsOn: checkoutSnapshot) {
group = 'Repository'
description = "Updates development snapshot from '${checkoutSnapshot.repo}'."
repo = checkoutSnapshot.repo
}
task revertSnapshot(type: SvnRevert, dependsOn: checkoutSnapshot) {
group = 'Repository'
description = "Reverts changes to the development snapshot."
repo = checkoutSnapshot.repo
}
File releaseVerFile = new File(project.buildDir, 'release-ver.txt')
File releaseTagFile = new File(project.buildDir, 'release-tag.txt')
File rcQualifierFile = new File(project.buildDir, 'rc-qualifier.txt')
File rcTagFile = new File(project.buildDir, 'rc-tag.txt')
File rcRevisionFile = new File(project.buildDir, 'rc-revision.txt')
File distRevisionFile = new File(project.buildDir, 'dist-revision.txt')
File releaseRevisionFile = new File(project.buildDir, 'release-revision.txt')
File distRelRevisionFile = new File(project.buildDir, 'dist-release-revision.txt')
File nextVerFile = new File(project.buildDir, 'next-ver.txt')
File nextVerRevisionFile = new File(project.buildDir, 'next-ver-revision.txt')
if (!rcTagFile.exists()) {
task buildSnapshot(dependsOn: checkoutSnapshot) {
group = 'Release'
description = "Compiles and builds snapshot artifacts."
inputs.files fileTree(dir: checkoutSnapshot.localDir, excludes:['**/target/**','**/.svn/**'])
outputs.files fileTree(dir: checkoutSnapshot.localDir, includes:['**/target/*.jar'])
doLast {
Svn.revert(checkoutSnapshot.localDir)
File pomFile = new File(checkoutSnapshot.localDir, 'pom.xml')
def pomModel = new XmlSlurper().parse(pomFile)
String artifactId = pomModel.artifactId
String version = pomModel.version
String name = getProductName(artifactId)
println "Building ${name} ${version}"
mvn.exec(checkoutSnapshot.localDir, 'clean', 'install')
}
}
}
task prepareRelease(dependsOn: checkoutSnapshot) {
group = 'Release'
description = "Prepares release based on development snapshot from ${checkoutSnapshot.repo}."
outputs.files files(releaseVerFile, releaseTagFile)
doLast {
File pomFile = new File(checkoutSnapshot.localDir, 'pom.xml')
def pomModel = new XmlSlurper().parse(pomFile)
String ver = pomModel.version
if (ver.endsWith('-SNAPSHOT')) {
ver = ver - '-SNAPSHOT'
}
String releaseVer = ver
console.println("Please enter release version: [defaults to ${releaseVer}]")
String s = console.readLine()
if (s) {
releaseVer = s
}
URI releaseTag = Release.rewriteAsReleaseTag(checkoutSnapshot.repo, releaseVer)
releaseVerFile.text = releaseVer
releaseTagFile.text = releaseTag.toASCIIString()
println "Release tag to be created: ${releaseTag}"
}
}
task restartRelease(dependsOn: checkoutSnapshot) {
group = 'Release'
description = "Re-starts release based on development snapshot from ${checkoutSnapshot.repo}."
doLast {
Svn.revert(checkoutSnapshot.localDir)
[releaseVerFile, releaseTagFile, rcQualifierFile, rcTagFile, rcRevisionFile,
releaseRevisionFile, distRevisionFile, distRelRevisionFile, nextVerFile,
nextVerRevisionFile].each { File file ->
GFileUtils.deleteQuietly(file)
}
}
}
task prepareRC(dependsOn: prepareRelease) {
group = 'Release'
description = "Prepares release candidate (RC) tag."
inputs.files files(releaseVerFile, releaseTagFile)
outputs.files files(rcQualifierFile, rcTagFile)
doLast {
String releaseVer = releaseVerFile.text.trim()
URI releaseTag = new URI(releaseTagFile.text.trim())
String rcQualifier = rcQualifierFile.exists() ? rcQualifierFile.text.trim() : 'RC1'
console.println("Please enter release candidate qualifier: [defaults to ${rcQualifier}]")
String s = console.readLine()
if (s) {
rcQualifier = s
}
URI rcTag = new URI(releaseTag.scheme, releaseTag.userInfo, releaseTag.host, releaseTag.port,
releaseTag.path + '-' + rcQualifier, null, null)
println "Rewriting POMs"
Release.rewritePom(checkoutSnapshot.localDir, releaseVer, releaseTag)
rcQualifierFile.text = rcQualifier
rcTagFile.text = rcTag.toASCIIString()
println "RC tag to be created: ${rcTag}"
}
}
task previewRC(type: SvnStatus, dependsOn: prepareRC) {
group = 'Release'
description = "Displays local changes for release candidate (RC) tag."
repo = checkoutSnapshot.repo
doFirst {
URI rcTag = new URI(rcTagFile.text.trim())
println "Local changes for ${rcTag}"
println "${checkoutSnapshot.localDir}"
}
}
task commitRCTag(dependsOn: prepareRC) {
group = 'Release'
description = "Commits release candidate (RC) tag."
inputs.files files(releaseVerFile, rcTagFile, rcQualifierFile)
outputs.files file(rcRevisionFile)
doLast {
String releaseVer = releaseVerFile.text.trim()
String rcQualifier = rcQualifierFile.text.trim()
URI rcTag = new URI(rcTagFile.text.trim())
File pomFile = new File(checkoutSnapshot.localDir, 'pom.xml')
def pomModel = new XmlSlurper().parse(pomFile)
String artifactId = pomModel.artifactId
String name = getProductName(artifactId)
println "Creating tag for ${name} ${releaseVer} ${rcQualifier} from local content"
long revision = Svn.copyLocal(checkoutSnapshot.localDir, rcTag, "${name} ${releaseVer} ${rcQualifier} tag")
println ""
rcRevisionFile.text = revision
}
}
if (!HC_DIST_STAGING) {
throw InvalidUserDataException("HC_DIST_STAGING not set")
}
task checkoutDistStage(type: SvnGet) {
group = 'Repository'
description = "Checks out dist staging from '${HC_DIST_STAGING}'."
repo = new URI(HC_DIST_STAGING)
}
task updateDistStage(type: SvnUpdate, dependsOn: checkoutDistStage) {
group = 'Repository'
description = "Checks out dist staging from '${checkoutDistStage.repo}'."
repo = checkoutDistStage.repo
}
task revertDistStage(type: SvnRevert, dependsOn: checkoutDistStage) {
group = 'Repository'
description = "Reverts changes to the development snapshot."
repo = checkoutDistStage.repo
}
if (rcTagFile.exists() && rcRevisionFile.exists()) {
task checkoutRC(type: SvnGet) {
group = 'Repository'
description = "Checks out RC."
repo = new URI(rcTagFile.text.trim())
}
task buildRC(dependsOn: checkoutRC) {
group = 'Release'
description = "Compiles and builds RC artifacts."
inputs.files fileTree(dir: checkoutRC.localDir, excludes:['**/target/**','**/.svn/**'])
outputs.files fileTree(dir: checkoutRC.localDir, includes:['**/target/*.jar'])
doLast {
String releaseVer = releaseVerFile.text.trim()
String rcQualifier = rcQualifierFile.text.trim()
File pomFile = new File(checkoutRC.localDir, 'pom.xml')
def pomModel = new XmlSlurper().parse(pomFile)
String artifactId = pomModel.artifactId
String name = getProductName(artifactId)
println "Building ${name} ${releaseVer} based on ${rcQualifier}"
mvn.exec(checkoutRC.localDir, 'install', 'site')
}
}
File dir = checkoutRC.localDir
if (dir.exists() && file("${dir}/target").exists()) {
task locateRC(dependsOn: buildRC) {
group = 'Release'
description = "Displays RC location."
doLast {
String releaseVer = releaseVerFile.text.trim()
String rcQualifier = rcQualifierFile.text.trim()
File pomFile = new File(checkoutRC.localDir, 'pom.xml')
def pomModel = new XmlSlurper().parse(pomFile)
String artifactId = pomModel.artifactId
String name = getProductName(artifactId)
println "Please deploy ${name} ${releaseVer} based on ${rcQualifier} " +
"from the following directory using 'mvn deploy -Prelease'"
println checkoutRC.localDir
}
}
task deployRC(dependsOn: buildRC) {
group = 'Release'
description = "Deploys RC artifacts to Apache staging repository."
doLast {
String releaseVer = releaseVerFile.text.trim()
String rcQualifier = rcQualifierFile.text.trim()
File pomFile = new File(checkoutRC.localDir, 'pom.xml')
def pomModel = new XmlSlurper().parse(pomFile)
String artifactId = pomModel.artifactId
String name = getProductName(artifactId)
println "Deploying ${name} ${releaseVer} based on ${rcQualifier}"
mvn.exec(checkoutRC.localDir, 'deploy', '-Prelease')
}
}
Pom pom = Mvn.parsePom(dir)
Configuration binCfg = project.configurations.create('rc')
// Declare dependencies (excluding OSGi bundle)
pom.modules.each { PomModule submodule ->
if (!submodule.name.endsWith('-osgi')) {
project.dependencies.add(
binCfg.name,
['group': submodule.artifact.groupId, 'name': submodule.artifact.id, 'version': submodule.artifact.version])
}
}
configurations {
dist
}
task distWinBin(type: Zip) {
with docs(dir, pom, Line.CRLF), atrifacts(configurations.rc)
into "${getPackageName(pom.artifactId)}-${pom.version}"
classifier = 'bin'
}
task distUxBin(type: Tar) {
with docs(dir, pom, Line.LF), atrifacts(configurations.rc)
into "${getPackageName(pom.artifactId)}-${pom.version}"
classifier = 'bin'
}
task distWinOSGiBin(type: Zip) {
with docs(dir, pom, Line.CRLF), osgiBundle(dir, pom)
into "${getPackageName(pom.artifactId)}-${pom.version}"
classifier = 'osgi-bin'
}
task distUxOSGiBin(type: Tar) {
with docs(dir, pom, Line.LF), osgiBundle(dir, pom)
into "${getPackageName(pom.artifactId)}-${pom.version}"
classifier = 'osgi-bin'
}
task distWinSrc(type: Zip) {
with sources(dir, pom, Line.CRLF)
into "${getPackageName(pom.artifactId)}-${pom.version}"
classifier = 'src'
}
task distUxSrc(type: Tar) {
with sources(dir, pom, Line.LF)
into "${getPackageName(pom.artifactId)}-${pom.version}"
classifier = 'src'
}
String rcQualifier = rcQualifierFile.text.trim()
String rcName = getProductName(pom.artifactId).toLowerCase(Locale.ROOT)
String rcFullName = "${rcName}-${pom.version}-${rcQualifier}"
String releaseNotes = "RELEASE_NOTES-${pom.major}.${pom.minor}.x.txt"
tasks.withType(AbstractArchiveTask) { AbstractArchiveTask archive ->
archive.dependsOn checkoutDistStage
archive.baseName = getPackageName(pom.artifactId)
archive.version = pom.version
archive.destinationDir = file("${checkoutDistStage.localDir}/${rcFullName}")
}
tasks.withType(Tar) { Tar tar ->
tar.extension = "tar.gz"
tar.compression = Compression.GZIP
}
tasks.withType(Tar) { Tar tar ->
tar.extension = "tar.gz"
tar.compression = Compression.GZIP
}
task sign(type: Sign, dependsOn: checkoutDistStage) {
sign configurations.dist
}
task digest(type: Digest, dependsOn: checkoutDistStage) {
digest configurations.dist
}
task docs(type: Copy, dependsOn: checkoutDistStage) {
from "${checkoutRC.localDir}/RELEASE_NOTES.txt"
into "${checkoutDistStage.localDir}/${rcFullName}"
rename { releaseNotes }
}
artifacts {
tasks.withType(AbstractArchiveTask) { AbstractArchiveTask archive ->
dist archive
}
sign.signatures.each { PublishArtifact artifact ->
archives artifact
}
digest.hashes.each { PublishArtifact artifact ->
archives artifact
}
archives(new File(docs.destinationDir, releaseNotes)) {
classifier = 'doc'
}
}
assemble.dependsOn = [sign, digest, docs]
}
task prepareDist(dependsOn: assemble) {
group = 'Release'
description = "Prepares and stages release dist packages based on RC."
doLast {
Svn.scheduleForAddition(checkoutDistStage.localDir)
}
}
task previewDist(type: SvnStatus, dependsOn: prepareDist) {
group = 'Release'
description = "Displays local changes for staged release dist packages."
repo = checkoutDistStage.repo
doFirst {
println "Local changes for release dist ${checkoutDistStage.repo}"
println "${checkoutDistStage.localDir}"
}
}
task commitDist(dependsOn: prepareDist) {
group = 'Release'
description = "Commits staged release dist packages."
inputs.files files(releaseVerFile, rcTagFile, rcQualifierFile)
outputs.files file(distRevisionFile)
doLast {
String releaseVer = releaseVerFile.text.trim()
String rcQualifier = rcQualifierFile.text.trim()
File pomFile = new File(checkoutSnapshot.localDir, 'pom.xml')
def pomModel = new XmlSlurper().parse(pomFile)
String artifactId = pomModel.artifactId
String name = getProductName(artifactId)
println "Committing ${name} ${releaseVer} ${rcQualifier} dist packages to the staging repo"
long revision = Svn.commit(checkoutDistStage.localDir, "${name} ${releaseVer} ${rcQualifier} dist")
println ""
distRevisionFile.text = revision
}
}
task cancelRC(dependsOn: checkoutDistStage) {
group = 'Release'
description = "Cancels current RC."
doLast {
String releaseVer = releaseVerFile.text.trim()
String rcQualifier = rcQualifierFile.text.trim()
File pomFile = new File(checkoutSnapshot.localDir, 'pom.xml')
def pomModel = new XmlSlurper().parse(pomFile)
String artifactId = pomModel.artifactId
String rcName = getProductName(artifactId).toLowerCase(Locale.ROOT)
String rcFullName = "${rcName}-${releaseVer}-${rcQualifier}"
if (distRevisionFile.exists()) {
println "Removing ${name} ${releaseVer} ${rcQualifier} dist packages from repository"
URI distUri = new URI("${checkoutDistStage.repo.toASCIIString()}${rcFullName}")
Svn.deleteRemote(distUri, "Removed ${rcFullName} dist")
}
if (rcQualifier) {
def m = rcQualifier =~ 'RC(\\d)'
if (m.find()) {
int n = Integer.parseInt(m.group(1))
rcQualifier = 'RC' + (++n)
}
}
if (!rcQualifier) {
rcQualifier = 'RC1'
}
GFileUtils.deleteQuietly(rcQualifierFile)
GFileUtils.deleteQuietly(rcTagFile)
GFileUtils.deleteQuietly(rcRevisionFile)
GFileUtils.deleteQuietly(distRevisionFile)
rcQualifierFile.text = rcQualifier
}
}
if (distRevisionFile.exists()) {
task prepareVote(dependsOn: checkoutRC) {
group = 'Release'
description = "Generates release vote message content."
doLast {
Pom pom = Mvn.parsePom(checkoutRC.localDir)
String name = "${getProductName(pom.artifactId)}"
String rcQualifier = rcQualifierFile.text.trim()
String rcName = getProductName(pom.artifactId).toLowerCase(Locale.US)
String rcFullName = "${rcName}-${pom.version}-${rcQualifier}"
String releaseNotes = "RELEASE_NOTES-${pom.major}.${pom.minor}.x.txt"
URI rcTag = new URI(rcTagFile.text.trim())
String rcRevision = rcRevisionFile.text.trim()
String distRevision = distRevisionFile.text.trim()
String releaseVer = pom.version
println '----------------8<-------------[ cut here ]------------------'
println "[VOTE] Release ${name} ${releaseVer} based on ${rcQualifier}"
println ""
println "Please vote on releasing these packages as ${name} ${releaseVer}."
println "The vote is open for the at least 72 hours, and only votes from"
println "HttpComponents PMC members are binding. The vote passes if at least"
println "three binding +1 votes are cast and there are more +1 than -1 votes."
println ""
println "Release notes:"
println " ${checkoutDistStage.repo}${rcFullName}/${releaseNotes}"
println ""
println "Maven artefacts:"
println " [link]"
println ""
println "SVN tag:"
println " ${rcTag}"
println " revision ${rcRevision}"
println ""
println "Packages:"
println " ${checkoutDistStage.repo}${rcFullName}"
println " revision ${distRevision}"
println ""
println "Hashes:"
digest.hashes.each { PublishArtifact artifact ->
println " ${artifact.file.text} ${artifact.toDigestArtifact.file.name}"
}
println ""
println "Keys:"
println " http://www.apache.org/dist/httpcomponents/${rcName}/KEYS"
println ""
println "--------------------------------------------------------------------------"
println "Vote: ${name} ${releaseVer} release"
println "[ ] +1 Release the packages as ${name} ${releaseVer}."
println "[ ] -1 I am against releasing the packages (must include a reason)."
println '----------------8<-------------[ cut here ]------------------'
}
}
}
task svnmucc(dependsOn: checkoutRC) {
group = 'Release'
description = "Generates svnmucc command file."
doLast {
Pom pom = Mvn.parsePom(checkoutRC.localDir)
String rcQualifier = rcQualifierFile.text.trim()
String rcName = getProductName(pom.artifactId).toLowerCase(Locale.US)
String rcFullName = "${rcName}-${pom.version}-${rcQualifier}"
String releaseNotes = "RELEASE_NOTES-${pom.major}.${pom.minor}.x.txt"
println 'svnmucc file'
println '----------------8<-------------[ cut here ]------------------'
println "rm"
println "release/httpcomponents/${rcName}/${releaseNotes}"
println ""
Configuration cfg = configurations.archives
cfg.artifacts.each { PublishArtifact artifact ->
println "mv"
println "dev/httpcomponents/${rcFullName}/${artifact.file.name}"
switch(artifact.classifier) {
case ~/^(osgi-)?bin/:
println "release/httpcomponents/${rcName}/binary/${artifact.file.name}"
break
case "src":
println "release/httpcomponents/${rcName}/source/${artifact.file.name}"
break
default:
println "release/httpcomponents/${rcName}/${artifact.file.name}"
break
}
println ""
}
println "rm"
println "dev/httpcomponents/${rcFullName}"
println '----------------8<-------------[ cut here ]------------------'
}
}
task promoteRC(dependsOn: checkoutRC) {
group = 'Release'
description = "Promotes RC to official release."
inputs.files files(releaseVerFile, rcQualifierFile, releaseTagFile, rcTagFile)
outputs.files file(releaseRevisionFile)
doLast {
String releaseVer = releaseVerFile.text.trim()
String rcQualifier = rcQualifierFile.text.trim()
URI releaseTag = new URI(releaseTagFile.text.trim())
URI rcTag = new URI(rcTagFile.text.trim())
File pomFile = new File(checkoutRC.localDir, 'pom.xml')
def pomModel = new XmlSlurper().parse(pomFile)
String artifactId = pomModel.artifactId
String name = getProductName(artifactId)
println "Promoting ${name} ${releaseVer} ${rcQualifier } to official release"
println "Copying ${rcTag} to ${releaseTag}"
long revision = Svn.copyRemote(rcTag, releaseTag, "${name} ${releaseVer} release tag")
releaseRevisionFile.text = revision
}
}
task promoteDist(dependsOn: checkoutRC) {
group = 'Release'
description = "Promotes dist packages."
inputs.files files(releaseVerFile, rcQualifierFile)
outputs.files file(distRelRevisionFile)
doLast {
Pom pom = Mvn.parsePom(checkoutRC.localDir)
String releaseVer = releaseVerFile.text.trim()
String rcQualifier = rcQualifierFile.text.trim()
String name = getProductName(pom.artifactId)
String rcName = name.toLowerCase(Locale.US)
String rcFullName = "${rcName}-${pom.version}-${rcQualifier}"
String releaseNotes = "RELEASE_NOTES-${pom.major}.${pom.minor}.x.txt"
String root = "$HC_DIST_STAGING"
if (!root.endsWith('/')) {
root = root + '/'
}
root = root - 'dev/httpcomponents/'
List bulkOps = []
bulkOps.add(new SvnBulkOp.Rm(new File("release/httpcomponents/${rcName}/${releaseNotes}")))
Configuration cfg = configurations.archives
cfg.artifacts.each { PublishArtifact artifact ->
File src = new File("dev/httpcomponents/${rcFullName}/${artifact.file.name}")
File dst
switch(artifact.classifier) {
case ~/^(osgi-)?bin/:
dst = new File("release/httpcomponents/${rcName}/binary/${artifact.file.name}")
break
case "src":
dst = new File("release/httpcomponents/${rcName}/source/${artifact.file.name}")
break
default:
dst = new File("release/httpcomponents/${rcName}/${artifact.file.name}")
break
}
bulkOps.add(new SvnBulkOp.CpFile(dst, src))
bulkOps.add(new SvnBulkOp.Rm(src))
}
bulkOps.add(new SvnBulkOp.Rm(new File("dev/httpcomponents/${rcFullName}")))
long revision = Svn.mucc(new URI(root), bulkOps, "${name} ${releaseVer} release dist")
distRelRevisionFile.text = revision
}
}
}
if (releaseTagFile.exists() && releaseRevisionFile.exists()) {
task prepareNextVersion(dependsOn: checkoutSnapshot) {
group = 'Release'
description = "Prepares next development version."
inputs.files file(releaseVerFile)
outputs.files file(nextVerFile)
doLast {
String releaseVer = releaseVerFile.text.trim()
String nextVer = Release.upgradeVersion(releaseVer)
console.println("Please enter new development version: [defaults to ${nextVer}]")
String s = console.readLine()
if (s) {
nextVer = s
}
if (!nextVer.endsWith('-SNAPSHOT')) {
nextVer = nextVer + '-SNAPSHOT'
}
Release.rewritePom(checkoutSnapshot.localDir, nextVer, checkoutSnapshot.repo)
nextVerFile.text = nextVer
}
}
task previewNextVersion(type: SvnStatus, dependsOn: prepareNextVersion) {
group = 'Release'
description = "Displays local changes for next development version."
repo = checkoutSnapshot.repo
doFirst {
String nextVer = nextVerFile.text.trim()
println "Next development version: ${nextVer}"
println "${checkoutSnapshot.localDir}"
}
}
task commitNextVersion(dependsOn: prepareNextVersion) {
group = 'Release'
description = "Commits next development version."
inputs.files file(nextVerFile)
outputs.files file(nextVerRevisionFile)
doLast {
String nextVer = nextVerFile.text.trim()
File pomFile = new File(checkoutSnapshot.localDir, 'pom.xml')
def pomModel = new XmlSlurper().parse(pomFile)
String artifactId = pomModel.artifactId
String name = getProductName(artifactId)
println "Committing changes to upgrade ${name} to version ${nextVer}"
long revision = Svn.commit(checkoutSnapshot.localDir, "Upgraded ${name} version to ${nextVer}")
println ""
nextVerRevisionFile.text = revision
}
}
}
/////////////////////////// Copy specs ////////////////////////////////////////
CopySpec docs(File dir, Pom pom, String delim) {
CopySpec spec = copySpec {
from (dir) {
include 'README.txt'
include 'LICENSE.txt'
include 'NOTICE.txt'
include 'RELEASE_NOTES.txt'
filter(Line.delim(delim), Line.filter())
}
from ("${dir}/target/site/apidocs") {
into 'javadoc'
}
from ("${dir}/target/site/tutorial") {
into 'tutorial'
}
}
pom.modules.each { PomModule submodule ->
spec.from ("${dir}/${submodule.name}/target/site/examples") {
into 'examples'
filter(Line.delim(delim), Line.filter())
}
}
spec
}
CopySpec atrifacts(Configuration cfg) {
CopySpec spec = copySpec {
into 'lib'
}
cfg.resolvedConfiguration.resolvedArtifacts.each { ResolvedArtifact artifact ->
spec.from(artifact.file.absolutePath) {
include artifact.file.name
}
}
spec
}
CopySpec osgiBundle(File dir, Pom pom) {
CopySpec spec = copySpec {
}
pom.modules.each { PomModule submodule ->
if (submodule.name.endsWith('-osgi')) {
spec.from("${dir}/${submodule.name}/target") {
include "*.jar"
exclude "*-sources.jar"
exclude "*-javadoc.jar"
}
}
}
spec
}
CopySpec sources(File dir, Pom pom, String delim) {
copySpec {
from (dir) {
include '**/src/**'
include '**/*.txt'
include '**/*.xml'
include '**/*.yml'
include '**/*.md'
include '**/*.rdf'
include '**/docker/**'
exclude '**/resources/**/*.keystore'
exclude '**/resources/**/*.truststore'
exclude '**/resources/**/*.png'
exclude '**/resources/**/*.jpg'
exclude '**/resources/**/*.gif'
exclude '**/bin/**'
exclude '**/target/**'
exclude '**/build/**'
exclude '**/lib/**'
filter(Line.delim(delim), Line.filter())
}
from (dir) {
include '**/resources/**/*.keystore'
include '**/resources/**/*.truststore'
include '**/resources/**/*.png'
include '**/resources/**/*.jpg'
include '**/resources/**/*.gif'
exclude '**/bin/**'
exclude '**/target/**'
exclude '**/build/**'
exclude '**/lib/**'
}
}
}
/////////////////////////// Website publishing ////////////////////////////////
URI websiteURI = new URI(HC_PROJECT_SITE)
task checkoutMainWebsite(type: SvnGet) {
group = 'Repository'
description = "Checks out main website source from '${websiteURI}'."
repo = websiteURI
}
task updateMainWebsite(type: SvnUpdate, dependsOn: checkoutMainWebsite) {
group = 'Repository'
description = "Update main website source from '${websiteURI}'."
repo = checkoutMainWebsite.repo
}
task generateMainWebsite(dependsOn: checkoutMainWebsite) {
group = 'Website generation'
description = "Generates main website content."
inputs.files fileTree(dir:checkoutMainWebsite.localDir, excludes:['**/target/**','**/.svn/**'])
outputs.files fileTree(dir:checkoutMainWebsite.localDir, includes:['**/target/site/**'])
doLast {
mvn.exec(checkoutMainWebsite.localDir, 'clean', 'install', 'site')
}
}
task checkoutFullWebsite(dependsOn: checkoutMainWebsite) {
group = 'Repository'
description = "Checks out full website source including published releases."
}
task generateFullWebsite(dependsOn: generateMainWebsite) {
group = 'Website generation'
description = "Generates full website content including published releases."
}
Set uris = HC_PUBLISHED_RELEASES ?
HC_PUBLISHED_RELEASES.split(/[ \t]+/).collect { new URI(it) } : []
if (releaseTagFile.exists() && nextVerRevisionFile.exists()) {
uris.add(new URI(releaseTagFile.text))
}
if (!uris.empty) {
uris.eachWithIndex { URI uri, int idx ->
task "checkoutPublishedRelease${idx + 1}" (type: SvnGet) {
group = 'Repository'
description = "Checks out published release from '${uri}'."
repo = uri
}
task "generatePublishedRelease${idx + 1}" {
group = 'Website generation'
description = "Generates published release content from '${uri}'."
SvnGet svnget = tasks["checkoutPublishedRelease${idx + 1}"]
dependsOn checkoutMainWebsite, svnget
inputs.files fileTree(dir: svnget.localDir, excludes:['**/target/**','**/.svn/**'])
outputs.files fileTree(dir :svnget.localDir, includes:['**/target/site/**'])
doLast {
// Rewrite POM's parent
Pom mainWebsite = mvn.parsePom(checkoutMainWebsite.localDir)
Release.rewritePomParent(svnget.localDir, mainWebsite)
// Generate content
mvn.exec(svnget.localDir, 'clean', 'site')
// Revert
Svn.revert(svnget.localDir)
}
}
}
checkoutFullWebsite.dependsOn {
tasks.findAll { Task task -> task.name.startsWith('checkoutPublishedRelease') }
}
generateFullWebsite.dependsOn {
tasks.findAll { Task task -> task.name.startsWith('generatePublishedRelease') }
}
}
if (!HC_SITE_STAGING) {
throw InvalidUserDataException("HC_SITE_STAGING not set")
}
task checkoutSiteStage(type: SvnGet) {
group = 'Repository'
description = "Checks out website content from ${HC_SITE_STAGING} to a local stage."
repo = new URI(HC_SITE_STAGING)
}
task updateSiteStage(type: SvnUpdate, dependsOn: checkoutSiteStage) {
group = 'Repository'
description = "Update website content stage from ${checkoutSiteStage.repo}."
repo = checkoutSiteStage.repo
}
task siteStage(dependsOn: [checkoutSiteStage, generateFullWebsite]) {
group = 'Website generation'
description = "Copies generated website content to local stage."
doLast {
tasks.withType(SvnGet) { SvnGet releaseCheckout ->
if (releaseCheckout.name.startsWith('checkoutPublishedRelease')) {
Pom releasePom = Mvn.parsePom(releaseCheckout.localDir)
String releaseSeries = "${getPackageName(releasePom.artifactId)}-${releasePom.major}.${releasePom.minor}.x"
String releaseStaging = "${checkoutSiteStage.localDir}/${releaseSeries}"
println("Copying content of release ${getPackageName(releasePom.artifactId)}:${releasePom.version} to ${releaseStaging}")
copy {
into "${checkoutSiteStage.localDir}/${releaseSeries}"
with siteContent(releaseCheckout.localDir)
}
releasePom.modules.each { PomModule submodule ->
println("Copying content of release module ${submodule.name}:${releasePom.version} to ${releaseStaging}/${submodule.name}")
copy {
into "${checkoutSiteStage.localDir}/${releaseSeries}/${submodule.name}"
with siteContent(file("${releaseCheckout.localDir}/${submodule.name}"))
}
}
fixLinks(releasePom, file(releaseStaging))
rewriteSiteCss(releasePom, file(releaseStaging))
}
}
Pom websitePom = Mvn.parsePom(checkoutMainWebsite.localDir)
println("Copying content of ${websitePom.artifactId}:${websitePom.version} to ${checkoutSiteStage.localDir}")
copy {
into checkoutSiteStage.localDir
with siteContent(checkoutMainWebsite.localDir)
}
Svn.scheduleForAddition(checkoutSiteStage.localDir)
}
}
task revertSiteStage(type: SvnRevert, dependsOn: checkoutSiteStage) {
group = 'Repository'
description = "Revert changes to website content stage."
repo = checkoutSiteStage.repo
}
task previewSiteStage(type: SvnStatus, dependsOn: checkoutSiteStage) {
group = 'Website generation'
description = "Displays local changes for project website."
repo = checkoutSiteStage.repo
doFirst {
println "Local changes for project website"
println "${checkoutSiteStage.localDir}"
}
}
task commitSiteStage(dependsOn: checkoutSiteStage) {
group = 'Repository'
description = "Commit changes from website content stage to ${HC_SITE_STAGING}."
doLast {
console.println("Please enter commit message:")
String message = console.readLine()
if (message) {
message = "Updated project website"
}
Svn.commit(checkoutSiteStage.localDir, message)
}
}
/////////////////////////// Helper utilities //////////////////////////////////
void fixLinks(Pom pom, File dstDir) {
// Deal with crappy links generated by Maven Site Plugin
project.fileTree(dir: dstDir, include: '*.html').each {
File f ->
Html.rewriteLinks(f, { URI href, String localName ->
if (!href.isAbsolute()) {
def m1 = href.path =~ /^..(\/..\/scp:\/people.apache.org\/www)?\/hc.apache.org\//
if (m1.find()) {
return new URI(m1.replaceFirst('../'))
}
}
return href
})
}
pom.modules.each { PomModule submodule ->
project.fileTree(dir: new File(dstDir, submodule.name), include: '*.html').each {
File f ->
Html.rewriteLinks(f, { URI href, String localName ->
if (!href.isAbsolute()) {
def m1 = href.path =~ /^..\/..(\/..\/scp:\/people.apache.org\/www)?\/hc.apache.org\//
if (m1.find()) {
return new URI(m1.replaceFirst('../../'))
}
if (href.path == '../images/logos/httpcomponents.png') {
return new URI('../../images/logos/httpcomponents.png')
}
}
return href
})
}
}
}
void rewriteSiteCss(Pom pom, File dstDir) {
File siteCss = new File(dstDir, 'css/site.css')
if (siteCss.exists()) {
siteCss.withWriter { Writer w ->
w << '@import url("../../css/hc-maven.css");'
}
}
pom.modules.each { PomModule submodule ->
File moduleDstDir = new File(dstDir, submodule.name)
File moduleSiteCss = new File(moduleDstDir, 'css/site.css')
if (moduleSiteCss.exists()) {
moduleSiteCss.withWriter { Writer w ->
w << '@import url("../../../css/hc-maven.css");'
}
}
}
}
/////////////////////////// Copy specs ////////////////////////////////////////
CopySpec siteContent(File dir) {
copySpec {
from ("${dir}/target/site") {
exclude '**/*.html'
}
from ("${dir}/target/site") {
include '**/*.html'
filter(Line.filter())
}
}
}
/////////////////////////// Post-init configuration ////////////////////////////////////////
def askPassphrase = {
String password = project.ext.has('signing.password') ? project.ext.'signing.password' : null
String keyId = project.ext.has('signing.keyId') ? project.ext.'signing.keyId' : null
if (keyId && !password) {
char[] raw = console.readPassword("\n> Please provide password for PGP key ${keyId}: ")
project.ext.'signing.password' = new String(raw)
}
}
gradle.taskGraph.whenReady { TaskExecutionGraph taskGraph ->
taskGraph.allTasks.findAll { Task task -> task instanceof Sign }.each { Sign task ->
task.doFirst { askPassphrase() }
}
}
/////////////////////////// Helper utilities //////////////////////////////////
String getPackageName(String artifactId) {
def packageNameMap = [
'httpcore5-parent':'httpcomponents-core',
'httpclient5-parent':'httpcomponents-client'
]
String s = packageNameMap[artifactId]
s ? s : artifactId
}
String getProductName(String artifactId) {
def projectNameMap = [
'httpcore5-parent':'HttpCore',
'httpclient5-parent':'HttpClient',
'httpcomponents-core':'HttpCore',
'httpcomponents-client':'HttpClient',
'httpcomponents-asyncclient':'HttpAsyncClient'
]
String s = projectNameMap[artifactId]
s ? s : artifactId
}