What is the best practice for archiving Jenkins pipeline artifacts - maven

I see that you can add a goal to a maven Pom to archive artifacts to a repo manager such as nexus
https://www.baeldung.com/maven-deploy-nexus
distributionManagement>
   <snapshotRepository>
      <id>nexus-snapshots</id>
      <url>http://localhost:8081/nexus/content/repositories/snapshots</url>
   </snapshotRepository>
</distributionManagement>
But Jenkins also allows you to do this from the pipeline itself
https://wiki.jenkins.io/plugins/servlet/mobile?contentId=96076078#content/view/96076078
freeStyleJob('NexusArtifactUploaderJob') {
steps {
nexusArtifactUploader {
nexusVersion('nexus2')
protocol('http')
nexusUrl('localhost:8080/nexus')
groupId('sp.sd')
version('2.4')
repository('NexusArtifactUploader')
credentialsId('44620c50-1589-4617-a677-7563985e46e1')
artifact {
artifactId('nexus-artifact-uploader')
type('jar')
classifier('debug')
file('nexus-artifact-uploader.jar')
}
artifact {
artifactId('nexus-artifact-uploader')
type('hpi')
classifier('debug')
file('nexus-artifact-uploader.hpi')
}
}
}
}
What is the difference between the two approaches, is one more commonly used?

The main difference is that if you use maven, you can manually add artifacts to Nexus from your local computer, using mvn deploy. So it really comes down to how you want to create the artifacts that end up being used in production. In my experience, the preferred way of doing this is through using Jenkins. The advantage of using Jenkins is that you link your new version builds to other activities, as well as the possibility to trigger a release when certain conditions have been met, rather than starting the build manually. Also, you end up with all versions being built on the same platform, and you avoid differences between computers if every developer builds such versions from their own computer.
But you might still need the maven configuration. Jenkins might use this information to find the URL to upload the artifact to (your example says nothing about how Jenkins finds Nexus), and sometimes it is useful to upload a SNAPSHOT-version, or some other temporary version not meant for production. In your example you only define Nexus for upload SNAPSHOT-versions, I guess this is done on purpose to enforce a rule that uploading final version from local computers is disallowed.
By the way, having a repository defined in your pom.xml does not automatically mean that anything will be uploaded. It is only if you do mvn deploy with a repository defined in your pom that something will be uploaded.

Related

Custom build tagging with Jenkins, Artifactory, Maven

I'm working on a strategy to tag builds in my continuous integration and delivery pipeline. When a fresh build is produced it then goes through multiple stages of testing; after each stage I would like to tag the build. My idea was to expand on the standard Maven system, so an example would be:
my-artifact-1.0-SNAPSHOT.jar
my-artifact-1.0-PASSED_TESTS_1.jar
my-artifact-1.0-PASSED_TESTS_2.jar
...
my-artifact-1.0-RELEASE.jar
As a build passes each stage its tag, which is part of its name/version, gets updated. Eventually, after all testing stages the build is tagged as releasable with RELEASE.
I'm using a Jenkins server and storing artifacts on Artifactory (non-Pro) in Maven repositories. My plan is to use separate Maven repositories for each tag type above, and to move an artifact from one to the other as its tag is updated.
My pseudo-code for the promotion looks like:
(1) Download artifacts that passed in Jenkins
(2) Text-replace the tag (maybe pom.xml as well?)
(3) Upload to new repository
(4) Update the associated Git commit with tag also
I'm not sure how to actually implement this cleanly - is this a common way of doing things? Am I missing something important? Can a Jenkins + Artifactory (non-Pro) + Maven (repos only, Gradle for builds) system accomplish this?
Thanks!
I can see where the idea of adding more metadata to the file names come. Usually, we don't have any other place to add this kind of information, except of the name. But with a proper artifact repository manager (as Artifactory), you don't need it anymore. You can attach any metadata to the artifacts in the repository manager, and then manipulate (e.g. promote) the artifacts based on those properties.
Here's a screencast showing what it takes to add this kind of metadata to the artifacts, and how to promote artifacts based on it.

How do I block redeployments to Sonatype Nexus OSSRH

