getChunks() {
return new ArrayList<>(allChunks);
@@ -69,20 +69,20 @@ private static void assertChunkBoundary(FlowChunkWithContext chunk, int beforeId
public void testBlockStage() throws Exception {
WorkflowJob job = jenkinsRule.jenkins.createProject(WorkflowJob.class, "Blocky job");
- job.setDefinition(new CpsFlowDefinition("" +
- "node {" +
- " stage ('Build') { " +
- " echo ('Building'); " +
- " } \n" +
- " stage ('Test') { " +
- " echo ('Testing'); " +
- " } \n" +
- " stage ('Deploy') { " +
- " writeFile file: 'file.txt', text:'content'; " +
- " archive(includes: 'file.txt'); " +
- " echo ('Deploying'); " +
- " } \n" +
- "}", true));
+ job.setDefinition(new CpsFlowDefinition("""
+ node {
+ stage ('Build') {
+ echo ('Building')
+ }
+ stage ('Test') {
+ echo ('Testing')
+ }
+ stage ('Deploy') {
+ writeFile file: 'file.txt', text:'content'
+ archive(includes: 'file.txt')
+ echo ('Deploying')
+ }
+ }""", true));
/*
* Node dump follows, format:
[ID]{parent,ids} flowNodeClassName stepDisplayName [st=startId if a block node]
diff --git a/src/test/java/org/jenkinsci/plugins/workflow/pipelinegraphanalysis/StatusAndTimingTest.java b/src/test/java/org/jenkinsci/plugins/workflow/pipelinegraphanalysis/StatusAndTimingTest.java
index 1ff2787..bc7e712 100644
--- a/src/test/java/org/jenkinsci/plugins/workflow/pipelinegraphanalysis/StatusAndTimingTest.java
+++ b/src/test/java/org/jenkinsci/plugins/workflow/pipelinegraphanalysis/StatusAndTimingTest.java
@@ -70,9 +70,9 @@
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
public class StatusAndTimingTest {
@@ -91,7 +91,7 @@ private static FlowNode[] getNodes(FlowExecution exec, int[] ids) throws IOExcep
}
@Test
- public void testStatusCoercion() throws Exception {
+ public void testStatusCoercion() {
// Test that we don't modify existing statuses
for (GenericStatus st : StatusAndTiming.API_V1.getAllowedStatuses()) {
Assert.assertEquals(st, StatusAndTiming.coerceStatusApi(st, StatusAndTiming.API_V1));
@@ -114,11 +114,12 @@ private static long doTiming(FlowExecution exec, int firstNodeId, int nodeAfterE
@Test
public void testBasicPass() throws Exception {
WorkflowJob job = j.jenkins.createProject(WorkflowJob.class, "Passes");
- job.setDefinition(new CpsFlowDefinition("" +
- "sleep 1 \n" +
- "echo 'first stage' \n" +
- "sleep 1 \n" +
- "echo 'done' \n", true));
+ job.setDefinition(new CpsFlowDefinition("""
+ sleep 1
+ echo 'first stage'
+ sleep 1
+ echo 'done'
+ """, true));
/* Node dump follows, format:
[ID]{parent,ids}(millisSinceStartOfRun) flowClassName displayName [st=startId if a block node]
@@ -153,7 +154,7 @@ public void testBasicPass() throws Exception {
status = StatusAndTiming.computeChunkStatus2(run, n[0], n[1], n[4], n[5]);
timing = StatusAndTiming.computeChunkTiming(run, 2, n[1], n[4], n[5]);
assertEquals(GenericStatus.SUCCESS, status);
- assertEquals(timing.getPauseDurationMillis(), 2);
+ assertEquals(2, timing.getPauseDurationMillis());
assertEquals(TimingAction.getStartTime(n[5]) - TimingAction.getStartTime(n[1]), timing.getTotalDurationMillis());
// Whole flow
@@ -186,11 +187,12 @@ public void testBasicPass() throws Exception {
@Test
public void testFail() throws Exception {
WorkflowJob job = j.jenkins.createProject(WorkflowJob.class, "Fails");
- job.setDefinition(new CpsFlowDefinition("" +
- "sleep 1 \n" +
- "echo 'first stage' \n" +
- "sleep 1 \n" +
- "error('fails') \n", true));
+ job.setDefinition(new CpsFlowDefinition("""
+ sleep 1
+ echo 'first stage'
+ sleep 1
+ error('fails')
+ """, true));
/* Node dump follows, format:
[ID]{parent,ids} flowClassName displayName [st=startId if a block node]
Action format:
@@ -234,12 +236,12 @@ public void testFail() throws Exception {
@Test
public void testBasicParallelFail() throws Exception {
WorkflowJob job = j.jenkins.createProject(WorkflowJob.class, "Fails");
- job.setDefinition(new CpsFlowDefinition("" +
- "echo 'primero stage'\n" +
- "def branches = ['failFast': false]\n" +
- "branches['success'] = {sleep 1; echo 'succeed'}\n" +
- "branches['fail'] = {error('autofail');}\n" +
- "parallel branches", true));
+ job.setDefinition(new CpsFlowDefinition("""
+ echo 'primero stage'
+ def branches = ['failFast': false]
+ branches['success'] = {sleep 1; echo 'succeed'}
+ branches['fail'] = {error('autofail')}
+ parallel branches""", true));
/*
* Node dump from a run follows, format:
@@ -340,11 +342,12 @@ public void testBasicParallelFail() throws Exception {
@Test
public void testInProgress() throws Exception {
WorkflowJob job = j.jenkins.createProject(WorkflowJob.class, "Fails");
- job.setDefinition(new CpsFlowDefinition("" +
- "sleep 1 \n" +
- "echo 'first stage' \n" +
- "sleep 1 \n" +
- "semaphore('wait') \n", true));
+ job.setDefinition(new CpsFlowDefinition("""
+ sleep 1
+ echo 'first stage'
+ sleep 1
+ semaphore('wait')
+ """, true));
WorkflowRun run = job.scheduleBuild2(0).getStartCondition().get();
SemaphoreStep.waitForStart("wait/1", run);
FlowExecution exec = run.getExecution();
@@ -362,10 +365,10 @@ public void testInProgress() throws Exception {
@Test
public void timingTest() throws Exception {
// Problem here: for runs in progress we should be using current time if they're the last run node, aka the in-progress node
- String jobScript = ""+
- "echo 'first stage'\n" +
- "parallel 'long' : { sleep 30; }, \n" +
- " 'short': { sleep 2; }";
+ String jobScript = """
+ echo 'first stage'
+ parallel 'long' : {sleep 30},
+ 'short': {sleep 2}""";
// This must be amateur science fiction because the exposition for the setting goes on FOREVER
ForkScanner scan = new ForkScanner();
@@ -398,12 +401,12 @@ public void timingTest() throws Exception {
@Test
public void testInProgressParallel() throws Exception {
WorkflowJob job = j.jenkins.createProject(WorkflowJob.class, "Fails");
- job.setDefinition(new CpsFlowDefinition("" +
- "echo 'primero stage'\n" +
- "def branches = ['failFast': false]\n" +
- "branches['success'] = {echo 'succeed'}\n" +
- "branches['pause'] = { sleep 1; semaphore 'wait'; }\n" +
- "parallel branches", true));
+ job.setDefinition(new CpsFlowDefinition("""
+ echo 'primero stage'
+ def branches = ['failFast': false]
+ branches['success'] = {echo 'succeed'}
+ branches['pause'] = {sleep 1; semaphore 'wait'}
+ parallel branches""", true));
/*
* Node dump follows, format:
[ID]{parentIds,...} flowNodeClassName displayName [st=startId if a block node]
@@ -552,12 +555,14 @@ public void busyStepTest() throws Exception {
@Test
public void queuedAndRunningOnAgent() throws Exception {
WorkflowJob job = j.jenkins.createProject(WorkflowJob.class, "queuedAndRunning");
- job.setDefinition(new CpsFlowDefinition("stage('some-stage') {\n" +
- " node('test') {\n" +
- " echo 'hello'\n" +
- " semaphore 'wait'\n" +
- " }\n" +
- "}\n", true));
+ job.setDefinition(new CpsFlowDefinition("""
+ stage('some-stage') {
+ node('test') {
+ echo 'hello'
+ semaphore 'wait'
+ }
+ }
+ """, true));
WorkflowRun b1 = job.scheduleBuild2(0).waitForStart();
j.waitForMessage("Still waiting to schedule task", b1);
@@ -591,12 +596,14 @@ public void queuedAndRunningOnAgent() throws Exception {
@Test
public void queuedAndCanceled() throws Exception {
WorkflowJob job = j.jenkins.createProject(WorkflowJob.class, "queuedAndCanceled");
- job.setDefinition(new CpsFlowDefinition("stage('some-stage') {\n" +
- " node('test') {\n" +
- " echo 'hello'\n" +
- " semaphore 'wait'\n" +
- " }\n" +
- "}\n", true));
+ job.setDefinition(new CpsFlowDefinition("""
+ stage('some-stage') {
+ node('test') {
+ echo 'hello'
+ semaphore 'wait'
+ }
+ }
+ """, true));
WorkflowRun b1 = job.scheduleBuild2(0).waitForStart();
j.waitForMessage("Still waiting to schedule task", b1);
@@ -660,21 +667,23 @@ public void queuedAndParallel() throws Exception {
[25]{24}FlowEndNode End of Pipeline [st=2]
------------------------------------------------------------------------------------------
*/
- job.setDefinition(new CpsFlowDefinition("stage('some-stage') {\n" +
- " parallel(\n" +
- " a: {\n" +
- " node('second') {\n" +
- " echo 'hello'\n" +
- " semaphore 'wait-a'\n" +
- " }\n" +
- " },\n" +
- " b: {\n" +
- " node('first') {\n" +
- " semaphore 'wait-b'\n" +
- " }\n" +
- " }\n" +
- " )\n" +
- "}\n", true));
+ job.setDefinition(new CpsFlowDefinition("""
+ stage('some-stage') {
+ parallel(
+ a: {
+ node('second') {
+ echo 'hello'
+ semaphore 'wait-a'
+ }
+ },
+ b: {
+ node('first') {
+ semaphore 'wait-b'
+ }
+ }
+ )
+ }
+ """, true));
WorkflowRun b1 = job.scheduleBuild2(0).waitForStart();
try {
@@ -721,7 +730,7 @@ public void queuedAndParallel() throws Exception {
SemaphoreStep.waitForStart("wait-a/1", b1);
- // Now get the end nodes as of the entry of the semaphore on the a branch...
+ // Now get the end nodes as of the entry of the semaphore on the `a` branch...
branchEndNodes = Arrays.asList(getNodes(execution, new int[]{18, 15}));
statuses = StatusAndTiming.computeBranchStatuses2(b1, execution.getNode("5"), branchStartNodes, branchEndNodes, null);
@@ -741,29 +750,30 @@ public void queuedAndParallel() throws Exception {
@Issue("JENKINS-47219")
public void parallelStagesOneSkipped() throws Exception {
WorkflowJob job = j.jenkins.createProject(WorkflowJob.class, "parallel stages, one skipped job");
- job.setDefinition(new CpsFlowDefinition("" +
- "pipeline { \n" +
- " agent any \n" +
- " stages { \n" +
- " stage('Run Tests') { \n"+
- " parallel { \n" +
- " stage('Test on Windows') { \n" +
- " when { \n" +
- " branch 'cake' \n" +
- " } \n"+
- " steps { \n"+
- " echo 'hello world' \n"+
- " } \n"+
- " } \n"+
- " stage('Test on Linux') { \n" +
- " steps { \n"+
- " echo 'hello world' \n"+
- " } \n"+
- " } \n"+
- " } \n"+
- " } \n"+
- " } \n"+
- "} \n",
+ job.setDefinition(new CpsFlowDefinition("""
+ pipeline {
+ agent any
+ stages {
+ stage('Run Tests') {
+ parallel {
+ stage('Test on Windows') {
+ when {
+ branch 'cake'
+ }
+ steps {
+ echo 'hello world'
+ }
+ }
+ stage('Test on Linux') {
+ steps {
+ echo 'hello world'
+ }
+ }
+ }
+ }
+ }
+ }
+ """,
true));
WorkflowRun build = j.assertBuildStatusSuccess(job.scheduleBuild2(0));
@@ -778,13 +788,15 @@ public void parallelStagesOneSkipped() throws Exception {
public void catchOutsideFailingStage() throws Exception {
WorkflowJob job = j.jenkins.createProject(WorkflowJob.class, "catchOutsideFailingStage");
job.setDefinition(new CpsFlowDefinition(
- "try {\n" +
- " stage('throws-error') {\n" +
- " error('oops')\n" +
- " }\n" +
- "} catch(err) {\n" +
- " echo('caught error')\n" +
- "}\n", true));
+ """
+ try {
+ stage('throws-error') {
+ error('oops')
+ }
+ } catch(err) {
+ echo('caught error')
+ }
+ """, true));
WorkflowRun run = j.assertBuildStatusSuccess(job.scheduleBuild2(0));
StagesAndParallelBranchesVisitor visitor = new StagesAndParallelBranchesVisitor(run);
assertEquals(1, visitor.chunks.size());
@@ -796,17 +808,18 @@ public void catchOutsideFailingStage() throws Exception {
public void parallelFailFast() throws Exception {
WorkflowJob job = j.jenkins.createProject(WorkflowJob.class, "parallelFailFast");
job.setDefinition(new CpsFlowDefinition(
- "parallel failFast: true,\n" +
- " aborts: {\n" +
- " sleep 5\n" +
- " },\n" +
- " fails: {\n" +
- " sleep 1\n" +
- " error('oops')\n" +
- " },\n" +
- " succeeds: {\n" +
- " echo 'success'" +
- " }", true));
+ """
+ parallel failFast: true,
+ aborts: {
+ sleep 5
+ },
+ fails: {
+ sleep 1
+ error('oops')
+ },
+ succeeds: {
+ echo 'success'
+ }""", true));
WorkflowRun run = j.assertBuildStatus(Result.FAILURE, job.scheduleBuild2(0));
StagesAndParallelBranchesVisitor visitor = new StagesAndParallelBranchesVisitor(run);
assertEquals(3, visitor.chunks.size());
@@ -820,12 +833,14 @@ public void parallelFailFast() throws Exception {
public void parallel() throws Exception {
WorkflowJob job = j.jenkins.createProject(WorkflowJob.class, "parallel");
job.setDefinition(new CpsFlowDefinition(
- "parallel fails: {\n" +
- " error('oops')\n" +
- "},\n" +
- "succeeds: {\n" +
- " echo('succeeds')" +
- "}\n", true));
+ """
+ parallel fails: {
+ error('oops')
+ },
+ succeeds: {
+ echo('succeeds')
+ }
+ """, true));
WorkflowRun run = j.assertBuildStatus(Result.FAILURE, job.scheduleBuild2(0));
StagesAndParallelBranchesVisitor visitor = new StagesAndParallelBranchesVisitor(run);
assertEquals(2, visitor.chunks.size());
@@ -838,18 +853,20 @@ public void parallel() throws Exception {
public void unstableWithWarningAction() throws Exception {
WorkflowJob job = j.jenkins.createProject(WorkflowJob.class, "unstable");
job.setDefinition(new CpsFlowDefinition(
- "stage('unstable') {\n" +
- " echo('foo')\n" +
- " unstable('oops')\n" +
- " echo('foo')\n" +
- "}\n" +
- "stage('success') {\n" +
- " echo('no problem')" +
- "}\n" +
- "stage('failure') {\n" +
- " unstable('second oops')\n" +
- " error('failure')\n" +
- "}\n", true));
+ """
+ stage('unstable') {
+ echo('foo')
+ unstable('oops')
+ echo('foo')
+ }
+ stage('success') {
+ echo('no problem')
+ }
+ stage('failure') {
+ unstable('second oops')
+ error('failure')
+ }
+ """, true));
WorkflowRun run = j.assertBuildStatus(Result.FAILURE, job.scheduleBuild2(0));
StagesAndParallelBranchesVisitor visitor = new StagesAndParallelBranchesVisitor(run);
assertEquals(3, visitor.chunks.size());
@@ -863,13 +880,15 @@ public void unstableWithWarningAction() throws Exception {
public void unstableInBlockScopeStep() throws Exception {
WorkflowJob job = j.jenkins.createProject(WorkflowJob.class, "unstableInBlockScopeStep");
job.setDefinition(new CpsFlowDefinition(
- "stage('unstable') {\n" +
- " timeout(1) {\n" +
- " timeout(1) {\n" +
- " unstable('oops')\n" +
- " }\n" +
- " }\n" +
- "}\n", true));
+ """
+ stage('unstable') {
+ timeout(1) {
+ timeout(1) {
+ unstable('oops')
+ }
+ }
+ }
+ """, true));
WorkflowRun run = j.assertBuildStatus(Result.UNSTABLE, job.scheduleBuild2(0));
StagesAndParallelBranchesVisitor visitor = new StagesAndParallelBranchesVisitor(run);
assertEquals(1, visitor.chunks.size());
@@ -881,15 +900,17 @@ public void unstableInBlockScopeStep() throws Exception {
public void catchErrorWithStageResult() throws Exception {
WorkflowJob job = j.jenkins.createProject(WorkflowJob.class, "catchErrorWithStageResult");
job.setDefinition(new CpsFlowDefinition(
- "stage('failure') {\n" +
- " catchError(stageResult: 'FAILURE') {\n" +
- " error('oops')\n" +
- " }\n" +
- " unstable('failure takes priority')\n" +
- "}\n" +
- "stage('success') {\n" +
- " echo('foo')" +
- "}\n", true));
+ """
+ stage('failure') {
+ catchError(stageResult: 'FAILURE') {
+ error('oops')
+ }
+ unstable('failure takes priority')
+ }
+ stage('success') {
+ echo('foo')
+ }
+ """, true));
WorkflowRun run = j.assertBuildStatus(Result.FAILURE, job.scheduleBuild2(0));
StagesAndParallelBranchesVisitor visitor = new StagesAndParallelBranchesVisitor(run);
assertEquals(2, visitor.chunks.size());
@@ -902,11 +923,13 @@ public void catchErrorWithStageResult() throws Exception {
public void nestedStageParentStatus() throws Exception {
WorkflowJob job = j.jenkins.createProject(WorkflowJob.class, "unstable");
job.setDefinition(new CpsFlowDefinition(
- "stage('parent') {\n" +
- " stage('child') {\n" +
- " error('oops')\n" +
- " }\n" +
- "}\n", true));
+ """
+ stage('parent') {
+ stage('child') {
+ error('oops')
+ }
+ }
+ """, true));
WorkflowRun run = j.assertBuildStatus(Result.FAILURE, job.scheduleBuild2(0));
StagesAndParallelBranchesVisitor visitor = new StagesAndParallelBranchesVisitor(run);
assertEquals(2, visitor.chunks.size());
@@ -919,7 +942,7 @@ public void nestedStageParentStatus() throws Exception {
/**
* Visitor that collects stages and parallel branches into chunks in a way similar to what
* Blue Ocean does.
- *
+ *
* This visitor should only be used for pipelines which have finished executing and for
* which all stage and parallel branch names are unique.
*/