Skip to content

Commit b61790d

Browse files
committed
improvement(WorkArea): Add Test Execute button
This commits adds a new button to the test runs within argus, allowing user to either start a build from scratch or rebuild a latest run without having to open a run to do so. The from scratch implementation will try to retrieve previous build parameters (In case previous build wasn't submitted to argus) and if that's not possible, will offer user to start a build without parameters to be able to retrieve the build on subsequent call. Fixes #542
1 parent 6f31bca commit b61790d

File tree

5 files changed

+84
-9
lines changed

5 files changed

+84
-9
lines changed

argus/backend/service/jenkins_service.py

+18-4
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,18 @@ def __init__(self) -> None:
5050
username=current_app.config["JENKINS_USER"],
5151
password=current_app.config["JENKINS_API_TOKEN"])
5252

53-
def retrieve_job_parameters(self, build_id: str, build_number: int) -> list[Parameter]:
54-
job_info = self._jenkins.get_build_info(name=build_id, number=build_number)
53+
def retrieve_job_parameters(self, build_id: str, build_number: int | None) -> list[Parameter]:
54+
job_info = self._jenkins.get_job_info(name=build_id)
55+
if not build_number:
56+
next_build_number = job_info.get("nextBuildNumber")
57+
if not next_build_number:
58+
raise JenkinsServiceError("#noBuildsAvailable")
59+
try:
60+
build_info = self._jenkins.get_build_info(name=build_id, number=next_build_number - 1)
61+
except jenkins.JenkinsException:
62+
raise JenkinsServiceError("#noBuildsAvailable")
63+
else:
64+
build_info = self._jenkins.get_build_info(name=build_id, number=build_number)
5565
raw_config = self._jenkins.get_job_config(name=build_id)
5666
config = ET.fromstring(raw_config)
5767
parameter_defs = config.find("*//parameterDefinitions")
@@ -62,8 +72,12 @@ def retrieve_job_parameters(self, build_id: str, build_number: int) -> list[Para
6272
}
6373
else:
6474
descriptions = {}
65-
params = next(a for a in job_info["actions"] if a.get("_class", "#NONE") == "hudson.model.ParametersAction")["parameters"]
66-
params = [param for param in params if param["name"] != self.RESERVED_PARAMETER_NAME]
75+
params = next((a for a in build_info["actions"] if a.get("_class", "#NONE") == "hudson.model.ParametersAction"), None)
76+
if params:
77+
params = [param for param in params["parameters"] if param["name"] != self.RESERVED_PARAMETER_NAME]
78+
else:
79+
default_params = next((prop for prop in job_info["property"] if prop.get("_class", "") == "hudson.model.ParametersDefinitionProperty"), {}).get("parameterDefinitions", {})
80+
params = [{"name": param["name"], "value": param.get("defaultParameterValue", {}).get("value", "")} for param in default_params if param["name"] != self.RESERVED_PARAMETER_NAME]
6781
for idx, param in enumerate(params):
6882
params[idx]["description"] = descriptions.get(param["name"], "")
6983

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<script>
2+
import { createEventDispatcher } from "svelte";
3+
4+
/**
5+
* @type {Object} args
6+
*/
7+
export let args;
8+
const dispatch = createEventDispatcher();
9+
</script>
10+
11+
<div>
12+
This test contains no runs and no runs were found inside Jenkins. A build will be started without parameters to later retrieve them. Do you wish to continue?
13+
<div class="p-2">
14+
<button class="btn btn-primary me-1" on:click={() => dispatch("exit", { confirm: true })}>OK</button>
15+
<button class="btn btn-secondary" on:click={() => dispatch("exit", { confirm: false })}>Cancel</button>
16+
</div>
17+
</div>

frontend/TestRun/Jenkins/JenkinsBuildModal.svelte

