Skip to content

Commit

Permalink
Add show-waiting-runner option (#148)
Browse files Browse the repository at this point in the history
  • Loading branch information
Kesin11 authored Jul 4, 2024
2 parents 518da3e + e69eb6b commit da70bef
Show file tree
Hide file tree
Showing 13 changed files with 1,314 additions and 979 deletions.
6 changes: 5 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,9 @@ jobs:
uses: actions/download-artifact@v4
with:
name: js_dist
- name: Run self action
- name: Run self action with no options
uses: ./
- name: Run self action with 'show-waiting-runner=false'
uses: ./
with:
show-waiting-runner: false
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ jobs:
# e.g.: ${{ secrets.MY_PAT }}
# Default: ${{ github.token }}
github-token: ''
# Show waiting runner time in the timeline.
# Default: true
show-waiting-runner: true

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

# Similar works

Expand Down
4 changes: 4 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ inputs:
description: The GitHub token used to create an authenticated client
default: ${{ github.token }}
required: false
show-waiting-runner:
description: Show waiting runner time in the timeline.
default: true
required: false
runs:
using: "node20"
main: "dist/main.js"
Expand Down
9 changes: 8 additions & 1 deletion cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ const { options, args } = await new Command()
"-o, --output <output:file>",
"Output md file path. If not set output to STDOUT. ex: output.md",
)
.option(
"--show-waiting-runner <showWaitingRunner:boolean>",
"Show waiting runner time in the timeline. Default: true",
{ default: true },
)
.arguments("<url:string>")
.parse(Deno.args);

Expand Down Expand Up @@ -49,7 +54,9 @@ const workflowJobs = await fetchWorkflowRunJobs(
runUrl.runId,
runAttempt,
);
const gantt = createMermaid(workflow, workflowJobs);
const gantt = createMermaid(workflow, workflowJobs, {
showWaitingRunner: options.showWaitingRunner,
});

if (options.output) {
await Deno.writeTextFile(options.output, gantt);
Expand Down
236 changes: 235 additions & 1 deletion deno.lock

Large diffs are not rendered by default.

73 changes: 44 additions & 29 deletions dist/post.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 9 additions & 2 deletions src/post.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { setTimeout } from "node:timers/promises";
import process from "node:process";
import { debug, getInput, info, summary } from "npm:@actions/[email protected]";
import {
debug,
getBooleanInput,
getInput,
info,
summary,
} from "npm:@actions/[email protected]";
import * as github from "npm:@actions/[email protected]";
import { createMermaid } from "./workflow_gantt.ts";
import {
Expand All @@ -11,6 +17,7 @@ import {

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

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

info("Create gantt mermaid diagram...");
const gantt = createMermaid(workflow, workflowJobs);
const gantt = createMermaid(workflow, workflowJobs, { showWaitingRunner });
await summary.addRaw(gantt).write();
debug(gantt);

Expand Down
4 changes: 4 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,7 @@ export type StepConclusion =
| "timed_out"
| "action_required"
| null;

export type GanttOptions = {
showWaitingRunner?: boolean;
};
70 changes: 48 additions & 22 deletions src/workflow_gantt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ import {
formatName,
formatSection,
} from "./format_util.ts";
import type { ganttJob, ganttStep, StepConclusion } from "./types.ts";
import type {
ganttJob,
GanttOptions,
ganttStep,
StepConclusion,
} from "./types.ts";

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

// job.created_at does not exist in < GHES v3.9.
// 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.
// Also, it is not possible to create an exact job start time position. So use job.started_at instead of job.created_at.
if (job.created_at === undefined) {
const startJobElapsedSec = diffSec(
workflow.run_started_at,
job.started_at,
);
// dummy sec for gantt look and feel
const waitingRunnerElapsedSec = startJobElapsedSec;
return {
name: `Waiting for a runner (not supported < GHES v3.9)`,
id: `job${jobIndex}-0`,
status,
// dummy position for gantt look and feel
position: formatElapsedTime(0),
sec: waitingRunnerElapsedSec,
};
// >= GHES v3.9 or GitHub.com
return undefined;
} else {
// >= GHES v3.9 or GitHub.com
const startJobElapsedSec = diffSec(
workflow.run_started_at,
job.created_at,
Expand All @@ -70,17 +62,46 @@ const createWaitingRunnerStep = (
export const createGanttJobs = (
workflow: Workflow,
workflowJobs: WorkflowJobs,
showWaitingRunner = true,
): ganttJob[] => {
return filterJobs(workflowJobs).map(
(job, jobIndex, _jobs): ganttJob => {
(job, jobIndex, _jobs): ganttJob | undefined => {
if (job.steps === undefined) return undefined;

const section = escapeName(job.name);
let firstStep: ganttStep;

const waitingRunnerStep = createWaitingRunnerStep(
workflow,
job,
jobIndex,
);
if (!showWaitingRunner || waitingRunnerStep === undefined) {
const rawFirstStep = job.steps.shift();
if (rawFirstStep === undefined) return undefined;

const steps = filterSteps(job.steps ?? []).map(
const startJobElapsedSec = diffSec(
workflow.run_started_at,
job.started_at,
);
const stepElapsedSec = diffSec(
rawFirstStep.started_at,
rawFirstStep.completed_at,
);
firstStep = {
name: formatName(rawFirstStep.name, stepElapsedSec),
id: `job${jobIndex}-0`,
status: convertStepToStatus(
rawFirstStep.conclusion as StepConclusion,
),
position: formatElapsedTime(startJobElapsedSec),
sec: stepElapsedSec,
};
} else {
firstStep = waitingRunnerStep;
}

const steps = filterSteps(job.steps).map(
(step, stepIndex, _steps): ganttStep => {
const stepElapsedSec = diffSec(step.started_at, step.completed_at);
return {
Expand All @@ -93,9 +114,9 @@ export const createGanttJobs = (
},
);

return { section, steps: [waitingRunnerStep, ...steps] };
return { section, steps: [firstStep, ...steps] };
},
);
).filter((gantJobs): gantJobs is ganttJob => gantJobs !== undefined);
};

export const createGanttDiagrams = (
Expand Down Expand Up @@ -135,8 +156,13 @@ axisFormat %H:%M:%S
export const createMermaid = (
workflow: Workflow,
workflowJobs: WorkflowJobs,
options: GanttOptions,
): string => {
const title = workflow.name ?? "";
const jobs = createGanttJobs(workflow, workflowJobs);
const jobs = createGanttJobs(
workflow,
workflowJobs,
options.showWaitingRunner,
);
return createGanttDiagrams(title, jobs).join("\n");
};
Loading

0 comments on commit da70bef

Please sign in to comment.