Skip to content

Commit 9eaaf80

Browse files
committed
Handle NOT_BUILT and ABORTED as other results
Use case -------- My use case is a post build script trigger a job which does not need to fully complete. The step can be cancelled while waiting (or building) and that caused the triggering build to be marked as a failure. To fix that, I need the plugin to pass the result of the build step through BlockingBehaviour which lets one define how to behave when the triggered build got NOT_BUILT or ABORTED, in my case I need it to never block. See: https://phabricator.wikimedia.org/T352319 Solution -------- There are multiple reasons for a job to not fully complete: - it is interrupted, an InterruptedException is thrown, this is still rethrow and Jenkins will make the build as ABORTED. - it can be cancelled from the build queue raising a CancellationException. This previously raised an AbortException which marks the build as a failure, I have changed it to a NOT_BUILT result which can be process as other results (notably never block on it). The Jenkins Result class ranks the results as: - SUCCESS - UNSTABLE - FAILURE - NOT_BUILT - ABORTED. The NOT_BUILT and ABORTED results are thus worse than a FAILURE and would be matched as such in BlockingBehavior mapBuildStepResult() and mapBuildResult() which uses isWorseOrEqualTo() for comparison. Add a test testCancelledFromBuildQueue() to cover the CancellationException() is caught and it results in a SUCCESS (since the test blocking behavior is to never block). ResultConditionTest covers the BlockingBehavior is able to map NOT_BUILD and ABORTED since it has two tests explicitly cancelling and interrupting jobs. Examples -------- When a build is aborted, by aborting it: Waiting for the completion of downstream-project downstream-project #7 started. downstream-project #7 completed. Result was ABORTED Build step 'Trigger/call builds on other projects' marked build as failure Finished: FAILURE When it is waiting in the build queue and cancelled: Waiting for the completion of downstream-project Not built: downstream-project has been cancelled while waiting in the queue. Build step 'Trigger/call builds on other projects' marked build as failure Finished: FAILURE
1 parent 8980535 commit 9eaaf80

File tree

2 files changed

+67
-30
lines changed

2 files changed

+67
-30
lines changed

