Re: Failing a Build Flow
Nicolas, Do you have a recommendation on how I can accomplish the goal at hand? Otherwise, I see no other option but to try Marc's groovy script. Thanks. On Jan 10, 2014, at 2:51 AM, nicolas de loof nicolas.del...@gmail.com wrote: I don't recommend such a fully programmatic approach, build-flow is designed as a DSL, admittedly not constrained to just supported keywords (because I didn't know how to do this when I started this plugin) but clearly not supposed to be used to create such a groovy script. 2014/1/10 Marc MacIntyre marc...@purestorage.com You are overthinking it :) The trick is to grab the return value from the build() call and check the result of that, then explicitly set the failure state of the buildflow. This is what I'm doing; it's more solution than you need, but it solves your problem. This buildflow takes a map of jobs and the pass criteria, and fires everything off in parallel. If you want to retry on failures, that's supported, and/or you can start several in parallel and pass if some portion of them pass. We use job names as the map key, so if you want to start multiple runs of a particular job with different params, you'll need to modify the script somewhat. def createBuildClosure(String jn, Map args, int retryCount = 0) { // This indirection is needed to force a clone of args, so it's out of scope and gets // re-bound to the closure each time - otherwise jenkins will deduplicate our builds. def ags = args.clone() ags.put(_dedup, java.lang.System.nanoTime()) if (retryCount) { return { retry(retryCount) {build(ags, jn)} } } else { return {build(ags, jn)} } } def startParallelRuns(Map buildsToRun) { def m = [:] buildsToRun.each { jobName, params - def maxFailures = params.get(maxFailures, 0) def retryCount = params.get(retryCount, 0) println Running +jobName+ +params.count+ times (max failures +maxFailures+) for (int idx = 0; idx params.count; idx++) { m.put(jobName+_+idx, createBuildClosure(jobName, params.args, retryCount)) } } ignore(FAILURE) { join = parallel(m) } results = [:] // process the results by job name buildsToRun.each { jobName, params - def passcount = 0 def maxFailures = params.get(maxFailures, 0) for (int idx = 0; idx params.count; idx++) { run = join[jobName+_+idx] if (run.result == SUCCESS) { passcount += 1} } result = (params.count - passcount) maxFailures ? FAILURE : SUCCESS println +result+: +jobName+: +passcount+/+params.count+ passed (Max failures: +maxFailures+) results[jobName] = result } return results } build_params = params.clone() // Modify your build params here build_params.put('UPSTREAM_JOB', build.project.name) buildsToRun = [ job1: [count: 1, maxFailures: 0, args: build_params, retryCount: 2], job2: [count: 1, maxFailures: 0, args: build_params], job3: [count: 1, maxFailures: 0, args: build_params], jobX: [count: 2, maxFailures: 0, args: build_params], jobY: [count: 1, maxFailures: 0, args: build_params], ] results = startParallelRuns(buildsToRun) build.state.result = results.any { job, result - result == FAILURE} ? FAILURE : SUCCESS On Thu, Jan 9, 2014 at 8:22 PM, silver pja...@gmail.com wrote: Sorry for any confusion. The line: ”println(“There were “+FailuresPresent+ test(s) that failed”); is outside of the if statement resulting in the example output at the end of this message. On Jan 9, 2014, at 9:55 PM, silver pja...@gmail.com wrote: When I run jobs in parallel, the Build Flow fails or passes as I’d expect. Example: parallel ( { build(job1) }, { build(job2) }, { build(job3) }, ) All of the jobs are started and if they all pass, the Build Flow passes. If one fails, the Build Flow fails. What I’d like to do is to run jobs sequentially, ignoring a failure *for that moment* but at the end, fail or pass the Build Flow as a whole. Using “ignore(FAILURE) doesn’t give me what I want because it will ignore a failure and pass the Build Flow regardless: ignore(FAILURE) {build(job1)} ignore(FAILURE) {build(job2)} ignore(FAILURE) {build(job3)} If they all fail, the Build Flow still passes because failures are ignored. But I really need ALL of the jobs to run no matter the outcome of the other jobs, and the Build Flow to pass/fail, depending on each outcome. Therefore, I have tried something like this (which I thought I got to actually work at one point but I can’t get it to work again!?! The closest I can get is explained further down.): FailuresPresent = 0; try { build(job1) }catch(e) { FailuresPresent =
Re: Failing a Build Flow
This isn't supported at this time - I don't really get your use-case why can't you run those jobs in parallel ? If they actually depend on each other sequentially, why not stop the flow when first one fails ? 2014/1/10 silver pja...@gmail.com Nicolas, Do you have a recommendation on how I can accomplish the goal at hand? Otherwise, I see no other option but to try Marc's groovy script. Thanks. On Jan 10, 2014, at 2:51 AM, nicolas de loof nicolas.del...@gmail.com wrote: I don't recommend such a fully programmatic approach, build-flow is designed as a DSL, admittedly not constrained to just supported keywords (because I didn't know how to do this when I started this plugin) but clearly not supposed to be used to create such a groovy script. 2014/1/10 Marc MacIntyre marc...@purestorage.com You are overthinking it :) The trick is to grab the return value from the build() call and check the result of that, then explicitly set the failure state of the buildflow. This is what I'm doing; it's more solution than you need, but it solves your problem. This buildflow takes a map of jobs and the pass criteria, and fires everything off in parallel. If you want to retry on failures, that's supported, and/or you can start several in parallel and pass if some portion of them pass. We use job names as the map key, so if you want to start multiple runs of a particular job with different params, you'll need to modify the script somewhat. def createBuildClosure(String jn, Map args, int retryCount = 0) { // This indirection is needed to force a clone of args, so it's out of scope and gets // re-bound to the closure each time - otherwise jenkins will deduplicate our builds. def ags = args.clone() ags.put(_dedup, java.lang.System.nanoTime()) if (retryCount) { return { retry(retryCount) {build(ags, jn)} } } else { return {build(ags, jn)} } } def startParallelRuns(Map buildsToRun) { def m = [:] buildsToRun.each { jobName, params - def maxFailures = params.get(maxFailures, 0) def retryCount = params.get(retryCount, 0) println Running +jobName+ +params.count+ times (max failures +maxFailures+) for (int idx = 0; idx params.count; idx++) { m.put(jobName+_+idx, createBuildClosure(jobName, params.args, retryCount)) } } ignore(FAILURE) { join = parallel(m) } results = [:] // process the results by job name buildsToRun.each { jobName, params - def passcount = 0 def maxFailures = params.get(maxFailures, 0) for (int idx = 0; idx params.count; idx++) { run = join[jobName+_+idx] if (run.result == SUCCESS) { passcount += 1} } result = (params.count - passcount) maxFailures ? FAILURE : SUCCESS println +result+: +jobName+: +passcount+/+params.count+ passed (Max failures: +maxFailures+) results[jobName] = result } return results } build_params = params.clone() // Modify your build params here build_params.put('UPSTREAM_JOB', build.project.name) buildsToRun = [ job1: [count: 1, maxFailures: 0, args: build_params, retryCount: 2], job2: [count: 1, maxFailures: 0, args: build_params], job3: [count: 1, maxFailures: 0, args: build_params], jobX: [count: 2, maxFailures: 0, args: build_params], jobY: [count: 1, maxFailures: 0, args: build_params], ] results = startParallelRuns(buildsToRun) build.state.result = results.any { job, result - result == FAILURE} ? FAILURE : SUCCESS On Thu, Jan 9, 2014 at 8:22 PM, silver pja...@gmail.com wrote: Sorry for any confusion. The line: ”println(“There were “+FailuresPresent+ test(s) that failed”); is outside of the if statement resulting in the example output at the end of this message. On Jan 9, 2014, at 9:55 PM, silver pja...@gmail.com wrote: When I run jobs in parallel, the Build Flow fails or passes as I’d expect. Example: parallel ( { build(job1) }, { build(job2) }, { build(job3) }, ) All of the jobs are started and if they all pass, the Build Flow passes. If one fails, the Build Flow fails. What I’d like to do is to run jobs sequentially, ignoring a failure *for that moment* but at the end, fail or pass the Build Flow as a whole. Using “ignore(FAILURE) doesn’t give me what I want because it will ignore a failure and pass the Build Flow regardless: ignore(FAILURE) {build(job1)} ignore(FAILURE) {build(job2)} ignore(FAILURE) {build(job3)} If they all fail, the Build Flow still passes because failures are ignored. But I really need ALL of the jobs to run no matter the outcome of the other jobs, and the Build Flow to pass/fail, depending on each outcome. Therefore, I have tried something like this (which I thought I got to actually work at
Re: Failing a Build Flow
I can’t run the jobs in parallel because I’m resource limited on my Selenium hub. They do *not* depend on each other sequentially. The use case is that I need a group of jobs to run through to completion in succession, not parallel, but at the end, if at any point a job had failed, to fail the build…not ignore failures. There is a guard/rescue for try/finally. Why not have a try/catch equivalent? That’s basically what I need, I think. On Jan 10, 2014, at 8:32 AM, nicolas de loof nicolas.del...@gmail.com wrote: This isn't supported at this time - I don't really get your use-case why can't you run those jobs in parallel ? If they actually depend on each other sequentially, why not stop the flow when first one fails ? 2014/1/10 silver pja...@gmail.com Nicolas, Do you have a recommendation on how I can accomplish the goal at hand? Otherwise, I see no other option but to try Marc's groovy script. Thanks. On Jan 10, 2014, at 2:51 AM, nicolas de loof nicolas.del...@gmail.com wrote: I don't recommend such a fully programmatic approach, build-flow is designed as a DSL, admittedly not constrained to just supported keywords (because I didn't know how to do this when I started this plugin) but clearly not supposed to be used to create such a groovy script. 2014/1/10 Marc MacIntyre marc...@purestorage.com You are overthinking it :) The trick is to grab the return value from the build() call and check the result of that, then explicitly set the failure state of the buildflow. This is what I'm doing; it's more solution than you need, but it solves your problem. This buildflow takes a map of jobs and the pass criteria, and fires everything off in parallel. If you want to retry on failures, that's supported, and/or you can start several in parallel and pass if some portion of them pass. We use job names as the map key, so if you want to start multiple runs of a particular job with different params, you'll need to modify the script somewhat. def createBuildClosure(String jn, Map args, int retryCount = 0) { // This indirection is needed to force a clone of args, so it's out of scope and gets // re-bound to the closure each time - otherwise jenkins will deduplicate our builds. def ags = args.clone() ags.put(_dedup, java.lang.System.nanoTime()) if (retryCount) { return { retry(retryCount) {build(ags, jn)} } } else { return {build(ags, jn)} } } def startParallelRuns(Map buildsToRun) { def m = [:] buildsToRun.each { jobName, params - def maxFailures = params.get(maxFailures, 0) def retryCount = params.get(retryCount, 0) println Running +jobName+ +params.count+ times (max failures +maxFailures+) for (int idx = 0; idx params.count; idx++) { m.put(jobName+_+idx, createBuildClosure(jobName, params.args, retryCount)) } } ignore(FAILURE) { join = parallel(m) } results = [:] // process the results by job name buildsToRun.each { jobName, params - def passcount = 0 def maxFailures = params.get(maxFailures, 0) for (int idx = 0; idx params.count; idx++) { run = join[jobName+_+idx] if (run.result == SUCCESS) { passcount += 1} } result = (params.count - passcount) maxFailures ? FAILURE : SUCCESS println +result+: +jobName+: +passcount+/+params.count+ passed (Max failures: +maxFailures+) results[jobName] = result } return results } build_params = params.clone() // Modify your build params here build_params.put('UPSTREAM_JOB', build.project.name) buildsToRun = [ job1: [count: 1, maxFailures: 0, args: build_params, retryCount: 2], job2: [count: 1, maxFailures: 0, args: build_params], job3: [count: 1, maxFailures: 0, args: build_params], jobX: [count: 2, maxFailures: 0, args: build_params], jobY: [count: 1, maxFailures: 0, args: build_params], ] results = startParallelRuns(buildsToRun) build.state.result = results.any { job, result - result == FAILURE} ? FAILURE : SUCCESS On Thu, Jan 9, 2014 at 8:22 PM, silver pja...@gmail.com wrote: Sorry for any confusion. The line: ”println(“There were “+FailuresPresent+ test(s) that failed”); is outside of the if statement resulting in the example output at the end of this message. On Jan 9, 2014, at 9:55 PM, silver pja...@gmail.com wrote: When I run jobs in parallel, the Build Flow fails or passes as I’d expect. Example: parallel ( { build(job1) }, { build(job2) }, { build(job3) }, ) All of the jobs are started and if they all pass, the Build Flow passes. If one fails, the Build Flow fails. What I’d like to do is to run jobs sequentially, ignoring a failure *for that moment* but at the
Re: Failing a Build Flow
ok, then the issue isn't an orchestration but resource one - this applies to all jobs on your instance, not just the ones from a specific flow - and you should use https://wiki.jenkins-ci.org/display/JENKINS/Locks+and+Latches+plugin to ensure your selenium jobs don't run concurrently 2014/1/10 silver pja...@gmail.com I can’t run the jobs in parallel because I’m resource limited on my Selenium hub. They do *not* depend on each other sequentially. The use case is that I need a group of jobs to run through to completion in succession, not parallel, but at the end, if at any point a job had failed, to fail the build…not ignore failures. There is a guard/rescue for try/finally. Why not have a try/catch equivalent? That’s basically what I need, I think. On Jan 10, 2014, at 8:32 AM, nicolas de loof nicolas.del...@gmail.com wrote: This isn't supported at this time - I don't really get your use-case why can't you run those jobs in parallel ? If they actually depend on each other sequentially, why not stop the flow when first one fails ? 2014/1/10 silver pja...@gmail.com Nicolas, Do you have a recommendation on how I can accomplish the goal at hand? Otherwise, I see no other option but to try Marc's groovy script. Thanks. On Jan 10, 2014, at 2:51 AM, nicolas de loof nicolas.del...@gmail.com wrote: I don't recommend such a fully programmatic approach, build-flow is designed as a DSL, admittedly not constrained to just supported keywords (because I didn't know how to do this when I started this plugin) but clearly not supposed to be used to create such a groovy script. 2014/1/10 Marc MacIntyre marc...@purestorage.com You are overthinking it :) The trick is to grab the return value from the build() call and check the result of that, then explicitly set the failure state of the buildflow. This is what I'm doing; it's more solution than you need, but it solves your problem. This buildflow takes a map of jobs and the pass criteria, and fires everything off in parallel. If you want to retry on failures, that's supported, and/or you can start several in parallel and pass if some portion of them pass. We use job names as the map key, so if you want to start multiple runs of a particular job with different params, you'll need to modify the script somewhat. def createBuildClosure(String jn, Map args, int retryCount = 0) { // This indirection is needed to force a clone of args, so it's out of scope and gets // re-bound to the closure each time - otherwise jenkins will deduplicate our builds. def ags = args.clone() ags.put(_dedup, java.lang.System.nanoTime()) if (retryCount) { return { retry(retryCount) {build(ags, jn)} } } else { return {build(ags, jn)} } } def startParallelRuns(Map buildsToRun) { def m = [:] buildsToRun.each { jobName, params - def maxFailures = params.get(maxFailures, 0) def retryCount = params.get(retryCount, 0) println Running +jobName+ +params.count+ times (max failures +maxFailures+) for (int idx = 0; idx params.count; idx++) { m.put(jobName+_+idx, createBuildClosure(jobName, params.args, retryCount)) } } ignore(FAILURE) { join = parallel(m) } results = [:] // process the results by job name buildsToRun.each { jobName, params - def passcount = 0 def maxFailures = params.get(maxFailures, 0) for (int idx = 0; idx params.count; idx++) { run = join[jobName+_+idx] if (run.result == SUCCESS) { passcount += 1} } result = (params.count - passcount) maxFailures ? FAILURE : SUCCESS println +result+: +jobName+: +passcount+/+params.count+ passed (Max failures: +maxFailures+) results[jobName] = result } return results } build_params = params.clone() // Modify your build params here build_params.put('UPSTREAM_JOB', build.project.name) buildsToRun = [ job1: [count: 1, maxFailures: 0, args: build_params, retryCount: 2], job2: [count: 1, maxFailures: 0, args: build_params], job3: [count: 1, maxFailures: 0, args: build_params], jobX: [count: 2, maxFailures: 0, args: build_params], jobY: [count: 1, maxFailures: 0, args: build_params], ] results = startParallelRuns(buildsToRun) build.state.result = results.any { job, result - result == FAILURE} ? FAILURE : SUCCESS On Thu, Jan 9, 2014 at 8:22 PM, silver pja...@gmail.com wrote: Sorry for any confusion. The line: ”println(“There were “+FailuresPresent+ test(s) that failed”); is outside of the if statement resulting in the example output at the end of this message. On Jan 9, 2014, at 9:55 PM, silver pja...@gmail.com wrote: When I run jobs in parallel, the Build Flow fails or passes as I’d expect. Example: parallel (
Re: Failing a Build Flow
That aside, I'm using this in production and it works well. Sent from my iPhone On Jan 9, 2014, at 11:51 PM, nicolas de loof nicolas.del...@gmail.com wrote: I don't recommend such a fully programmatic approach, build-flow is designed as a DSL, admittedly not constrained to just supported keywords (because I didn't know how to do this when I started this plugin) but clearly not supposed to be used to create such a groovy script. 2014/1/10 Marc MacIntyre marc...@purestorage.com You are overthinking it :) The trick is to grab the return value from the build() call and check the result of that, then explicitly set the failure state of the buildflow. This is what I'm doing; it's more solution than you need, but it solves your problem. This buildflow takes a map of jobs and the pass criteria, and fires everything off in parallel. If you want to retry on failures, that's supported, and/or you can start several in parallel and pass if some portion of them pass. We use job names as the map key, so if you want to start multiple runs of a particular job with different params, you'll need to modify the script somewhat. def createBuildClosure(String jn, Map args, int retryCount = 0) { // This indirection is needed to force a clone of args, so it's out of scope and gets // re-bound to the closure each time - otherwise jenkins will deduplicate our builds. def ags = args.clone() ags.put(_dedup, java.lang.System.nanoTime()) if (retryCount) { return { retry(retryCount) {build(ags, jn)} } } else { return {build(ags, jn)} } } def startParallelRuns(Map buildsToRun) { def m = [:] buildsToRun.each { jobName, params - def maxFailures = params.get(maxFailures, 0) def retryCount = params.get(retryCount, 0) println Running +jobName+ +params.count+ times (max failures +maxFailures+) for (int idx = 0; idx params.count; idx++) { m.put(jobName+_+idx, createBuildClosure(jobName, params.args, retryCount)) } } ignore(FAILURE) { join = parallel(m) } results = [:] // process the results by job name buildsToRun.each { jobName, params - def passcount = 0 def maxFailures = params.get(maxFailures, 0) for (int idx = 0; idx params.count; idx++) { run = join[jobName+_+idx] if (run.result == SUCCESS) { passcount += 1} } result = (params.count - passcount) maxFailures ? FAILURE : SUCCESS println +result+: +jobName+: +passcount+/+params.count+ passed (Max failures: +maxFailures+) results[jobName] = result } return results } build_params = params.clone() // Modify your build params here build_params.put('UPSTREAM_JOB', build.project.name) buildsToRun = [ job1: [count: 1, maxFailures: 0, args: build_params, retryCount: 2], job2: [count: 1, maxFailures: 0, args: build_params], job3: [count: 1, maxFailures: 0, args: build_params], jobX: [count: 2, maxFailures: 0, args: build_params], jobY: [count: 1, maxFailures: 0, args: build_params], ] results = startParallelRuns(buildsToRun) build.state.result = results.any { job, result - result == FAILURE} ? FAILURE : SUCCESS On Thu, Jan 9, 2014 at 8:22 PM, silver pja...@gmail.com wrote: Sorry for any confusion. The line: ”println(“There were “+FailuresPresent+ test(s) that failed”); is outside of the if statement resulting in the example output at the end of this message. On Jan 9, 2014, at 9:55 PM, silver pja...@gmail.com wrote: When I run jobs in parallel, the Build Flow fails or passes as I’d expect. Example: parallel ( { build(job1) }, { build(job2) }, { build(job3) }, ) All of the jobs are started and if they all pass, the Build Flow passes. If one fails, the Build Flow fails. What I’d like to do is to run jobs sequentially, ignoring a failure *for that moment* but at the end, fail or pass the Build Flow as a whole. Using “ignore(FAILURE) doesn’t give me what I want because it will ignore a failure and pass the Build Flow regardless: ignore(FAILURE) {build(job1)} ignore(FAILURE) {build(job2)} ignore(FAILURE) {build(job3)} If they all fail, the Build Flow still passes because failures are ignored. But I really need ALL of the jobs to run no matter the outcome of the other jobs, and the Build Flow to pass/fail, depending on each outcome. Therefore, I have tried something like this (which I thought I got to actually work at one point but I can’t get it to work again!?! The closest I can get is explained further down.): FailuresPresent = 0; try { build(job1) }catch(e) { FailuresPresent = FailuresPresent++; } try { build(job2) }catch(e) { FailuresPresent =
Re: Failing a Build Flow
yes I think so 2014/1/10 silver pja...@gmail.com Would “Throttle Concurrent Builds plugin do the same? The Locks and Latches plugin displays this message when I visit the page: This plugin is on the Proposed Plugin Deprecation list. Take a look at the Throttle Concurrent Builds Plugin. On Jan 10, 2014, at 8:59 AM, nicolas de loof nicolas.del...@gmail.com wrote: ok, then the issue isn't an orchestration but resource one - this applies to all jobs on your instance, not just the ones from a specific flow - and you should use https://wiki.jenkins-ci.org/display/JENKINS/Locks+and+Latches+plugin to ensure your selenium jobs don't run concurrently 2014/1/10 silver pja...@gmail.com I can’t run the jobs in parallel because I’m resource limited on my Selenium hub. They do *not* depend on each other sequentially. The use case is that I need a group of jobs to run through to completion in succession, not parallel, but at the end, if at any point a job had failed, to fail the build…not ignore failures. There is a guard/rescue for try/finally. Why not have a try/catch equivalent? That’s basically what I need, I think. On Jan 10, 2014, at 8:32 AM, nicolas de loof nicolas.del...@gmail.com wrote: This isn't supported at this time - I don't really get your use-case why can't you run those jobs in parallel ? If they actually depend on each other sequentially, why not stop the flow when first one fails ? 2014/1/10 silver pja...@gmail.com Nicolas, Do you have a recommendation on how I can accomplish the goal at hand? Otherwise, I see no other option but to try Marc's groovy script. Thanks. On Jan 10, 2014, at 2:51 AM, nicolas de loof nicolas.del...@gmail.com wrote: I don't recommend such a fully programmatic approach, build-flow is designed as a DSL, admittedly not constrained to just supported keywords (because I didn't know how to do this when I started this plugin) but clearly not supposed to be used to create such a groovy script. 2014/1/10 Marc MacIntyre marc...@purestorage.com You are overthinking it :) The trick is to grab the return value from the build() call and check the result of that, then explicitly set the failure state of the buildflow. This is what I'm doing; it's more solution than you need, but it solves your problem. This buildflow takes a map of jobs and the pass criteria, and fires everything off in parallel. If you want to retry on failures, that's supported, and/or you can start several in parallel and pass if some portion of them pass. We use job names as the map key, so if you want to start multiple runs of a particular job with different params, you'll need to modify the script somewhat. def createBuildClosure(String jn, Map args, int retryCount = 0) { // This indirection is needed to force a clone of args, so it's out of scope and gets // re-bound to the closure each time - otherwise jenkins will deduplicate our builds. def ags = args.clone() ags.put(_dedup, java.lang.System.nanoTime()) if (retryCount) { return { retry(retryCount) {build(ags, jn)} } } else { return {build(ags, jn)} } } def startParallelRuns(Map buildsToRun) { def m = [:] buildsToRun.each { jobName, params - def maxFailures = params.get(maxFailures, 0) def retryCount = params.get(retryCount, 0) println Running +jobName+ +params.count+ times (max failures +maxFailures+) for (int idx = 0; idx params.count; idx++) { m.put(jobName+_+idx, createBuildClosure(jobName, params.args, retryCount)) } } ignore(FAILURE) { join = parallel(m) } results = [:] // process the results by job name buildsToRun.each { jobName, params - def passcount = 0 def maxFailures = params.get(maxFailures, 0) for (int idx = 0; idx params.count; idx++) { run = join[jobName+_+idx] if (run.result == SUCCESS) { passcount += 1} } result = (params.count - passcount) maxFailures ? FAILURE : SUCCESS println +result+: +jobName+: +passcount+/+params.count+ passed (Max failures: +maxFailures+) results[jobName] = result } return results } build_params = params.clone() // Modify your build params here build_params.put('UPSTREAM_JOB', build.project.name) buildsToRun = [ job1: [count: 1, maxFailures: 0, args: build_params, retryCount: 2], job2: [count: 1, maxFailures: 0, args: build_params], job3: [count: 1, maxFailures: 0, args: build_params], jobX: [count: 2, maxFailures: 0, args: build_params], jobY: [count: 1, maxFailures: 0, args: build_params], ] results = startParallelRuns(buildsToRun) build.state.result = results.any { job, result - result == FAILURE} ? FAILURE : SUCCESS On Thu, Jan 9, 2014 at 8:22 PM, silver
Re: Failing a Build Flow
Thanks Nicolas and Marc. I’m trying the throttle plug-in, which I had already installed but obviously did not take advantage of. On Jan 10, 2014, at 9:11 AM, nicolas de loof nicolas.del...@gmail.com wrote: yes I think so 2014/1/10 silver pja...@gmail.com Would “Throttle Concurrent Builds plugin do the same? The Locks and Latches plugin displays this message when I visit the page: This plugin is on the Proposed Plugin Deprecation list. Take a look at the Throttle Concurrent Builds Plugin. On Jan 10, 2014, at 8:59 AM, nicolas de loof nicolas.del...@gmail.com wrote: ok, then the issue isn't an orchestration but resource one - this applies to all jobs on your instance, not just the ones from a specific flow - and you should use https://wiki.jenkins-ci.org/display/JENKINS/Locks+and+Latches+plugin to ensure your selenium jobs don't run concurrently 2014/1/10 silver pja...@gmail.com I can’t run the jobs in parallel because I’m resource limited on my Selenium hub. They do *not* depend on each other sequentially. The use case is that I need a group of jobs to run through to completion in succession, not parallel, but at the end, if at any point a job had failed, to fail the build…not ignore failures. There is a guard/rescue for try/finally. Why not have a try/catch equivalent? That’s basically what I need, I think. On Jan 10, 2014, at 8:32 AM, nicolas de loof nicolas.del...@gmail.com wrote: This isn't supported at this time - I don't really get your use-case why can't you run those jobs in parallel ? If they actually depend on each other sequentially, why not stop the flow when first one fails ? 2014/1/10 silver pja...@gmail.com Nicolas, Do you have a recommendation on how I can accomplish the goal at hand? Otherwise, I see no other option but to try Marc's groovy script. Thanks. On Jan 10, 2014, at 2:51 AM, nicolas de loof nicolas.del...@gmail.com wrote: I don't recommend such a fully programmatic approach, build-flow is designed as a DSL, admittedly not constrained to just supported keywords (because I didn't know how to do this when I started this plugin) but clearly not supposed to be used to create such a groovy script. 2014/1/10 Marc MacIntyre marc...@purestorage.com You are overthinking it :) The trick is to grab the return value from the build() call and check the result of that, then explicitly set the failure state of the buildflow. This is what I'm doing; it's more solution than you need, but it solves your problem. This buildflow takes a map of jobs and the pass criteria, and fires everything off in parallel. If you want to retry on failures, that's supported, and/or you can start several in parallel and pass if some portion of them pass. We use job names as the map key, so if you want to start multiple runs of a particular job with different params, you'll need to modify the script somewhat. def createBuildClosure(String jn, Map args, int retryCount = 0) { // This indirection is needed to force a clone of args, so it's out of scope and gets // re-bound to the closure each time - otherwise jenkins will deduplicate our builds. def ags = args.clone() ags.put(_dedup, java.lang.System.nanoTime()) if (retryCount) { return { retry(retryCount) {build(ags, jn)} } } else { return {build(ags, jn)} } } def startParallelRuns(Map buildsToRun) { def m = [:] buildsToRun.each { jobName, params - def maxFailures = params.get(maxFailures, 0) def retryCount = params.get(retryCount, 0) println Running +jobName+ +params.count+ times (max failures +maxFailures+) for (int idx = 0; idx params.count; idx++) { m.put(jobName+_+idx, createBuildClosure(jobName, params.args, retryCount)) } } ignore(FAILURE) { join = parallel(m) } results = [:] // process the results by job name buildsToRun.each { jobName, params - def passcount = 0 def maxFailures = params.get(maxFailures, 0) for (int idx = 0; idx params.count; idx++) { run = join[jobName+_+idx] if (run.result == SUCCESS) { passcount += 1} } result = (params.count - passcount) maxFailures ? FAILURE : SUCCESS println +result+: +jobName+: +passcount+/+params.count+ passed (Max failures: +maxFailures+) results[jobName] = result } return results } build_params = params.clone() // Modify your build params here build_params.put('UPSTREAM_JOB', build.project.name) buildsToRun = [ job1: [count: 1, maxFailures: 0, args: build_params, retryCount: 2], job2: [count: 1, maxFailures: 0, args: build_params], job3: [count: 1, maxFailures: 0, args: build_params], jobX: [count: 2,
Re: Failing a Build Flow
Hmm… That didn’t seem to work at all. I have “Throttle Concurrent Builds” checked and “Throttle this project alone” selected. Then, “Maximum Total Concurrent Builds set to “1” and Maximum Concurrent Builds Per Node set to “1” (I have only 1 node). I have switched the job back to the standard parallel paradigm and am now seeing this, which tells me that they were all started. I also checked my output directory and the xml file for each individual test has been created, which means the test has indeed kicked off…and my hub is pegged as expected. parallel { Schedule job 4.0-211-HTMLGUI-LINUX_FIREFOX Schedule job 4.0-211-HTMLGUI-WIN7_FIREFOX Schedule job 4.0-211-HTMLGUI-WIN8_SAFARI Schedule job 4.0-211-HTMLGUI-WIN8_IE10 Schedule job 4.0-211-HTMLGUI-WIN8_FIREFOX Schedule job 4.0-211-HTMLGUI-WIN7_SAFARI Schedule job 4.0-211-HTMLGUI-WIN7_IE9 Schedule job 4.0-211-HTMLGUI-WIN7_CHROME Schedule job 4.0-211-HTMLGUI-WIN8_CHROME Build 4.0-211-HTMLGUI-WIN7_CHROME #11 started Build 4.0-211-HTMLGUI-WIN8_SAFARI #9 started Build 4.0-211-HTMLGUI-WIN7_IE9 #9 started Build 4.0-211-HTMLGUI-WIN7_SAFARI #9 started Build 4.0-211-HTMLGUI-WIN8_IE10 #12 started Build 4.0-211-HTMLGUI-WIN8_FIREFOX #9 started Build 4.0-211-HTMLGUI-LINUX_FIREFOX #35 started Build 4.0-211-HTMLGUI-WIN7_FIREFOX #15 started Build 4.0-211-HTMLGUI-WIN8_CHROME #9 started 4.0-211-HTMLGUI-WIN7_FIREFOX #15 completed : FAILURE On Jan 10, 2014, at 9:46 AM, silver pja...@gmail.com wrote: Thanks Nicolas and Marc. I’m trying the throttle plug-in, which I had already installed but obviously did not take advantage of. On Jan 10, 2014, at 9:11 AM, nicolas de loof nicolas.del...@gmail.com wrote: yes I think so 2014/1/10 silver pja...@gmail.com Would “Throttle Concurrent Builds plugin do the same? The Locks and Latches plugin displays this message when I visit the page: This plugin is on the Proposed Plugin Deprecation list. Take a look at the Throttle Concurrent Builds Plugin. On Jan 10, 2014, at 8:59 AM, nicolas de loof nicolas.del...@gmail.com wrote: ok, then the issue isn't an orchestration but resource one - this applies to all jobs on your instance, not just the ones from a specific flow - and you should use https://wiki.jenkins-ci.org/display/JENKINS/Locks+and+Latches+plugin to ensure your selenium jobs don't run concurrently 2014/1/10 silver pja...@gmail.com I can’t run the jobs in parallel because I’m resource limited on my Selenium hub. They do *not* depend on each other sequentially. The use case is that I need a group of jobs to run through to completion in succession, not parallel, but at the end, if at any point a job had failed, to fail the build…not ignore failures. There is a guard/rescue for try/finally. Why not have a try/catch equivalent? That’s basically what I need, I think. On Jan 10, 2014, at 8:32 AM, nicolas de loof nicolas.del...@gmail.com wrote: This isn't supported at this time - I don't really get your use-case why can't you run those jobs in parallel ? If they actually depend on each other sequentially, why not stop the flow when first one fails ? 2014/1/10 silver pja...@gmail.com Nicolas, Do you have a recommendation on how I can accomplish the goal at hand? Otherwise, I see no other option but to try Marc's groovy script. Thanks. On Jan 10, 2014, at 2:51 AM, nicolas de loof nicolas.del...@gmail.com wrote: I don't recommend such a fully programmatic approach, build-flow is designed as a DSL, admittedly not constrained to just supported keywords (because I didn't know how to do this when I started this plugin) but clearly not supposed to be used to create such a groovy script. 2014/1/10 Marc MacIntyre marc...@purestorage.com You are overthinking it :) The trick is to grab the return value from the build() call and check the result of that, then explicitly set the failure state of the buildflow. This is what I'm doing; it's more solution than you need, but it solves your problem. This buildflow takes a map of jobs and the pass criteria, and fires everything off in parallel. If you want to retry on failures, that's supported, and/or you can start several in parallel and pass if some portion of them pass. We use job names as the map key, so if you want to start multiple runs of a particular job with different params, you'll need to modify the script somewhat. def createBuildClosure(String jn, Map args, int retryCount = 0) { // This indirection is needed to force a clone of args, so it's out of scope and gets // re-bound to the closure each time - otherwise jenkins will deduplicate our builds. def ags = args.clone() ags.put(_dedup, java.lang.System.nanoTime()) if (retryCount) { return { retry(retryCount) {build(ags, jn)} } } else { return {build(ags, jn)} } }
RE: Failing a Build Flow
My 2 cents worth not being a Groovy programmer but I use the build flow. You can call build like this : A = build(buildA) From A you can get the status: Aresult = A.build.getResult() From: jenkinsci-users@googlegroups.com [mailto:jenkinsci-users@googlegroups.com] On Behalf Of Marc MacIntyre Sent: Friday, January 10, 2014 9:00 AM To: jenkinsci-users@googlegroups.com Cc: jenkinsci-users@googlegroups.com Subject: Re: Failing a Build Flow That aside, I'm using this in production and it works well. Sent from my iPhone On Jan 9, 2014, at 11:51 PM, nicolas de loof nicolas.del...@gmail.commailto:nicolas.del...@gmail.com wrote: I don't recommend such a fully programmatic approach, build-flow is designed as a DSL, admittedly not constrained to just supported keywords (because I didn't know how to do this when I started this plugin) but clearly not supposed to be used to create such a groovy script. 2014/1/10 Marc MacIntyre marc...@purestorage.commailto:marc...@purestorage.com You are overthinking it :) The trick is to grab the return value from the build() call and check the result of that, then explicitly set the failure state of the buildflow. This is what I'm doing; it's more solution than you need, but it solves your problem. This buildflow takes a map of jobs and the pass criteria, and fires everything off in parallel. If you want to retry on failures, that's supported, and/or you can start several in parallel and pass if some portion of them pass. We use job names as the map key, so if you want to start multiple runs of a particular job with different params, you'll need to modify the script somewhat. def createBuildClosure(String jn, Map args, int retryCount = 0) { // This indirection is needed to force a clone of args, so it's out of scope and gets // re-bound to the closure each time - otherwise jenkins will deduplicate our builds. def ags = args.clone() ags.put(_dedup, java.lang.System.nanoTime()) if (retryCount) { return { retry(retryCount) {build(ags, jn)} } } else { return {build(ags, jn)} } } def startParallelRuns(Map buildsToRun) { def m = [:] buildsToRun.each { jobName, params - def maxFailures = params.get(maxFailures, 0) def retryCount = params.get(retryCount, 0) println Running +jobName+ +params.count+ times (max failures +maxFailures+) for (int idx = 0; idx params.count; idx++) { m.put(jobName+_+idx, createBuildClosure(jobName, params.args, retryCount)) } } ignore(FAILURE) { join = parallel(m) } results = [:] // process the results by job name buildsToRun.each { jobName, params - def passcount = 0 def maxFailures = params.get(maxFailures, 0) for (int idx = 0; idx params.count; idx++) { run = join[jobName+_+idx] if (run.result == SUCCESS) { passcount += 1} } result = (params.count - passcount) maxFailures ? FAILURE : SUCCESS println +result+: +jobName+: +passcount+/+params.count+ passed (Max failures: +maxFailures+) results[jobName] = result } return results } build_params = params.clone() // Modify your build params here build_params.put('UPSTREAM_JOB', build.project.namehttp://build.project.name) buildsToRun = [ job1: [count: 1, maxFailures: 0, args: build_params, retryCount: 2], job2: [count: 1, maxFailures: 0, args: build_params], job3: [count: 1, maxFailures: 0, args: build_params], jobX: [count: 2, maxFailures: 0, args: build_params], jobY: [count: 1, maxFailures: 0, args: build_params], ] results = startParallelRuns(buildsToRun) build.state.result = results.any { job, result - result == FAILURE} ? FAILURE : SUCCESS On Thu, Jan 9, 2014 at 8:22 PM, silver pja...@gmail.commailto:pja...@gmail.com wrote: Sorry for any confusion. The line: println(There were +FailuresPresent+ test(s) that failed); is outside of the if statement resulting in the example output at the end of this message. On Jan 9, 2014, at 9:55 PM, silver pja...@gmail.commailto:pja...@gmail.com wrote: When I run jobs in parallel, the Build Flow fails or passes as I'd expect. Example: parallel ( { build(job1) }, { build(job2) }, { build(job3) }, ) All of the jobs are started and if they all pass, the Build Flow passes. If one fails, the Build Flow fails. What I'd like to do is to run jobs sequentially, ignoring a failure *for that moment* but at the end, fail or pass the Build Flow as a whole. Using ignore(FAILURE) doesn't give me what I want because it will ignore a failure and pass the Build Flow regardless: ignore(FAILURE) {build(job1)} ignore(FAILURE) {build(job2)} ignore(FAILURE) {build(job3)} If they all fail, the Build Flow still passes because failures are ignored. But I really need ALL of the jobs to run no matter the outcome
Re: Failing a Build Flow
On 10.01.2014, at 16:26, Ginga, Dick dick.gi...@perkinelmer.com wrote: My 2 cents worth not being a Groovy programmer but I use the build flow. You can call build like this : A = build(“buildA”) From A you can get the status: Aresult = A.build.getResult() How'd you set the build flow's result based on that? -- You received this message because you are subscribed to the Google Groups Jenkins Users group. To unsubscribe from this group and stop receiving emails from it, send an email to jenkinsci-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out.
RE: Failing a Build Flow
Well, I just use it as a condition test for a further build step. Because I am testing the result of 1 of 2 parallel builds the build flow returns the combined status. Maybe return(FAILURE) will work -Original Message- From: jenkinsci-users@googlegroups.com [mailto:jenkinsci-users@googlegroups.com] On Behalf Of Daniel Beck Sent: Friday, January 10, 2014 10:41 AM To: jenkinsci-users@googlegroups.com Subject: Re: Failing a Build Flow On 10.01.2014, at 16:26, Ginga, Dick dick.gi...@perkinelmer.com wrote: My 2 cents worth not being a Groovy programmer but I use the build flow. You can call build like this : A = build(buildA) From A you can get the status: Aresult = A.build.getResult() How'd you set the build flow's result based on that? -- You received this message because you are subscribed to the Google Groups Jenkins Users group. To unsubscribe from this group and stop receiving emails from it, send an email to jenkinsci-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out. -- You received this message because you are subscribed to the Google Groups Jenkins Users group. To unsubscribe from this group and stop receiving emails from it, send an email to jenkinsci-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out.
Re: Failing a Build Flow
build.state.result = FAILURE On Fri, Jan 10, 2014 at 7:41 AM, Daniel Beck m...@beckweb.net wrote: On 10.01.2014, at 16:26, Ginga, Dick dick.gi...@perkinelmer.com wrote: My 2 cents worth not being a Groovy programmer but I use the build flow. You can call build like this : A = build(“buildA”) From A you can get the status: Aresult = A.build.getResult() How'd you set the build flow's result based on that? -- You received this message because you are subscribed to the Google Groups Jenkins Users group. To unsubscribe from this group and stop receiving emails from it, send an email to jenkinsci-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out. -- Marc MacIntyre -- You received this message because you are subscribed to the Google Groups Jenkins Users group. To unsubscribe from this group and stop receiving emails from it, send an email to jenkinsci-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out.
Re: Failing a Build Flow
SUCCESS and FAILURE are constants, you don't need to do string comparisons. On Fri, Jan 10, 2014 at 9:06 AM, silver pja...@gmail.com wrote: I’m losing hope…. build_result = build(“job1); if ( build_result.build.getResult().equals(SUCCESS) ) { build_result = build(job2”); …more stuff here... } else { throw new Exception(“FAIL!”); } When br contains the string “SUCCESS”, the if…else evaluates to else...every time! If I println( br.equals(“SUCCESS”) );, it evaluates to false every time, which matches the if..else evaluation. This is fighting me every step of the way. The concurrent throttle plugin doesn’t seem to work as I’d expect…I just want a try/catch! Might have to just do what I need using Python and leave Jenkins out of the decision-making process altogether! On Jan 10, 2014, at 11:01 AM, Ginga, Dick dick.gi...@perkinelmer.com wrote: Well, I just use it as a condition test for a further build step. Because I am testing the result of 1 of 2 parallel builds the build flow returns the combined status. Maybe return(FAILURE) will work -Original Message- From: jenkinsci-users@googlegroups.com [mailto: jenkinsci-users@googlegroups.com] On Behalf Of Daniel Beck Sent: Friday, January 10, 2014 10:41 AM To: jenkinsci-users@googlegroups.com Subject: Re: Failing a Build Flow On 10.01.2014, at 16:26, Ginga, Dick dick.gi...@perkinelmer.com wrote: My 2 cents worth not being a Groovy programmer but I use the build flow. You can call build like this : A = build(buildA) From A you can get the status: Aresult = A.build.getResult() How'd you set the build flow's result based on that? -- You received this message because you are subscribed to the Google Groups Jenkins Users group. To unsubscribe from this group and stop receiving emails from it, send an email to jenkinsci-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out. -- You received this message because you are subscribed to the Google Groups Jenkins Users group. To unsubscribe from this group and stop receiving emails from it, send an email to jenkinsci-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out. -- Marc MacIntyre -- You received this message because you are subscribed to the Google Groups Jenkins Users group. To unsubscribe from this group and stop receiving emails from it, send an email to jenkinsci-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out.
Re: Failing a Build Flow
I’m losing hope…. build_result = build(“job1); if ( build_result.build.getResult().equals(SUCCESS) ) { build_result = build(job2”); …more stuff here... } else { throw new Exception(“FAIL!”); } When br contains the string “SUCCESS”, the if…else evaluates to else...every time! If I println( br.equals(“SUCCESS”) );, it evaluates to false every time, which matches the if..else evaluation. This is fighting me every step of the way. The concurrent throttle plugin doesn’t seem to work as I’d expect…I just want a try/catch! Might have to just do what I need using Python and leave Jenkins out of the decision-making process altogether! On Jan 10, 2014, at 11:01 AM, Ginga, Dick dick.gi...@perkinelmer.com wrote: Well, I just use it as a condition test for a further build step. Because I am testing the result of 1 of 2 parallel builds the build flow returns the combined status. Maybe return(FAILURE) will work -Original Message- From: jenkinsci-users@googlegroups.com [mailto:jenkinsci-users@googlegroups.com] On Behalf Of Daniel Beck Sent: Friday, January 10, 2014 10:41 AM To: jenkinsci-users@googlegroups.com Subject: Re: Failing a Build Flow On 10.01.2014, at 16:26, Ginga, Dick dick.gi...@perkinelmer.com wrote: My 2 cents worth not being a Groovy programmer but I use the build flow. You can call build like this : A = build(buildA) From A you can get the status: Aresult = A.build.getResult() How'd you set the build flow's result based on that? -- You received this message because you are subscribed to the Google Groups Jenkins Users group. To unsubscribe from this group and stop receiving emails from it, send an email to jenkinsci-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out. -- You received this message because you are subscribed to the Google Groups Jenkins Users group. To unsubscribe from this group and stop receiving emails from it, send an email to jenkinsci-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out. smime.p7s Description: S/MIME cryptographic signature
Re: Failing a Build Flow
THANK YOU! That might have gotten me over the hump. At least I’m smiling again. On Jan 10, 2014, at 12:09 PM, Marc MacIntyre marc...@purestorage.com wrote: SUCCESS and FAILURE are constants, you don't need to do string comparisons. On Fri, Jan 10, 2014 at 9:06 AM, silver pja...@gmail.com wrote: I’m losing hope…. build_result = build(“job1); if ( build_result.build.getResult().equals(SUCCESS) ) { build_result = build(job2”); …more stuff here... } else { throw new Exception(“FAIL!”); } When br contains the string “SUCCESS”, the if…else evaluates to else...every time! If I println( br.equals(“SUCCESS”) );, it evaluates to false every time, which matches the if..else evaluation. This is fighting me every step of the way. The concurrent throttle plugin doesn’t seem to work as I’d expect…I just want a try/catch! Might have to just do what I need using Python and leave Jenkins out of the decision-making process altogether! On Jan 10, 2014, at 11:01 AM, Ginga, Dick dick.gi...@perkinelmer.com wrote: Well, I just use it as a condition test for a further build step. Because I am testing the result of 1 of 2 parallel builds the build flow returns the combined status. Maybe return(FAILURE) will work -Original Message- From: jenkinsci-users@googlegroups.com [mailto:jenkinsci-users@googlegroups.com] On Behalf Of Daniel Beck Sent: Friday, January 10, 2014 10:41 AM To: jenkinsci-users@googlegroups.com Subject: Re: Failing a Build Flow On 10.01.2014, at 16:26, Ginga, Dick dick.gi...@perkinelmer.com wrote: My 2 cents worth not being a Groovy programmer but I use the build flow. You can call build like this : A = build(buildA) From A you can get the status: Aresult = A.build.getResult() How'd you set the build flow's result based on that? -- You received this message because you are subscribed to the Google Groups Jenkins Users group. To unsubscribe from this group and stop receiving emails from it, send an email to jenkinsci-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out. -- You received this message because you are subscribed to the Google Groups Jenkins Users group. To unsubscribe from this group and stop receiving emails from it, send an email to jenkinsci-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out. -- Marc MacIntyre -- You received this message because you are subscribed to the Google Groups Jenkins Users group. To unsubscribe from this group and stop receiving emails from it, send an email to jenkinsci-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out. smime.p7s Description: S/MIME cryptographic signature
Re: Failing a Build Flow
Sorry for any confusion. The line: ”println(“There were “+FailuresPresent+ test(s) that failed”); is outside of the if statement resulting in the example output at the end of this message. On Jan 9, 2014, at 9:55 PM, silver pja...@gmail.com wrote: When I run jobs in parallel, the Build Flow fails or passes as I’d expect. Example: parallel ( { build(job1) }, { build(job2) }, { build(job3) }, ) All of the jobs are started and if they all pass, the Build Flow passes. If one fails, the Build Flow fails. What I’d like to do is to run jobs sequentially, ignoring a failure *for that moment* but at the end, fail or pass the Build Flow as a whole. Using “ignore(FAILURE) doesn’t give me what I want because it will ignore a failure and pass the Build Flow regardless: ignore(FAILURE) {build(job1)} ignore(FAILURE) {build(job2)} ignore(FAILURE) {build(job3)} If they all fail, the Build Flow still passes because failures are ignored. But I really need ALL of the jobs to run no matter the outcome of the other jobs, and the Build Flow to pass/fail, depending on each outcome. Therefore, I have tried something like this (which I thought I got to actually work at one point but I can’t get it to work again!?! The closest I can get is explained further down.): FailuresPresent = 0; try { build(job1) }catch(e) { FailuresPresent = FailuresPresent++; } try { build(job2) }catch(e) { FailuresPresent = FailuresPresent++; } try { build(job3) }catch(e) { FailuresPresent = FailuresPresent++; } if ( FailuresPresent0) { println(“There were “+FailuresPresent+ test(s) that failed”); throw new Exception(FAILED!”); }else { println Tests PASSED!; } But the Build Flow will still stop immediately after a failed job (I don’t see my println at the end). If I use an ignore(FAILURE) wrapper, then the “catch” is ignored and the Build Flow passes. I am not using guard/rescue because I don’t need the FailuresPresent to increment every time, only when there is a failure (or do I? Guard/Rescue is like try/finally, not a try/catch.) None of my jobs are dependent on another, I just want them all grouped together and to run sequentially in a single Build Flow if possible. Running them in parallel maxes out my resources (not Jenkins but my Selenium hub). If I wrap the above jobs in a parallel statement, it seems to gives the appearance of it finishing to completion (my print statement at the end is seen) but the Build Flow doesn’t run the other jobs. This is the output with the entire try/catch/builds wrapped in a parallel statement (notice job2 and job3 aren’t run but my println at the end is seen: parallel { Schedule job job1 Build job1 #34 started job1 #34 completed : UNSTABLE } There were 0 test(s) that failed Tests PASSED! Suggestions? I hope I’m over-thinking this. Thanks. smime.p7s Description: S/MIME cryptographic signature