Jenkins pipeline, bitbucket hook and maven release plugin infinite loop - maven

I haven't been able to find any info about this, so i hope you guys can help me on this one
I've a maven project hosted in bitbucket that has a BitBucket WebHook pointing to someurl/bitbucket-hook/ , this hooks triggers the build of my project that is defined by a pipeline that has this structure:
node {
stage 'Checkout'
git url: 'https:...'
def mvnHome = tool 'M3'
#Various stages here
...
stage 'Release'
sh "${mvnHome}/bin/mvn -B clean install release:prepare release:perform release:clean"
}
the problem is that maven release plugin pushes changes to BitBucket, and this triggers again the jenkins script, making an infinite loop of builds, is there a way to prevent this?
I've tried setting a quiet period in Jenkins with no success

From my perspective you should have specific jobs for build and release, and the release job should be triggered manually. Anyway, if there is some reason to have them in the job you can check for the message of the last commit:
node {
git 'https...'
sh 'git log -1 > GIT_LOG'
git_log = readFile 'GIT_LOG'
if (git_log.contains('[maven-release-plugin]')) {
currentBuild.result = 'ABORTED'
return
}
... // continue with release or whatever
}

A New Way to Do Continuous Delivery with Maven and Jenkins Pipeline article approach solves the infinite loop:
Use the Maven release plugin to prepare a release with
pushChanges=false (we are not going to push the release commits back
to master) and preparationGoals=initialize (we don't care if the tag
is bad as we will only push tags that are good)
sh "${mvnHome}/bin/mvn -DreleaseVersion=${version} -DdevelopmentVersion=${pom.version} -DpushChanges=false -DlocalCheckout=true -DpreparationGoals=initialize release:prepare release:perform -B"

Another solution can be to change the git hook (post-receive) and add a conditional curl similar to this script:
#!/bin/bash
git_log=$(git log --branches -1)
if ! [[ $git_log =~ .*maven-release-plugin.* ]] ;
then
curl http://buildserver:8080/git/notifyCommit?url=ssh://git#server/projects/name.git;
fi

Related

How to configure the branch of the jenkins #Library( 'pipeline#branch') _ programmatically

Context: MultiBranchPipeline Shred Library
We are working on test automation for pipeline development in our CI/CD system.
Our CI/CD system triggers builds based on commits to a bitbucket repositories having a Jenkinsfile (MultiBranch pipeline) for the micro services that we are deploying.
Each commit (with a Jenkinsfile in the root) triggers a build with the multibranch plugin.
The current approach is based on using those commits also for the the shared pipeline repository containing the shared Library used for the system.
So we are using a Jenkinsfile in the sharedLibrary Project which is executed on each commit and contains code to reference itself.
#Library('sharedLibrary#currentBranch') _ // this is the relevant part
#Field def projectList = [p1, p2, ... ] // list of Projects to be tested
node('testNode') {
projectList.each { project2Test ->
def gitConfig = setupGitParameters(project2Test)
stage('checkout ' + project2Test) {
withCredentials(gitConfig){
sh """"
git clone ${project2Test}
cd ${project2Test}
git config ....
git checkout -b ${testBranch}
echo 'patch Jenkinsfile'
sed -i ${changeWhatisNeeded} Jenkinsfile
git commit -am "pipeline test mit Library ${env.BRANCH_NAME} #${env.BUILD_NUMBER}" # to force a commit
git push origin ${it.new} # this push creates a new build on the MB pipeline
"""
}
}
}
}
So I am trying to parameterize the branch of the #Library annototation to match the current Branch automatically. But I failed so far.
I am hoping for any pointers to solve this issue as it is essential for a complete test automation.
As we all know, the manual editing of string constants is a proven NOGO for anything automatated!!

Use Git command line for a repository from within another Git repository