src/main/java/hudson/plugins/parameterizedtrigger/TriggerBuilder.java

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -150,55 +150,59 @@ public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListen
150150
continue;
151151
}
152152
for (QueueTaskFuture<AbstractBuild> future : futures.get(p)) {
153-
try {
154-
if (future == null) {
155-
listener.getLogger()
156-
.println("Skipping " + ModelHyperlinkNote.encodeTo(p)
157-
+ ". The project was not triggered for some reason.");
158-
continue;
159-
}
160-
153+
if (future == null) {
161154
listener.getLogger()
162-
.println("Waiting for the completion of "
163-
+ HyperlinkNote.encodeTo('/' + p.getUrl(), p.getFullDisplayName()));
164-
Run startedRun;
165-
try {
166-
startedRun = future.waitForStart();
167-
} catch (InterruptedException x) {
168-
listener.getLogger()
169-
.println("Build aborting: cancelling queued project "
170-
+ HyperlinkNote.encodeTo('/' + p.getUrl(), p.getFullDisplayName()));
171-
future.cancel(true);
172-
throw x; // rethrow so that the triggering project get flagged as cancelled
173-
}
155+
.println("Skipping " + ModelHyperlinkNote.encodeTo(p)
156+
+ ". The project was not triggered for some reason.");
157+
continue;
158+
}
174159

160+
listener.getLogger()
161+
.println("Waiting for the completion of "
162+
+ HyperlinkNote.encodeTo('/' + p.getUrl(), p.getFullDisplayName()));
163+
Run startedRun;
164+
Result completedResult;
165+
try {
166+
startedRun = future.waitForStart();
175167
listener.getLogger()
176168
.println(HyperlinkNote.encodeTo(
177169
'/' + startedRun.getUrl(), startedRun.getFullDisplayName())
178170
+ " started.");
179171

180172
Run completedRun = future.get();
181-
Result completedResult = completedRun.getResult();
173+
completedResult = completedRun.getResult();
182174
listener.getLogger()
183175
.println(HyperlinkNote.encodeTo(
184176
'/' + completedRun.getUrl(), completedRun.getFullDisplayName())
185177
+ " completed. Result was " + completedResult);
178+
186179
BuildInfoExporterAction.addBuildInfoExporterAction(
187180
build,
188181
completedRun.getParent().getFullName(),
189182
completedRun.getNumber(),
190183
completedResult);
191184

192-
if (buildStepResult && config.getBlock().mapBuildStepResult(completedResult)) {
193-
Result r = config.getBlock().mapBuildResult(completedResult);
194-
if (r != null) { // The blocking job is not a success
195-
build.setResult(r);
196-
}
197-
} else {
198-
buildStepResult = false;
199-
}
185+
} catch (InterruptedException x) {
186+
listener.getLogger()
187+
.println("Build aborting: cancelling queued project "
188+
+ HyperlinkNote.encodeTo('/' + p.getUrl(), p.getFullDisplayName()));
189+
future.cancel(true);
190+
throw x; // rethrow so that the triggering project get flagged as cancelled
200191
} catch (CancellationException x) {
201-
throw new AbortException(p.getFullDisplayName() + " aborted.");
192+
listener.getLogger()
193+
.println("Not built: " + p.getFullDisplayName()
194+
+ " has been cancelled while waiting in the queue.");
195+
completedResult = Result.NOT_BUILT;
196+
}
197+
198+
if (buildStepResult && config.getBlock().mapBuildStepResult(completedResult)) {
199+
200+
Result r = config.getBlock().mapBuildResult(completedResult);
201+
if (r != null) { // The blocking job is not a success
202+
build.setResult(r);
203+
}
204+
} else {
205+
buildStepResult = false;
202206
}
203207
}
204208
}

src/test/java/hudson/plugins/parameterizedtrigger/test/TriggerBuilderTest.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,39 @@ public void testCancelsDownstreamBuildWhenInterrupted() throws Exception {
253253
assertEquals("No build left in queue", 0, r.jenkins.getQueue().countBuildableItems());
254254
}
255255

256+
@Test
257+
public void testCancelledFromBuildQueue() throws Exception {
258+
r.jenkins.setNumExecutors(1); // the downstream-project would be in the build queue
259+
260+
FreeStyleProject triggerProject = r.createFreeStyleProject("upstream-project");
261+
FreeStyleProject downstreamProject = r.createFreeStyleProject("downstream-project");
262+
263+
TriggerBuilder triggerBuilder = new TriggerBuilder(createTriggerConfig("downstream-project"));
264+
265+
triggerProject.getBuildersList().add(triggerBuilder);
266+
QueueTaskFuture<FreeStyleBuild> parentBuild = triggerProject.scheduleBuild2(0);
267+
268+
parentBuild.waitForStart();
269+
Thread.sleep(500);
270+
271+
assertEquals(
272+
"Downstream project is in build queue", 1, r.jenkins.getQueue().countBuildableItems());
273+
274+
// Cancel the queued build
275+
r.jenkins.getQueue().clear();
276+
parentBuild.get();
277+
278+
assertLines(
279+
triggerProject.getLastBuild(),
280+
"Waiting for the completion of downstream-project",
281+
"Not built: downstream-project has been cancelled while waiting in the queue.",
282+
// The test class configures the BlockingBehaviour to never
283+
// fail and that includes cancelled job.
284+
"Finished: SUCCESS");
285+
assertNull("No downstream build has been run", downstreamProject.getLastBuild());
286+
assertEquals("No build left in queue", 0, r.jenkins.getQueue().countBuildableItems());
287+
}
288+
256289
@Test
257290
public void testConsoleOutputWithCounterParameters() throws Exception {
258291
r.createFreeStyleProject("project1");

0 commit comments

Comments
 (0)