Artifactory gradle and properties mutation by artifactoryPublish task DSL - gradle

My problem with build-info-extractor gralde plugin for artifactory
Source code with example for reproduce problem: https://github.com/lavcraft/gradle-artifactory-build-info-extractor-problems
Configure environment – artifactory_user artifactory_password artifactory_contextUrl
Run ./gradlew build aP
See jar artifacts properties in you artifactory instance
I expect, that this example (see below) works perfectly
artifactoryPublish {
properties = ['aa':'aaa']
properties {
nebula '**:**:**:*#*', 'not_added_prop':'sub0'
}
}
see sub0/build.gradle in github project
But it does not work. What is wrong with my example?

I think I found the cause of this issue.
Here's the artifactory closure configured in the build.gradle file, in the project you shared:
artifactory {
contextUrl = project.findProperty('artifactory_contextUrl')
publish {
repository {
repoKey = 'libs-snapshot-local'
username = project.findProperty('artifactory_user')
password = project.findProperty('artifactory_password')
}
defaults {
publications('nebula')
publishConfigs('archives')
publishIvy = false
properties {
nebula '*:*:*:*#*', 'want_to_add':'but not' // add only to *.pom artifacts. Why?
mavenJava commonProperties, '*:*:*:*#*'
}
}
}
}
As you can see above, the closure includes one publication (nebula) and one configuration (archives).
Running the build script as is prompts the following deployed artifacts:
$ gradle clean artifactoryPublish
Deploying artifact: http://localhost:8081/artifactory/libs-snapshot-local/ru/alfalab/platform/tests/sub0/0.1.1-SNAPSHOT/sub0-0.1.1-SNAPSHOT.jar
Deploying artifact: http://localhost:8081/artifactory/libs-snapshot-local/ru/alfalab/platform/tests/sub0/0.1.1-SNAPSHOT/sub0-0.1.1-SNAPSHOT.pom
Deploying artifact: http://localhost:8081/artifactory/libs-snapshot-local/ru/alfalab/platform/tests/sub1/0.1.1-SNAPSHOT/sub1-0.1.1-SNAPSHOT.jar
Deploying artifact: http://localhost:8081/artifactory/libs-snapshot-local/ru/alfalab/platform/tests/sub1/0.1.1-SNAPSHOT/sub1-0.1.1-SNAPSHOT.pom
Now, if you comment out the publication as follows:
//publications('nebula')
publishConfigs('archives')
You can the following:
Deploying artifact: http://localhost:8081/artifactory/libs-snapshot-local/ru/alfalab/platform/tests/sub0/0.1.1-SNAPSHOT/sub0-0.1.1-SNAPSHOT.jar
Deploying artifact: http://localhost:8081/artifactory/libs-snapshot-local/ru/alfalab/platform/tests/sub1/0.1.1-SNAPSHOT/sub1-0.1.1-SNAPSHOT.jar
So it looks like both the archives configuration and the nebula publication contribute the same two artifacts above.
Since "want_to_add" property is configured on the nebula publication (and not on the archives publication), the 2 jars contributed by the configuration don't get the property.
A simple fix for this is issue is to remove the archives configuration:
publications('nebula')
//publishConfigs('archives')
Alternatively, if for some reason you do want to have both the configuration and publication, you can add the property to your configuration as well. Here's how you do this:
properties = ['want_to_add': 'but not']
So the full closure, with both the publication, configuration and properties for both is this:
defaults {
publications('nebula')
publishConfigs('archives')
publishIvy = false
properties = ['want_to_add': 'but not']
properties {
nebula '*:*:*:*#*', 'want_to_add':'but not' // add only to *.pom artifacts. Why?
mavenJava commonProperties, '*:*:*:*#*'
}
}
You can read more about this here:
https://www.jfrog.com/confluence/display/RTF/Gradle+Artifactory+Plugin

Related

How to publish to Artifactory with Gradle without publishing dependent projects

