diff --git a/lib/jobs/job-builder.js b/lib/jobs/job-builder.js
index f752bcc..9df5c47 100644
--- a/lib/jobs/job-builder.js
+++ b/lib/jobs/job-builder.js
@@ -8,58 +8,60 @@ const pipelineMapping = [
];
const buildCommon = (jobRequest) => {
- const { testName } = jobRequest;
- if (!testName) throw Error("'testName' must be provided!");
- const command = [baseCommand, suiteEntry, `test=${testName}`];
-
+ const { isTriage, ignore, region, testNames } = jobRequest;
+ const command = [baseCommand, suiteEntry];
// Apply Common Flags
- command.push("isRetry=false");
-
+ command.push(`isTriage=${isTriage}`);
+ if(ignore && ignore.length > 0) console.log("Would ignore", ignore);
+ if(region)
+ command.push(`region=${region}`);
+
// Return new request
return { ...jobRequest, command };
};
-const buildSingle = (jobReq) => jobReq;
-
-const buildMarker = (jobReq) => {};
-
-const buildProject = (jobReq) => {};
-
-const pipelineMaxLife = (testName) => {
- const pipelines = pipelineMapping
- .filter((m) => m.pipeline.find((t) => t.name === testName))
- .map((m) => m.pipeline);
- return Math.max(pipelines.map((p) => p.length)) + 1;
-};
-
-const buildCompound = (jobReq, socketId) => {
- const { testName, command } = jobReq;
- const { pipeline } = jobReq;
- if (pipeline) {
- pipeline.dashboardSocketId = socketId;
- const pipelineArg = Buffer.from(JSON.stringify(pipeline), "utf8").toString(
- "base64"
- );
- command.push(`pipeline=${pipelineArg}`);
- }
+const buildManual = (jobReq) => {
+ const {testNames} = jobReq;
+ if(testNames.length > 1) throw Error("Currently only 1 test can be selected!");
+ command.push(`test=${testNames[0]}`);
+
return { ...jobReq, command };
};
-function nextCompound(previousTest) {}
+const buildTags = (jobReq) => {
+ const {command, tags, testNames} = jobReq;
+ if(testNames && testNames.length > 0){
+ return console.log("Would run tags as manual");
+ }
+ const arg = Buffer.from(JSON.stringify(tags), "utf8").toString(
+ "base64"
+ );
+ command.push(`tags=${arg}`);
+ return {...jobReq, command};
+};
+
+const buildPipeline = (jobReq, socketId) => {
+ const { command, pipeline } = jobReq;
+ const {__test: test} = pipeline;
+ if(!test) throw Error("__test is required for pipeline jobs!");
+ pipeline.dashboardSocketId = socketId;
+ const arg = Buffer.from(JSON.stringify(pipeline), "utf8").toString(
+ "base64"
+ );
+ command.push(`pipeline=${arg}`);
+ command.push(`test=${test}`);
+ return { ...jobReq, command };
+};
export default function jobBuilder(jobRequest, id) {
const jobReq = buildCommon(jobRequest, id);
- switch (jobRequest.type) {
- case "single":
- return buildSingle(jobReq);
- case "marker":
- return buildMarker(jobReq);
- case "project":
- return buildProject(jobReq);
- case "compound":
- return buildCompound(jobReq, id);
- default:
- throw Error("No Job Request Type Specified!");
- }
+ const {pipeline, testNames, tags } = jobReq;
+ if(pipeline)
+ return buildPipeline(jobReq, id);
+ else if(tags)
+ return buildTags(jobReq);
+ else if(testNames)
+ return buildManual(jobReq); //TODO currently does nothing
+ else throw Error("At least 1 'pipeline or tags or testNames' is required! ");
}
diff --git a/lib/sockets/clients/Initiator.js b/lib/sockets/clients/Initiator.js
index b2bb2de..c0aca30 100644
--- a/lib/sockets/clients/Initiator.js
+++ b/lib/sockets/clients/Initiator.js
@@ -64,8 +64,7 @@ export default class Initiator {
delete triggers[testName].__testDelay;
const jobReq = {
...jobRequest,
- pipeline: { ...pipeline, triggers: triggers[testName] },
- testName,
+ pipeline: {...pipeline, triggers: triggers[testName],__test:testName },
};
setTimeout(
() =>
diff --git a/src/ctx/JobContext.jsx b/src/ctx/JobContext.jsx
index 15d5cb7..1bb3df3 100644
--- a/src/ctx/JobContext.jsx
+++ b/src/ctx/JobContext.jsx
@@ -25,14 +25,6 @@ const initialState = {
pipelines: [],
};
-/*
-pipelines: [{tracks:[
-{
-
-}
-]}]
-*/
-
const reducer = (state, action) => {
// Current Jobs
const { jobs, pipelines } = state;
@@ -80,7 +72,7 @@ export const JobProvider = ({ children }) => {
return jobFactory({ testNames: ["single"] });
}
- function pipelineComponentJob(jobPipeline, testName) {
+ function pipelineComponentJob(jobPipeline, pipelineReq) {
const i = new Initiator(url);
const jobId = `j${Date.now()}`;
const job = {
@@ -88,15 +80,14 @@ export const JobProvider = ({ children }) => {
status: jobStatus.PENDING,
jobId,
isPipeline: true,
- builderCache: {},
initiator: i,
+ pipelineId: jobPipeline.id,
+ branchId: pipelineReq.pipeline.__test
};
const request = {
- testName,
image: "node",
- type: "pipeline",
name: jobId,
- pipelineTriggers: "secondary",
+ pipeline: pipelineReq,
};
jobCreate(job);
@@ -113,8 +104,26 @@ export const JobProvider = ({ children }) => {
job.status = c === 0 ? jobStatus.OK : jobStatus.ERROR;
jobUpdate({ ...job }, jobId);
};
- const onPipelineTrigger = (trigger) => {
- console.log("Got trigger", trigger);
+ const onPipelineTrigger = (p) => {
+ const { triggers } = p;
+ for (var t in triggers) {
+ const delay = triggers[t].__testDelay ?? 0;
+ delete triggers[t].__testDelay;
+ const jobReq = {
+ ...request,
+ pipeline: {
+ ...pipeline,
+ triggers: triggers[t],__test:t
+ },
+ };
+ jobPipeline.pendingTriggers[t].push(
+ {
+
+ testName: t,
+ timer: setTimeout(() => pipelineComponentJob(jobPipeline, jobReq),delay),
+ triggerAt: Date.now() + delay
+ });
+ }
};
const started = i.newPipelineJob(
request,
@@ -127,10 +136,16 @@ export const JobProvider = ({ children }) => {
function pipelineFactory(builderCache) {
console.log("Would create pipeline with cache");
- console.log(builderCache);
- return pipelineComponentJob(state.pipelines, builderCache.branches[0][0]);
- // return jobId;
- /*return jobFactory({testNames: ["primary"]});*/
+ const { tree, branches } = builderCache;
+ const __test = Object.keys(tree)[0];
+ const pipelineReq = {image: "node", pipeline:{__test, triggers: { ...tree[__test] }}}
+ const id = `pij${Date.now()}`;
+ const pipeline = {id, branches, pendingTriggers: {} };
+ const {pipelines} = state;
+ pipelines.push(pipeline);
+ updatePipelines([...pipelines]);
+ return pipelineComponentJob(pipeline, pipelineReq);
+
}
function jobCancel(jobId) {
diff --git a/src/views/jobs/JobPipelineBox.jsx b/src/views/jobs/JobPipelineBox.jsx
new file mode 100644
index 0000000..b05b262
--- /dev/null
+++ b/src/views/jobs/JobPipelineBox.jsx
@@ -0,0 +1,50 @@
+import React, { useState, useContext } from "react";
+import StoreContext from "../../ctx/StoreContext.jsx";
+import JobContext, { jobStatus } from "../../ctx/JobContext.jsx";
+
+import Accordion from "@mui/material/Accordion";
+import AccordionDetails from "@mui/material/AccordionDetails";
+import AccordionSummary from "@mui/material/AccordionSummary";
+import Typography from "@mui/material/Typography";
+
+import IconButton from "@mui/material/IconButton";
+import CheckIcon from "@mui/icons-material/Check";
+import ClearIcon from "@mui/icons-material/Clear";
+import ViewColumnIcon from "@mui/icons-material/ViewColumn";
+import PendingIcon from "@mui/icons-material/Pending";
+import VisibilityIcon from "@mui/icons-material/Visibility";
+import DoNotDisturbIcon from "@mui/icons-material/DoNotDisturb";
+
+import Box from "@mui/material/Box";
+import Stack from "@mui/material/Stack";
+
+export default function JobPipelineBox(props) {
+ const { pipeline } = props;
+
+ function jobIcon() {
+ return ;
+ }
+
+ return (
+
+
+
+ {pipeline.id}
+
+
+
+ {jobIcon()}
+
+
+
+
+ );
+}
diff --git a/src/views/jobs/JobPipelineDisplay.jsx b/src/views/jobs/JobPipelineDisplay.jsx
new file mode 100644
index 0000000..ff33eb8
--- /dev/null
+++ b/src/views/jobs/JobPipelineDisplay.jsx
@@ -0,0 +1,63 @@
+import React, { useContext } from "react";
+import {useNavigate} from "react-router-dom";
+import JobContext from "../../ctx/JobContext.jsx";
+import Button from "@mui/material/Button";
+import DialogActions from "@mui/material/DialogActions";
+import DialogContent from "@mui/material/DialogContent";
+
+import Accordion from "@mui/material/Accordion";
+import AccordionSummary from "@mui/material/AccordionSummary";
+import Box from "@mui/material/Box";
+import Typography from "@mui/material/Typography";
+import Stack from "@mui/material/Stack";
+
+function JobPipelineDisplay(props) {
+ const { back, pipeline } = props;
+ const {state: jobState} = useContext(JobContext);
+ const navigate = useNavigate();
+ const pipelineJobs = jobState.jobs.filter((j)=>j.isPipeline && j.pipelineId === pipeline.id);
+
+ const selectJob = (testName) => () =>{
+ const job = pipelineJobs.find((j)=>j.branchId === testName);
+ if(!job) return; navigate(`/qualiteer/jobs#${job.jobId}`);
+ }
+
+ return (
+
+ {}
+ {pipeline.branches.map((track, i) => (
+
+ {i + 1}
+
+ {track.map((test, j) => (
+
+
+
+ {test}
+
+ I
+
+
+ ))}
+
+
+ ))}
+
+ );
+}
+
+export default JobPipelineDisplay;
diff --git a/src/views/jobs/JobView.jsx b/src/views/jobs/JobView.jsx
index d7dc8fb..55182e1 100644
--- a/src/views/jobs/JobView.jsx
+++ b/src/views/jobs/JobView.jsx
@@ -72,7 +72,10 @@ export default function JobView(props) {
cb();
};
+
+
function navigateToJobs() {
+ if(job.isPipeline) return navigate(`/qualiteer/jobs#p${job.pipelineId}`)
navigate("/qualiteer/jobs");
}
diff --git a/src/views/jobs/Jobs.jsx b/src/views/jobs/Jobs.jsx
index 0571fd1..4e260c9 100644
--- a/src/views/jobs/Jobs.jsx
+++ b/src/views/jobs/Jobs.jsx
@@ -3,7 +3,9 @@ import { useLocation, useNavigate } from "react-router-dom";
import JobContext from "../../ctx/JobContext.jsx";
import JobBox from "./JobBox.jsx";
+import JobPipelineBox from "./JobPipelineBox.jsx";
import JobView from "./JobView.jsx";
+import JobPipelineDisplay from "./JobPipelineDisplay.jsx";
import JobBuilder from "./builder/JobBuilder.jsx";
import Typography from "@mui/material/Typography";
import Box from "@mui/material/Box";
@@ -15,7 +17,11 @@ export default function Jobs() {
useEffect(() => {
const jobName = location.hash.slice(1);
- if (!jobName || jobState.jobs.find((job) => job.name === jobName)) return;
+ const pipelineId = jobName.slice(1);
+ const noPipeline = !jobName || jobState.pipelines.find((p)=>p.id ===pipelineId);
+
+ const noJob = !jobName || jobState.jobs.find((job) => job.name === jobName)
+ if(!noPipeline || !noJob) return;
navigate("/qualiteer/jobs");
});
@@ -45,8 +51,9 @@ export default function Jobs() {
) : null}
- {location.hash === "" &&
- jobState.jobs
+ {location.hash === "" &&(
+
+ {jobState.jobs
.filter((j) => !j.isPipeline)
.map((v, i) => (
-
- ))}
- {jobState.jobs.find((job) => job.name === location.hash.slice(1)) && (
- ))}
+ {jobState.pipelines.map((p,i)=>
+
+ )}
+ )
+ }
+
+ { location.hash[1] === "p"? p.id===location.hash.slice(2))}/> :
+ jobState.jobs.find((job) => job.name === location.hash.slice(1)) && ( job.name === location.hash.slice(1))}
/>
)}
diff --git a/tests/index.js b/tests/index.js
index aaf717c..f5be35d 100644
--- a/tests/index.js
+++ b/tests/index.js
@@ -12,16 +12,20 @@ const url = process.env.QUALITEER_URL;
// Create an initiator and make a job request
const primary = new Initiator(url);
const job = {
- type: "compound",
- testName: "primary",
pipeline: {
+ __test: "primary",
triggers: {
secondary1: {
- tertiary1: {},
- tertiary2: { __testDelay: 5000 },
__testDelay: 1000,
+ tertiary1: {},
+ tertiary2: {
+ __testDelay: 8000 },
+ },
+ secondary2: {
+ __testDelay: 20000,
+ tertiary3: {
+ __testDelay: 3000 },
},
- secondary2: { tertiary3: { __testDelay: 3000 }, __testDelay: 15000 },
},
},
name: "testing",