+31-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import ParamFetchPlaceholder from "./ParamFetchPlaceholder.svelte";
66
import ParameterEditor from "./ParameterEditor.svelte";
77
import ModalError from "./ModalError.svelte";
8+
import BuildConfirmationDialog from "./BuildConfirmationDialog.svelte";
89
910
export let buildId;
1011
export let buildNumber;
@@ -17,6 +18,7 @@
1718
PARAM_EDIT: "param_edit",
1819
BUILD_START: "build_start",
1920
BUILD_CONFIRMED: "build_confirmed",
21+
BUILD_CONFIRM: "build_confirmation",
2022
ERROR: "error",
2123
};
2224
@@ -28,8 +30,12 @@
2830
let res = await fetchLastBuildParams(this.args.buildId, this.args.buildNumber);
2931
setState(STATES.PARAM_EDIT, {params: res});
3032
} catch (error) {
31-
setState(STATES.ERROR, { message: error.message });
32-
console.log(error);
33+
if (error.message == "#noBuildsAvailable") {
34+
setState(STATES.BUILD_CONFIRM);
35+
} else {
36+
setState(STATES.ERROR, { message: error.message });
37+
console.log(error);
38+
}
3339
}
3440
},
3541
/**
@@ -60,6 +66,24 @@
6066
params: {}
6167
},
6268
},
69+
[STATES.BUILD_CONFIRM]: {
70+
component: BuildConfirmationDialog,
71+
onEnter: async function () {
72+
//empty
73+
},
74+
/**
75+
* @param {CustomEvent} event
76+
*/
77+
onExit: async function (e) {
78+
if (e.detail.confirm) {
79+
setState(STATES.BUILD_START, { buildParams: {} });
80+
} else {
81+
dispatch("rebuildCancel");
82+
}
83+
},
84+
args: {
85+
},
86+
},
6387
[STATES.BUILD_START]: {
6488
component: BuildStartPlaceholder,
6589
onEnter: async function () {
@@ -181,7 +205,11 @@
181205
<div class="d-flex align-items-center justify-content-center p-4">
182206
<div class="rounded bg-white p-4 h-50">
183207
<div class="mb-2 d-flex border-bottom pb-2">
184-
<h5>Rebuilding <span class="fw-bold">{buildId}#{buildNumber}</span></h5>
208+
{#if buildNumber}
209+
<h5>Rebuilding <span class="fw-bold">{buildId}#{buildNumber}</span></h5>
210+
{:else}
211+
<h5>Starting <span class="fw-bold">{buildId}</span></h5>
212+
{/if}
185213
<div class="ms-auto">
186214
<button
187215
class="btn btn-close"

frontend/TestRun/Jenkins/JenkinsCloneModal.svelte

+5-1
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,11 @@
327327
<div class="d-flex align-items-center justify-content-center p-4">
328328
<div class="rounded bg-white p-4 h-50">
329329
<div class="mb-2 d-flex border-bottom pb-2">
330-
<h5>Cloning <span class="fw-bold">{buildId}#{buildNumber}</span></h5>
330+
{#if buildNumber != -1}
331+
<h5>Cloning <span class="fw-bold">{buildId}#{buildNumber}</span></h5>
332+
{:else}
333+
<h5>Cloning <span class="fw-bold">{buildId}</span></h5>
334+
{/if}
331335
<div class="ms-auto">
332336
<button
333337
class="btn btn-close"

frontend/WorkArea/TestRuns.svelte

+13-1
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,15 @@
1212
import { AVAILABLE_PLUGINS } from "../Common/PluginDispatch";
1313
import { sendMessage } from "../Stores/AlertStore";
1414
import TestRunsMessage from "./TestRunsMessage.svelte";
15-
import { faGear, faTimes } from "@fortawesome/free-solid-svg-icons";
15+
import { faGear, faPlay, faTimes } from "@fortawesome/free-solid-svg-icons";
1616
import Fa from "svelte-fa";
1717
import { Collapse } from "bootstrap";
1818
import JobConfigureModal from "./JobConfigureModal.svelte";
1919
import { applicationCurrentUser } from "../argus";
2020
import ResultsGraphs from "../TestRun/ResultsGraphs.svelte";
2121
import { faCopy } from "@fortawesome/free-regular-svg-icons";
2222
import JenkinsCloneModal from "../TestRun/Jenkins/JenkinsCloneModal.svelte";
23+
import JenkinsBuildModal from "../TestRun/Jenkins/JenkinsBuildModal.svelte";
2324
2425
export let testId;
2526
export let listId = uuidv4();
@@ -119,6 +120,7 @@
119120
let selectedPlugin = "";
120121
let configureRequested = false;
121122
let cloneRequested = false;
123+
let execRequested = false;
122124
let open = true;
123125
let pluginFixed = false;
124126
let runsBody = undefined;
@@ -324,6 +326,7 @@
324326
{#if applicationCurrentUser.roles.some(v => ["ROLE_ADMIN", "ROLE_MANAGER"].includes(v)) || testInfo.release.name.includes("staging")}
325327
<button class="btn" on:click={(e) => {configureRequested = true; e.stopPropagation();}}><Fa icon={faGear}/></button>
326328
{/if}
329+
<button class="btn" on:click={(e) => {execRequested = true; e.stopPropagation();}}><Fa icon={faPlay} /></button>
327330
<button class="btn" on:click={(e) => {cloneRequested = true; e.stopPropagation();}}><Fa icon={faCopy} /></button>
328331
</div>
329332
{#if removableRuns}
@@ -359,6 +362,15 @@
359362
on:cloneComplete={(e) => { cloneRequested = false; dispatch("cloneSelect", { testId: e.detail.testId }); }}
360363
/>
361364
{/if}
365+
{#if execRequested}
366+
<JenkinsBuildModal
367+
buildId={testInfo.test.build_system_id}
368+
buildNumber={runs.length > 0 ? extractBuildNumber(runs[0]) : undefined}
369+
pluginName={testInfo.test.plugin_name}
370+
on:rebuildCancel={() => (execRequested = false)}
371+
on:rebuildComplete={() => (execRequested = false)}
372+
/>
373+
{/if}
362374
<div class="collapse show bg-main shadow-sm rounded" id="collapse-{listId}">
363375
{#if !isPluginSupported(testInfo.test.plugin_name)}
364376
<div class="rounded shadow-sm bg-white p-2 text-center">

0 commit comments

Comments
 (0)