I'm updating some build.gradle files to add Artifactory publishing. In some cases I want to publish the top level project's artifacts without publishing artifacts for its dependent projects. The dependent projects get published on their own or when built by a different project.
I've added basic publishing and artifactory tasks to the build.gradle files and they work, but for example if there's a project called "api" that has a dependent project called "db", when I run the build.gradle for "api", it publishes the artifacts for both "api" and "db". I want it to only publish the api artifacts.
I'm not having much luck finding what I want on Jfrog's site. The documentation mentions "Use the artifactoryPublish.skip flag to deactivate analysis and publication", but honestly I don't know what to do with that and if it would help in my case.
The gradle scripts are referencing dependencies like this:
implementation project(path: ':db', configuration: 'default')
I've run the builds in both Eclipse and Jenkins. We use Gradle 7.4. I'm calling the clean, build, and artifactoryPublish tasks. I suspect there's probably an easy way to do this, and I'm just not seeing it.
For reference, this is my publishing task:
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
}
}
}
And here's the publish part of the artifactory section:
publish {
repository {
repoKey = 'libs-release-local'
username = "${artifactory_user}"
password = "${artifactory_password}"
ivy {
ivyLayout = '[organization]/[module]/[revision]/ivy-[revision].xml'
artifactLayout = '[organization]/[module]/[revision]/[artifact]-[revision].[ext]'
mavenCompatible = true
}
}
defaults {
publications('mavenJava')
publishArtifacts = true
properties = ['qa.level': 'basic', 'dev.team' : 'core']
publishPom = true
publishIvy = true
}
}
I found an answer. For a project that has "db" as a dependency, after the dependencies section of my build.gradle file, I added the following:
gradle.startParameter.excludedTaskNames += "db:artifactoryPublish"
Now when I run the artifactoryPublish task for the api project, it does not execute for the db project, too.
For excluding the "db" project from publishing to Artifactory, you can add the following in your build.gradle file:
project('db') {
artifactoryPublish.skip = true
}

Publish executable binary as Maven SNAPSHOT in Artifactory

