Publish executable binary as Maven SNAPSHOT in Artifactory - maven

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.

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
}

Artifactory gradle and properties mutation by artifactoryPublish task DSL

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

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 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"

Gradle script to copy maven artifact from local folder to another folder

In my project i want to copy certain artifact (war file) from maven repo to local folder in order to deploy. I tried using configurations object but i couldn't give specific groupid, artifact id, and version in that way
repositories {
mavenCentral() // or some other repo
}
configurations {
deploy
}
dependencies {
deploy "someGroup:someArtifact:someVersion"
}
task copyDeploy(type: Copy) {
from configurations.deploy
into "deploy"
}
You can find all of this and more in the Gradle User Guide (e.g. under "Working with dependencies") and the many samples in the full Gradle distribution.

Resources