Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import hudson.Plugin;
import hudson.console.AnnotatedLargeText;
Expand Down Expand Up @@ -34,7 +35,6 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ExecutionException;
import jenkins.model.Jenkins;
import net.sf.json.JSONObject;
import org.jenkins.ui.icon.IconSpec;
Expand Down Expand Up @@ -364,40 +364,81 @@
*/
@RequirePOST
@JavaScriptMethod
public boolean doRerun() throws IOException, ExecutionException {
if (run != null) {
run.checkPermission(Item.BUILD);
ReplayAction replayAction = run.getAction(ReplayAction.class);
Queue.Item item =
replayAction.run2(replayAction.getOriginalScript(), replayAction.getOriginalLoadedScripts());
public HttpResponse doRerun() {
if (run == null) {

Check warning on line 368 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 368 is only partially covered, one branch is missing
return HttpResponses.errorJSON(Messages.scheduled_failure());

Check warning on line 369 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 369 is not covered by tests
}
run.checkPermission(Item.BUILD);

if (!run.getParent().isBuildable()) {

Check warning on line 373 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 373 is only partially covered, one branch is missing
return HttpResponses.errorJSON(Messages.scheduled_failure());

Check warning on line 374 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 374 is not covered by tests
}
ReplayAction replayAction = run.getAction(ReplayAction.class);
Queue.Item item = replayAction.run2(replayAction.getOriginalScript(), replayAction.getOriginalLoadedScripts());

if (item == null) {
return HttpResponses.errorJSON(Messages.scheduled_failure());

Check warning on line 380 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 380 is not covered by tests
}

if (item == null) {
return false;
JSONObject obj = new JSONObject();
obj.put("message", Messages.scheduled_success());
obj.put("queueId", item.getId());
return HttpResponses.okJSON(obj);
}

@SuppressWarnings("unused")
@GET
@WebMethod(name = "nextBuild")
public HttpResponse hasNextBuild(StaplerRequest2 req) {
if (run == null) {

Check warning on line 393 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 393 is only partially covered, one branch is missing
return HttpResponses.errorJSON("No run to check for next build");

Check warning on line 394 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 394 is not covered by tests
}
run.checkPermission(Item.READ);
String queueId = req.getParameter("queueId");
if (queueId == null || queueId.isBlank()) {

Check warning on line 398 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 398 is only partially covered, 2 branches are missing
return HttpResponses.errorJSON("No queueId provided");

Check warning on line 399 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 399 is not covered by tests
}
long id = Long.parseLong(queueId);
logger.debug("Searching for build with queueId: {}", id);
WorkflowRun nextRun = findBuildByQueueId(id);
if (nextRun == null) {

Check warning on line 404 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 404 is only partially covered, one branch is missing
return HttpResponses.okJSON();

Check warning on line 405 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 405 is not covered by tests
}

JSONObject obj = new JSONObject();
obj.put("nextBuildUrl", nextRun.getUrl() + URL_NAME + "/");
return HttpResponses.okJSON(obj);
}

private @CheckForNull WorkflowRun findBuildByQueueId(long queueId) {
for (WorkflowRun build : run.getParent().getBuilds()) {

Check warning on line 414 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 414 is only partially covered, one branch is missing
if (build.getNumber() <= this.run.getNumber()) {

Check warning on line 415 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 415 is only partially covered, one branch is missing
break;

Check warning on line 416 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 416 is not covered by tests
}
if (build.getQueueId() == queueId) {

Check warning on line 418 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 418 is only partially covered, one branch is missing
return build;
}
return true;
}
return false;
return null;

Check warning on line 422 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 421-422 are not covered by tests
}

/**
* Handles the cancel request.
*/
@RequirePOST
@JavaScriptMethod
public HttpResponse doCancel() throws IOException, ExecutionException {
if (run != null) {
run.checkPermission(getCancelPermission());
if (run.isBuilding()) {
run.doStop();
return HttpResponses.okJSON();
} else {
String message = Result.ABORTED.equals(run.getResult())
? Messages.run_alreadyCancelled()
: Messages.run_isFinished();
return HttpResponses.errorJSON(message);
}
public HttpResponse doCancel() {
if (run == null) {

Check warning on line 431 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 431 is only partially covered, one branch is missing
return HttpResponses.errorJSON("No run to cancel");
}
run.checkPermission(getCancelPermission());
if (run.isBuilding()) {
run.doStop();
return HttpResponses.okJSON();
}
return HttpResponses.errorJSON("No run to cancel");
String message =
Result.ABORTED.equals(run.getResult()) ? Messages.run_alreadyCancelled() : Messages.run_isFinished();

Check warning on line 440 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 432-440 are not covered by tests
return HttpResponses.errorJSON(message);
}

public String getFullProjectDisplayName() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ FlowNodeWrapper.noStage=System Generated
run.alreadyCancelled=Run was already cancelled
run.isFinished=Run is already finished

scheduled.success=Build scheduled
scheduled.failure=Could not schedule a build

# Settings
settings=Settings
settings.showStageName=Show stage names
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
<j:set var="proxyId" value="${h.generateId()}" />
<st:bind value="${it}" var="rerunAction${proxyId}"/>
<div class="jenkins-split-button">
<button id="pgv-rerun" data-success-message="${%Build scheduled}"
<button id="pgv-rerun"
data-proxy-name="rerunAction${proxyId}"
class="jenkins-button jenkins-!-build-color">
<div class="jenkins-dropdown__item__icon">
Expand Down
50 changes: 43 additions & 7 deletions src/main/webapp/js/build.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,52 @@
/* global notificationBar */

const rerunButton = document.getElementById("pgv-rerun");

if (rerunButton) {
rerunButton.addEventListener("click", (event) => {
event.preventDefault();

async function redirectToNextBuild(queueId) {
while (true) {
try {
const response = await fetch(`nextBuild?queueId=${queueId}`);
if (!response.ok) {
throw new Error(
`Failed to fetch next build data: ${response.status} - ${response.statusText}`,
);
}
const { status, data, message } = await response.json();
if (status === "ok") {
if (data?.nextBuildUrl) {
let root = document.querySelector("head").dataset.rooturl;
if (!root.endsWith("/")) {
root += "/";
}
window.location = `${root}${data.nextBuildUrl}`;
break;
}
} else {
console.warn("Error in next build response:", message);
}
} catch (error) {
console.error("Error fetching next build data:", error);
}
await new Promise((resolve) => setTimeout(resolve, 1000));
}
}

const rerunAction = window[`${rerunButton.dataset.proxyName}`];
rerunAction.doRerun(function (success) {
const result = success.responseJSON;
if (result) {
notificationBar.show(
rerunButton.dataset.successMessage,
notificationBar.SUCCESS,
);
rerunAction.doRerun(async function (response) {
const { status, data, message } = response.responseJSON;
if (status === "ok") {
notificationBar.show(data.message, notificationBar.SUCCESS);
await redirectToNextBuild(data.queueId);
} else {
const failMessage =
status === "error" && message
? message
: "Unknown error occurred while trying to rerun the build.";
notificationBar.show(failMessage, notificationBar.WARNING);
}
});
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package io.jenkins.plugins.pipelinegraphview;

import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
import static org.awaitility.Awaitility.await;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.hasSize;
import static org.junit.jupiter.api.Assertions.assertEquals;

import com.microsoft.playwright.Page;
Expand Down Expand Up @@ -30,19 +32,21 @@ class PipelineGraphViewRebuildTest {
void rerunButtonStartsNewBuild(Page p, JenkinsConfiguredWithCodeRule j) throws Exception {
WorkflowRun run =
TestUtils.createAndRunJob(j, "hello_world", "helloWorldScriptedPipeline.jenkinsfile", Result.SUCCESS);
WorkflowJob job = run.getParent();

PipelineOverviewPage op = new PipelineJobPage(p, run.getParent())
PipelineOverviewPage op = new PipelineJobPage(p, job)
.goTo()
.hasBuilds(1)
.nthBuild(0)
.goToBuild()
.goToPipelineOverview();

String currentUrl = p.url();
String jobUrl = j.getURL() + job.getUrl();
assertThat(p).hasURL(jobUrl + "1/pipeline-overview/");

op.rerun();

String newUrl = p.url();
assertEquals(currentUrl, newUrl);
assertThat(p).hasURL(jobUrl + "2/pipeline-overview/");

waitUntilBuildIsComplete(j, run);
}
Expand Down Expand Up @@ -110,7 +114,7 @@ void restartFromStageButtonRedirects(Page p, JenkinsConfiguredWithCodeRule j) th
private static void waitUntilBuildIsComplete(JenkinsConfiguredWithCodeRule j, WorkflowRun run) {
await().until(() -> j.jenkins.getQueue().isEmpty(), is(true));
WorkflowJob parent = run.getParent();
await().until(() -> parent.getBuilds().size(), is(2));
await().until(parent::getBuilds, hasSize(2));

WorkflowRun lastBuild = parent.getLastBuild();
await().until(() -> lastBuild, RunMatchers.completed());
Expand Down