Asking as a relative newbie to repo terminology and semantics:
I have a gradle project that builds a Spring-Boot jar file, and then runs an InstallAnywhere project file to package the jar as an installer for a Windows service. I need to publish the executable installer as a SNAPSHOT. I am using the gradle artifactory plugin (not the artifactory-publish plugin, only because I'm following the example of sister project).
The artifact is being published to the Maven snapshot repo, but the "-SNAPSHOT" placeholder is not being replaced by a timestamp. When I add the original Jar file to the artifacts to publish, the Jar file gets a timestamp added, but the .exe still does not. Relevant gradle code follows, and project version is set to "1.0.0-SNAPSHOT" in gradle.properties, along with other shown artifactory configuration properties:
task buildInstaller {
inputs.files cleanJarName.outputs
outputs.file installerFile
doLast {
project.exec {
workingDir 'InstallKit'
commandLine "${System.env.INSTALLANYWHERE_HOME}\\build.exe", 'MyInstallAnywhereProject.iap_xml', '-nupd'
}
}
}
artifactoryPublish {
dependsOn buildInstaller
}
configurations {
published
}
artifacts {
published installerFile
}
artifactory {
contextUrl = project.artifactoryContextUrl
publish {
repository {
repoKey = project.artifactoryPublishRepo
username = project.artifactoryUser
password = project.artifactoryPassword
}
defaults {
publishConfigs('published')
publishBuildInfo = true
publishArtifacts = true
publishPom = true
publishIvy = true
}
}
resolve {
repository {
repoKey = project.artifactoryResolveRepo
username = project.artifactoryUser
password = project.artifactoryPassword
maven=true
}
}
}
So why won't Artifactory properly snapshot an .exe? We were going to see if it was a limitation of Maven repos only handling Java-related types (jar, war, ear, etc.). So we looked at creating another Artifactory repo for binary snapshots using the generic(?) repo type, but the configuration screens do not offer the snapshot options present in the Maven repo configuration.
SNAPSHOT (actually Integration Revision) terminology is mandated by repository layouts.
Since Artifactory enforces single-typed repositories you are correct that a Maven repo will not handle the versioning of an .exe file.
Using a generic repo is the correct path to take - but you need to define your own folder and file integration revision to have Artifactory pick up on it.

Gradle: publish an artifact with a subset of files/dependencies of a project

I am lost in all these plugins :(
What I have so far, looks something like this:
artifactory {
contextUrl = artifactoryUrl
publish {
repository {
repoKey = project.repo
username = artifactoryUser
password = artifactoryPassword
maven = true
defaults {
publications('mavenJava')
}
}
}
version = "${majorVersion}${buildNumber}${snapshot}"
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
artifact sourceJar {
classifier = 'sources'
}
}
}
}
I am sorry, I did write this myself, but, mostly by copying and pasting things from various examples I found on the web, so I am not sure what this is actually doing :(
Surprisingly, this works: I can do gradle artifactoryPublish, and uploads a pom file and two jars (classes and sources) to artifactory.
But, I need to modify it, so that I can publish a subset of the project as a different artifact, and only include the dependencies that it requires.
I managed to build a jar file:
task utilJar(type: Jar) {
from sourceSets.main.output.classesDir
include '**/util/*.class'
baseName 'basic-util'
}
I also defined a Configuration with a subset of dependencies:
configurations {
util
}
dependencies {
util "org.apache.commons:commons-lang3:3.4"
util "com.google.guava:guava:18.0"
}
artifacts {
util utilJar
}
This is where I get stuck. How do I get this new artifact published?
I tried following the same strategy:
publishing {
publications {
mavenUtil(MavenPublication) {
from components.java
artifact utilJar {
classifier = 'util'
}
}
}
}
artifactory {
defaults {
publications('mavenUtil')
}
}
(this is in a subproject, so I need it do be incremental)
This does not work:
Could not find method defaults() for arguments [build_8axxghkylu3559p5lal6spy1u$_run_closure7$_closure11#38abcbd4]
But, even if it did, it would still be not be quite what I need, because I don't know how I could then publish a particular artifact: the only way I could ever publish anything at all is gradle artifactoryPublish, but that does not ask me which artifacts to publish. Will it publish everything every time?
As you can see, I am hopelessly lost here :(
Could someone with a clue please show me the light?
UPDATE So, I removed the last artifactory closure from the build, and now I not getting the error, but still can't get it to do what I need.
My artifactory seems to be not in good mood right now, so I am publishing locally.
gradle publishToMavenLocal creates a single artifact as before, but adds my new "-util" jar to it. This is not at all what I want. I need a new, separate artifact, with that jar file, and its own set of dependencies.
Here: https://docs.gradle.org/current/userguide/publishing_maven.html#publishing_maven:repositories I found a suggestion, that "The created task is named “publish«PUBNAME»PublicationTo«REPONAME»Repository”". This does not seem to to be true, because gradle publishUtilMavenPublicationToMavenLocalRepository (with all the case variations I could think off) says that there is no such task. :(
Have you tried using the set me up feature? It available for all version of Artifactory. It should provide a good starting point to configure you gradle project to work with Artifactory.
Specifically for Gradle it can assist you with generating the relevant configuration according to the repositories you wish to resolve / publish from / to, defining the relevant dependencies to install the jfrog plugin etc.

How to use gradle Artifactory plugin in gradle subproject

I have a multi-project gradle build wherein one of the subprojects is applying the Artifactory plugin (version 4.2.0), and configuring the contextUrl and resolve repoKey.
It sets up a simple configuration and dependency entry, and then has a copy task to retrieve the dependency as a zip file and extract it into a directory.
However, when the copy task runs, I get the error below. What am I doing wrong? Is this a problem with the Artifactory plugin, or gradle, or...?
The problem does not appear to be related to whether or not this is a subproject. I get the same error if I remove the multiproject configuration and run the task from the subproject directory.
FAILURE: Build failed with an exception.
* Where:
Build file 'C:\Users\hoobajoob\project\subproject\package.gradle' line: 36
* What went wrong:
A problem occurred evaluating project ':subproject'.
> Could not resolve all dependencies for configuration ':subproject:runtimeDep'.
> Cannot resolve external dependency company.com:artifact-id:1.0.0 because no repositories are defined.
Here are the contents of subproject/package.gradle (Artifactory url/user/password properties are in a gradle.properties file for the subproject):
plugins {
id "com.jfrog.artifactory" version "4.2.0"
}
artifactory {
contextUrl = "${artifactory_contextUrl}"
resolve {
repository {
username = "${artifactory_user}"
password = "${artifactory_password}"
repoKey = 'some-repo'
}
}
}
configurations {
runtimeDep
}
dependencies {
runtimeDep 'company.com:artifact-id:1.0.0#zip'
}
ext.destination = null
task getDependencies(type: Copy) {
from zipTree { configurations.runtimeDep.singleFile }
into ".artifacts/runtime"
}
The root project build script is empty except for the wrapper task. Below is the settings.gradle file:
include 'subproject'
rootProject.children.each { project -> project.buildFileName = "package.gradle" }
While the task setup in my question is different, this appears to be the same symptom as described in this other SO question.
The problem seems to be related to the fact that the Artifactory plugin will not perform dependency resolution until gradle's execution phase. I had assumed that defining the argument to the zipTree step in the getDependencies task with a closure would have the effect of deferring the dependency resolution until that phase.
But, for this to be deferred by the copy task, I need to define the from configuration of the getDependencies task as a closure, and include the zipTree operation in that closure.
It's the difference between:
from zipTree { configurations.runtimeDep.singleFile } // doesn't work
...and
from { zipTree( configurations.runtimeDep.singleFile ) } // works
Making this change gets the resolve working (with no required maven repositories block).
Another solution is to drop the Artifactory configuration altogether (which I can do in this case because I do not need to utilize anything unique to Artifactory) and use the traditional gradle repositories block, as described in the other SO question and by crazyjavahacking. Doing this makes the build script shorter, and I can leave the zipTree step configured as it was originally written:
repositories {
maven {
url "${artifactory_contextUrl}/repo-key"
}
}
configurations {
runtimeDep
}
dependencies {
runtimeDep 'company.com:artifact-id:1.0.0#zip'
}
ext.destination = null
task getDependencies(type: Copy) {
from zipTree { configurations.runtimeDep.singleFile }
into ".artifacts/runtime"
}
As the Gradle print to the console:
You did not define repositories{} block and so it does not know how to download declared dependency.

How to specify module name when publishing to Artifactory from Jenkins

I'm using the gradle artifactory publish plugin documented here: http://www.jfrog.com/confluence/display/RTF/Gradle+1.6+Publishing+Artifactory+Plugin
I'm using the standard config exactly as laid out in the documentation.
When I run the gradle publishArtifactory task from the command line I get output like this. I.e. It deploys to my correct module name.
Deploying artifact: http://<my server>/artifactory/libs-snapshot-local/<my actual module name>/web/0.1-SNAPSHOT/web-0.1-SNAPSHOT.war
When I configure Jenkins to run the gradle publishArtifactory task using the same gradle build file I get output like this. I.e. It uses the Jenkins build for the module name.
Deploying artifact: http://artifactory01.bcinfra.net:8081/artifactory/libs-snapshot-local/<the name of the jenkins build>/web/0.1-SNAPSHOT/web-0.1-SNAPSHOT.war
Any ideas on how to prevent the artifactory plugin from using the Jenkins build name for the module name?
The module name used for uploading is derived from the gradle project name. The default value for a gradle project name is taken from the project folder name. I suspect that on your jenkins job you check out your code into a folder named like your build job. That's why per default this folder name is used as project name.
The cleanest solution is to explicitly set your project name in gradle.
Therefore you need a settings.gradle file in your project root folder that contains the project name:
rootProject.name = "web"
You can also let Gradle single-handedly do the publishing to Artifactory, without the need for the Artifactory plugin in Jenkins.
This way, you can set the names of the artifacts using artifactId "your artifact name" without changing the project's name as suggested by Rene Groeschke.
Here's my publish.gradle that demonstrates this:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "org.jfrog.buildinfo:build-info-extractor-gradle:3.0.1"
}
}
// Because this is a helper script that's sourced in from a build.gradle, we can't use the ID of external plugins
// We either use the full class name of the plugin without quotes or an init script: http://www.gradle.org/docs/current/userguide/init_scripts.html
apply plugin: org.jfrog.gradle.plugin.artifactory.ArtifactoryPublicationsPlugin
// Pack the sources into a jar
task sourceJar(type: Jar) {
from sourceSets.main.allSource; classifier = "sources"
}
// Pack the Javadoc into a jar
task javadocJar(type: Jar) {
from javadoc.outputs.files; classifier = "javadoc"
}
apply plugin: "maven-publish"
publishing {
publications {
mavenJava(MavenPublication){
from components.java
// Set the base name of the artifacts
artifactId "your artifact name"
artifact jar
artifact sourceJar
artifact javadocJar
}
}
}
artifactory {
contextUrl = "http://localhost:8081/artifactory"
publish {
// Publish these artifacts
defaults{ publications ("mavenJava") }
repository {
repoKey = "libs-release-local"
// Provide credentials like this:
//-Partifactory.publish.password=yourPassword
//-Partifactory.publish.username=yourUsername
}
}
resolve {
repository {
repoKey = "libs-release"
}
}
}
You can use this script in your build.gradle via apply from: "path/to/publish.gradle" and call it like this:
./gradlew artifactoryPublish -Partifactory.publish.username="yourUsername" -Partifactory.publish.password="yourPassword"

Resources