I'm working on a build job in Bamboo right now that conducts a few tasks (updating various dependencies) on a project in Git-repository A. This build is triggered by changes in a Git-repository B. So whenever a commit is pushed to repository B the build in repository A starts.
However, this build should only be started if the commit in repository B is made by a specific user. So in the build script of repository A I'd like to do a git log in repository B to check if the latest commit is done by this specific user and if not, I want to exit the script.
What I currently do is this:
if [ "$(git log -1 --pretty=format:'%an')" != "SPECIFIC_USERNAME" ]; then
echo '-----THIS COMMIT IS NOT SCHEDULED FOR BUILD-----'
exit 0
fi
However doing git log here, only shows me the logs of repository A although I need the log from repository B.
Can this be done somehow?
I appreciate any help!

SCM Poll in jenkins multibranch pipeline

Wanted to accommodate scheduled build starting 12AM every 3 hrs till 3PM on every weekday(mon-fri). It should be triggered build only if anything is committed into github repository.
Please provide the exact code as few code is working for multi-branch but not for above schedule.
Sorry what do you mean by the scheduled "build"?
Do you want the Multi-Branch to check for more branches on your given interval?
If so you can only do it by "Scan Multibranch Pipeline with defaults Triggers"
Do you want to issue a build on the branch when there is change on it?
Noted that the option in
the mult-branch folder > "Scan Multibranch Pipeline with defaults Now" and get all current branches > status > the jobs > View Configuration
is read only.
So, to alter the option, from https://issues.jenkins-ci.org/browse/JENKINS-33900?focusedCommentId=326181&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-326181
, I think you should use the Jenkinsfile to do theSCM for every job.
So, for all jobs you need to configure for SCM poll,
include a Jenkinsfile on Git for each of them (Don't forget to install the pipeline-model-definition plugin and all its dependent plugins):
pipeline {
triggers {
pollSCM('H 0-15/3 * * H(1-5)')
}
agent any
stages{
stage('Build') {
steps {
echo 'Building.. or whatever'
}
}
}
}
That should do the job, at least it works for me``
Hope it helps

Can't seem to get Multi-branch Pipeline to work with JenkinsFile

I'm sure I'm doing something stupid that most of you are going to laugh at, but I can't seem to get Jenkins to build with multi-branch pipeline. I've simplified the problem down to the very essence. A single branch (master) with an empty node JenkinsFile. I have a second project, a standard Freestyle project that basically runs true to verify it builds.
Here's my Freestyle configuration:
Repository URL: ssh://git#rgit.vegicorp.net:7999/dw/foobar.git
Credentials: None
BUILD
Execute Shell
Command: True
And the build works. (Basically, the repo checks out, true runs, and the build is reported as a success.
Here's my Multibranch build configuration:
BRANCH SOURCES
Project Repository: ssh://git#rgit.vegicorp.net:7999/dw/foobar.git
Credentials: None
BUILD CONFIGURATION
Mode: By JenkinsFile
When I do Branch Indexing, I get a failure and the log says:
Started
Setting origin to ssh://git#cmstash.travelclick.net:7999/dw/foobar.git
Fetching origin...
FATAL: Failed to recompute children of test » Jenkinsfile Test \
java.lang.IllegalStateException: Cannot open session, connection is \
not authenticated.
at com.trilead.ssh2.Connection.openSession(Connection.java:1127)
at org.jenkinsci.plugins.gitclient.trilead.TrileadSession.exec(TrileadSession.java:32)
at org.eclipse.jgit.transport.TransportGitSsh$SshFetchConnection.<init>(TransportGitSsh.java:262)
at org.eclipse.jgit.transport.TransportGitSsh.openFetch(TransportGitSsh.java:161)
at org.eclipse.jgit.transport.FetchProcess.executeImp(FetchProcess.java:136)
at org.eclipse.jgit.transport.FetchProcess.execute(FetchProcess.java:122)
at org.eclipse.jgit.transport.Transport.fetch(Transport.java:1138)
at org.eclipse.jgit.api.FetchCommand.call(FetchCommand.java:130)
at org.jenkinsci.plugins.gitclient.JGitAPIImpl.fetch(JGitAPIImpl.java:678)
at jenkins.plugins.git.AbstractGitSCMSource.retrieve(AbstractGitSCMSource.java:174)
at jenkins.scm.api.SCMSource.fetch(SCMSource.java:146)
at jenkins.branch.MultiBranchProject.computeChildren(MultiBranchProject.java:294)
at com.cloudbees.hudson.plugins.folder.computed.ComputedFolder.updateChildren(ComputedFolder.java:157)
at com.cloudbees.hudson.plugins.folder.computed.FolderComputation.run(FolderComputation.java:122)
at hudson.model.ResourceController.execute(ResourceController.java:98)
at hudson.model.Executor.run(Executor.java:410)
Finished: FAILURE
My JenkinsFile (which sits in the root of the Repo) says:
node {
}
This works when I am not doing a multi-branch pipeline and just put this in as a Jenkins build script. I just want to verify that Jenkins is able to pick up my JenkinsFile.
Found the issue: You must have credentials set even if you don't need to use credentials. The freestyle job has no credentials set and has access to this particular Git repository. In our old Jenkins server, we use ssh:// and setup public/private keys in the $HOME/.ssh directory for our Git projects. None of our Git projects use credentials and don't need them.
However, Multibranch Pipeline does require credentials -- and a non-null JenkinsFile. When I finally set the credential, the job I had to add at least one step in the JenkinsFile or else it wouldn't trigger a single build.)
i think you are also hitting BUG like me ..
{`https://issues.jenkins-ci.org/browse/JENKINS-35567
Jenkins workflow-multibranch with git - IllegalStateException  Tried adding jgit and that didn’t help
`}
Did you got this resolved ?

Restricting which downstream builds are triggered on SNAPSHOT dependency

We have a Jenkins server, using jenkins-build-per-branch to sync from git whenever a (php or java) project has a valid pom.xml. We use maven versioning strategy to manage our artefacts, and git-flow as a branching strategy / tool. We also use the jenkins option "Build whenever a SNAPSHOT dependency is built" wherever possible.
The problem we have is when building a -SNAPSHOT artefact - all hell breaks loose and everything wants to build at once. (Building a 'develop' -SNAPSHOT causes all downstream 'feature' AND 'develop' branches to start)
Ideally we would like to find some way that we don't cross pollenate between feature and develop builds when jenkins launches downstream jobs.
Has anyone tried this? Would something like the Conditional+BuildStep+Plugin help? https://wiki.jenkins-ci.org/display/JENKINS/Conditional+BuildStep+Plugin
This is an old question but it's still relevant 6 years later. There is a "threshold" field on the Build whenever a SNAPSHOT dependency is built setting that provides some control over which builds will trigger
From the pipeline-maven-plugin README:
Threshold based on the Maven lifecycle phase reached in the Maven
build of the upstream job (package, install, deploy). By default, only
the maven builds who reach the deploy phase will trigger downstream
builds.
For example, in a scripted pipeline's withMaven() you can set a pipelineGraphPublisher with lifecycleThreshold: 'deploy' like:
withMaven(
maven: MAVEN_VERSION,
jdk: JAVA_VERSION,
mavenOpts: MAVEN_OPTS,
globalMavenSettingsConfig: globals.MAVEN_SETTINGS_ID,
options: [
pipelineGraphPublisher(
lifecycleThreshold: 'deploy',
includeSnapshotVersions: true
)
]) {
sh("mvn ${PHASE}")
}
Then any SNAPSHOT build that executes a lifecycle phase below deploy (e.g. package or install) will not trigger a downstream job. Note that deploy is already the default so this example isn't particularly useful, but it shows how to use the setting and you may want to set this to another phase.
That's part one done, but now you need a way to conditionally execute different Maven lifecycle phases for the builds that you do want to trigger downstream builds vs. the ones that you don't want to trigger downstream builds. We do this based on the branch name so that Pull Request and Release branches don't trigger upstream packages:
/**
* Return the correct Maven goal for the current branch
*
* Because the pipelineGraphPublisher's lifecycleThreshold in the withMaven() call above is set to 'deploy', pipelines
* that run the 'install' goal will not trigger downstream jobs; this helps us minimize superfluous Jenkins builds:
*
* https://github.com/jenkinsci/pipeline-maven-plugin/blob/master/README.adoc#trigger-downstream-pipeline-when-a-snapshot-is-built
*/
String getGoalForCurrentBranch() {
if ( env.BRANCH_NAME ==~ /(^PR-(\d+)$)|(^releases\/v.*)/ ) {
echo("Pull Request or release branch detected! Executing Maven 'install' goal rather than 'deploy' goal to avoid triggering downstream Jenkins jobs")
return 'install'
}
return 'deploy'
}
You can then call this getGoalForCurrentBranch() method wherever you're executing mvn to determine which lifecycle phase is executed:
withMaven(
...
sh("mvn ${getGoalForCurrentBranch()}")
)
Most branches will execute mvn deploy and will trigger a downstream Jenkins job, but Pull Request branches will execute mvn install and will not trigger a downstream job.
The caveat to this is that you may have other things that depend on certain lifecycle phases. In the above example, Pull Request branch artifacts won't get deployed to your artifact repository (e.g. Nexus). In our case this is actually the desired behavior but you'll need to determine what's acceptable for you and tweak your threshold accordingly.
In the dependent projects you can disable the "Build whenever a SNAPSHOT dependency is built" hook via
if (branchName.indexOf("mule4auto") >= 0) {
println "for mule4auto do not build when mulestac is build";
// for mule4auto do not build when mulestac is build, wait for
// mule4auto-converter project has run (commited something).
} else {
tempPipelineTriggers += [
snapshotDependencies()
];
}
println "triggers: tempPipelineTriggers=${tempPipelineTriggers}";
Additionally you may need to disable the fingerprint for the specific branches which should not be build (mule4auto in our case):
// see https://github.com/jenkinsci/pipeline-maven-plugin/blob/master/README.adoc
def tempMavenOptions = [];
// disable Archiving (fingerprinting should still work)
tempMavenOptions += artifactsPublisher(disabled: true);
if (branchName.indexOf("mule4auto") >= 0) {
println "Disable fingerprint for mule4auto to prevent jobs building when mulestac4 SNAPSHOT is build";
tempMavenOptions += dependenciesFingerprintPublisher(disabled: true);
tempMavenOptions += pipelineGraphPublisher(disabled: true);
}
// see https://plugins.jenkins.io/pipeline-maven
withMaven(
// Maven installation declared in the Jenkins "Global Tool Configuration"
maven: toolMaven,
jdk: toolJdkToBeUsed,
options: tempMavenOptions
) {
println "JAVA_HOME ${JAVA_HOME}";
println "MAVEN_HOME ${MAVEN_HOME}";
....
})
(both in destination pipeline)
I do not see an option like "Build whenever an upstream dependency is built" in our Jenkin's jobs. It's called "Build whenever a SNAPSHOT dependency is built" here (Jenkins v1.592 with its latest plugins). Is that what you mean?
There's also this last sentence in its inline help: "If this behavior is problematic, uncheck this option." :-)
I don't know whether Conditional BuildStep Plugin would help in this case. We use it but not to achieve such.
Depending on how long your jobs run I'd suggest to:
use the Build whenever ... in conjunction with Advanced Project Options → Quiet period if the jobs don't run long (let's say a few minutes)
deactivate the build-whenever-all-and-everywhere as suggested and use Post-build Actions → Build other projects or Trigger parameterized build on other project to establish a real up-/downstream build flow if your jobs run longer

Resources