Creating a maven wrapper pom.xml from gradle: can't create the <build> element - gradle

How do I set the sourceDirectory, testSourceDirectory and build plugins in a pom.xml that I'm creating using the gradle maven-plugin's pom DSL?
When I add build without a Closure to my DSL section, it's ok.. but when I add build { /* anything else, like actual compile plugins */} it gives me this error:
Execution failed for task ':mavenWrapper'.
> No such property: _SCRIPT_CLASS_NAME_ for class: org.apache.maven.model.Model
I'm guessing that gradle is treating build as the task rather than the DSL verb generated by org.sonatype.maven.polyglot.groovy.builder.ModelBuilder.
Is there a way to force build to be treated as part of the DSL? Can it be cast or something?
Right now I'm working around this by using .withXml but it's massively verbose and much less maintainable.
Here's an abbreviated version of what I've got working:
task mavenWrapper {
doLast {
delete 'pom.xml', 'mvnw', 'mvnw.cmd'
pom {
project {
packaging 'pom'
repositories {
repository {
id 'spring-milestones'
name 'Spring Milestones'
url 'https://repo.spring.io/libs-milestone'
snapshots {
enabled 'false'
}
}
}
properties {
'kotlin.compiler.incremental' 'true'
}
/* ******** Problem is here
build {
plugins {
plugin {
// ... etc. etc.
}
}
}
******* */
dependencyManagement {
dependencies {
dependency {
groupId 'org.jetbrains.kotlin'
artifactId 'kotlin-stdlib-jre8'
version "${kotlin_version}"
scope 'compile'
}
}
}
}
}.withXml {
// Workaround for the missing build { ... } section above.
asNode().appendNode('build').appendNode('plugins')
// etc. etc.
}.writeTo("${projectDir}/pom.xml")
exec {
commandLine 'mvn', '-N', 'io.takari:maven:wrapper', '-Dmaven=3.5.0'
}
}
}

Related

Use of Gradle Plugin in external .gradle file

Background:
I'm trying to use the gradle-dependency-graph-generator-plugin in a gradle build, and configure it with custom Generator configurations. When I place the configuration within the _root.gradle, our root gradle project:
buildscript {
repositories {
maven {
url artifactoryRepoURL + '/repo'
}
}
dependencies {
//...
classpath "com.vanniktech:gradle-dependency-graph-generator-plugin:0.5.0"
}
}
//...
allprojects {
//...
apply plugin: "com.vanniktech.dependency.graph.generator"
//...
}
...it works just fine. (Though, Intellij reports errors in the import, it builds and runs both on command line and in the IDE)
The Problem
I'd like to put this code in a separate gradle file, just so it's not cluttering up the root project. So I move the code to a dependencyGraph.gradle file, and include it with an
apply from: "$rootProject.projectDir/dependencyGraph.gradle"
However, I get compilation errors, class not found. So I add the buildScript and dependencies/classpath from the root project file, and try again. This time, it gives a class cast exception:
com.vanniktech.dependency.graph.generator.DependencyGraphGeneratorExtension$Generator cannot be cast to com.vanniktech.dependency.graph.generator.DependencyGraphGeneratorExtension$Generator
Its the same classname, so I assume this is some kind of classloader problem. So, how does one include a build script that references plugin classes into a project.gradle?
EDIT:
Per – #EugenMartynov 's comment, the file looks like:
buildscript {
repositories {
maven {
url artifactoryRepoURL + '/repo'
}
}
dependencies {
classpath "com.vanniktech:gradle-dependency-graph-generator-plugin:0.5.0"
}
}
import com.vanniktech.dependency.graph.generator.DependencyGraphGeneratorPlugin
import com.vanniktech.dependency.graph.generator.DependencyGraphGeneratorExtension.Generator
import guru.nidi.graphviz.attribute.Color
import guru.nidi.graphviz.attribute.Style
import guru.nidi.graphviz.attribute.Label
def updateNode(node, dependency) {
def group = dependency.getModuleGroup()
def colorCodeFor = { starts, color ->
if (group.startsWith(starts)) {
node.add(Style.FILLED, Color.rgb(color))
return color
}
return null
}
def color = colorCodeFor("commons", "#ff008c")
?: colorCodeFor("org.apache", "#ff008c")
?: colorCodeFor("org.springframework", "#6db33f")
?: colorCodeFor("javax", "#ff0000")
?: colorCodeFor("com.fasterxml", "#3a772e")
?: colorCodeFor("ch.qos.logback", "#ffd0a0")
?: colorCodeFor("", String.format("#%06x", Math.abs(group.hashCode()) % (255*255*255))) // base off the group
return node
}
def colorCodedGenerator = new Generator(
"ColorCoded", // Suffix for our Gradle task.
{ dependency -> true }, // filter
{ dependency -> true }, // Include transitive dependencies.
{ node, dependency -> updateNode(node, dependency) }, // Give them some color.
{ node, project ->node.add(Style.FILLED, Color.rgb("#2cc2e4")) }, // project nodes.
)
dependencyGraphGenerator {
generators = [ Generator.ALL, colorCodedGenerator ]
}
and is applied within the allprojects block:
allprojects {
...
apply plugin: "com.vanniktech.dependency.graph.generator"
apply from: "$rootProject.projectDir/dependencyGraph.gradle"
...
}
though I also tried only within the root project. As configured, I get:
FAILURE: Build failed with an exception.
...
* What went wrong:
A problem occurred configuring root project 'dar'.
> com.vanniktech.dependency.graph.generator.DependencyGraphGeneratorExtension$Generator cannot be cast to com.vanniktech.dependency.graph.generator.DependencyGraphGeneratorExtension$Generator
This is gradle 4.9, btw

