I'm trying to create two individual pipelines which should run based on a boolean value. I'm able to create boolean conditions which help to run pipelines, but I'm not getting a proper way to create pipelines.
stage('creating env') {
steps {
dir("${WORKSPACE}/test") {
echo 'creating work env'
catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
sh "python3 -u test.py"
}
}
}
}
static def test_1() {
echo 'Running test_1'
stage('TEST_1') {
parallel {
steps {
script {
def startTime = new Date()
long l1 = startTime.getTime()
Date endTime = new Date()
long l2 = endTime.getTime()
long diff = l2 - l1
long secondInMillis = 1000
long minuteInMillis = secondInMillis * 60
long hourInMillis = minuteInMillis * 60
long elapsedHours = diff / hourInMillis
diff = diff % hourInMillis
long elapsedMinutes = diff / minuteInMillis
diff = diff % minuteInMillis
long elapsedSeconds = diff / secondInMillis
if (elapsedMinutes>10){
buildbadgevdi.setColor('orange')
}
buildbadgevdi.setStatus("${elapsedMinutes}min ${elapsedSeconds}sec ")
stage('Tests') {
if (params.Test_1) {
Test_1()
}
if (params.Test_2) {
Test_2()
}
}
}
post {
Same Logic I want repeat in Test_2() with different sets of test.
Above logic is failing with error:
Method definition not expected here. Please define the method at an appropriate place or perhaps try using a block/Closure instead
Related
I am trying to place timeout in below code and skip rest of the stages in jenkins if still "status = progress" after 3 minutes.
script {
def date = new Date()
currtime = date.getTime()
future_time = date.getTime() + 3 * 60000
while (currtime < future_time) {
date = new Date()
currtime = date.getTime()
Status= "IN_PROGRESS"
if (Status == 'IN_PROGRESS') {
echo 'Status is IN_PROGRESS'
} else if (Status == 'SUCCEEDED') {
break
} else if (Status == 'FAILED') {
echo "Status is FAILED"
exit(1)
} else {
exit(1)
}
}
}
You can just use timeout inside your pipeline without any custom time calculation. It automatically works while stage in the "IN_PROGRESS" status. When a timeout is reached, all next stages will be skipped, and job status will be "ABORTED".
pipeline {
agent {
label 'agent_name'
}
stages {
stage('Stage_name') {
steps {
timeout(time: 3, unit: 'MINUTES') {
script {
// Your logic here ...
}
}
}
}
stage { .. }
stage { .. }
}
}
Also, I guess your question is related to this one. You can find there more examples.
I want to schedule a job to be at the top of the build queue in Jenkins via a Groovy Postbuild.
For example, for Build X
If previously the build queue looks like this:
Generic Build 1
Generic Build 2
Generic build 3
Now it should look like:
Build X
Generic Build 1
Generic Build 2
Generic Build 3
So far I've been able to schedule the job using
def waitingItem = Jenkins.get().getQueue().schedule(job, 0)
if (waitingItem == null) {
manager.listener.logger.println "Error scheduling ${job}!"
} else {
manager.listener.logger.println "${job.name} was scheduled!"
}
but now I also want waitingItem to be at the top of the queue.
Any help is much appreciated.
Ok so after countless hours of browsing the web I've been able to come up with a Groovy Postbuild script that does the following: once it finishes the build, it triggers another build (let's call it buildToBeTriggered) and buildToBeTriggered automatically gets pushed at the front of the queue.
The code is below:
import hudson.model.AbstractProject
import hudson.model.Queue
import hudson.model.queue.QueueSorter
import jenkins.model.Jenkins
def job = (AbstractProject)Jenkins.get().getItem('gcimpoies-toTrigger')
def isSuccess = manager.getResult() == 'SUCCESS'
def isRelease = manager.getEnvVariable('RELEASE') == 'true'
def secondsToWait = 20
if (isSuccess) {
def waitingItem = Jenkins.get().getQueue().schedule(job, 0)
if (waitingItem == null) {
manager.listener.logger.println "Error scheduling ${job}!"
} else {
manager.listener.logger.println "${job.name} was scheduled!"
}
Thread.sleep(secondsToWait * 1000)
//replace the original queue sorter with one that will place our project build first in the queue
QueueSorter originalQueueSorter = Jenkins.get().getQueue().getSorter()
AcceleratedBuildNowSorter acceleratedBuildNowSorter = new AcceleratedBuildNowSorter(job, originalQueueSorter)
Jenkins.get().getQueue().setSorter(acceleratedBuildNowSorter);
// we sort the queue so that our project is next to be built on the list
Jenkins.get().getQueue().getSorter().sortBuildableItems(Jenkins.getInstance().getQueue().getBuildableItems())
}
class AcceleratedBuildNowSorter extends QueueSorter {
private final AbstractProject project
private final QueueSorter originalQueueSorter
private final AcceleratedBuildNowComparator comparator
AcceleratedBuildNowSorter(AbstractProject project, QueueSorter originalQueueSorter) {
this.project = project
this.originalQueueSorter = originalQueueSorter
comparator = new AcceleratedBuildNowComparator(this.project)
}
#Override
void sortBuildableItems(List<Queue.BuildableItem> buildables) {
if (this.originalQueueSorter != null) {
this.originalQueueSorter.sortBuildableItems(buildables)
}
Collections.sort(buildables, comparator)
}
}
class AcceleratedBuildNowComparator implements Comparator<Queue.BuildableItem> {
private final AbstractProject mostPriorityProject;
AcceleratedBuildNowComparator(AbstractProject mostPriorityProject) {
this.mostPriorityProject = mostPriorityProject;
}
int compare(Queue.BuildableItem buildableItem0, Queue.BuildableItem buildableItem1) {
AbstractProject<?, ?> project0 = (AbstractProject<?, ?>) buildableItem0.task
AbstractProject<?, ?> project1 = (AbstractProject<?, ?>) buildableItem1.task
if (project0.equals(mostPriorityProject)) {
return -1
}
if (project1.equals(mostPriorityProject)) {
return 1
}
return 0
}
}
I want to view the more recent X builds for several Jenkins jobs.
So if I wanted to show the last 5 builds for jobs 1-5 it would looks something like this:
status build time
-------------------------
pass job1#3 13:54
fail job1#2 13:05
fail job1#1 13:01
pass job5#1 12:17
pass job3#1 11:03
How can I accomplish this?
Notice the builds of the jobs are woven together so if one job has run many builds recently it will show up more than other jobs that haven't run as much.
Executing the following script in the Script Console (Manage Jenkins -> Script Console):
import java.text.SimpleDateFormat
def numHoursBack = 24
def dateFormat = new SimpleDateFormat("HH:mm")
def buildNameWidth = 30
def cutOfTime = System.currentTimeMillis() - numHoursBack * 3600 * 1000
SortedMap res = new TreeMap();
for (job in Jenkins.instance.getAllItems(BuildableItem.class)) {
for (build in job.getBuilds()) {
if (build.getTimeInMillis() < cutOfTime) {
break;
}
res.put(build.getTimeInMillis(), build)
}
}
def format = "%-10s%-${buildNameWidth}s%-10s"
println(String.format(format, "status", "build", "Time"))
for (entry in res.descendingMap().entrySet()) {
def build = entry.getValue()
println(String.format(format, build.getResult(), build.getFullDisplayName(), dateFormat.format(build.getTime())))
}
For me this gives:
status build Time
SUCCESS xxx #107393 17:53
SUCCESS xxx #107392 17:48
SUCCESS xxx #107391 17:43
null yyy #3030 17:38
SUCCESS xxx #107390 17:38
FAILURE zzz #3248 17:37
...
You might need to change the numHoursBack constant, it controls the number of hours back to look for builds. As well as the buildNameWidth which determines the column width of the build column (if you have really long job and build names you might need to extend this).
Here is a bit cleanup version of Jon S Groovy script. Also displaying worst build information.
import hudson.model.*;
import java.text.SimpleDateFormat;
//
// Settings
//
def numHoursBack = 24;
def dateFormat = new SimpleDateFormat("HH:mm");
def cutOfTime = System.currentTimeMillis() - numHoursBack * 3600 * 1000;
/**
* Basic build information.
*/
def printBuildInfo(finalizedBuild) {
String level = "INFO";
String result = finalizedBuild.getResult().toString();
switch (result) {
case "UNSTABLE":
level = "WARNING";
break;
case "FAILURE":
level = "ERROR";
break;
}
// basic info and URL
println(String.format(
"[%s] Build %s result is: %s.",
level,
finalizedBuild.getFullDisplayName(),
result
));
// pipe description from downstream
def description = finalizedBuild.getDescription();
if (description != null && !description.isEmpty()) {
println(description.replaceAll("<br>", ""));
}
return finalizedBuild;
}
/**
* Get recent build items.
*/
def getRencentBuilds(cutOfTime) {
SortedMap res = new TreeMap();
for (job in Jenkins.instance.getAllItems(BuildableItem.class)) {
for (build in job.getBuilds()) {
if (build.getTimeInMillis() < cutOfTime) {
break;
}
res.put(build.getTimeInMillis(), build);
}
}
return res;
}
/**
* Print build items.
*
* minResult - minimum to print
*/
def printBuilds(builds, minResult, dateFormat) {
def format = "%-10s %-8s %s";
Result worstResult = Result.SUCCESS;
def worstBuild = null;
// header
println(String.format(format, "status", "Time", "build"));
// list
for (entry in builds.descendingMap().entrySet()) {
def build = entry.getValue();
Result result = build.getResult();
if (result.isWorseThan(worstResult)) {
worstResult = result;
worstBuild = build;
}
if (result.isWorseOrEqualTo(minResult)) {
println(String.format(
format, build.getResult(), dateFormat.format(build.getTime()), build.getFullDisplayName()
));
}
}
return worstBuild;
}
def builds = getRencentBuilds(cutOfTime);
println ("\n\n----------------------\n Failed builds:\n");
def worstBuild = printBuilds(builds, Result.FAILURE, dateFormat);
println ("\n\n----------------------\n Worst build:\n");
if (worstBuild != null) {
printBuildInfo(worstBuild);
}
println ("\n\n----------------------\n All builds:\n");
printBuilds(builds, Result.SUCCESS, dateFormat);
I am using a jenkins pipeline project. In the script I would like to write the parallel block in a dynamic way, since the number of nodes can change. For instance, from this:
parallel(
node1: {
node(){
stage1()
stage2()
...
}
},
node2: {
node(){
stage1()
stage2()
...
}
},
...
)
to something like this
for (int i = 0; i < $NODE_NUMBER; i++) {
"node${i}": {
node (’namenode-' + ${i}) {
something()
}
}
but this way doesn’t work, Groovy/Jenkins is not happy about this syntax. Can someone suggest a better way for doing this?
You can define node map like branches first, and then execute them as parallel branches.
def numNodes = 4
def branches = [:]
for(int i = 0; i < numNodes; i++) {
branches["node${i}"] = {
node("namenode-${i}") {
something()
}
}
}
parallel branches
Anyone have a Jenkins Pipeline script that can stuff all the changes since the previous successful build in a variable? I'm using git and a multibranch pipeline job.
Well I managed to cobble something together. I'm pretty sure you can iterate the arrays better but here's what I've got for now:
node('Android') {
passedBuilds = []
lastSuccessfulBuild(passedBuilds, currentBuild);
def changeLog = getChangeLog(passedBuilds)
echo "changeLog ${changeLog}"
}
def lastSuccessfulBuild(passedBuilds, build) {
if ((build != null) && (build.result != 'SUCCESS')) {
passedBuilds.add(build)
lastSuccessfulBuild(passedBuilds, build.getPreviousBuild())
}
}
#NonCPS
def getChangeLog(passedBuilds) {
def log = ""
for (int x = 0; x < passedBuilds.size(); x++) {
def currentBuild = passedBuilds[x];
def changeLogSets = currentBuild.rawBuild.changeSets
for (int i = 0; i < changeLogSets.size(); i++) {
def entries = changeLogSets[i].items
for (int j = 0; j < entries.length; j++) {
def entry = entries[j]
log += "* ${entry.msg} by ${entry.author} \n"
}
}
}
return log;
}
Based on the answer from CaptRespect I came up with the following script for use in the declarative pipeline:
def changes = "Changes:\n"
build = currentBuild
while(build != null && build.result != 'SUCCESS') {
changes += "In ${build.id}:\n"
for (changeLog in build.changeSets) {
for(entry in changeLog.items) {
for(file in entry.affectedFiles) {
changes += "* ${file.path}\n"
}
}
}
build = build.previousBuild
}
echo changes
This is quite useful in stage->when->expression parts to run a stage only when certain files were changed. I haven't gotten to that part yet though, I'd love to create a shared library from this and make it possible to pass it some globbing patterns to check for.
EDIT: Check the docs btw, in case you want to delve a little deeper. You should be able to convert all the object.getSomeProperty() calls into just entry.someProperty.
This is what I've used:
def listFilesForBuild(build) {
def files = []
currentBuild.changeSets.each {
it.items.each {
it.affectedFiles.each {
files << it.path
}
}
}
files
}
def filesSinceLastPass() {
def files = []
def build = currentBuild
while(build.result != 'SUCCESS') {
files += listFilesForBuild(build)
build = build.getPreviousBuild()
}
return files.unique()
}
def files = filesSinceLastPass()
There's the Changes Since Last Success Plugin that could help you with that.
For anyone using Accurev here is an adaptation of andsens answer. andsens answer can't be used because the Accurev plugin doesn't implement getAffectedFiles. Documentation for the AccurevTransaction that extends the ChangeLogSet.Entry class can be found at here.
import hudson.plugins.accurev.*
def changes = "Changes: \n"
build = currentBuild
// Go through the previous builds and get changes until the
// last successful build is found.
while (build != null && build.result != 'SUCCESS') {
changes += "Build ${build.id}:\n"
for (changeLog in build.changeSets) {
for (AccurevTransaction entry in changeLog.items) {
changes += "\n Issue: " + entry.getIssueNum()
changes += "\n Change Type: " + entry.getAction()
changes += "\n Change Message: " + entry.getMsg()
changes += "\n Author: " + entry.getAuthor()
changes += "\n Date: " + entry.getDate()
changes += "\n Files: "
for (path in entry.getAffectedPaths()) {
changes += "\n " + path;
}
changes += "\n"
}
}
build = build.previousBuild
}
echo changes
writeFile file: "changeLog.txt", text: changes
In order to return the changes as a list of strings, instead of just printing them, you may use this function (based on #andsens answer):
def getChangesSinceLastSuccessfulBuild() {
def changes = []
def build = currentBuild
while (build != null && build.result != 'SUCCESS') {
changes += (build.changeSets.collect { changeSet ->
(changeSet.items.collect { item ->
(item.affectedFiles.collect { affectedFile ->
affectedFile.path
}).flatten()
}).flatten()
}).flatten()
build = build.previousBuild
}
return changes.unique()
}