// declaration of plugins (1)['java','maven-publish'].each{applyplugin:it}group='com.yourdomain'version='1.0'repositories{mavenCentral()}dependencies{compile'org.apache.commons:commons-lang3:3.1'testCompile'junit:junit:4.11'}publishing{publications{myPublication(MavenPublication){// telling gradle to publish project's jar archive (2)fromcomponents.java// telling gradle to publish README file (2)artifact('README.txt'){classifier='README'extension='txt'}}}// telling gradle to publish artifact to local directory (3)repositories{maven{url"file:/${project.projectDir}/artifacts"}}}
With this script you can publish your artifact via this command.
build.gradle
1
$gradlepublish
Then you will find some file is generated at artifact directory.
These files are …
sample-project.jar
sample-project.jar.md5
sample-project.jar.sha1
sample-project.pom
sample-project.pom.md5
sample-project.pom.sha1
sample-project-README.txt
sample-project-README.txt.md5
sample-project-README.txt.sha1
Conventions
maven-publish plugin has some conventions.
base archive name is project name.
classifier is given after the project name.
extension is given after the project name and classifier.
classifier and extension should be unique in all artifacts in a publication.
Publishing javadoc and source code as jar
javadoc
Following shows the way to publish javadoc as jar.
call javadoc task.
create a task of zipping javadoc and call it.
give th zipping task to artifact method in publication container.
maven-publish plugin generates POM, but it lacks some elements required by Sonatype OSS repository. Folowing shows list of elements to be added.
<name> – the name of project
<description> – the description for the project
<url> – project’s url
<scm><url> – repository url.
<scm><connection> – repository url for scm tool. for example using git – github, it becomes scm:git:git://github.com/your-name/project-name.git
<scm><developerConnection> – repository url for scm tool via ssh. for example using git – github, it becomes scm:git:ssh:git@github.com:your-name/project-name.git
<licenses><license><name> – license name (i.e. The Apache Software License, Version 2.0 etc…). In the case of the project being licensed under multiple license, licenses elements can have multiple <license> elements.
<licenses><license><url> – license url (e.x. if the project is licensed under Apache version 2, it becomes http://www.apache.org/license/LICENSE-2.0.txt)
<licenses><license><distribution> – repo
<developers><developer><id> – developer’s id. If there are more than one developers, you can write <developer> elements more than one times.
publishing{publications{myPublication(MavenPublication){fromcomponents.javapom.withXml{asNode().children().last()+{resolveStrategy=Closure.DELEGATE_FIRSTname'project-name'description'description for project'urlprojectUrlscm{urlscmUrlconnectionconnectionUrldeveloperConnectiondeveloperConnectionUrl}licenses{license{name'The Apache Software License, Version 2.0'url'http://www.apache.org/license/LICENSE-2.0.txt'distribution'repo'}}developers{developer{id'your id or nick name'name'Your Name'email'your@mail.address'}}}}}}}
Signing Jar
To keep quality of maven central repo, signing files is required.
These files should be signed.
main jar (file name is project-name.jar.asc)
javadoc jar (file name is project-name-javadoc.jar.asc)
sources jar (file name is project-name-sources.jar.asc)
pom file (file name is project-name.pom.asc, on this signature this post will mention later)
// adding 'signing' pluginapplyplugin:'signing'// summarize artifactsartifacts{archivesjararchivessourceJararchivesjavadocJar}// sign all artifactstasksignJars(type:Sign,dependsOn:[jar,javadocJar,sourceJar]){signconfigurations.archives}// call signJar task before publish tasktaskpreparePublish(dependsOn:signJar)// extract signature file and give them proper namedefgetSignatureFiles={defallFiles=project.tasks.signJars.signatureFiles.collect{it}defsignedSources=allFiles.find{it.name.contains('-sources')}defsignedJavadoc=allFiles.find{it.name.contains('-javadoc')}defsignedJar=(allFiles-[signedSources,signedJavadoc])[0]return[[archive:signedSources,classifier:'sources',extension:'jar.asc'],[archive:signedJavadoc,classifier:'javadoc',extension:'jar.asc'],[archive:signedJar,classifier:null,extension:'jar.asc']]}publishing{publications{signatures(MavenPublication){// give signature files to rtifact methodgetSignatureFiles().each{signature->artifact(signature.archive){classifier=signature.classifierextension=signature.extension}}}}}
Signing POM
Before running publish task, there are no POM file, so calling signing POM task will fail. To avoid this, whether calling POM task or not is defined dynamicly. And writing POM is available writeTo(File) method via XmlProviderContainer (i.e. on the Closure block of pom.withXml)
ext{pomFilePath="${project.projectDir}/tmp/pom.xml"pomFile=file(pomFilePath)}configurations{pom}artifacts{archivesjararchivessourceJararchivesjavadocJarif(pomFile.exists()){pompomFile}}tasksignPom(type:Sign){signconfigurations.pom}defgetPomSignature={returnproject.tasks.signPom.signatureFiles.collect{it}[0]}if(project.ext.pomFile.exists()){taskpreparePublication(dependsOn:[signJars,signPom])}else{taskpreparePublication(dependsOn:signJars)}publishing{publications{jar(MavenPublication){// publishing main jarspom.withXml{// add required elements// here writing pom fileif(!project.ext.pomFile.exists()){writeTo(project.ext.pomFile)}}}gpgJars(MavenPublication){// publishing signature of jars}// dynamic publication definition// pom file does exist signature of pom file is publishedif(project.ext.pomFile.exists()){gpgPom(MavenPublication){artifact(getPomSignature()){classifier=nullextension='pom.asc'}}}}repositories{maven{if(project.ext.pomFile.exists()){urlsonatypeUrlcredentials{username=sonatypeUsernamepassword=sonatypePassword}}else{urlfileDirectory}}}}
and execute gradle tasks as follows
build.gradle
12
$gradlecleanpPpublish$gradlecleanpPpublish
You should execute gradle publish task twice.
The first execution is generating pom file and publishing som artifacts to machine’s directory.
The second execution is publishing pom signature to Sonatype OSS repository.
Please note…
publish task will execute publication tasks according to the alphabetiacl order of publishing task name. And each publication task will generate POM file. So please take care of publication name. The recomending name for publications is …
gpgJars – publish signatures of jar files.
gpgPom – publish signature of POM.
jar – publish all jars and POM.
Credential
You may know an account of Sonatype OSS is required to upload artifact into maven central repo. Here shows settings of sonatype account in maven-publish plugin.
['java','siging','maven-publish'].each{applyplguin:it}// project informationgroup='com.yourdomain'version='1.0'// dependency management as you likerepositories{mavenCentral()}dependencies{compile'org.apache.commons:commons-lang3:3.1'testCompile'junit:junit:4.11'}// javadoc.jar generationtaskjavadocJar(type:Jar,dependsOn:javadoc){// (1)classifier='javadoc'fromjavadoc.destinationDir}// sources.jar generationtasksourceJar(type:Jar){classifier='sources'fromsourceSets.main.allSource}// pom file nameext{pomFilePath="${project.projectDir}/tmp/pom.xml"pomFile=file(pomFilePath)}// add configuration for pom signingconfigurations{pom}// summarize artifactsartifacts{archivesjararchivessourceJararchivesjavadocJarif(pomFile.exists()){pompomFile}}// sign all artifactstasksignJars(type:Sign,dependsOn:[jar,javadocJar,sourceJar]){signconfigurations.archives}// sign pomtasksignPom(type:Sign){signconfigurations.pom}// defining which tasks should be calledif(project.ext.pomFile.exists()){taskpreparePublication(dependsOn:[signJars,signPom])}else{taskpreparePublication(dependsOn:signJars)}// extract signatures and add classifier and extension to themdefgetSignatureFiles={defallFiles=project.tasks.signJars.signatureFiles.collect{it}defsignedSources=allFiles.find{it.name.contains('-sources')}defsignedJavadoc=allFiles.find{it.name.contains('-javadoc')}defsignedJar=(allFiles-[signedSources,signedJavadoc])[0]return[[archive:signedSources,classifier:'sources',extension:'jar.asc'],[archive:signedJavadoc,classifier:'javadoc',extension:'jar.asc'],[archive:signedJar,classifier:null,extension:'jar.asc']]}// extract pom signaturedefgetPomSignature={returnproject.tasks.signPom.signatureFiles.collect{it}[0]}publishing{publicaitons{gpgJars(MavenPublication){getSignatureFiles().each{signature->artifact(signature.archive){classifier=signature.classifierextension=signature.extension}}}if(project.ext.pomFile.exists()){gpgPom(MavenPublication){artifact(getPomSignature()){classifier=nullextension='pom.asc'}}}jar(MavenPublication){fromcomponents.javapom.withXml{asNode().children().last()+{resolveStrategy=Closure.DELEGATE_FIRSTname'project-name'description'description for project'urlprojectUrlscm{urlscmUrlconnectionconnectionUrldeveloperConnectiondeveloperConnectionUrl}licenses{license{name'The Apache Software License, Version 2.0'url'http://www.apache.org/license/LICENSE-2.0.txt'distribution'repo'}}developers{developer{id'your id or nick name'name'Your Name'email'your@mail.address'}}}}}}repositories{if(project.ext.pomFile.exists()){url'https://oss.sonatype.org/service/local/staging/deploy/maven2/'credentials{username=sonatypeUsernamepassword=sonatypePassword}}else{urlfileDirectory}}}
and execute gradle tasks as follows
build.gradle
12
$gradlecleanpPpublish$gradlecleanpPpublish
… Eh? maven plugin is easier than this way? You, right!
But this plugin will become more smart, I believe.
@mike_neck You're doing cool stuff with 'maven-publish': latest gradle nightly has ability to set GAV of publication, too. Docs soon.