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