Trigger Jenkins Build on Perforce submit by keyword - jenkins

I am wondering if anyone knows if it is possible to trigger a Jenkins build on a Perforce commit, only if it has a certain keyword in it?
My use case is that I am looking to find a way to trigger a Jenkins build that will build a Nuget package of the library I am working on, and place it in the correct Nuget server directory. I don't want to build a Nuget package each and every time I make a submit to Perforce, so I was wondering if it is possible to set up some kind of trigger to only run the Jenkins build if some keyword was included in the changelist description.
Does anyone know if this is possible, or any other possible ideas on how to implement this?

This works for me. I'm sure it could be more efficient, but it works. This looks for the string "buildit" in the changelist description.
First, create a change-submit trigger in Perforce, e.g.,
buildit change-submit //... "/usr/bin/buildthis %changelist%"
(wherever you place it should be writable, and create a file called "description" that should also be writable).
Below is the contents of the buildthis script:
#!/bin/sh
changelist="$1"
P4PORT=perforce:1666
P4CLIENT=myclient
P4USER=myuser
p4 -p $P4PORT -c $P4CLIENT -u $P4USER describe $changelist >/usr/bin/description
if grep -q buildit /usr/bin/description;
then
curl -X POST http://jenkinsserver:port/job/jobname/build?token=TOKEN
else
exit 0
fi

Related

What's the best way to bulk update Jenkins projects?

