Skip to content

Commit 4f2c864

Browse files
committed
Run and attempt tooltip, use run number
1 parent 59fff02 commit 4f2c864

File tree

7 files changed

+153
-3
lines changed

7 files changed

+153
-3
lines changed

package-lock.json

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

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@
377377
"devDependencies": {
378378
"@types/js-yaml": "^3.12.1",
379379
"@types/libsodium-wrappers": "^0.7.10",
380+
"@types/moment-duration-format": "^2.2.3",
380381
"@types/node": "^14.14.32",
381382
"@types/uuid": "^3.4.6",
382383
"@types/vscode": "^1.72.0",
@@ -405,6 +406,8 @@
405406
"abab": "^2.0.5",
406407
"crypto-browserify": "^3.12.0",
407408
"libsodium-wrappers": "^0.7.10",
409+
"moment": "^2.29.4",
410+
"moment-duration-format": "^2.3.2",
408411
"ssh-config": "^3.0.0",
409412
"stream-browserify": "^3.0.0",
410413
"timers-browserify": "^2.0.12",

src/store/workflowRun.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,16 @@ abstract class WorkflowRunBase {
2222
return (this.run.run_attempt || 1) > 1;
2323
}
2424

25+
duration(): number {
26+
if (this.run.run_started_at) {
27+
const started_at = new Date(this.run.run_started_at);
28+
29+
const updated_at = new Date(this.run.updated_at);
30+
return updated_at.getTime() - started_at.getTime();
31+
}
32+
return 0;
33+
}
34+
2535
updateRun(run: model.WorkflowRun) {
2636
if (this._run.updated_at !== run.updated_at) {
2737
// Run has changed, reset jobs. Note: this doesn't work in all cases, there might be race conditions

src/treeViews/icons.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ function _getIconForWorkflowrun(
3737
return getAbsoluteIconPath("conclusions/failure.svg");
3838

3939
case "cancelled":
40+
case "skipped":
4041
return getAbsoluteIconPath("conclusions/cancelled.svg");
4142
}
4243
break;
@@ -72,6 +73,7 @@ export function getCodIconForWorkflowrun(runOrJob?: IStatusAndConclusion): strin
7273
return "error";
7374

7475
case "cancelled":
76+
case "skipped":
7577
return "circle-slash";
7678
}
7779
break;

src/treeViews/shared/attemptNode.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,25 @@ import * as vscode from "vscode";
22
import {GitHubRepoContext} from "../../git/repository";
33
import {WorkflowRunAttempt} from "../../store/workflowRun";
44
import {getIconForWorkflowRun} from "../icons";
5+
import {getEventString, getStatusString} from "./runTooltipHelper";
56
import {WorkflowJobNode} from "./workflowJobNode";
67

78
export class AttemptNode extends vscode.TreeItem {
89
constructor(private gitHubRepoContext: GitHubRepoContext, private attempt: WorkflowRunAttempt) {
910
super(`Attempt #${attempt.attempt}`, vscode.TreeItemCollapsibleState.Collapsed);
1011

1112
this.iconPath = getIconForWorkflowRun(this.attempt.run);
12-
this.tooltip = `#${this.attempt.attempt}: ${this.attempt.run.status || ""} ${this.attempt.run.conclusion || ""}`;
13+
this.tooltip = this.getTooltip();
14+
}
15+
16+
getTooltip(): vscode.MarkdownString {
17+
let markdownString = `#${this.attempt.attempt}: `;
18+
19+
markdownString += getStatusString(this.attempt);
20+
markdownString += `\n\n`;
21+
markdownString += getEventString(this.attempt);
22+
23+
return new vscode.MarkdownString(markdownString);
1324
}
1425

1526
async getJobs(): Promise<WorkflowJobNode[]> {
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import moment from "moment";
2+
import "moment-duration-format";
3+
import {WorkflowRun} from "../../store/workflowRun";
4+
import {WorkflowRunAttempt} from "../../store/workflowRun";
5+
6+
// Reutrns a string like "**Succeeded** in **1m 2s**"
7+
// For use in markdown tooltip
8+
export function getStatusString(item: WorkflowRun | WorkflowRunAttempt, capitalize: boolean = false): string {
9+
let statusText = item.run.conclusion || item.run.status || "";
10+
switch (statusText) {
11+
case "success":
12+
statusText = "succeeded";
13+
break;
14+
case "failure":
15+
statusText = "failed";
16+
break;
17+
}
18+
19+
statusText = statusText.replace("_", " ");
20+
21+
if (capitalize) {
22+
statusText = statusText.charAt(0).toUpperCase() + statusText.slice(1);
23+
}
24+
25+
statusText = `**${statusText}**`;
26+
27+
if (item.run.conclusion && item.run.conclusion !== "skipped") {
28+
const duration = moment.duration(item.duration());
29+
statusText += ` in **${duration.format("D[d] h[h] m[m] s[s]")}**`;
30+
}
31+
32+
return statusText;
33+
}
34+
35+
// Reutrns a string like "Manually run by [user](user_url) 4 minutes ago *(December 31, 1969 7:00 PM)*"
36+
// For use in markdown tooltip
37+
export function getEventString(item: WorkflowRun | WorkflowRunAttempt): string {
38+
let eventString = "Triggered";
39+
if (item.hasPreviousAttempts) {
40+
eventString = "Re-run";
41+
} else {
42+
const event = item.run.event;
43+
if (event) {
44+
switch (event) {
45+
case "workflow_dispatch":
46+
eventString = "Manually triggered";
47+
break;
48+
case "dynamic":
49+
eventString = "Triggered";
50+
break;
51+
default:
52+
eventString = "Triggered via " + event.replace("_", " ");
53+
}
54+
}
55+
}
56+
57+
if (item.run.triggering_actor) {
58+
eventString += ` by [${item.run.triggering_actor.login}](${item.run.triggering_actor.html_url})`;
59+
}
60+
61+
let started_at = moment(item.run.run_started_at);
62+
eventString += ` ${started_at.fromNow()} *(${started_at.format("LLL")})*`;
63+
64+
return eventString;
65+
}

src/treeViews/shared/workflowRunNode.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {GitHubRepoContext} from "../../git/repository";
44
import {RunStore} from "../../store/store";
55
import {WorkflowRun} from "../../store/workflowRun";
66
import {getIconForWorkflowRun} from "../icons";
7+
import {getEventString, getStatusString} from "./runTooltipHelper";
78
import {NoWorkflowJobsNode} from "./noWorkflowJobsNode";
89
import {PreviousAttemptsNode} from "./previousAttemptsNode";
910
import {WorkflowJobNode} from "./workflowJobNode";
@@ -33,7 +34,7 @@ export class WorkflowRunNode extends vscode.TreeItem {
3334
}
3435

3536
this.iconPath = getIconForWorkflowRun(this.run.run);
36-
this.tooltip = `${this.run.run.status || ""} ${this.run.run.conclusion || ""}`;
37+
this.tooltip = this.getTooltip();
3738
}
3839

3940
async getJobs(): Promise<(WorkflowJobNode | NoWorkflowJobsNode | PreviousAttemptsNode)[]> {
@@ -50,7 +51,21 @@ export class WorkflowRunNode extends vscode.TreeItem {
5051
return children;
5152
}
5253

54+
getTooltip(): vscode.MarkdownString {
55+
let markdownString = "";
56+
57+
if (this.run.hasPreviousAttempts) {
58+
markdownString += `Attempt #${this.run.run.run_attempt} `;
59+
}
60+
61+
markdownString += getStatusString(this.run, markdownString.length == 0);
62+
markdownString += `\n\n`;
63+
markdownString += getEventString(this.run);
64+
65+
return new vscode.MarkdownString(markdownString);
66+
}
67+
5368
private static _getLabel(run: WorkflowRun, workflowName?: string): string {
54-
return `${workflowName ? workflowName + " " : ""}#${run.run.id}`;
69+
return `${workflowName ? workflowName + " " : ""}#${run.run.run_number}`;
5570
}
5671
}

0 commit comments

Comments
 (0)