Skip to content

Commit da70bef

Browse files
authored
Add show-waiting-runner option (#148)
2 parents 518da3e + e69eb6b commit da70bef

File tree

13 files changed

+1314
-979
lines changed

13 files changed

+1314
-979
lines changed

.github/workflows/ci.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,5 +76,9 @@ jobs:
7676
uses: actions/download-artifact@v4
7777
with:
7878
name: js_dist
79-
- name: Run self action
79+
- name: Run self action with no options
8080
uses: ./
81+
- name: Run self action with 'show-waiting-runner=false'
82+
uses: ./
83+
with:
84+
show-waiting-runner: false

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ jobs:
2222
# e.g.: ${{ secrets.MY_PAT }}
2323
# Default: ${{ github.token }}
2424
github-token: ''
25+
# Show waiting runner time in the timeline.
26+
# Default: true
27+
show-waiting-runner: true
2528

2629
# Your build steps...
2730
```
@@ -88,7 +91,7 @@ GET `workflow_job` API response does not contain `created_at` field in
8891
it is added from
8992
[GHES v3.9](https://docs.github.com/en/[email protected]/rest/actions/workflow-jobs?apiVersion=2022-11-28).
9093
So it is not possible to calculate the elapsed time the runner is waiting for a
91-
job, `actions-timeline` inserts a dummy step instead.
94+
job, `actions-timeline` omits `Waiting for a runner` step in the timeline.
9295

9396
# Similar works
9497

action.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ inputs:
99
description: The GitHub token used to create an authenticated client
1010
default: ${{ github.token }}
1111
required: false
12+
show-waiting-runner:
13+
description: Show waiting runner time in the timeline.
14+
default: true
15+
required: false
1216
runs:
1317
using: "node20"
1418
main: "dist/main.js"

cli.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ const { options, args } = await new Command()
1616
"-o, --output <output:file>",
1717
"Output md file path. If not set output to STDOUT. ex: output.md",
1818
)
19+
.option(
20+
"--show-waiting-runner <showWaitingRunner:boolean>",
21+
"Show waiting runner time in the timeline. Default: true",
22+
{ default: true },
23+
)
1924
.arguments("<url:string>")
2025
.parse(Deno.args);
2126

@@ -49,7 +54,9 @@ const workflowJobs = await fetchWorkflowRunJobs(
4954
runUrl.runId,
5055
runAttempt,
5156
);
52-
const gantt = createMermaid(workflow, workflowJobs);
57+
const gantt = createMermaid(workflow, workflowJobs, {
58+
showWaitingRunner: options.showWaitingRunner,
59+
});
5360

5461
if (options.output) {
5562
await Deno.writeTextFile(options.output, gantt);

deno.lock

Lines changed: 235 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/post.js

Lines changed: 44 additions & 29 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/post.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import { setTimeout } from "node:timers/promises";
22
import process from "node:process";
3-
import { debug, getInput, info, summary } from "npm:@actions/[email protected]";
3+
import {
4+
debug,
5+
getBooleanInput,
6+
getInput,
7+
info,
8+
summary,
9+
} from "npm:@actions/[email protected]";
410
import * as github from "npm:@actions/[email protected]";
511
import { createMermaid } from "./workflow_gantt.ts";
612
import {
@@ -11,6 +17,7 @@ import {
1117

1218
const main = async () => {
1319
const token = getInput("github-token", { required: true });
20+
const showWaitingRunner = getBooleanInput("show-waiting-runner");
1421
const octokit = createOctokitForAction(token);
1522

1623
info("Wait for workflow API result stability...");
@@ -41,7 +48,7 @@ const main = async () => {
4148
debug(JSON.stringify(workflowJobs, null, 2));
4249

4350
info("Create gantt mermaid diagram...");
44-
const gantt = createMermaid(workflow, workflowJobs);
51+
const gantt = createMermaid(workflow, workflowJobs, { showWaitingRunner });
4552
await summary.addRaw(gantt).write();
4653
debug(gantt);
4754

src/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,7 @@ export type StepConclusion =
2121
| "timed_out"
2222
| "action_required"
2323
| null;
24+
25+
export type GanttOptions = {
26+
showWaitingRunner?: boolean;
27+
};

src/workflow_gantt.ts

Lines changed: 48 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@ import {
88
formatName,
99
formatSection,
1010
} from "./format_util.ts";
11-
import type { ganttJob, ganttStep, StepConclusion } from "./types.ts";
11+
import type {
12+
ganttJob,
13+
GanttOptions,
14+
ganttStep,
15+
StepConclusion,
16+
} from "./types.ts";
1217

1318
// ref: MAX_TEXTLENGTH https://github.com/mermaid-js/mermaid/blob/develop/packages/mermaid/src/mermaidAPI.ts
1419
const MERMAID_MAX_CHAR = 50_000;
@@ -29,29 +34,16 @@ const createWaitingRunnerStep = (
2934
workflow: Workflow,
3035
job: WorkflowJobs[0],
3136
jobIndex: number,
32-
): ganttStep => {
37+
): ganttStep | undefined => {
3338
const status: ganttStep["status"] = "active";
3439

3540
// job.created_at does not exist in < GHES v3.9.
3641
// So it is not possible to calculate the elapsed time the runner is waiting for a job, is not supported instead of the elapsed time.
3742
// Also, it is not possible to create an exact job start time position. So use job.started_at instead of job.created_at.
3843
if (job.created_at === undefined) {
39-
const startJobElapsedSec = diffSec(
40-
workflow.run_started_at,
41-
job.started_at,
42-
);
43-
// dummy sec for gantt look and feel
44-
const waitingRunnerElapsedSec = startJobElapsedSec;
45-
return {
46-
name: `Waiting for a runner (not supported < GHES v3.9)`,
47-
id: `job${jobIndex}-0`,
48-
status,
49-
// dummy position for gantt look and feel
50-
position: formatElapsedTime(0),
51-
sec: waitingRunnerElapsedSec,
52-
};
53-
// >= GHES v3.9 or GitHub.com
44+
return undefined;
5445
} else {
46+
// >= GHES v3.9 or GitHub.com
5547
const startJobElapsedSec = diffSec(
5648
workflow.run_started_at,
5749
job.created_at,
@@ -70,17 +62,46 @@ const createWaitingRunnerStep = (
7062
export const createGanttJobs = (
7163
workflow: Workflow,
7264
workflowJobs: WorkflowJobs,
65+
showWaitingRunner = true,
7366
): ganttJob[] => {
7467
return filterJobs(workflowJobs).map(
75-
(job, jobIndex, _jobs): ganttJob => {
68+
(job, jobIndex, _jobs): ganttJob | undefined => {
69+
if (job.steps === undefined) return undefined;
70+
7671
const section = escapeName(job.name);
72+
let firstStep: ganttStep;
73+
7774
const waitingRunnerStep = createWaitingRunnerStep(
7875
workflow,
7976
job,
8077
jobIndex,
8178
);
79+
if (!showWaitingRunner || waitingRunnerStep === undefined) {
80+
const rawFirstStep = job.steps.shift();
81+
if (rawFirstStep === undefined) return undefined;
8282

83-
const steps = filterSteps(job.steps ?? []).map(
83+
const startJobElapsedSec = diffSec(
84+
workflow.run_started_at,
85+
job.started_at,
86+
);
87+
const stepElapsedSec = diffSec(
88+
rawFirstStep.started_at,
89+
rawFirstStep.completed_at,
90+
);
91+
firstStep = {
92+
name: formatName(rawFirstStep.name, stepElapsedSec),
93+
id: `job${jobIndex}-0`,
94+
status: convertStepToStatus(
95+
rawFirstStep.conclusion as StepConclusion,
96+
),
97+
position: formatElapsedTime(startJobElapsedSec),
98+
sec: stepElapsedSec,
99+
};
100+
} else {
101+
firstStep = waitingRunnerStep;
102+
}
103+
104+
const steps = filterSteps(job.steps).map(
84105
(step, stepIndex, _steps): ganttStep => {
85106
const stepElapsedSec = diffSec(step.started_at, step.completed_at);
86107
return {
@@ -93,9 +114,9 @@ export const createGanttJobs = (
93114
},
94115
);
95116

96-
return { section, steps: [waitingRunnerStep, ...steps] };
117+
return { section, steps: [firstStep, ...steps] };
97118
},
98-
);
119+
).filter((gantJobs): gantJobs is ganttJob => gantJobs !== undefined);
99120
};
100121

101122
export const createGanttDiagrams = (
@@ -135,8 +156,13 @@ axisFormat %H:%M:%S
135156
export const createMermaid = (
136157
workflow: Workflow,
137158
workflowJobs: WorkflowJobs,
159+
options: GanttOptions,
138160
): string => {
139161
const title = workflow.name ?? "";
140-
const jobs = createGanttJobs(workflow, workflowJobs);
162+
const jobs = createGanttJobs(
163+
workflow,
164+
workflowJobs,
165+
options.showWaitingRunner,
166+
);
141167
return createGanttDiagrams(title, jobs).join("\n");
142168
};

0 commit comments

Comments
 (0)