From 440e729f29182f64b14ffeed4980c5ea63b329e8 Mon Sep 17 00:00:00 2001 From: Sanjula Ganepola Date: Sat, 28 Sep 2024 19:15:53 -0400 Subject: [PATCH] Fix cli and extension status Signed-off-by: Sanjula Ganepola --- src/componentManager.ts | 116 ++++++++++++------ src/views/components/component.ts | 8 +- .../components/componentsTreeDataProvider.ts | 8 +- src/views/decorationProvider.ts | 16 ++- 4 files changed, 99 insertions(+), 49 deletions(-) diff --git a/src/componentManager.ts b/src/componentManager.ts index 0a9ad82..fb5d795 100644 --- a/src/componentManager.ts +++ b/src/componentManager.ts @@ -1,51 +1,93 @@ -export interface Component { +import * as child_process from "child_process"; +import { extensions } from "vscode"; + +export interface Component { name: string, icon: string, - status: ComponentStatus, + status: T, required: boolean message?: string } -export enum ComponentStatus { - Enabled = 'Enabled', - Warning = 'Warning', - Disabled = 'Disabled' +export enum CliStatus { + Installed = 'Installed', + NotInstalled = 'Not Installed' +} + +export enum ExtensionStatus { + Activated = 'Activated', + NotActivated = 'Not Activated' } export class ComponentManager { - static async getComponents(): Promise { - return [ - { - name: 'nektos/act', - icon: 'package', - status: ComponentStatus.Enabled, - required: true - }, - { - name: 'Docker Engine', - icon: 'dashboard', - status: ComponentStatus.Enabled, - required: true - }, - { - name: 'GitHub Actions Extension', - icon: 'extensions', - status: ComponentStatus.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: ComponentStatus.Warning, - required: false, - message: 'GitHub CLI is not required, but is recommended if you plan to use it to retrieve GitHub tokens.' - } - ]; + static async getComponents(): Promise[]> { + const components: Component[] = []; + + const actCliStatus = await ComponentManager.getCliStatus('act'); + components.push({ + name: 'nektos/act CLI', + icon: 'terminal', + status: actCliStatus, + required: true + }); + + const dockerEngineStatus = CliStatus.Installed; + components.push({ + name: 'Docker Engine', + icon: 'dashboard', + status: dockerEngineStatus, + required: true + }); + + const githubActionsExtensionStatus = await ComponentManager.getExtensionStatus('github.vscode-github-actions'); + components.push({ + name: 'GitHub Actions Extension', + icon: 'extensions', + status: githubActionsExtensionStatus, + required: false, + message: 'GitHub Actions extension is not required, but is recommended to take advantage of workflow editor features.' + }); + + const isGithubCliInstalled = await ComponentManager.getCliStatus('gh'); + components.push({ + name: 'GitHub CLI', + icon: 'terminal', + status: isGithubCliInstalled, + required: false, + message: 'GitHub CLI is not required, but is recommended if you plan to use it to retrieve GitHub tokens.' + }); + + return components; } - static async getUnreadyComponents(): Promise { + static async getUnreadyComponents(): Promise[]> { const components = await ComponentManager.getComponents(); - return components.filter(component => component.required && component.status !== ComponentStatus.Enabled); + return components.filter(component => component.required && (component.status === CliStatus.NotInstalled || component.status === ExtensionStatus.NotActivated)); + } + + static async getCliStatus(component: string): Promise { + return new Promise((resolve, reject) => { + child_process.exec(`${component} --version`, (error, stdout, stderr) => { + if (error) { + resolve(CliStatus.NotInstalled); + } else { + resolve(CliStatus.Installed); + } + }); + }); + } + + static async getExtensionStatus(extensionId: string): Promise { + const allExtensions = extensions.all; + const extension = allExtensions.find(extension => extension.id === extensionId); + if (extension) { + if (!extension.isActive) { + await extension.activate(); + } + + return ExtensionStatus.Activated; + } else { + return ExtensionStatus.NotActivated; + } } } \ No newline at end of file diff --git a/src/views/components/component.ts b/src/views/components/component.ts index 7112ba4..40cfd61 100644 --- a/src/views/components/component.ts +++ b/src/views/components/component.ts @@ -1,17 +1,17 @@ import { ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri } from "vscode"; -import { Component } from "../../componentManager"; +import { CliStatus, Component, ExtensionStatus } from "../../componentManager"; import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem"; export default class ComponentTreeItem extends TreeItem implements GithubLocalActionsTreeItem { static contextValue = 'githubLocalActions.component'; - component: Component; + component: Component; - constructor(component: Component) { + constructor(component: Component) { super(component.name, TreeItemCollapsibleState.None); this.component = component; this.contextValue = ComponentTreeItem.contextValue; this.iconPath = new ThemeIcon(component.icon); - this.resourceUri = Uri.parse(`${ComponentTreeItem.contextValue}:${component.name}?status=${component.status}`, true); + this.resourceUri = Uri.parse(`${ComponentTreeItem.contextValue}:${component.name}?status=${component.status}&required=${component.required}`, true); this.tooltip = `Name: ${component.name}\n` + `Status: ${component.status}\n` + (component.message ? `Message: ${component.message}` : ``); diff --git a/src/views/components/componentsTreeDataProvider.ts b/src/views/components/componentsTreeDataProvider.ts index d06fb32..3d36f28 100644 --- a/src/views/components/componentsTreeDataProvider.ts +++ b/src/views/components/componentsTreeDataProvider.ts @@ -1,4 +1,4 @@ -import { CancellationToken, commands, EventEmitter, ExtensionContext, TreeDataProvider, TreeItem } from "vscode"; +import { CancellationToken, commands, EventEmitter, ExtensionContext, extensions, TreeDataProvider, TreeItem } from "vscode"; import { ComponentManager } from "../../componentManager"; import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem"; import ComponentTreeItem from "./component"; @@ -9,7 +9,11 @@ export default class ComponentsTreeDataProvider implements TreeDataProvider { + this.refresh(); + }); + + context.subscriptions.push( commands.registerCommand('githubLocalActions.refreshComponents', async () => { this.refresh(); }) diff --git a/src/views/decorationProvider.ts b/src/views/decorationProvider.ts index 9e177d3..7f7474e 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 { ComponentStatus } from "../componentManager"; +import { CliStatus, ExtensionStatus } from "../componentManager"; import ComponentTreeItem from "./components/component"; import WorkflowTreeItem from "./workflows/workflow"; @@ -9,25 +9,29 @@ export class DecorationProvider implements FileDecorationProvider { const params = new URLSearchParams(uri.query); if (uri.scheme === ComponentTreeItem.contextValue) { - if (params.get('status') === ComponentStatus.Enabled) { + const status = params.get('status'); + const required = params.get('required'); + + if (status === CliStatus.Installed || status === ExtensionStatus.Activated) { return { badge: '✅', color: new ThemeColor('GitHubLocalActions.green') }; - } else if (params.get('status') === ComponentStatus.Warning) { + } else if (!required && (status === CliStatus.NotInstalled || status === ExtensionStatus.NotActivated)) { return { badge: '⚠️', color: new ThemeColor('GitHubLocalActions.yellow') }; - } else if (params.get('status') === ComponentStatus.Disabled) { + } else if (required && (status === CliStatus.NotInstalled || status === ExtensionStatus.NotActivated)) { return { badge: '❌', color: new ThemeColor('GitHubLocalActions.red') }; } } else if (uri.scheme === WorkflowTreeItem.contextValue) { - // TODO: Fix color - if (params.get('error')) { + const error = params.get('error'); + + if (error) { return { badge: '❌', color: new ThemeColor('GitHubLocalActions.red')