Add history view, rework to use history status, remove old classes
Signed-off-by: Sanjula Ganepola <sanjulagane@gmail.com>
This commit is contained in:
71
package.json
71
package.json
@@ -52,6 +52,11 @@
|
||||
"name": "Workflows",
|
||||
"icon": "$(layers)"
|
||||
},
|
||||
{
|
||||
"id": "history",
|
||||
"name": "History",
|
||||
"icon": "$(book)"
|
||||
},
|
||||
{
|
||||
"id": "settings",
|
||||
"name": "Settings",
|
||||
@@ -59,6 +64,42 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"viewsWelcome": [
|
||||
{
|
||||
"view": "components",
|
||||
"contents": "Loading components..."
|
||||
},
|
||||
{
|
||||
"view": "workflows",
|
||||
"contents": "Loading components...",
|
||||
"when": "!githubLocalActions:noWorkflows"
|
||||
},
|
||||
{
|
||||
"view": "workflows",
|
||||
"contents": "No workflows found.",
|
||||
"when": "githubLocalActions:noWorkflows"
|
||||
},
|
||||
{
|
||||
"view": "history",
|
||||
"contents": "Loading history...",
|
||||
"when": "!githubLocalActions:noHistory"
|
||||
},
|
||||
{
|
||||
"view": "history",
|
||||
"contents": "No history found.",
|
||||
"when": "githubLocalActions:noHistory"
|
||||
},
|
||||
{
|
||||
"view": "settings",
|
||||
"contents": "Loading settings...",
|
||||
"when": "!githubLocalActions:noSettings"
|
||||
},
|
||||
{
|
||||
"view": "settings",
|
||||
"contents": "No workflows found.",
|
||||
"when": "githubLocalActions:noSettings"
|
||||
}
|
||||
],
|
||||
"commands": [
|
||||
{
|
||||
"category": "GitHub Local Actions",
|
||||
@@ -114,6 +155,18 @@
|
||||
"title": "Run Workflow",
|
||||
"icon": "$(debug-start)"
|
||||
},
|
||||
{
|
||||
"category": "GitHub Local Actions",
|
||||
"command": "githubLocalActions.runJob",
|
||||
"title": "Run Job",
|
||||
"icon": "$(debug-start)"
|
||||
},
|
||||
{
|
||||
"category": "GitHub Local Actions",
|
||||
"command": "githubLocalActions.refreshHistory",
|
||||
"title": "Refresh",
|
||||
"icon": "$(refresh)"
|
||||
},
|
||||
{
|
||||
"category": "GitHub Local Actions",
|
||||
"command": "githubLocalActions.refreshSettings",
|
||||
@@ -159,6 +212,14 @@
|
||||
"command": "githubLocalActions.runWorkflow",
|
||||
"when": "never"
|
||||
},
|
||||
{
|
||||
"command": "githubLocalActions.runJob",
|
||||
"when": "never"
|
||||
},
|
||||
{
|
||||
"command": "githubLocalActions.refreshHistory",
|
||||
"when": "never"
|
||||
},
|
||||
{
|
||||
"command": "githubLocalActions.refreshSettings",
|
||||
"when": "never"
|
||||
@@ -185,6 +246,11 @@
|
||||
"when": "view == workflows",
|
||||
"group": "navigation@2"
|
||||
},
|
||||
{
|
||||
"command": "githubLocalActions.refreshHistory",
|
||||
"when": "view == history",
|
||||
"group": "navigation@0"
|
||||
},
|
||||
{
|
||||
"command": "githubLocalActions.refreshSettings",
|
||||
"when": "view == settings",
|
||||
@@ -216,6 +282,11 @@
|
||||
"command": "githubLocalActions.runWorkflow",
|
||||
"when": "view == workflows && viewItem =~ /^githubLocalActions.workflow.*/",
|
||||
"group": "inline@1"
|
||||
},
|
||||
{
|
||||
"command": "githubLocalActions.runJob",
|
||||
"when": "view == workflows && viewItem =~ /^githubLocalActions.job.*/",
|
||||
"group": "inline@0"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
228
src/act.ts
228
src/act.ts
@@ -1,12 +1,12 @@
|
||||
import * as child_process from 'child_process';
|
||||
import * as path from "path";
|
||||
import { commands, CustomExecution, env, EventEmitter, Pseudoterminal, ShellExecution, TaskDefinition, TaskGroup, TaskPanelKind, TaskRevealKind, tasks, TaskScope, TerminalDimensions, window, workspace } from "vscode";
|
||||
import { commands, CustomExecution, env, EventEmitter, Pseudoterminal, ShellExecution, TaskDefinition, TaskGroup, TaskPanelKind, TaskRevealKind, tasks, TaskScope, TerminalDimensions, window, workspace, WorkspaceFolder } from "vscode";
|
||||
import { ComponentsManager } from "./componentsManager";
|
||||
import { workflowsTreeDataProvider } from './extension';
|
||||
import { historyTreeDataProvider } from './extension';
|
||||
import { SettingsManager } from './settingsManager';
|
||||
import { Workflow, WorkflowsManager } from "./workflowsManager";
|
||||
|
||||
export enum EventTrigger {
|
||||
export enum Event {
|
||||
BranchProtectionRule = 'branch_protection_rule',
|
||||
CheckRun = 'check_run',
|
||||
CheckSuite = 'check_suite',
|
||||
@@ -44,27 +44,11 @@ export enum EventTrigger {
|
||||
|
||||
export enum Option {
|
||||
Workflows = '--workflows',
|
||||
Job = '--job',
|
||||
Variable = '--var',
|
||||
Json = "--json"
|
||||
}
|
||||
|
||||
export interface WorkflowLog {
|
||||
name: string,
|
||||
status: WorkflowStatus
|
||||
jobLogs: JobLog[]
|
||||
}
|
||||
|
||||
export interface JobLog {
|
||||
name: string,
|
||||
status: JobStatus,
|
||||
stepLogs: StepLog[]
|
||||
}
|
||||
|
||||
export interface StepLog {
|
||||
name: string,
|
||||
status: StepStatus
|
||||
}
|
||||
|
||||
export interface RawLog {
|
||||
dryrun: boolean,
|
||||
job: string,
|
||||
@@ -74,42 +58,34 @@ export interface RawLog {
|
||||
msg: string,
|
||||
time: string,
|
||||
|
||||
stage: string,
|
||||
step: string,
|
||||
stepID: string[],
|
||||
raw_output?: boolean,
|
||||
|
||||
jobResult: string, //TODO: Could be an enum?
|
||||
stage?: string,
|
||||
step?: string,
|
||||
stepID?: string[],
|
||||
stepResult?: string, //TODO: Could be an enum?
|
||||
|
||||
jobResult?: string, //TODO: Could be an enum?
|
||||
}
|
||||
|
||||
export enum WorkflowStatus {
|
||||
Queued = 'queued',
|
||||
InProgress = 'inProgress',
|
||||
Success = 'success',
|
||||
Failed = 'failed',
|
||||
Cancelled = 'cancelled'
|
||||
export interface History {
|
||||
name: string,
|
||||
status: HistoryStatus,
|
||||
start?: string,
|
||||
end?: string,
|
||||
output?: string
|
||||
}
|
||||
|
||||
export enum JobStatus {
|
||||
Queued = 'queued',
|
||||
InProgress = 'inProgress',
|
||||
Skipped = 'skipped',
|
||||
Success = 'success',
|
||||
Failed = 'failed',
|
||||
Cancelled = 'cancelled'
|
||||
}
|
||||
|
||||
export enum StepStatus {
|
||||
Queued = 'queued',
|
||||
InProgress = 'inProgress',
|
||||
Skipped = 'skipped',
|
||||
Success = 'success',
|
||||
Failed = 'failed',
|
||||
Cancelled = 'cancelled'
|
||||
export enum HistoryStatus {
|
||||
Running = 'Running',
|
||||
Success = 'Success',
|
||||
Failed = 'Failed',
|
||||
Cancelled = 'Cancelled'
|
||||
}
|
||||
|
||||
export class Act {
|
||||
private static base: string = 'act';
|
||||
workflowLogs: { [path: string]: WorkflowLog[] };
|
||||
workspaceHistory: { [path: string]: History[] };
|
||||
componentsManager: ComponentsManager;
|
||||
workflowsManager: WorkflowsManager;
|
||||
settingsManager: SettingsManager;
|
||||
@@ -117,7 +93,7 @@ export class Act {
|
||||
prebuiltExecutables: { [architecture: string]: string };
|
||||
|
||||
constructor() {
|
||||
this.workflowLogs = {};
|
||||
this.workspaceHistory = {};
|
||||
this.componentsManager = new ComponentsManager();
|
||||
this.workflowsManager = new WorkflowsManager();
|
||||
this.settingsManager = new SettingsManager();
|
||||
@@ -178,15 +154,28 @@ export class Act {
|
||||
// TODO: Implement
|
||||
}
|
||||
|
||||
async runEvent(eventTrigger: EventTrigger) {
|
||||
// return await this.runCommand(`${Act.base} ${eventTrigger}`);
|
||||
}
|
||||
|
||||
async runWorkflow(workflow: Workflow) {
|
||||
return await this.runCommand(workflow, `${Act.base} ${Option.Json} ${Option.Workflows} ".github/workflows/${path.parse(workflow.uri.fsPath).base}"`);
|
||||
const workspaceFolder = workspace.getWorkspaceFolder(workflow.uri);
|
||||
if (workspaceFolder) {
|
||||
return await this.runCommand(workspaceFolder, `${Option.Workflows} ".github/workflows/${path.parse(workflow.uri.fsPath).base}"`, workflow.name, [`Workflow: ${workflow.name}`]);
|
||||
} else {
|
||||
window.showErrorMessage(`Failed to locate workspace folder for ${workflow.uri.fsPath}`);
|
||||
}
|
||||
}
|
||||
|
||||
async runCommand(workflow: Workflow, command: string) {
|
||||
// TODO: Implement
|
||||
// async runJob(workspaceFolder: WorkspaceFolder, workflow: Workflow, job: Job) {
|
||||
// return await this.runCommand(workspaceFolder, `${Option.Workflows} ".github/workflows/${path.parse(workflow.uri.fsPath).base}" ${Option.Job} "${job.id}"`, `${workflow.name}/${job.name}`, [`Workflow: ${workflow.name}`, `Job: ${job.name}`]);
|
||||
// }
|
||||
|
||||
// TODO: Implement
|
||||
// async runEvent(workspaceFolder: WorkspaceFolder, event: Event) {
|
||||
// return await this.runCommand(workspaceFolder, `${Option.Workflows} ${event}`, event, [`Event: ${event}`]);
|
||||
// }
|
||||
|
||||
async runCommand(workspaceFolder: WorkspaceFolder, options: string, name: string, typeText: string[]) {
|
||||
const command = `${Act.base} ${Option.Json} ${options}`;
|
||||
|
||||
const unreadyComponents = await this.componentsManager.getUnreadyComponents();
|
||||
if (unreadyComponents.length > 0) {
|
||||
window.showErrorMessage(`The following required components are not ready: ${unreadyComponents.map(component => component.name).join(', ')}`, 'Fix...').then(async value => {
|
||||
@@ -197,37 +186,20 @@ export class Act {
|
||||
return;
|
||||
}
|
||||
|
||||
const workspaceFolder = workspace.getWorkspaceFolder(workflow.uri);
|
||||
if (!workspaceFolder) {
|
||||
window.showErrorMessage('Failed to detect workspace folder');
|
||||
return;
|
||||
if (!this.workspaceHistory[workspaceFolder.uri.fsPath]) {
|
||||
this.workspaceHistory[workspaceFolder.uri.fsPath] = [];
|
||||
}
|
||||
|
||||
if (!this.workflowLogs[workflow.uri.fsPath]) {
|
||||
this.workflowLogs[workflow.uri.fsPath] = [];
|
||||
}
|
||||
|
||||
this.workflowLogs[workflow.uri.fsPath].push({
|
||||
name: `${workflow.name} #${this.workflowLogs[workflow.uri.fsPath].length + 1}`,
|
||||
status: WorkflowStatus.Queued,
|
||||
jobLogs: Object.entries<any>(workflow.yaml.jobs).map(([key, value]) => {
|
||||
return {
|
||||
name: value.name ? value.name : key,
|
||||
status: JobStatus.Queued,
|
||||
stepLogs: Object.entries<any>(workflow.yaml.jobs[key].steps).map(([key, value]) => {
|
||||
return {
|
||||
name: value.name ? value.name : key,
|
||||
status: StepStatus.Queued,
|
||||
stepLogs: []
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
const historyIndex = this.workspaceHistory[workspaceFolder.uri.fsPath].length;
|
||||
this.workspaceHistory[workspaceFolder.uri.fsPath].push({
|
||||
name: `${name} #${this.workspaceHistory[workspaceFolder.uri.fsPath].length + 1}`,
|
||||
status: HistoryStatus.Running,
|
||||
start: new Date().toISOString()
|
||||
});
|
||||
workflowsTreeDataProvider.refresh();
|
||||
historyTreeDataProvider.refresh();
|
||||
|
||||
await tasks.executeTask({
|
||||
name: workflow.name,
|
||||
name: name,
|
||||
detail: 'Run workflow',
|
||||
definition: { type: 'GitHub Local Actions' },
|
||||
source: 'GitHub Local Actions',
|
||||
@@ -249,53 +221,77 @@ export class Act {
|
||||
const writeEmitter = new EventEmitter<string>();
|
||||
const closeEmitter = new EventEmitter<number>();
|
||||
|
||||
const exec = child_process.spawn(command, { cwd: workspaceFolder.uri.fsPath, shell: env.shell });
|
||||
const handleIO = (data: any) => {
|
||||
const lines: string[] = data.toString().split('\n').filter((line: string) => line != '');
|
||||
for (const line of lines) {
|
||||
const jsonLine = JSON.parse(line);
|
||||
|
||||
if (!this.workspaceHistory[workspaceFolder.uri.fsPath][historyIndex].start) {
|
||||
this.workspaceHistory[workspaceFolder.uri.fsPath][historyIndex].start = jsonLine.time;
|
||||
}
|
||||
|
||||
if (jsonLine.jobResult) {
|
||||
this.workspaceHistory[workspaceFolder.uri.fsPath][historyIndex].end = jsonLine.time;
|
||||
|
||||
switch (jsonLine.jobResult) {
|
||||
case 'success':
|
||||
this.workspaceHistory[workspaceFolder.uri.fsPath][historyIndex].status = HistoryStatus.Success;
|
||||
break;
|
||||
case 'failure':
|
||||
this.workspaceHistory[workspaceFolder.uri.fsPath][historyIndex].status = HistoryStatus.Failed;
|
||||
break;
|
||||
// TODO: Handle cancelled
|
||||
}
|
||||
}
|
||||
|
||||
historyTreeDataProvider.refresh();
|
||||
writeEmitter.fire(`${jsonLine.msg.trimEnd()}\r\n`);
|
||||
}
|
||||
}
|
||||
exec.stdout.on('data', handleIO);
|
||||
exec.stderr.on('data', handleIO);
|
||||
exec.on('close', (code) => {
|
||||
if (!this.workspaceHistory[workspaceFolder.uri.fsPath][historyIndex].end) {
|
||||
this.workspaceHistory[workspaceFolder.uri.fsPath][historyIndex].end = new Date().toISOString();
|
||||
}
|
||||
|
||||
if (this.workspaceHistory[workspaceFolder.uri.fsPath][historyIndex].status === HistoryStatus.Running) {
|
||||
this.workspaceHistory[workspaceFolder.uri.fsPath][historyIndex].status = HistoryStatus.Failed;
|
||||
}
|
||||
|
||||
historyTreeDataProvider.refresh();
|
||||
closeEmitter.fire(code || 0);
|
||||
});
|
||||
|
||||
return {
|
||||
onDidWrite: writeEmitter.event,
|
||||
onDidClose: closeEmitter.event,
|
||||
open: async (initialDimensions: TerminalDimensions | undefined): Promise<void> => {
|
||||
writeEmitter.fire(`Workflow: ${workflow.name}\r\n`);
|
||||
writeEmitter.fire(`Path: ${workflow.uri.fsPath}\r\n`);
|
||||
writeEmitter.fire(`Command: ${command}\r\n`);
|
||||
writeEmitter.fire(`Name: ${name}\r\n`);
|
||||
writeEmitter.fire(`Path: ${workspaceFolder.uri.fsPath}\r\n`);
|
||||
for (const text of typeText) {
|
||||
writeEmitter.fire(`${text}\r\n`);
|
||||
}
|
||||
writeEmitter.fire(`Environments: OSSBUILD\r\n`);
|
||||
writeEmitter.fire(`Variables: VARIABLE1=ABC, VARIABLE2=DEF\r\n`);
|
||||
writeEmitter.fire(`Secrets: SECRET1=ABC, SECRET2=DEF\r\n`);
|
||||
writeEmitter.fire(`Timestamp: ${new Date().toLocaleTimeString()}\r\n`);
|
||||
writeEmitter.fire(`Command: ${command}\r\n`);
|
||||
writeEmitter.fire(`\r\n`);
|
||||
|
||||
const exec = child_process.spawn(command, { cwd: workspaceFolder.uri.fsPath, shell: env.shell });
|
||||
exec.stdout.on('data', (data) => {
|
||||
const lines = data.toString().split('\n');
|
||||
for (const line of lines) {
|
||||
const rawLog: RawLog = JSON.parse(line);
|
||||
|
||||
if (rawLog.stepID) {
|
||||
|
||||
} else if (rawLog.jobID) {
|
||||
// this.workflowLogs[workflow.uri.fsPath][Object.values(this.workflowLogs).length - 1].jobLogs.push({
|
||||
// name: '',
|
||||
// status: '',
|
||||
// stepLogs: []
|
||||
// });
|
||||
} else if (rawLog.jobResult) {
|
||||
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
writeEmitter.fire(lines);
|
||||
});
|
||||
|
||||
exec.stderr.on('data', (data) => {
|
||||
const error = data.toString();
|
||||
writeEmitter.fire(error);
|
||||
});
|
||||
|
||||
exec.on('close', (code) => {
|
||||
closeEmitter.fire(code || 0);
|
||||
});
|
||||
},
|
||||
|
||||
close: () => { }
|
||||
close: () => {
|
||||
if (this.workspaceHistory[workspaceFolder.uri.fsPath][historyIndex].status === HistoryStatus.Running) {
|
||||
this.workspaceHistory[workspaceFolder.uri.fsPath][historyIndex].status = HistoryStatus.Cancelled;
|
||||
}
|
||||
|
||||
historyTreeDataProvider.refresh();
|
||||
exec.stdout.destroy();
|
||||
exec.stdin.destroy();
|
||||
exec.stderr.destroy();
|
||||
exec.kill();
|
||||
}
|
||||
};
|
||||
})
|
||||
});
|
||||
|
||||
@@ -3,12 +3,14 @@ import { window, workspace } from 'vscode';
|
||||
import { Act } from './act';
|
||||
import ComponentsTreeDataProvider from './views/components/componentsTreeDataProvider';
|
||||
import { DecorationProvider } from './views/decorationProvider';
|
||||
import HistoryTreeDataProvider from './views/history/historyTreeDataProvider';
|
||||
import SettingsTreeDataProvider from './views/settings/settingsTreeDataProvider';
|
||||
import WorkflowsTreeDataProvider from './views/workflows/workflowsTreeDataProvider';
|
||||
|
||||
export let act: Act;
|
||||
export let componentsTreeDataProvider: ComponentsTreeDataProvider;
|
||||
export let workflowsTreeDataProvider: WorkflowsTreeDataProvider;
|
||||
export let historyTreeDataProvider: HistoryTreeDataProvider;
|
||||
export let settingsTreeDataProvider: SettingsTreeDataProvider;
|
||||
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
@@ -22,6 +24,8 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
const componentsTreeView = window.createTreeView(ComponentsTreeDataProvider.VIEW_ID, { treeDataProvider: componentsTreeDataProvider });
|
||||
workflowsTreeDataProvider = new WorkflowsTreeDataProvider(context);
|
||||
const workflowsTreeView = window.createTreeView(WorkflowsTreeDataProvider.VIEW_ID, { treeDataProvider: workflowsTreeDataProvider });
|
||||
historyTreeDataProvider = new HistoryTreeDataProvider(context);
|
||||
const historyTreeView = window.createTreeView(HistoryTreeDataProvider.VIEW_ID, { treeDataProvider: historyTreeDataProvider });
|
||||
settingsTreeDataProvider = new SettingsTreeDataProvider(context);
|
||||
const settingsTreeView = window.createTreeView(SettingsTreeDataProvider.VIEW_ID, { treeDataProvider: settingsTreeDataProvider });
|
||||
|
||||
@@ -43,6 +47,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
context.subscriptions.push(
|
||||
componentsTreeView,
|
||||
workflowsTreeView,
|
||||
historyTreeView,
|
||||
settingsTreeView,
|
||||
window.registerFileDecorationProvider(decorationProvider),
|
||||
workflowsFileWatcher
|
||||
|
||||
46
src/views/history/history.ts
Normal file
46
src/views/history/history.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { ThemeColor, ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode";
|
||||
import { History, HistoryStatus } from "../../act";
|
||||
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
|
||||
|
||||
export default class HistoryTreeItem extends TreeItem implements GithubLocalActionsTreeItem {
|
||||
static contextValue = 'githubLocalActions.history';
|
||||
history: History;
|
||||
|
||||
constructor(history: History) {
|
||||
super(history.name, TreeItemCollapsibleState.None);
|
||||
this.history = history;
|
||||
|
||||
let totalDuration: string | undefined;
|
||||
if (history.start) {
|
||||
const start = new Date(history.start).getTime();
|
||||
const end = history.end ? new Date(history.end).getTime() : new Date().getTime();
|
||||
totalDuration = `${((end - start) / 1000).toFixed(0).toString()}s`;
|
||||
this.description = totalDuration;
|
||||
}
|
||||
|
||||
this.contextValue = `${HistoryTreeItem.contextValue}_${history.status}`;
|
||||
switch (history.status) {
|
||||
case HistoryStatus.Running:
|
||||
this.iconPath = new ThemeIcon('loading~spin');
|
||||
break;
|
||||
case HistoryStatus.Success:
|
||||
this.iconPath = new ThemeIcon('pass', new ThemeColor('GitHubLocalActions.green'));
|
||||
break;
|
||||
case HistoryStatus.Failed:
|
||||
this.iconPath = new ThemeIcon('error', new ThemeColor('GitHubLocalActions.red'));
|
||||
break;
|
||||
case HistoryStatus.Cancelled:
|
||||
this.iconPath = new ThemeIcon('circle-slash', new ThemeColor('GitHubLocalActions.yellow'));
|
||||
break;
|
||||
}
|
||||
this.tooltip = `Name: ${history.name}\n` +
|
||||
`Status: ${history.status}\n` +
|
||||
`Started: ${history.start ? history.start : 'N/A'}\n` +
|
||||
`Ended: ${history.end ? history.end : 'N/A'}\n` +
|
||||
(totalDuration ? `Total Duration: ${totalDuration}\n` : ``);
|
||||
}
|
||||
|
||||
async getChildren(): Promise<GithubLocalActionsTreeItem[]> {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
59
src/views/history/historyTreeDataProvider.ts
Normal file
59
src/views/history/historyTreeDataProvider.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { CancellationToken, commands, EventEmitter, ExtensionContext, extensions, TreeDataProvider, TreeItem, workspace } from "vscode";
|
||||
import { act } from "../../extension";
|
||||
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
|
||||
import HistoryTreeItem from "./history";
|
||||
|
||||
export default class HistoryTreeDataProvider implements TreeDataProvider<GithubLocalActionsTreeItem> {
|
||||
private _onDidChangeTreeData = new EventEmitter<GithubLocalActionsTreeItem | undefined | null | void>();
|
||||
readonly onDidChangeTreeData = this._onDidChangeTreeData.event;
|
||||
static VIEW_ID = 'history';
|
||||
|
||||
constructor(context: ExtensionContext) {
|
||||
extensions.onDidChange(e => {
|
||||
this.refresh();
|
||||
});
|
||||
|
||||
context.subscriptions.push(
|
||||
commands.registerCommand('githubLocalActions.refreshHistory', async () => {
|
||||
this.refresh();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
refresh(element?: GithubLocalActionsTreeItem) {
|
||||
this._onDidChangeTreeData.fire(element);
|
||||
}
|
||||
|
||||
getTreeItem(element: GithubLocalActionsTreeItem): GithubLocalActionsTreeItem | Thenable<GithubLocalActionsTreeItem> {
|
||||
return element;
|
||||
}
|
||||
|
||||
async resolveTreeItem(item: TreeItem, element: GithubLocalActionsTreeItem, token: CancellationToken): Promise<GithubLocalActionsTreeItem> {
|
||||
if (element.getToolTip) {
|
||||
element.tooltip = await element.getToolTip();
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
async getChildren(element?: GithubLocalActionsTreeItem): Promise<GithubLocalActionsTreeItem[]> {
|
||||
if (element) {
|
||||
return element.getChildren();
|
||||
} else {
|
||||
const items: GithubLocalActionsTreeItem[] = [];
|
||||
|
||||
const workspaceFolders = workspace.workspaceFolders;
|
||||
if (workspaceFolders && workspaceFolders.length > 0) {
|
||||
const workspaceHistory = act.workspaceHistory[workspaceFolders[0].uri.fsPath]; //TODO: Fix for multi workspace support
|
||||
if (workspaceHistory) {
|
||||
for (const history of workspaceHistory) {
|
||||
items.push(new HistoryTreeItem(history));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await commands.executeCommand('setContext', 'githubLocalActions:noHistory', items.length == 0);
|
||||
return items;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import { CancellationToken, commands, EventEmitter, ExtensionContext, TreeDataProvider, TreeItem } from "vscode";
|
||||
import { act } from "../../extension";
|
||||
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
|
||||
import ContainerEnginesTreeItem from "./containerEngines";
|
||||
import EnvironmentsTreeItem from "./environments";
|
||||
@@ -40,14 +41,22 @@ export default class SettingsTreeDataProvider implements TreeDataProvider<Github
|
||||
if (element) {
|
||||
return element.getChildren();
|
||||
} else {
|
||||
return [
|
||||
const items: GithubLocalActionsTreeItem[] = [];
|
||||
|
||||
const workflows = await act.workflowsManager.getWorkflows();
|
||||
if (workflows.length > 0) {
|
||||
items.push(...[
|
||||
new EnvironmentsTreeItem(),
|
||||
new SecretsTreeItem(),
|
||||
new VariablesTreeItem(),
|
||||
new InputsTreeItem(),
|
||||
new RunnersTreeItem(),
|
||||
new ContainerEnginesTreeItem()
|
||||
];
|
||||
]);
|
||||
}
|
||||
|
||||
await commands.executeCommand('setContext', 'githubLocalActions:noSettings', items.length == 0);
|
||||
return items;
|
||||
}
|
||||
}
|
||||
}
|
||||
23
src/views/workflows/job.ts
Normal file
23
src/views/workflows/job.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode";
|
||||
import { Job, Workflow } from "../../workflowsManager";
|
||||
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
|
||||
|
||||
export default class JobTreeItem extends TreeItem implements GithubLocalActionsTreeItem {
|
||||
static contextValue = 'githubLocalActions.job';
|
||||
job: Job;
|
||||
workflow: Workflow;
|
||||
|
||||
constructor(workflow: Workflow, job: Job) {
|
||||
super(job.name, TreeItemCollapsibleState.None);
|
||||
this.workflow = workflow;
|
||||
this.job = job;
|
||||
this.contextValue = JobTreeItem.contextValue;
|
||||
this.iconPath = new ThemeIcon('rocket');
|
||||
this.tooltip = `Name: ${job.name}` +
|
||||
`ID: ${job.id}`;
|
||||
}
|
||||
|
||||
async getChildren(): Promise<GithubLocalActionsTreeItem[]> {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode";
|
||||
import { JobLog } from "../../act";
|
||||
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
|
||||
import StepTreeItem from "./stepLog";
|
||||
|
||||
export default class JobLogTreeItem extends TreeItem implements GithubLocalActionsTreeItem {
|
||||
static contextValue = 'githubLocalActions.jobLog';
|
||||
jobLog: JobLog;
|
||||
|
||||
constructor(jobLog: JobLog) {
|
||||
super(jobLog.name, TreeItemCollapsibleState.Collapsed);
|
||||
this.jobLog = jobLog;
|
||||
this.contextValue = JobLogTreeItem.contextValue;
|
||||
this.iconPath = new ThemeIcon('pass-filled');
|
||||
// this.tooltip = `Name: ${workflow.name}\n` +
|
||||
// `Path: ${workflow.uri.fsPath}\n` +
|
||||
// (workflow.error ? `Error: ${workflow.error}` : ``);
|
||||
|
||||
// TODO: Add tooltip and resourceUri
|
||||
}
|
||||
|
||||
async getChildren(): Promise<GithubLocalActionsTreeItem[]> {
|
||||
const stepLogs = this.jobLog.stepLogs;
|
||||
if (stepLogs) {
|
||||
return this.jobLog.stepLogs.map(step => new StepTreeItem(step));
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode";
|
||||
import { StepLog } from "../../act";
|
||||
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
|
||||
|
||||
export default class StepLogTreeItem extends TreeItem implements GithubLocalActionsTreeItem {
|
||||
static contextValue = 'githubLocalActions.stepLog';
|
||||
stepLog: StepLog;
|
||||
|
||||
constructor(stepLog: StepLog) {
|
||||
super(stepLog.name, TreeItemCollapsibleState.None);
|
||||
this.stepLog = stepLog;
|
||||
this.contextValue = StepLogTreeItem.contextValue;
|
||||
this.iconPath = new ThemeIcon('pass-filled');
|
||||
// this.tooltip = `Name: ${workflow.name}\n` +
|
||||
// `Path: ${workflow.uri.fsPath}\n` +
|
||||
// (workflow.error ? `Error: ${workflow.error}` : ``);
|
||||
|
||||
// TODO: Add tooltip and resourceUri
|
||||
}
|
||||
|
||||
async getChildren(): Promise<GithubLocalActionsTreeItem[]> {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
import { ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri } from "vscode";
|
||||
import { act } from "../../extension";
|
||||
import { Workflow } from "../../workflowsManager";
|
||||
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
|
||||
import WorkflowLogTreeItem from "./workflowLog";
|
||||
import JobTreeItem from "./job";
|
||||
|
||||
export default class WorkflowTreeItem extends TreeItem implements GithubLocalActionsTreeItem {
|
||||
static contextValue = 'githubLocalActions.workflow';
|
||||
@@ -23,11 +22,15 @@ export default class WorkflowTreeItem extends TreeItem implements GithubLocalAct
|
||||
}
|
||||
|
||||
async getChildren(): Promise<GithubLocalActionsTreeItem[]> {
|
||||
const workflowLogs = act.workflowLogs[this.workflow.uri.fsPath];
|
||||
if (workflowLogs) {
|
||||
return workflowLogs.map(workflowLog => new WorkflowLogTreeItem(workflowLog));
|
||||
} else {
|
||||
return [];
|
||||
const items: GithubLocalActionsTreeItem[] = [];
|
||||
|
||||
const jobs = this.workflow.yaml.jobs;
|
||||
if (jobs) {
|
||||
for (const [key, value] of Object.entries<any>(jobs)) {
|
||||
items.push(new JobTreeItem(this.workflow, { name: value.name ? value.name : key, id: key }));
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode";
|
||||
import { WorkflowLog } from "../../act";
|
||||
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
|
||||
import JobLogTreeItem from "./jobLog";
|
||||
|
||||
export default class WorkflowLogTreeItem extends TreeItem implements GithubLocalActionsTreeItem {
|
||||
static contextValue = 'githubLocalActions.workflowLog';
|
||||
workflowLog: WorkflowLog;
|
||||
|
||||
constructor(workflowLog: WorkflowLog) {
|
||||
super(workflowLog.name, TreeItemCollapsibleState.Collapsed);
|
||||
this.workflowLog = workflowLog;
|
||||
this.contextValue = WorkflowLogTreeItem.contextValue;
|
||||
this.iconPath = new ThemeIcon('pass-filled');
|
||||
// this.tooltip = `Name: ${workflow.name}\n` +
|
||||
// `Path: ${workflow.uri.fsPath}\n` +
|
||||
// (workflow.error ? `Error: ${workflow.error}` : ``);
|
||||
|
||||
// TODO: Add tooltip and resourceUri
|
||||
}
|
||||
|
||||
async getChildren(): Promise<GithubLocalActionsTreeItem[]> {
|
||||
return this.workflowLog.jobLogs.map(jobLog => new JobLogTreeItem(jobLog));
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CancellationToken, commands, EventEmitter, ExtensionContext, TreeDataProvider, TreeItem, window, workspace } from "vscode";
|
||||
import { EventTrigger } from "../../act";
|
||||
import { Event } from "../../act";
|
||||
import { act } from "../../extension";
|
||||
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
|
||||
import WorkflowTreeItem from "./workflow";
|
||||
@@ -15,13 +15,14 @@ export default class WorkflowsTreeDataProvider implements TreeDataProvider<Githu
|
||||
await act.runAllWorkflows();
|
||||
}),
|
||||
commands.registerCommand('githubLocalActions.runEvent', async () => {
|
||||
const event = await window.showQuickPick(Object.values(EventTrigger), {
|
||||
const event = await window.showQuickPick(Object.values(Event), {
|
||||
title: 'Select the event to run',
|
||||
placeHolder: 'Event'
|
||||
});
|
||||
|
||||
if (event) {
|
||||
await act.runEvent(event as EventTrigger);
|
||||
// TODO: Implement running event
|
||||
// await act.runEvent(event as Event);
|
||||
}
|
||||
}),
|
||||
commands.registerCommand('githubLocalActions.refreshWorkflows', async () => {
|
||||
@@ -33,6 +34,10 @@ export default class WorkflowsTreeDataProvider implements TreeDataProvider<Githu
|
||||
}),
|
||||
commands.registerCommand('githubLocalActions.runWorkflow', async (workflowTreeItem: WorkflowTreeItem) => {
|
||||
await act.runWorkflow(workflowTreeItem.workflow);
|
||||
}),
|
||||
commands.registerCommand('githubLocalActions.runJob', async (workflowTreeItem: WorkflowTreeItem) => {
|
||||
// TODO: Implement running job
|
||||
// await act.runJob()
|
||||
})
|
||||
);
|
||||
}
|
||||
@@ -57,8 +62,15 @@ export default class WorkflowsTreeDataProvider implements TreeDataProvider<Githu
|
||||
if (element) {
|
||||
return element.getChildren();
|
||||
} else {
|
||||
const items: GithubLocalActionsTreeItem[] = [];
|
||||
|
||||
const workflows = await act.workflowsManager.getWorkflows();
|
||||
return workflows.map(workflow => new WorkflowTreeItem(workflow));
|
||||
for (const workflow of workflows) {
|
||||
items.push(new WorkflowTreeItem(workflow));
|
||||
}
|
||||
|
||||
await commands.executeCommand('setContext', 'githubLocalActions:noWorkflows', items.length == 0);
|
||||
return items;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,11 @@ export interface Workflow {
|
||||
error?: string
|
||||
}
|
||||
|
||||
export interface Job {
|
||||
name: string
|
||||
id: string
|
||||
}
|
||||
|
||||
export class WorkflowsManager {
|
||||
async getWorkflows(): Promise<Workflow[]> {
|
||||
const workflows: Workflow[] = [];
|
||||
|
||||
Reference in New Issue
Block a user