I have created pipelines which will clean, compile, test, & deploy the code every time we update it. But in case of a technical issue/or error I want to add a step which allows me to revert/rollback the "build" or deployment.
Is there a maven command that can be used to revert/rollback builds/deployments?
No.
If you just run clean package, then another clean will erase the results of package, but if you have run install or deploy the artifact is send to the local repository or remote repository. This cannot be "rolled back" by Maven.
The Maven Release Plugin has a rollback goal that rolls back the changes that it made to version control:
version changes in POMs are reverted
created tag is deleted
created branch is deleted
However, this rollback does not delete files that were uploaded to the remote repository! If the remote repository does not allow artifacts with final versions to get deleted or modified, then you would end up with a problem, because your next attempt would fail to re-upload.
The Maven Release Plugin internally uses the Maven Deploy Plugin to upload files, and the latter has an experimental deployAtEnd feature. Unfortunately, I did not manage to get it to work for my build (using the suggestion from this SO comment) - I still had a build in which the Maven Release Plugin uploaded files before exiting with a failure.
Related
I got a maven project (myApp) depending on another maven project in snapshot version.
like:
<dependency>
<groupId>org.group.dep</groupId>
<artifactId>arty</artifactId>
<version>12.1.4-SNAPSHOT</version>
</dependency>
But I got a problem with this after the "arty" got an update without changing the version (I know that would be the cleanest solution).
I build the myApp local and got still the old version of the "arty" dependency.
I verified tow option working for me (and a college):
1) Manual cleaning of the local repository: navigating to my .m2/repo/org/group/dep/arty and deleted all folders inside. After rebuilding the myApp local it was working fine - arty was downloaded form the artifactory.company.com again with the updated content.
2) Local building of the arty package so it got updated in the local repository. After rebuilding the myApp local it was working fine.
But I got similar problem on the Jenkins:
I got a Jenkins job just building org.group.myApp without building before org.group.dep.arty. It failed for the missing changes form "arty".
What can I do now to solve my problem there?
I can not rely on first building org.group.dep.arty as I can not be sure for Jenkins to run both jobs on the same host using same local repository (I don't want to change that).
Somehow the myApp-Jobs was failing after I manually cleared on that Jenkins node the org.group.dep.arty in the repository and running than the myApp-job (was somehow not downloading the package).
I finally found the mvn -u but as I tried this I was as well disappointed.
I tried different maven versions on that jenkins and got the same result.
Is there no way to force the update of the snapshot versions?
Is this "another project" is a part of the same multi-module project?
If so you can build your project with --also-make options so that maven will effectively rebuild your module and all of its dependencies
If its an entirely different project, use mvn -U to forcefully download all the snapshot dependencies of your project.
If there is a particular issue with one concrete dependency consider using mvn dependency:get. This get goal of maven-dependency-plugin downloads one specific artifact from the remote repository
Here is a link to the plugin documentation
The simplest solution to redownload -SNAPSHOT is by using the command line option: -U or as long option --update-snapshots
Furthermore your project sounds like the need for a multi module build which prevents such issues. Or you might need to define those Jobs depending on each other (There is an option to build if a SNAPSHOT has been updated in Jenkins).
I have a Java project. Some parts are jar files, some are war files. I also have Jenkins and Nexus Pro, whereby when a developer on the team commits to SVN, the Jenkins build automatically kicks off.
Using the Maven versions plugin, I am able to mvn versions:set -DnewVersion=1.0.$SVN_REVISION as a pre-build step, and then mvn clean test deploy. At the end of this process, I've got a my-artifact-1.0.1234.jar uploaded to my Nexus Pro Staging Repository.
Since we're working in a CI-type of environment, we might have a hundred (or more) staging builds. When the time is right, the QA team wants to promote a certain build to a "later" environment (think QA, or SIT, or whatever. Environments are more of a locked-down state here.)
The workflow that I want to have happen is this:
Someone decides that Build 1.0.1357 should be Promoted to QA
They go into Jenkins, go to the "Promote to QA" job
They're presented with a list of all possible builds in the Nexus Staging Repository in a drop-down. They select one, and click the "Run" button.
That artifact is "released" from Nexus Staging to Nexus Releases, and further deployed to the QA environment. (I'm not as concerned about the "and deployed to QA" part -- I know how to do that already. It's included here for completeness-of-my-story sake.)
I already know that I can do this from the command-line, and it's working:
mvn nexus-staging:rc-list -DserverId=nexus -DnexusUrl=http://my.nexus.ip:8081/nexus
mvn nexus-staging:rc-release -DserverId=nexus -DnexusUrl=http://my.nexus.ip:8081/nexus -DstagingRepositoryId=abcd-1000 -Ddescription="Release from CLI."
The problem I'm having is that you have to specify the stagingRepositoryId on the command-line. How might I go about accomplishing this?
What I was doing is parsing the output of
mvn nexus-staging:rc-list -DserverId=nexus -DnexusUrl=http://my.nexus.ip:8081/nexus
and then just match the needed repository with your specifique logic. Using python for me was the best solution (but you can do it on your own with any language):
output = subprocess.check_output("mvn nexus-staging:rc-list -DserverId=nexus -DnexusUrl=http://my.nexus.ip:8081/nexus")
for line in output.split('\n'):
if "repo" in line:
stagingRepositoryId = "repo-" + line[8:23]
Considering output as
[INFO] repo_qa-3514 OPEN Implicitly created (auto staging).
[INFO] repo_qa-3518 Implicitly created (auto staging).
[INFO] repo_qa-3521 OPEN Implicitly created (auto staging).
[INFO] repo-2011 OPEN Implicitly created (auto staging).
You will run the second command after parsing as:
mvn nexus-staging:rc-release -DserverId=nexus -DnexusUrl=http://my.nexus.ip:8081/nexus -DstagingRepositoryId=repo-2011 -Ddescription="Release from CLI."
I think what you are trying to do can be achieved readily by using SNAPSHOT and release repository.
So you do your normal development in a SNAPSHOT build and once you are ready for testing, you can create a tag build which removes SNAPSHOT from version in POM. All this can be achieved using jenkins and Nexus.
Also you dont need SVN revision number in your version, instead an incremental build number will be sufficient which can be managed via release plugin.
So to summarise:
Lets say you are working on release 1.0.
So you take a initial branch with pom version as 1.0-0-SNAPSHOT . Here 1.0 represents release number, '-0' represents next tag build number which we plan to deploy.
Now once you are ready for deployment or want your QA team to test. You run a job or a script with maven release plugin to create a tag. A tag build will be created with version 1.0-0 [Snapshot is removed so it will go to release repository] and uploaded to repository also version in branch will be incremented to 1.0-1-SNAPSHOT [So now changes in branch will be made to release and deploy 1.0-1 if any changes are needed]
All the above steps are automated using Maven release plugin and run via jenkins job.
I have the above setup for my work.
OP stated that 'SNAPSHOT' is not in picture.
In that case this post answers the query : automate deployment to sonatype's oss maven repository [Look at the second answer]
We use Maven with Subversion internally. We also use Maven's Release plugin. We noticed the issue described below when running through the following (correct, I presume) steps.
1. We run release:prepare:
Maven updates the trunk version to 1.0.0.
Maven runs svn copy trunk/myproject tags/myproject-1.0.0, thus creating tag myproject-1.0.0.
Maven updates the trunk version to 1.0.1-SNAPSHOT.
2. We run release:rollback:
Maven resets the trunk version to 1.0.0-SNAPSHOT.
Maven does not remove the tag, because Maven doesn't do this kind of stuff.
3. We commit more changes to trunk, obviously against version 1.0.0-SNAPSHOT.
4. We run release:prepare again:
Maven updates the trunk version to 1.0.0.
Maven runs svn copy trunk/myproject tags/myproject-1.0.0, thinking it created tag myproject-1.0.0 out of the latest trunk. But, alas, Subversion (1.6 and 1.7 alike) will instead create tags/myproject-1.0.0/myproject on Maven's behalf.
5. We run release:perform:
Maven checks out the contents of tag myproject-1.0.0.
Maven builds the contents and deploys the result to Nexus.
The problem is obvious: the change in step 3 did not make it into the tag. We are now releasing 1.0.0 without the change in it.
The questions are: How can we fix this? Is Maven's release rollback feature inherently broken?
In fairness, rollback should reset the project and SCM to a state that allows a second prepare to occur. This includes removing the tag. The answer is now apparent (Googling "maven release rollback remove tag"):
http://maven.apache.org/maven-release/maven-release-plugin/examples/rollback-release.html:
The created branch/tag in SCM for the release is removed. Note: This
is not yet implemented so you will need to manually remove the
branch/tag from your SCM. For more info see MRELEASE-229.
The resolution would then be to force release:rollback to include a command to delete the SCM tag using something like org.codehaus.mojo:exec-maven-plugin. Short of this, wrap rollback inside a script that does that externally.
As you've discovered, release:rollback doesn't have a whole lot of utility when it doesn't clean up SCM. What our shop has done is setup our Jenkins automation to run "mvn release:prepare release:perform" in combination with the Jenkins M2 Release Plugin.
If it fails we need to delete the tag in Subversion but, then again, we would have to do this anyway with rollback.
Today while doing the release of our project, the release:perform command failed in between as our nexus was having intermittent issues. The release command only able to upload one pom file to nexus.
Now, the nexus issue is resolved and I am trying to do the release, it fails as the pom file already exists and its not the snapshot version and we don't have access to nexus so that I can delete that file and start over again.
Is there any way I can pass an argument so that release:perform should continue if the file is already there and ignore this but continue with uploading the rest.
I have looked for options of such type but didn't find anything.
My last resource would be to start the release again, which will bump the version number, but would like to understand if there is any other approach where in I don't need to bump the version.
I am using maven 2.2.1
Here's how I have handled this in the past. The release:perform command does a checkout of the tag from your SCM provider (e.g. SVN). This is done in the target/checkout directory of that project - whatever is there should be an exact copy of the released tag, so it will have the right version number in the pom files etc.
If you move to that directory (target/checkout in the directory where you started the release), you can simply do a mvn deploy there and it should compile and package that version, and then upload it to your Nexus instance.
If you don't have the target/checkout directory, you can check out the Tag created as part of the release:prepare phase from your SCM system to a fresh directory and run mvn deploy there.
Since the tag in your SCM has already been created, the only thing that's left is really compiling, packaging and deploying the release, which is exactly what mvn deploy should do.
If you have provided additional parameters (e.g. for activating profiles) for the build during the call to mvn release:perform, you will have to provide these as well when you run mvn deploy.
Using this approach, your version number will not have to change, it can stay the same, since you're just uploading what has already been tagged as part of mvn release:prepare.
My advice would be for you to request from the admins that the old artifact be removed. You can either re-deploy the code from the tag by checking it out and simply doing
mvn deploy
Or rolling back your release:
mvn release:rollback
And re-doing it as usual.
It is essential to remove the old artifact from the remote repository, if the sizes do not match. Release repositories do not allow the redeployment of artifacts, unless this has been explicitly switched on on the server side.
Furthermore, #nwinkler's answer is also quite good.
I'm trying to setup a complete CI server, but I struggle on some points.
Currently, my system work as follow :
I commit local changes on my local GIT repository, then push to the GIT repository on the CI server
I then have a jenkins job triggered by the SCM change, who run a clean install and by doing so executes all my Junit and Jstestdriver test (via a local jstd server). This job deploy the snapshot artifact to a repository on my nexus repository
I installed M2-release-plugin for jenkins, and setup my pom.xml accordingly using maven-release-plugin. When i click on "Perform maven release" in jenkins job page, jenkins run mvn release:prepare release:perform, thus creating a tag in my git repo (say v000001) and deploying a versionned artifact on my nexus repository.
I don't really know if this process is fine, but i guess so...
My problem is that I want to deliver the versionned artifact in my nexus repo (say "artifact-v0000001.war") in my production tomcat. But I can't figure out how to do it.
When I do "mvn release:prepare release:perform tomcat:deploy" it deploys the new SNAPSHOT artifact built ... I don't want to do this, I want to reuse the artifact from the nexus repository.
Is there a way to doing this using a tool (maven/jenkins plugin, or external)?
Basically, I want to fetch the last release artifact on the repository, and send it to the tomcat manager for dereploying the webapp.
Do I need to setup a delivery job separated from the release job?
Jenkins, especially when combined with a tool like ANT, can do just about anything. It has a lot of plug-ins, and you can always write a script and incorporate it into a Jenkins build. Currently, I use Jenkins to deploy web applications to Windows IIS servers. What you could do here is have a Jenkins build that has your SVN path set in the source control section so that it fetches the latest version when you trigger the build. From there it should be fairly trivial to write an ANT script that copies it over the existing JAR in Tomcat, which will automatically restart it.
Your problem is that you are probably using the Jenkins release plugin, not the "m2 release plugin". The problem with the standard plugin is that it performs the regular build, saves the artifacts, then performs the release. It will then try to deploy the wrong artifacts that it created from the regular build.
The m2 release plugin solves this particular problem. There are some tricky workaround for this problem, but that's how it stands at the moment until this feature is implemented: https://issues.jenkins-ci.org/browse/JENKINS-11120 (log in and vote for it!)