diff --git a/bin/executor b/bin/executor
index 72bb3dd..000a93a 100755
Binary files a/bin/executor and b/bin/executor differ
diff --git a/lib/jobs/job-builder.js b/lib/jobs/job-builder.js
index 9df5c47..17fbc8f 100644
--- a/lib/jobs/job-builder.js
+++ b/lib/jobs/job-builder.js
@@ -11,57 +11,51 @@ const buildCommon = (jobRequest) => {
const { isTriage, ignore, region, testNames } = jobRequest;
const command = [baseCommand, suiteEntry];
// Apply Common Flags
- command.push(`isTriage=${isTriage}`);
- if(ignore && ignore.length > 0) console.log("Would ignore", ignore);
- if(region)
- command.push(`region=${region}`);
-
+ if (isTriage) 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 buildManual = (jobReq) => {
- const {testNames} = jobReq;
- if(testNames.length > 1) throw Error("Currently only 1 test can be selected!");
+ const { command, testNames } = jobReq;
+ if (testNames.length > 1)
+ throw Error("Currently only 1 test can be selected!");
command.push(`test=${testNames[0]}`);
-
+
return { ...jobReq, command };
};
const buildTags = (jobReq) => {
- const {command, tags, testNames} = jobReq;
- if(testNames && testNames.length > 0){
+ 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"
- );
+ const arg = Buffer.from(JSON.stringify(tags), "utf8").toString("base64");
command.push(`tags=${arg}`);
- return {...jobReq, command};
+ 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}`);
+ 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) {
+ console.log(jobRequest);
const jobReq = buildCommon(jobRequest, id);
- 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
+ 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 c0aca30..943793a 100644
--- a/lib/sockets/clients/Initiator.js
+++ b/lib/sockets/clients/Initiator.js
@@ -64,7 +64,11 @@ export default class Initiator {
delete triggers[testName].__testDelay;
const jobReq = {
...jobRequest,
- pipeline: {...pipeline, triggers: triggers[testName],__test:testName },
+ pipeline: {
+ ...pipeline,
+ triggers: triggers[testName],
+ __test: testName,
+ },
};
setTimeout(
() =>
diff --git a/package.json b/package.json
index ae38fc5..20456ca 100644
--- a/package.json
+++ b/package.json
@@ -19,7 +19,7 @@
"build:react": "vite build",
"start": "node dist/app.js",
"start:dev": "nodemon dist/app.js",
- "start:dev:replit": "npm run start:react:replit & (sleep 10 && npm run start:dev)",
+ "start:dev:replit": "npm run start:react:replit & (sleep 30 && npm run start:dev)",
"start:react": "vite preview",
"start:react:replit": "vite --host",
"test": "node tests/index.js",
diff --git a/src/ctx/JobContext.jsx b/src/ctx/JobContext.jsx
index 1bb3df3..7b70a81 100644
--- a/src/ctx/JobContext.jsx
+++ b/src/ctx/JobContext.jsx
@@ -82,17 +82,18 @@ export const JobProvider = ({ children }) => {
isPipeline: true,
initiator: i,
pipelineId: jobPipeline.id,
- branchId: pipelineReq.pipeline.__test
+ branchId: pipelineReq.pipeline.__test,
};
const request = {
image: "node",
name: jobId,
- pipeline: pipelineReq,
+ ...pipelineReq,
};
jobCreate(job);
const onLog = (d) => {
const job = state.jobs.find((j) => j.jobId === jobId);
+
job.log.push(d);
job.status = jobStatus.ACTIVE;
jobUpdate({ ...job }, jobId);
@@ -104,48 +105,86 @@ export const JobProvider = ({ children }) => {
job.status = c === 0 ? jobStatus.OK : jobStatus.ERROR;
jobUpdate({ ...job }, jobId);
};
+
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
- });
- }
+ for (var t in triggers) {
+ const delay = triggers[t].__testDelay ?? 0;
+ delete triggers[t].__testDelay;
+ const jobReq = {
+ ...request,
+ pipeline: {
+ triggers: triggers[t],
+ __test: t,
+ },
+ };
+ jobPipeline.pendingTriggers.push({
+ testName: t,
+ timer: setTimeout(
+ () => pipelineComponentJob(jobPipeline, jobReq),
+ delay
+ ),
+ triggerAt: Date.now() + delay,
+ });
+ }
};
const started = i.newPipelineJob(
request,
onLog,
onClose,
+ null,
onPipelineTrigger
);
started.then(() => jobUpdate({ status: jobStatus.ACTIVE }, jobId));
}
function pipelineFactory(builderCache) {
- console.log("Would create pipeline with cache");
- const { tree, branches } = builderCache;
+ const { tree, branches, selectedBranches } = builderCache;
const __test = Object.keys(tree)[0];
- const pipelineReq = {image: "node", pipeline:{__test, triggers: { ...tree[__test] }}}
+ const pipelineReq = {
+ image: "node",
+ pipeline: { __test, triggers: { ...tree[__test] } },
+ };
const id = `pij${Date.now()}`;
- const pipeline = {id, branches, pendingTriggers: {} };
- const {pipelines} = state;
+ const pipeline = { id, branches, pendingTriggers: [], selectedBranches };
+ const { pipelines } = state;
pipelines.push(pipeline);
updatePipelines([...pipelines]);
return pipelineComponentJob(pipeline, pipelineReq);
-
+ }
+
+ function pipelineCancel(pipelineId) {
+ const pipeline = state.pipelines.find((p) => p.id === pipelineId);
+ pipeline.pendingTriggers.forEach((t) => clearTimeout(t));
+ const jobs = state.jobs.filter(
+ (j) => j.isPipeline && j.pipelineId === pipelineId
+ );
+ for (var j of jobs) {
+ if (j.initiator.sk) j.initiator.sk.close();
+ j.status = jobStatus.CANCELED;
+ jobUpdate({ ...j }, j.jobId);
+ }
+ }
+
+ function pipelineDestroy(pipelineId) {
+ const pipelineIndex = state.pipelines.findIndex((p) => p.id === pipelineId);
+ const pipeline = state.pipelines[pipelineIndex];
+ pipeline.pendingTriggers.forEach((t) => clearTimeout(t));
+ const jobs = state.jobs.filter(
+ (j) => j.isPipeline && j.pipelineId === pipelineId
+ );
+ for (var j of jobs) {
+ if (
+ j.initiator.sk &&
+ j.status !== jobStatus.OK &&
+ j.status !== jobStatus.ERROR &&
+ j.status !== jobStatus.CANCELED
+ ) {
+ j.initiator.sk.close();
+ }
+ jobDelete(j.jobId);
+ }
+ state.pipelines.splice(pipelineIndex, 1);
}
function jobCancel(jobId) {
@@ -185,11 +224,12 @@ export const JobProvider = ({ children }) => {
};
const request = {
- testName: builderCache.testNames[0],
+ testNames: builderCache.testNames,
image: "node",
type: "single",
name: jobId,
};
+ console.log(request);
jobCreate(job);
@@ -223,6 +263,8 @@ export const JobProvider = ({ children }) => {
jobFactory,
jobCancel,
jobDestroy,
+ pipelineCancel,
+ pipelineDestroy,
};
const contextValue = useMemo(() => context, [state, dispatch]);
diff --git a/src/views/jobs/JobPipelineDisplay.jsx b/src/views/jobs/JobPipelineDisplay.jsx
index ff33eb8..00600a2 100644
--- a/src/views/jobs/JobPipelineDisplay.jsx
+++ b/src/views/jobs/JobPipelineDisplay.jsx
@@ -1,62 +1,114 @@
import React, { useContext } from "react";
-import {useNavigate} from "react-router-dom";
+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 Box from "@mui/material/Box";
+import AppBar from "@mui/material/AppBar";
+import Toolbar from "@mui/material/Toolbar";
+import IconButton from "@mui/material/IconButton";
+import Typography from "@mui/material/Typography";
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";
+import ArrowBackIcon from "@mui/icons-material/ArrowBack";
function JobPipelineDisplay(props) {
const { back, pipeline } = props;
- const {state: jobState} = useContext(JobContext);
+ const {
+ state: jobState,
+ pipelineCancel,
+ pipelineDestroy,
+ } = 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}`);
+ const pipelineJobs = jobState.jobs.filter(
+ (j) => j.isPipeline && j.pipelineId === pipeline.id
+ );
+ const selectedBranches = () => {
+ return pipeline.branches.map((b) => {
+ return b.filter((t) => pipeline.selectedBranches.includes(t));
+ });
+ };
+
+ const selectJob = (testName) => () => {
+ const job = pipelineJobs.find((j) => j.branchId === testName);
+ if (!job) return;
+ navigate(`/qualiteer/jobs#${job.jobId}`);
+ };
+
+ function navigateToJobs() {
+ navigate(`/qualiteer/jobs`);
}
-
+
+ function cancelPipeline() {
+ pipelineCancel(pipeline.id);
+ }
+
+ function deletePipeline() {
+ pipelineDestroy(pipeline.id);
+ }
+
return (
-
- {}
- {pipeline.branches.map((track, i) => (
-
- {i + 1}
-
- {track.map((test, j) => (
-
+
+
+
+
+
+
+
+
+ {pipeline.id}
+
+
+
+
+
+
+
+
+
+
+
+ {selectedBranches().map((track, i) => (
+
+ {i + 1}
+
+ {track.map((test, j) => (
+
+
-
-
- {test}
-
- I
-
-
- ))}
-
-
- ))}
-
+ {test}
+
+ I
+
+
+ ))}
+
+
+ ))}
+
);
}
diff --git a/src/views/jobs/JobView.jsx b/src/views/jobs/JobView.jsx
index 55182e1..94e95ef 100644
--- a/src/views/jobs/JobView.jsx
+++ b/src/views/jobs/JobView.jsx
@@ -72,10 +72,8 @@ export default function JobView(props) {
cb();
};
-
-
function navigateToJobs() {
- if(job.isPipeline) return navigate(`/qualiteer/jobs#p${job.pipelineId}`)
+ 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 62eb282..fd6d2f5 100644
--- a/src/views/jobs/Jobs.jsx
+++ b/src/views/jobs/Jobs.jsx
@@ -18,11 +18,11 @@ export default function Jobs() {
useEffect(() => {
const jobName = location.hash.slice(1);
const pipelineId = jobName.slice(1);
- if(!jobName || !pipelineId) return;
- const hasJob = jobState.pipelines.find((p)=>p.id ===pipelineId);
+ if (!jobName || !pipelineId) return;
+ const hasJob = jobState.pipelines.find((p) => p.id === pipelineId);
const hasPipeline = jobState.jobs.find((job) => job.name === jobName);
- if(hasPipeline || hasJob) return;
- if(jobName || pipelineId) navigate("/qualiteer/jobs");
+ if (hasPipeline || hasJob) return;
+ if (jobName || pipelineId) navigate("/qualiteer/jobs");
});
return (
@@ -51,29 +51,46 @@ export default function Jobs() {
) : null}
- {location.hash === "" &&(
-
- {jobState.jobs
- .filter((j) => !j.isPipeline)
- .map((v, i) => (
+ {location.hash === "" && (
+
+ {jobState.jobs
+ .filter((j) => !j.isPipeline)
+ .map((v, i) => (
+
+
+
+ ))}
+ {jobState.pipelines.map((p, i) => (
-
- ))}
- {jobState.pipelines.map((p,i)=>
-
- )}
- )
- }
-
- { location.hash[1] === "p"? jobState.pipelines.find((p)=>p.id===location.hash.slice(2)) && (p.id===location.hash.slice(2))}/>) :
- jobState.jobs.find((job) => job.name === location.hash.slice(1)) && ( job.name === location.hash.slice(1))}
- />
+
+
+ ))}
+
)}
+
+ {location.hash[1] === "p"
+ ? jobState.pipelines.find((p) => p.id === location.hash.slice(2)) && (
+ 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/src/views/jobs/builder/PipelineTrackSelector.jsx b/src/views/jobs/builder/PipelineTrackSelector.jsx
index 1683c08..11c84c4 100644
--- a/src/views/jobs/builder/PipelineTrackSelector.jsx
+++ b/src/views/jobs/builder/PipelineTrackSelector.jsx
@@ -47,6 +47,7 @@ function PipelineTrackSelector(props) {
...cache,
branches: asBranches(primaries),
tree: asTree(cache.tracks),
+ selectedBranches: as1d(cache.tracks),
});
next();
};
diff --git a/tests/assets/suite/runner.js b/tests/assets/suite/runner.js
index 114dc9d..481d9e1 100644
--- a/tests/assets/suite/runner.js
+++ b/tests/assets/suite/runner.js
@@ -57,7 +57,7 @@ const runTests = () => {
liveIndicator();
setTimeout(() => {
const status = runTests();
- pipeline.testData = status.pipelineData;
+ if (pipeline) pipeline.testData = status.pipelineData;
const testResult = {
...status,
name: test,
diff --git a/tests/index.js b/tests/index.js
index f5be35d..b2dbb1a 100644
--- a/tests/index.js
+++ b/tests/index.js
@@ -18,13 +18,15 @@ const job = {
secondary1: {
__testDelay: 1000,
tertiary1: {},
- tertiary2: {
- __testDelay: 8000 },
+ tertiary2: {
+ __testDelay: 8000,
+ },
},
- secondary2: {
- __testDelay: 20000,
- tertiary3: {
- __testDelay: 3000 },
+ secondary2: {
+ __testDelay: 20000,
+ tertiary3: {
+ __testDelay: 3000,
+ },
},
},
},