Gradle dependency resolution strategy with maven deployer

I am working on an android project. We are using the DependencyResoultionStrategy to swap some dependency versions. The code looks like this:
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
final version = getVersionForDependency(project, details.requested.group, details.requested.name)
if (version != null) {
details.useVersion(version)
}
}
So for example, the project requests the dependency group:name:1.1.2 but it is swapped so the dependency group:name:1.2.0 is used. This works perfectly and the project is built with the right dependency (the second one).
We also have a publish task, which deploys the project to a local maven repository. We use the maven plugin for this, the code looks like this:
apply plugin: 'maven'
task publish(dependsOn: uploadArchives)
uploadArchives {
configurations {
deployerFTP
}
repositories {
mavenDeployer {
configuration = configurations.deployerFTP
repository(URL) {
authentication(USERNAME, PASSWORD)
}
}
}
dependencies {
deployerFTP "org.apache.maven.wagon:wagon-ftp:2.4"
}
}
The problem is, if I publish the library, in the resulting .pom file, the dependency group:name:1.1.2 is entered, not the one which is actually used. How can I change this behavior, so the pom contains the right dependency?
I have found an answer, simply add this code block:
mavenDeployer {
// ...
pom.whenConfigured { pom ->
pom.dependencies = pom.dependencies.collect { dep ->
def version = getVersionForDependency(project, dep.groupId, dep.artifactId)
if (version != null) {
dep.version = version
}
return dep
}
}
}

Gradle copy build script dependency to folder

We are building one of our applications with gradle and part of the distribution I want to include an external jar which is not a run time dependency in a config folder. That jar is needed as part of the application install and it contains some custom ant tasks.
Our build script dependency looks like below:
buildscript {
...
dependencies {
classpath 'org.jfrog.buildinfo:build-info-extractor-gradle:3.1.1'
classpath 'my-group:custom-tasks:1.2.3'
}
}
How would I access and copy the custom-task-1.2.3.jar into a certain folder so I can include it in my distribution? Something like below:
task copyCustomTasks {
doLast {
copy {
// This below is a make up to express what I want
from buildscript.dependencies
include 'custom-tasks*.jar'
into "$buildDir/config"
}
}
}
If this is not the gradle way of doing things please let me know what alternatives I have.
Thank you in advance for your help.
UPDATE
I solved my problem in a different way by creating an extra configuration. However I would still be interested to find out how you can access build script dependencies at run time. Thanks again for your inputs.
configurations {
install {
description = "application install classpath"
transitive = true
}
}
...
dependencies {
...
install('my-group:custom-tasks:1.2.3')
...
}
...
task copyInstallDeps {
doLast {
copy {
from configurations.install
into "$buildDir/config"
}
}
}
You're quite close:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.google.guava:guava:18.0'
}
}
task copyLibs(type: Copy) {
from buildscript.configurations.classpath
into 'lib'
}

How to exclude dependencies in the POM file generated by the Gradle

