From 7bd3c448c25e466b2c16111b45a159d2ea248e05 Mon Sep 17 00:00:00 2001 From: Sanjula Ganepola Date: Thu, 26 Sep 2024 22:22:56 -0400 Subject: [PATCH] Add run workflow support Signed-off-by: Sanjula Ganepola --- package.json | 38 ++++++++++-- src/act.ts | 55 ++++++++++++++++ src/componentManager.ts | 62 +++++++++++-------- src/types.ts | 0 src/views/components/component.ts | 4 +- .../components/componentsTreeDataProvider.ts | 7 +-- src/views/decorationProvider.ts | 2 +- src/views/settings/environments.ts | 2 +- src/views/settings/secrets.ts | 2 +- .../settings/settingsTreeDataProvider.ts | 2 +- src/views/settings/variables.ts | 2 +- src/views/workflows/workflow.ts | 2 +- .../workflows/workflowsTreeDataProvider.ts | 13 ++-- src/workflowManager.ts | 2 +- 14 files changed, 142 insertions(+), 51 deletions(-) create mode 100644 src/act.ts delete mode 100644 src/types.ts diff --git a/package.json b/package.json index 4fffb8b..656d7c0 100644 --- a/package.json +++ b/package.json @@ -50,12 +50,12 @@ { "id": "workflows", "name": "Workflows", - "icon": "$(remote-explorer)" + "icon": "$(layers)" }, { "id": "settings", "name": "Settings", - "icon": "$(server-environment)" + "icon": "$(gear)" } ] }, @@ -66,6 +66,12 @@ "title": "Refresh", "icon": "$(refresh)" }, + { + "category": "GitHub Local Actions", + "command": "githubLocalActions.runAllWorkflows", + "title": "Run All Workflows", + "icon": "$(run-all)" + }, { "category": "GitHub Local Actions", "command": "githubLocalActions.refreshWorkflows", @@ -78,6 +84,12 @@ "title": "Open Workflow", "icon": "$(go-to-file)" }, + { + "category": "GitHub Local Actions", + "command": "githubLocalActions.runWorkflow", + "title": "Run Workflow", + "icon": "$(debug-start)" + }, { "category": "GitHub Local Actions", "command": "githubLocalActions.refreshSettings", @@ -91,6 +103,10 @@ "command": "githubLocalActions.refreshComponents", "when": "never" }, + { + "command": "githubLocalActions.runAllWorkflows", + "when": "never" + }, { "command": "githubLocalActions.refreshWorkflows", "when": "never" @@ -99,6 +115,10 @@ "command": "githubLocalActions.openWorkflow", "when": "never" }, + { + "command": "githubLocalActions.runWorkflow", + "when": "never" + }, { "command": "githubLocalActions.refreshSettings", "when": "never" @@ -111,10 +131,15 @@ "group": "navigation@0" }, { - "command": "githubLocalActions.refreshWorkflows", + "command": "githubLocalActions.runAllWorkflows", "when": "view == workflows", "group": "navigation@0" }, + { + "command": "githubLocalActions.refreshWorkflows", + "when": "view == workflows", + "group": "navigation@1" + }, { "command": "githubLocalActions.refreshSettings", "when": "view == settings", @@ -124,8 +149,13 @@ "view/item/context": [ { "command": "githubLocalActions.openWorkflow", - "when": "view == workflows && viewItem =~ /^workflow.*/", + "when": "view == workflows && viewItem =~ /^githubLocalActions.workflow.*/", "group": "inline@0" + }, + { + "command": "githubLocalActions.runWorkflow", + "when": "view == workflows && viewItem =~ /^githubLocalActions.workflow.*/", + "group": "inline@1" } ] }, diff --git a/src/act.ts b/src/act.ts new file mode 100644 index 0000000..5659a99 --- /dev/null +++ b/src/act.ts @@ -0,0 +1,55 @@ +import * as path from "path"; +import { commands, ShellExecution, TaskGroup, TaskPanelKind, TaskRevealKind, tasks, window, workspace } from "vscode"; +import { ComponentManager } from "./componentManager"; +import { Workflow } from "./workflowManager"; + +export enum Options { + Workflows = '-W' +} + +export class Act { + private static base: string = 'act'; + + static async runAllWorkflows() { + // TODO: Implement + } + + static async runWorkflow(workflow: Workflow) { + return await Act.runCommand(workflow, `${Act.base} ${Options.Workflows} '.github/workflows/${path.parse(workflow.uri.fsPath).base}'`); + } + + static async runCommand(workflow: Workflow, command: string) { + + const unreadyComponents = await ComponentManager.getUnreadyComponents(); + if (unreadyComponents.length > 0) { + window.showErrorMessage(`The following required components are not ready: ${unreadyComponents.map(component => component.name).join(', ')}`, 'Fix...').then(async value => { + if (value === 'Fix...') { + await commands.executeCommand('components.focus'); + } + }); + return; + } + + await tasks.executeTask({ + name: workflow.name, + detail: 'Run workflow', + definition: { type: 'GitHub Local Actions' }, + source: 'GitHub Local Actions', + scope: workspace.getWorkspaceFolder(workflow.uri), + isBackground: true, + presentationOptions: { + reveal: TaskRevealKind.Always, + focus: false, + clear: false, + close: false, + echo: true, + panel: TaskPanelKind.Dedicated, + showReuseMessage: false + }, + problemMatchers: [], + runOptions: {}, + group: TaskGroup.Build, + execution: new ShellExecution(command) + }); + } +} \ No newline at end of file diff --git a/src/componentManager.ts b/src/componentManager.ts index 8253270..ed4c55c 100644 --- a/src/componentManager.ts +++ b/src/componentManager.ts @@ -1,7 +1,8 @@ export interface Component { name: string, - status: Status, icon: string, + status: Status, + required: boolean message?: string } @@ -12,32 +13,39 @@ export enum Status { } export class ComponentManager { - components: Component[] = [ - { - name: 'nektos/act', - status: Status.Enabled, - icon: 'package' - }, - { - name: 'Docker Engine', - status: Status.Disabled, - icon: 'dashboard' - }, - { - name: 'GitHub Actions Extension', - status: Status.Warning, - icon: 'extensions', - message: 'GitHub Actions extension is not required but is recommended to take advantage of workflow editor features' - }, - { - name: 'GitHub CLI', - status: Status.Warning, - icon: 'terminal', - message: 'GitHub CLI is not required but is recommended if you plan to use it to retrieve GitHub tokens' - } - ]; + static async getComponents(): Promise { + return [ + { + name: 'nektos/act', + icon: 'package', + status: Status.Enabled, + required: true + }, + { + name: 'Docker Engine', + icon: 'dashboard', + status: Status.Enabled, + required: true + }, + { + name: 'GitHub Actions Extension', + icon: 'extensions', + status: Status.Warning, + required: false, + message: 'GitHub Actions extension is not required, but is recommended to take advantage of workflow editor features.' + }, + { + name: 'GitHub CLI', + icon: 'terminal', + status: Status.Warning, + required: false, + message: 'GitHub CLI is not required, but is recommended if you plan to use it to retrieve GitHub tokens.' + } + ]; + } - async getComponents(): Promise { - return this.components; + static async getUnreadyComponents(): Promise { + const components = await ComponentManager.getComponents(); + return components.filter(component => component.required && component.status !== Status.Enabled); } } \ No newline at end of file diff --git a/src/types.ts b/src/types.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/views/components/component.ts b/src/views/components/component.ts index c3d64fd..7112ba4 100644 --- a/src/views/components/component.ts +++ b/src/views/components/component.ts @@ -1,9 +1,9 @@ import { ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri } from "vscode"; -import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem"; import { Component } from "../../componentManager"; +import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem"; export default class ComponentTreeItem extends TreeItem implements GithubLocalActionsTreeItem { - static contextValue = 'component'; + static contextValue = 'githubLocalActions.component'; component: Component; constructor(component: Component) { diff --git a/src/views/components/componentsTreeDataProvider.ts b/src/views/components/componentsTreeDataProvider.ts index bc6bb92..d06fb32 100644 --- a/src/views/components/componentsTreeDataProvider.ts +++ b/src/views/components/componentsTreeDataProvider.ts @@ -6,12 +6,9 @@ import ComponentTreeItem from "./component"; export default class ComponentsTreeDataProvider implements TreeDataProvider { private _onDidChangeTreeData = new EventEmitter(); readonly onDidChangeTreeData = this._onDidChangeTreeData.event; - public static VIEW_ID = 'components'; - private componentManager: ComponentManager; + static VIEW_ID = 'components'; constructor(context: ExtensionContext) { - this.componentManager = new ComponentManager(); - context.subscriptions.push( commands.registerCommand('githubLocalActions.refreshComponents', async () => { this.refresh(); @@ -39,7 +36,7 @@ export default class ComponentsTreeDataProvider implements TreeDataProvider new ComponentTreeItem(component)); } } diff --git a/src/views/decorationProvider.ts b/src/views/decorationProvider.ts index 3ca61a4..870d1e1 100644 --- a/src/views/decorationProvider.ts +++ b/src/views/decorationProvider.ts @@ -1,5 +1,5 @@ import { CancellationToken, Event, FileDecoration, FileDecorationProvider, ProviderResult, ThemeColor, Uri } from "vscode"; -import { Status } from "../types"; +import { Status } from "../componentManager"; import ComponentTreeItem from "./components/component"; import WorkflowTreeItem from "./workflows/workflow"; diff --git a/src/views/settings/environments.ts b/src/views/settings/environments.ts index f2c8e7f..90498f1 100644 --- a/src/views/settings/environments.ts +++ b/src/views/settings/environments.ts @@ -2,7 +2,7 @@ import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode"; import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem"; export default class EnvironmentsTreeItem extends TreeItem implements GithubLocalActionsTreeItem { - static contextValue = 'environments'; + static contextValue = 'githubLocalActions.environments'; constructor() { super('Environments', TreeItemCollapsibleState.Collapsed); diff --git a/src/views/settings/secrets.ts b/src/views/settings/secrets.ts index fa41e12..95765e5 100644 --- a/src/views/settings/secrets.ts +++ b/src/views/settings/secrets.ts @@ -2,7 +2,7 @@ import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode"; import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem"; export default class SecretsTreeItem extends TreeItem implements GithubLocalActionsTreeItem { - static contextValue = 'secrets'; + static contextValue = 'githubLocalActions.secrets'; constructor() { super('Secrets', TreeItemCollapsibleState.Collapsed); diff --git a/src/views/settings/settingsTreeDataProvider.ts b/src/views/settings/settingsTreeDataProvider.ts index ce9feb0..a2589e4 100644 --- a/src/views/settings/settingsTreeDataProvider.ts +++ b/src/views/settings/settingsTreeDataProvider.ts @@ -7,7 +7,7 @@ import VariablesTreeItem from "./variables"; export default class SettingsTreeDataProvider implements TreeDataProvider { private _onDidChangeTreeData = new EventEmitter(); readonly onDidChangeTreeData = this._onDidChangeTreeData.event; - public static VIEW_ID = 'settings'; + static VIEW_ID = 'settings'; constructor(context: ExtensionContext) { context.subscriptions.push( diff --git a/src/views/settings/variables.ts b/src/views/settings/variables.ts index ec22a7a..7d350dd 100644 --- a/src/views/settings/variables.ts +++ b/src/views/settings/variables.ts @@ -2,7 +2,7 @@ import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode"; import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem"; export default class VariablesTreeItem extends TreeItem implements GithubLocalActionsTreeItem { - static contextValue = 'variables'; + static contextValue = 'githubLocalActions.variables'; constructor() { super('Variables', TreeItemCollapsibleState.Collapsed); diff --git a/src/views/workflows/workflow.ts b/src/views/workflows/workflow.ts index c7ff21c..64e479f 100644 --- a/src/views/workflows/workflow.ts +++ b/src/views/workflows/workflow.ts @@ -3,7 +3,7 @@ import { Workflow } from "../../workflowManager"; import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem"; export default class WorkflowTreeItem extends TreeItem implements GithubLocalActionsTreeItem { - static contextValue = 'workflow'; + static contextValue = 'githubLocalActions.workflow'; workflow: Workflow; constructor(workflow: Workflow) { diff --git a/src/views/workflows/workflowsTreeDataProvider.ts b/src/views/workflows/workflowsTreeDataProvider.ts index 3a4d7b0..ebf63dd 100644 --- a/src/views/workflows/workflowsTreeDataProvider.ts +++ b/src/views/workflows/workflowsTreeDataProvider.ts @@ -1,4 +1,5 @@ import { CancellationToken, commands, EventEmitter, ExtensionContext, TreeDataProvider, TreeItem, window, workspace } from "vscode"; +import { Act } from "../../act"; import { WorkflowManager } from "../../workflowManager"; import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem"; import WorkflowTreeItem from "./workflow"; @@ -6,13 +7,13 @@ import WorkflowTreeItem from "./workflow"; export default class WorkflowsTreeDataProvider implements TreeDataProvider { private _onDidChangeTreeData = new EventEmitter(); readonly onDidChangeTreeData = this._onDidChangeTreeData.event; - public static VIEW_ID = 'workflows'; - private workflowManager: WorkflowManager; + static VIEW_ID = 'workflows'; constructor(context: ExtensionContext) { - this.workflowManager = new WorkflowManager(); - context.subscriptions.push( + commands.registerCommand('githubLocalActions.runAllWorkflows', async () => { + await Act.runAllWorkflows(); + }), commands.registerCommand('githubLocalActions.refreshWorkflows', async () => { this.refresh(); }), @@ -21,7 +22,7 @@ export default class WorkflowsTreeDataProvider implements TreeDataProvider { - + await Act.runWorkflow(workflowTreeItem.workflow); }) ); } @@ -46,7 +47,7 @@ export default class WorkflowsTreeDataProvider implements TreeDataProvider new WorkflowTreeItem(workflow)); } } diff --git a/src/workflowManager.ts b/src/workflowManager.ts index 1e5ac9b..baa32d6 100644 --- a/src/workflowManager.ts +++ b/src/workflowManager.ts @@ -11,7 +11,7 @@ export interface Workflow { } export class WorkflowManager { - async getWorkflows(): Promise { + static async getWorkflows(): Promise { const workflows: Workflow[] = []; const workspaceFolders = workspace.workspaceFolders;