This repository has no description
1// mirrors the helpers on types.Pipeline in types/pipeline.go
2
3import type {
4 PipelineStatus,
5 PipelineSummary,
6 PipelineTriggerKind
7} from "$lib/components/repo/types";
8
9/** the trigger tabs */
10export type PipelineFilter = "all" | PipelineTriggerKind;
11
12/** what search looks at. a real bobbin query has to cover the same fields. */
13export const matchesQuery = (pipeline: PipelineSummary, query: string): boolean => {
14 const needle = query.trim().toLowerCase();
15 if (!needle) return true;
16
17 const haystack = [
18 pipeline.sha,
19 pipeline.trigger.kind === "manual" ? "manual dispatch" : pipeline.trigger.targetRef,
20 pipeline.trigger.kind === "pull_request" ? pipeline.trigger.sourceLabel : "",
21 ...pipeline.workflows.map((workflow) => workflow.name)
22 ];
23 return haystack.some((field) => field.toLowerCase().includes(needle));
24};
25
26/** the order the breakdown lists statuses in */
27export const STATUS_ORDER: PipelineStatus[] = [
28 "success",
29 "failed",
30 "timeout",
31 "cancelled",
32 "running",
33 "pending"
34];
35
36export const STATUS_LABELS: Record<PipelineStatus, string> = {
37 pending: "Pending",
38 running: "Running",
39 success: "Passed",
40 failed: "Failed",
41 timeout: "Timed out",
42 cancelled: "Cancelled"
43};
44
45export const statusCounts = (pipeline: PipelineSummary): Record<PipelineStatus, number> => {
46 const counts = {
47 pending: 0,
48 running: 0,
49 success: 0,
50 failed: 0,
51 timeout: 0,
52 cancelled: 0
53 };
54 for (const workflow of pipeline.workflows) counts[workflow.status]++;
55 return counts;
56};
57
58/** one status for the whole run. anything still going wins, so an in-flight run says so. */
59export const aggregateStatus = (pipeline: PipelineSummary): PipelineStatus => {
60 // no workflows yet means no spindle has picked it up
61 if (pipeline.workflows.length === 0) return "pending";
62
63 const counts = statusCounts(pipeline);
64 if (counts.running > 0) return "running";
65 if (counts.pending > 0) return "pending";
66 if (counts.failed > 0) return "failed";
67 if (counts.timeout > 0) return "timeout";
68 if (counts.cancelled > 0) return "cancelled";
69 return "success";
70};
71
72/** how many workflows are done — everything except pending and running */
73export const finishedCount = (pipeline: PipelineSummary): number => {
74 const counts = statusCounts(pipeline);
75 return counts.success + counts.failed + counts.timeout + counts.cancelled;
76};
77
78/** "2/3 passed, 1/3 failed" */
79export const longSummary = (pipeline: PipelineSummary): string => {
80 const counts = statusCounts(pipeline);
81 const total = pipeline.workflows.length;
82 return STATUS_ORDER.filter((status) => counts[status] > 0)
83 .map((status) => `${counts[status]}/${total} ${STATUS_LABELS[status].toLowerCase()}`)
84 .join(", ");
85};
86
87/** sum of the workflows, not wall time across the run */
88export const totalDuration = (pipeline: PipelineSummary): number =>
89 pipeline.workflows.reduce((sum, workflow) => sum + workflow.duration, 0);