We're deploying our open source libraries to the OSS instance of Sonatype Nexus (https://oss.sonatype.org/) using the nexus-staging-plugin. This works all fine and well. However, since we're using a build server I want to block an accidential re-deployment of an existing artifact id - as this is normally not suppoted by maven. However, the OSSRH happily accepts and updates an existing release. Is there any way to block this and make the build fail?
I know that Nexus can be configured to do that - it is just, that I don't have any permissions to reconfigure the OSSRH instance..
Is there any maven plugin which could check the repo first and fail in first place in case nexus/sonatype does not support this? I looked into the enforcer plugin but there isn't a rule available.
It is true that there is a staging rule in Nexus which prevents duplicate GAV's being staged, but it is not enabled on https://oss.sonatype.org. The reason for this is that some users stage artifacts repeatedly (creating multiple staging repositories) and then choose one of them for release based on testing results.
But the server at https://oss.sonatype.org is configured so that you cannot release the same artifacts twice. So if you have two staging repositories that contain the same artifacts you will only be able to release one of them.

How to preserve the timestamps generated for SNAPSHOT artifacts?

Currently a Maven build (inside Jenkins) is configured to deploy every artifact it builds (releases and snapshots) to a Nexus repository. Now I have to push some of those artifacts to application servers and thought of letting the target servers fetch them from Nexus - this is easy for releases but how can I reference the SNAPSHOT artifacts? Maven's deploy plugin adds a timestamp to make each artifact unique (which is good) but I couldn't find a way to get that generated timestamp for later use!
Quick Aside: I plan to use the promoted builds plugin to start a script on the target server(s) which then in turn ask Nexus for the new artifact to deploy.
Does anybody know how I can make Maven say the timestamp it generates? Or do I really have to parse the whole output for Uploaded: https://NEXUS_URL/content/repositories/snapshots/GROUP/ARTIFACT/VERSION/ARTIFACT-VERSION-TIMESTAMP-SUFFIX.TYPE?
As far as I know you do need to parse the output of the deploy goal.

Delete and/or Replace Artifacts in Nexus using Gradle

I am still new to Gradle and Nexus.
I want to be able to remove artifact from a hosted nexus repository with Gradle. Using the nexus GUI in order to do this is not an option, because I don't wanna.
Part of the reason for wanting this is to be able to automatically correct upload errors such as incorrectly labeled artifacts, or artifacts uploaded with he wrong version. I may also just want to wipe out an entire project and all versions of it (maybe because it was uploaded to the wrong repo, or I'm just doing some house cleaning. OR perhaps I want to overwrite the currently up-loaded version of an artifact. Anyways, I don't have a real use case right now, but I still want to know how to do it.
Edit: Also, I'm curious about ways to "gracefully" handle times when a certain artifact version is already uploaded, such as catching a specific exception and outputting a user friendly message to advise the developer to update the build version before uploading.
Here's my current uploadArtifact task.
uploadArchives {
repositories {
flatDir {
dirs 'repos'
}
mavenDeployer {
credentials {
username "user"
password "password"
}
url "http://localhost:8081/nexus/content/repositories/releases/"
}
}
}
There isn't anything built into Gradle to manage a Nexus repository. Unless you find a third-party Gradle plugin for this, you'll have to develop your own solution. For example, you could write one or more Gradle tasks that use Nexus' REST APIs to accomplish what you want.
PS: Maven repositories are designed to be immutable, and changing any data or metadata after it has been published is generally frowned upon. (Instead a new version should be published that fixes the problem.) For such a change to take affect, every developer and CI machine will have to run all affected builds with --refresh-dependencies in order to invalidate the local cache (or wipe out the whole cache). This will likely cause lots of pain.

Maven + Hudson + Nexus: Access to SNAPSHOT Build Number

Now that Maven3 has dropped support for setting uniqueVersion=false on deployment, I'm running into an issue. I have Hudson do an automatic deployment of my SNAPSHOT build to my Nexus repository manager. The resulting SNAPSHOT artifact looks like blah-0.0.1-20110517.233746-1.jar. Note the unique SNAPSHOT build id. The trick is that I'd link to that jar in my site documentation, but I'm not sure how to inject that snapshot build number into the docs. Perhaps there is a way to have Maven or Hudson or Nexus create a symlink on deployment from blah-0.0.1.jar => blah-0.0.1-20110517.233746-1.jar?
Ok, mod me down, but I think I found an answer to my own question. I'm posting here in case anyone else finds it useful.
It turns out the Nexus REST api has the ability to automatically retrieve the latest SNAPSHOT build of an artifact, which is exactly the functionality I needed. For more info, see:
https://docs.sonatype.com/display/SPRTNXOSS/Nexus+FAQ#NexusFAQ-Q.HowcanIretrieveasnapshotifIdon%27tknowtheexactfilename%3F

Resources