We have hundreds of Jenkins projects (mostly created from a few templates), often need to make the same change to all of them. e.g. today I need to add a post-build step to delete workspace at the end. Next I need to change the step to copy build result to a shared drive to Nexus repository.
What's the best way to apply such kind of bulk change to Jenkins projects?
You could use Configuration Slicing Plugin which is designed to do this.
It supports many configuration options.
The REST API is quite powerful. The following sequence worked for me:
In loop for all relevant projects (list of projects is available via e.g. /api/xml?tree=jobs[name]):
download config.xml via /job/{name}/config.xml
edit using your favorite scripted xml editor (mine was xmlstarlet)
upload new config xml via /job/{name}/config.xml
Some random notes:
do *BACKUP* before doing anything
I probably could post some bash script example if anyone is interested
Good luck!
EDIT> Example bash script:
#!/bin/bash
jenkinsUrlBase='http://user:token#jenkins'
callJenkins() { # funcPath
curl --silent --show-error -g "${jenkinsUrlBase}${1}"
}
postJenkinsFile() { # funcPath fileName
curl --silent --show-error -g -d "#${2}" "${jenkinsUrlBase}${1}"
}
callJenkins '/api/xml?tree=jobs[name]' | xmlstarlet sel -t -v '//hudson/job/name' | while read projectName ; do
echo "Processing ${projectName}..."
origFile="${projectName}_old.xml"
newFile="${projectName}_new.xml"
callJenkins "/job/${projectName}/config.xml" > "$origFile"
echo " - Updating artifactory url..."
cat "$origFile" \
| xmlstarlet ed -P -u '//maven2-moduleset/publishers/org.jfrog.hudson.ArtifactoryRedeployPublisher/details/artifactoryUrl' -v "http://newServer/artifactory" \
> "${newFile}"
if false ; then
echo " - Commiting new config file..."
postJenkinsFile "/job/${projectName}/config.xml" "$newFile"
else
echo " - Dry run: not commiting new config file"
fi
done
Groovy is by far the best way to bulk update jobs. You may have to do a little digging into the jenkins / plugin api to figure out what api calls to make, but the script console (http://yourJenkinsUrl/script) provides an easy way to play around with the code until you get it right.
To get you started, you can add / remove post-build steps by calling the getPublishersList() method on a job and then calling the add / remove methods.
def publishersList = Jenkins.instance.getJob("JobName").getPublishersList()
publishersList.removeAll { it.class == whatever.plugin.class }
publishersList.add(new PluginConstructor())
If you're not sure what publisher class you need to delete the workspace, I would suggest manually adding the desired configurations to one job, and then run getPublishersList() from the script console on that job. You will see the class you are working with in the list, and then you can go look at the api to see what is required to construct it.
You can then iterate through all your jobs and add the publisher doing something like this:
Jenkins.instance.getView("All Jobs").items.each { job ->
//Maybe some logic here to filter out specific jobs
job.getPublishersList().add(new PluginConstructor())
}
Alternatively, you can use the Jenkins CLI api or the REST api, but in order to update post-build actions, you will have to modify the project configuration xml file (which isn't trivial programmatically configure) and then overwrite the job configuration with the new configuration file.
You can edit the config.xml file with your favorite text tool (I use Python) and then reload the jenkins configuration.
In my setup the jobs are stored in ~/.jenkins/jobs/*/config.xml.
See: https://wiki.jenkins-ci.org/display/JENKINS/Administering+Jenkins
Here is a small example to update foo to bar:
</com.cwctravel.hudson.plugins.extended__choice__parameter.ExtendedChoiceParameterDefinition>
<hudson.model.StringParameterDefinition>
<name>additional_requirements</name>
<description>foo</description>
...
Script:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, unicode_literals, print_function
import sys
from lxml import etree
from collections import defaultdict
def change_parameter_description(config_xml_path, parameter_name, new_description):
tree=etree.parse(config_xml_path)
for tag in tree.findall('.//hudson.model.StringParameterDefinition'):
name_tag=tag.find('./name')
if not name_tag.text==parameter_name:
continue
description=tag.find('./description')
description.text=new_description
tree.write(config_xml_path)
for config_xml_path in sys.argv[1:]:
change_parameter_description(config_xml_path, 'additional_requirements', 'bar')
In this small example a regex would work, but if things span several lines, it is better to work with xml tools :-)
The other answers are great, but if you use pipelines, I'd suggest you to use Pipeline Shared Libraries.
We have all our jobs in a git repository. To develop a new feature we try it in a branch, since it is possible to point just one job to a specific branch. When we need to update them, just merge into master. The jobs are treated as code, with a proper release process.

Jenkins - pass build name to code being built

I have my Jenkins job defined to use a timestamp for the build name. I'd also like to be able to use that build name in the code being built. For example, suppose my application prints a "startup" message during initialization. Ideally, I would be able to somehow inject the build name into this startup message.
Example:
Application XYZ, build 20160503-0420, is starting up...
I'm curious what sort of techniques folks have come up with to do something like this.
Thanks!
Well, at first insert build number directly into your code it`s very bad practice.
We create debian package by Jenkins. Debian packages contains control file, some kind of description of package, version, dependency, etc.
In our repo control file contains
Section: misc
Priority: optional
Package: #packagename
Version: 0.1.0+#build~#repo
As you see we keep fixed only major version of software
Then we create package we replace texts started by # with build variables
sed -i 's/#build/$(BUILD_NUMBER)/' $(FAKEROOT)/DEBIAN/control
sed -i 's/#repo/$(REPONAME)/' $(FAKEROOT)/DEBIAN/control
sed -i 's/#packagename/$(PROJECTNAME)/' $(FAKEROOT)/DEBIAN/control
And after that we publish, deploy, send email, doing all Jenkins magic.
I think you can build binary and distribute it
Of course if you want to add this changes into you repository you can use Git publisher, or another source management systems, but tell you again this is bad practice.
We use powershell plugin in Jenkins and this is how we write our job ...
Write-Host Build id $env:BUILD_NUMBER started at Get-Date
For more build parameters refer to below URL
https://wiki.jenkins-ci.org/display/JENKINS/Building+a+software+project#Buildingasoftwareproject-JenkinsSetEnvironmentVariables

How can I delete files in directory using jenkins

In my system, I am downloading new build everyday in 1 folder and then use it for further causes but after running jenkins job I want to delete files in the folder (not workspace) which will delete specific folders from same directory. This will help me downloading new build every time based on different jenkins job running on same machine.
EG:
I am downloading x.x build and then running jenkins job on machine and then if I want to run other job which requires x.y build, it will just see if SOME build is already there in folder. if it is there, it will not download any kit after that. So, now simplest thing I can do is delete x.x after every jenkins run (post build ) so it will download x.y next time..
Please help.
Thanks in advance
You can delete the whole folder using this syntax to delete a folder called bin:
stage('Setup') {
steps {
dir ('bin') {
deleteDir()
}
}
}
If my understanding is right, consider my below assumptions
If your jenkins is running on a Unix server, then you can configure a post build step as suggested by nerdwaller above
In the job configuration, in the build step, select the option "execute unix command"
In the box for the shell script, you can use rm -rf <<directoryname>>
Else, if your jenkins is running on a windows server, then select "execute batch command" from the build step and give the appropriate command like rmdir /Q /S nonemptydir
However, my best approach would be to use a platform independent tool like ant to delete the folders using Ant Delete Task and it can be configured similarly like the above two approaches instead selecting "invoke ant" in the build step/ post build step.
This will help you to achieve what you need.

How to get surefire reports form Travis-CI build?

The question says it all really. How can I download or view the surefire-reports generated during a build on Travis?
You can just do
after_failure:
- cat target/surefire-reports/*.txt
Having not found a direct way to access the surefire-report files I came up with the this workaround:
In .travis.yml I added an after_failure hook:
after_failure: print_surefire_reports.sh
In the hook print_surefire_reports.sh I put:
#!/usr/bin/env sh
echo "Current directory is $(pwd)"
echo "\n=== SUREFIRE REPORTS ===\n"
for F in target/surefire-reports/*.txt
do
echo $F
cat $F
echo
done
I am using python html2text in travis after script phase.
My travis script looks like:
after_script:
- python html2text.py target/site/surefire-report.html
surefire-report.html is generated by surefire-report-plugin
See example output here: https://travis-ci.org/rmpestano/dbunit-rules/builds/160170324#L3541
Based on this bug report and this question, there is not a clean way to do this. There are, however, a couple unsupported methods of getting the reports listed in the bug report.
Those may provide options for you to look into, but the Travis CI maintainers have not provided or supported an explicit way to handle this yet. Note that those bug reports/questions are well over a year old too.
The prevailing suggestion in those threads seems to be to have Travis recommit the build artifacts back to the user's repository. This, however, requires authentication, which you probably shouldn't store in your .travis.yml file

Getting the list of files changed from a commit in perforce

Is there a way, in Hudson, of getting the list of files from a p4 change list and passing it to an ant build script ?
Do you want to just trigger your Ant build script if a check-in is made to Perforce ? If so, that's straightforward; use the Perforce plugin.
You might be able to parse them out of the change list that Hudson generates. I don't know of any way to get it from the p4 plugin, although I think it would be useful information also.
Try something like this:
wget ${BUILD_URL}/changes -O - > changes.txt

Resources