I'm using the "maven" plugin to upload the artifacts created by Gradle build to Maven central repository. I'm using a task similar to the following one:
uploadArchives {
repositories {
mavenDeployer {
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
pom.project {
name 'Example Application'
packaging 'jar'
url 'http://www.example.com/example-application'
scm {
connection 'scm:svn:http://foo.googlecode.com/svn/trunk/'
url 'http://foo.googlecode.com/svn/trunk/'
}
licenses {
license {
name 'The Apache License, Version 2.0'
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
}
}
}
}
However the POM file created by this task does not report correctly the dependencies that have been excluded in my Gradle build file. For example:
dependencies {
compile('org.eclipse.jgit:org.eclipse.jgit.java7:3.5.2.201411120430-r') { exclude module: 'commons-logging' }
compile('com.upplication:s3fs:0.2.8') { exclude module: 'commons-logging' }
}
How to have excluded dependencies managed correctly in the resulting POM file?
You can simply override the dependencies of the pom by filtering out the unwanted dependencies, e.g. to exclude junit you can add the following lines to the mavenDeployer configuration:
pom.whenConfigured {
p -> p.dependencies = p.dependencies.findAll {
dep -> dep.artifactId != "junit"
}
}
The problem was that in the exclude definition was not specified the group but only the module.
Adding the both of them the exclusions are added correctly in the POM file. For example:
compile('org.eclipse.jgit:org.eclipse.jgit.java7:3.5.2.201411120430-r') {
exclude group: 'commons-logging', module: 'commons-logging'
}
compile('com.upplication:s3fs:0.2.8') {
exclude group: 'commons-logging', module: 'commons-logging'
}
Using 'exclude' on a Gradle dependency is normally the correct answer, but I still needed to remove some of my "runtimeOnly" dependencies from the POM that led me to this StackOverflow page. My testing using Gradle 4.7 seems to show that using "compileOnly" leaves the dependency out of the pom entirely, but "runtimeOnly" adds a "runtime" dependency in the pom, which in my case, is not what I wanted. I couldn't figure out a "standard" Gradle way of leaving runtime dependencies out of the POM.
The pom.whenConfigured method shown in another answer works for legacy "maven" plugin publishing, but doesn't work for the newer "maven-publish" plugin. My experimentation led to this for "maven-publish":
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
pom.withXml {
asNode().dependencies.dependency.each { dep ->
if(dep.artifactId.last().value().last() in ["log4j", "slf4j-log4j12"]) {
assert dep.parent().remove(dep)
}
}
}
}
}
}

Trouble injecting the build block while exporting a Maven pom.xml file from gradle

task writeNewPom {
pom {
project {
/*
build {
plugins {
plugin {
groupId 'GROUP_ID'
artifactId 'maven-ipcentral-plugin'
version '4.7'
executions {}
configuration {
url "http://CENTRAL_REPORTING_SERVER"
logfileprefix "test"
ipcProject = true
businessUnit "FOUR_DIGIT_CODE"
componentEditorsGrouper "ccp-dev"
assetEditorsGrouper "ccp-dev"
username "USERNAME"
}
}
}
}
*/
pluginRepositories {
pluginRepository {
id 'ipcentral-snapshots'
name 'IPCentral Snapshot Repository'
url 'http://PLUGIN_SOURCE/'
snapshots {
enabled = false
}
releases {
enabled = true
}
}
}
profiles {
profile {
id 'inject-cec-credentials'
activation {
activeByDefault = true
}
properties {
username = "USERNAME"
}
}
}
}
}.writeTo("ipcentral/pom.xml")
}
I am attempting to create a pom.xml file using the gradle maven plugin. It must reference a maven plugin designed for central dependency reporting. As it is right now it successfully creates the pom.xml file containing all dependencies, plugin repository info, and profile info. However if the build section is un-commented the I get an error along the lines of:
> No such property: _SCRIPT_CLASS_NAME_ for class: org.apache.maven.model.
If I try something simple like
task writeNewPom {
pom {
project {
build {
}
}
}
}
then I get the same error. It seems that gradle does not recognize build as a valid identifier. I am just hoping for a more elegant solution than manually editing xml through groovy. The only documentation on this that I can find is Gradle docs Chap 53
This is due to the fact that the project {...} closure is delegating to an instance of ModelBuilder which extends Groovy's FactoryBuilderSupport class that already defines a method named build. So instead of configuring the build property of the Maven Model object, the preexisting build method is being called.
To get around this I'd use withXml {...} to configure that portion of your pom.
pom {
project {
// other non-<build> configuration
}
}.withXml {
asNode().appendNode('build').appendNode('plugins').appendNode('plugin').with {
appendNode('groupId', 'GROUP_ID')
}
}.writeTo('pom.xml')
Here is a more detailed example:
.withXml
{
asNode().appendNode('build').appendNode('plugins').with
{
with
{
appendNode('plugin')
.with
{
appendNode('groupId', 'groupId1')
appendNode('artifactId', 'artifactId1')
appendNode('version', 'version1')
}
}
with
{
appendNode('plugin')
.with{
appendNode('groupId', 'groupId2')
appendNode('artifactId', 'artifactId2')
appendNode('version', 'version2')
}
}
}
}
.writeTo("pom.xml")

Resources