Refactor to use workspace folders

Signed-off-by: Sanjula Ganepola <sanjulagane@gmail.com>
This commit is contained in:
Sanjula Ganepola
2024-10-19 20:20:48 -04:00
parent f4a73316f4
commit 49e934e297
26 changed files with 515 additions and 206 deletions

View File

@@ -193,7 +193,7 @@
"category": "GitHub Local Actions", "category": "GitHub Local Actions",
"command": "githubLocalActions.clearAll", "command": "githubLocalActions.clearAll",
"title": "Clear All", "title": "Clear All",
"enablement": "!githubLocalActions:isRunning && !githubLocalActions:noWorkflows && workspaceFolderCount > 0", "enablement": "!githubLocalActions:noHistory && !githubLocalActions:isRunning && !githubLocalActions:noWorkflows && workspaceFolderCount > 0",
"icon": "$(clear-all)" "icon": "$(clear-all)"
}, },
{ {
@@ -235,6 +235,36 @@
"command": "githubLocalActions.refreshSettings", "command": "githubLocalActions.refreshSettings",
"title": "Refresh", "title": "Refresh",
"icon": "$(refresh)" "icon": "$(refresh)"
},
{
"category": "GitHub Local Actions",
"command": "githubLocalActions.editSecret",
"title": "Edit Secret",
"icon": "$(edit)"
},
{
"category": "GitHub Local Actions",
"command": "githubLocalActions.editVariable",
"title": "Edit Variable",
"icon": "$(edit)"
},
{
"category": "GitHub Local Actions",
"command": "githubLocalActions.editInput",
"title": "Edit Input",
"icon": "$(edit)"
},
{
"category": "GitHub Local Actions",
"command": "githubLocalActions.addRunner",
"title": "Add Runner",
"icon": "$(add)"
},
{
"category": "GitHub Local Actions",
"command": "githubLocalActions.editContainerEngine",
"title": "Edit Container Engine",
"icon": "$(edit)"
} }
], ],
"menus": { "menus": {
@@ -306,6 +336,26 @@
{ {
"command": "githubLocalActions.refreshSettings", "command": "githubLocalActions.refreshSettings",
"when": "never" "when": "never"
},
{
"command": "githubLocalActions.editSecret",
"when": "never"
},
{
"command": "githubLocalActions.editVariable",
"when": "never"
},
{
"command": "githubLocalActions.editInput",
"when": "never"
},
{
"command": "githubLocalActions.addRunner",
"when": "never"
},
{
"command": "githubLocalActions.editContainerEngine",
"when": "never"
} }
], ],
"view/title": [ "view/title": [
@@ -395,6 +445,31 @@
"command": "githubLocalActions.remove", "command": "githubLocalActions.remove",
"when": "view == history && viewItem =~ /^githubLocalActions.history.*/", "when": "view == history && viewItem =~ /^githubLocalActions.history.*/",
"group": "inline@3" "group": "inline@3"
},
{
"command": "githubLocalActions.editSecret",
"when": "view == settings && viewItem =~ /^githubLocalActions.secret(?!s).*/",
"group": "inline@0"
},
{
"command": "githubLocalActions.editVariable",
"when": "view == settings && viewItem =~ /^githubLocalActions.variable(?!s).*/",
"group": "inline@0"
},
{
"command": "githubLocalActions.editInput",
"when": "view == settings && viewItem =~ /^githubLocalActions.input(?!s).*/",
"group": "inline@0"
},
{
"command": "githubLocalActions.addRunner",
"when": "view == settings && viewItem =~ /^githubLocalActions.runners.*/",
"group": "inline@0"
},
{
"command": "githubLocalActions.editContainerEngine",
"when": "view == settings && viewItem =~ /^githubLocalActions.containerEngine(?!s).*/",
"group": "inline@0"
} }
] ]
}, },

View File

@@ -1,8 +1,9 @@
import * as child_process from 'child_process'; import * as child_process from 'child_process';
import * as path from "path"; import * as path from "path";
import { commands, CustomExecution, env, EventEmitter, ExtensionContext, Pseudoterminal, ShellExecution, TaskDefinition, TaskExecution, TaskGroup, TaskPanelKind, TaskRevealKind, tasks, TaskScope, TerminalDimensions, window, workspace, WorkspaceFolder } from "vscode"; import { commands, CustomExecution, env, EventEmitter, ExtensionContext, Pseudoterminal, ShellExecution, TaskDefinition, TaskGroup, TaskPanelKind, TaskRevealKind, tasks, TaskScope, TerminalDimensions, window, workspace, WorkspaceFolder } from "vscode";
import { ComponentsManager } from "./componentsManager"; import { ComponentsManager } from "./componentsManager";
import { historyTreeDataProvider } from './extension'; import { historyTreeDataProvider } from './extension';
import { HistoryManager, HistoryStatus } from './historyManager';
import { SettingsManager } from './settingsManager'; import { SettingsManager } from './settingsManager';
import { StorageKey, StorageManager } from './storageManager'; import { StorageKey, StorageManager } from './storageManager';
import { Workflow, WorkflowsManager } from "./workflowsManager"; import { Workflow, WorkflowsManager } from "./workflowsManager";
@@ -50,26 +51,6 @@ export enum Option {
Json = "--json" Json = "--json"
} }
export interface History {
index: number,
name: string,
status: HistoryStatus,
date?: {
start: string,
end: string,
}
output?: string,
taskExecution?: TaskExecution,
commandArgs: CommandArgs
}
export enum HistoryStatus {
Running = 'Running',
Success = 'Success',
Failed = 'Failed',
Cancelled = 'Cancelled'
}
export interface CommandArgs { export interface CommandArgs {
workspaceFolder: WorkspaceFolder, workspaceFolder: WorkspaceFolder,
options: string, options: string,
@@ -79,31 +60,20 @@ export interface CommandArgs {
export class Act { export class Act {
private static base: string = 'act'; private static base: string = 'act';
storageManager: StorageManager;
componentsManager: ComponentsManager; componentsManager: ComponentsManager;
workflowsManager: WorkflowsManager; workflowsManager: WorkflowsManager;
historyManager: HistoryManager;
settingsManager: SettingsManager; settingsManager: SettingsManager;
storageManager: StorageManager;
workspaceHistory: { [path: string]: History[] };
installationCommands: { [packageManager: string]: string }; installationCommands: { [packageManager: string]: string };
prebuiltExecutables: { [architecture: string]: string }; prebuiltExecutables: { [architecture: string]: string };
constructor(context: ExtensionContext) { constructor(context: ExtensionContext) {
this.storageManager = new StorageManager(context);
this.componentsManager = new ComponentsManager(); this.componentsManager = new ComponentsManager();
this.workflowsManager = new WorkflowsManager(); this.workflowsManager = new WorkflowsManager();
this.historyManager = new HistoryManager(this.storageManager);
this.settingsManager = new SettingsManager(); this.settingsManager = new SettingsManager();
this.storageManager = new StorageManager(context);
const workspaceHistory = this.storageManager.get<{ [path: string]: History[] }>(StorageKey.WorkspaceHistory) || {};
for (const [path, historyLogs] of Object.entries(workspaceHistory)) {
workspaceHistory[path] = historyLogs.map(history => {
if (history.status === HistoryStatus.Running) {
history.status = HistoryStatus.Cancelled;
}
return history;
});
}
this.workspaceHistory = workspaceHistory;
switch (process.platform) { switch (process.platform) {
case 'win32': case 'win32':
@@ -200,22 +170,13 @@ export class Act {
return; return;
} }
if (!this.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath]) { if (!this.historyManager.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath]) {
this.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath] = []; this.historyManager.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath] = [];
this.storageManager.update(StorageKey.WorkspaceHistory, this.workspaceHistory); this.storageManager.update(StorageKey.WorkspaceHistory, this.historyManager.workspaceHistory);
} }
const historyIndex = this.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath].length; const historyIndex = this.historyManager.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath].length;
this.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath].unshift({ const taskExecution = await tasks.executeTask({
index: historyIndex,
name: `${commandArgs.name} #${this.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath].length + 1}`,
status: HistoryStatus.Running,
commandArgs: commandArgs
});
historyTreeDataProvider.refresh();
this.storageManager.update(StorageKey.WorkspaceHistory, this.workspaceHistory);
this.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath][historyIndex].taskExecution = await tasks.executeTask({
name: commandArgs.name, name: commandArgs.name,
detail: 'Run workflow', detail: 'Run workflow',
definition: { type: 'GitHub Local Actions' }, definition: { type: 'GitHub Local Actions' },
@@ -239,46 +200,66 @@ export class Act {
const closeEmitter = new EventEmitter<number>(); const closeEmitter = new EventEmitter<number>();
writeEmitter.event(data => { writeEmitter.event(data => {
if (!this.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath][historyIndex].output) { if (!this.historyManager.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath][historyIndex].output) {
this.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath][historyIndex].output = data; this.historyManager.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath][historyIndex].output = data;
} else { } else {
this.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath][historyIndex].output += data; this.historyManager.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath][historyIndex].output += data;
} }
this.storageManager.update(StorageKey.WorkspaceHistory, this.workspaceHistory); this.storageManager.update(StorageKey.WorkspaceHistory, this.historyManager.workspaceHistory);
}); });
const exec = child_process.spawn(command, { cwd: commandArgs.workspaceFolder.uri.fsPath, shell: env.shell }); const exec = child_process.spawn(command, { cwd: commandArgs.workspaceFolder.uri.fsPath, shell: env.shell });
const setDate = (actDate?: string) => { const setDate = (actDate?: string) => {
const date = actDate ? new Date(actDate).toString() : new Date().toString(); const date = actDate ? new Date(actDate).toString() : new Date().toString();
if (!this.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath][historyIndex].date) { if (!this.historyManager.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath][historyIndex].date) {
this.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath][historyIndex].date = { this.historyManager.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath][historyIndex].date = {
start: date, start: date,
end: date, end: date,
} }
} else { } else {
this.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath][historyIndex].date!.end = date; this.historyManager.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath][historyIndex].date!.end = date;
} }
} }
const handleIO = (data: any) => { const handleIO = (data: any) => {
if (typeof this.historyManager.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath][historyIndex] === 'undefined') {
this.historyManager.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath].push({
index: historyIndex,
name: `${commandArgs.name} #${this.historyManager.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath].length + 1}`,
status: HistoryStatus.Running,
taskExecution: taskExecution,
commandArgs: commandArgs
});
historyTreeDataProvider.refresh();
this.storageManager.update(StorageKey.WorkspaceHistory, this.historyManager.workspaceHistory);
}
const lines: string[] = data.toString().split('\n').filter((line: string) => line != ''); const lines: string[] = data.toString().split('\n').filter((line: string) => line != '');
for (const line of lines) { for (const line of lines) {
const jsonLine = JSON.parse(line); let jsonLine: any;
try {
jsonLine = JSON.parse(line);
} catch (error) {
jsonLine = {
time: new Date().toString(),
msg: line
}
}
setDate(jsonLine.time); setDate(jsonLine.time);
if (jsonLine.jobResult) { if (jsonLine.jobResult) {
switch (jsonLine.jobResult) { switch (jsonLine.jobResult) {
case 'success': case 'success':
this.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath][historyIndex].status = HistoryStatus.Success; this.historyManager.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath][historyIndex].status = HistoryStatus.Success;
break; break;
case 'failure': case 'failure':
this.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath][historyIndex].status = HistoryStatus.Failed; this.historyManager.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath][historyIndex].status = HistoryStatus.Failed;
break; break;
} }
} }
historyTreeDataProvider.refresh(); historyTreeDataProvider.refresh();
this.storageManager.update(StorageKey.WorkspaceHistory, this.workspaceHistory); this.storageManager.update(StorageKey.WorkspaceHistory, this.historyManager.workspaceHistory);
writeEmitter.fire(`${jsonLine.msg.trimEnd()}\r\n`); writeEmitter.fire(`${jsonLine.msg.trimEnd()}\r\n`);
} }
} }
@@ -287,12 +268,12 @@ export class Act {
exec.on('close', (code) => { exec.on('close', (code) => {
setDate(); setDate();
if (this.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath][historyIndex].status === HistoryStatus.Running) { if (this.historyManager.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath][historyIndex].status === HistoryStatus.Running) {
this.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath][historyIndex].status = HistoryStatus.Failed; this.historyManager.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath][historyIndex].status = HistoryStatus.Failed;
} }
historyTreeDataProvider.refresh(); historyTreeDataProvider.refresh();
this.storageManager.update(StorageKey.WorkspaceHistory, this.workspaceHistory); this.storageManager.update(StorageKey.WorkspaceHistory, this.historyManager.workspaceHistory);
closeEmitter.fire(code || 0); closeEmitter.fire(code || 0);
}); });
@@ -313,12 +294,12 @@ export class Act {
}, },
close: () => { close: () => {
if (this.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath][historyIndex].status === HistoryStatus.Running) { if (this.historyManager.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath][historyIndex].status === HistoryStatus.Running) {
this.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath][historyIndex].status = HistoryStatus.Cancelled; this.historyManager.workspaceHistory[commandArgs.workspaceFolder.uri.fsPath][historyIndex].status = HistoryStatus.Cancelled;
} }
historyTreeDataProvider.refresh(); historyTreeDataProvider.refresh();
this.storageManager.update(StorageKey.WorkspaceHistory, this.workspaceHistory); this.storageManager.update(StorageKey.WorkspaceHistory, this.historyManager.workspaceHistory);
exec.stdout.destroy(); exec.stdout.destroy();
exec.stdin.destroy(); exec.stdin.destroy();
@@ -328,7 +309,7 @@ export class Act {
}; };
}) })
}); });
this.storageManager.update(StorageKey.WorkspaceHistory, this.workspaceHistory); this.storageManager.update(StorageKey.WorkspaceHistory, this.historyManager.workspaceHistory);
} }
async install(packageManager: string) { async install(packageManager: string) {
@@ -357,34 +338,4 @@ export class Act {
}); });
} }
} }
async clearAll() {
//TODO: Fix for multi workspace support
const workspaceFolders = workspace.workspaceFolders;
if (workspaceFolders && workspaceFolders.length > 0) {
for (const workspaceFolder of workspaceFolders) {
this.workspaceHistory[workspaceFolder.uri.fsPath] = [];
historyTreeDataProvider.refresh();
this.storageManager.update(StorageKey.WorkspaceHistory, this.workspaceHistory);
}
}
}
async viewOutput(history: History) {
await workspace.openTextDocument({ content: history.output }).then(async document => {
await window.showTextDocument(document);
})
}
async stop(history: History) {
history.taskExecution?.terminate();
historyTreeDataProvider.refresh();
}
async remove(history: History) {
const historyIndex = this.workspaceHistory[history.commandArgs.workspaceFolder.uri.fsPath].findIndex(workspaceHistory => workspaceHistory.index === history.index)
this.workspaceHistory[history.commandArgs.workspaceFolder.uri.fsPath].splice(historyIndex, 1);
historyTreeDataProvider.refresh();
this.storageManager.update(StorageKey.WorkspaceHistory, this.workspaceHistory);
}
} }

76
src/historyManager.ts Normal file
View File

@@ -0,0 +1,76 @@
import { TaskExecution, window, workspace } from "vscode";
import { CommandArgs } from "./act";
import { act, historyTreeDataProvider } from "./extension";
import { StorageKey, StorageManager } from "./storageManager";
export interface History {
index: number,
name: string,
status: HistoryStatus,
date?: {
start: string,
end: string,
}
output?: string,
taskExecution?: TaskExecution,
commandArgs: CommandArgs
}
export enum HistoryStatus {
Running = 'Running',
Success = 'Success',
Failed = 'Failed',
Cancelled = 'Cancelled'
}
export class HistoryManager {
storageManager: StorageManager;
workspaceHistory: { [path: string]: History[] };
constructor(storageManager: StorageManager) {
this.storageManager = storageManager;
const workspaceHistory = this.storageManager.get<{ [path: string]: History[] }>(StorageKey.WorkspaceHistory) || {};
for (const [path, historyLogs] of Object.entries(workspaceHistory)) {
workspaceHistory[path] = historyLogs.map(history => {
if (history.status === HistoryStatus.Running) {
history.status = HistoryStatus.Cancelled;
}
return history;
});
}
this.workspaceHistory = workspaceHistory;
}
async clearAll() {
//TODO: Fix for multi workspace support
const workspaceFolders = workspace.workspaceFolders;
if (workspaceFolders && workspaceFolders.length > 0) {
for (const workspaceFolder of workspaceFolders) {
this.workspaceHistory[workspaceFolder.uri.fsPath] = [];
historyTreeDataProvider.refresh();
this.storageManager.update(StorageKey.WorkspaceHistory, this.workspaceHistory);
}
}
}
async viewOutput(history: History) {
await workspace.openTextDocument({ content: history.output }).then(async document => {
await window.showTextDocument(document);
})
}
async restart(history: History) {
await act.runCommand(history.commandArgs);
}
async stop(history: History) {
history.taskExecution?.terminate();
}
async remove(history: History) {
const historyIndex = this.workspaceHistory[history.commandArgs.workspaceFolder.uri.fsPath].findIndex(workspaceHistory => workspaceHistory.index === history.index)
this.workspaceHistory[history.commandArgs.workspaceFolder.uri.fsPath].splice(historyIndex, 1);
this.storageManager.update(StorageKey.WorkspaceHistory, this.workspaceHistory);
}
}

View File

@@ -1,25 +1,77 @@
import { WorkspaceFolder } from "vscode";
import { Workflow } from "./workflowsManager"; import { Workflow } from "./workflowsManager";
export interface Settings {
environments: Environment[],
secrets: Secret[],
variables: Variable[],
inputs: Input[],
runners: Runner[],
containerEngines: ContainerEngine[]
}
export interface Environment { export interface Environment {
name: string name: string
} }
export interface Secret { export interface Secret {
key: string, key: string,
value?: string value: string,
selected: boolean
} }
export interface Variable { export interface Variable {
key: string, key: string,
value?: string value: string,
selected: boolean
} }
export interface Input { export interface Input {
key: string, key: string,
value?: string value: string,
selected: boolean
}
export interface Runner {
key: string,
value: string,
selected: boolean
}
export interface ContainerEngine {
key: string,
value: string,
selected: boolean
} }
export class SettingsManager { export class SettingsManager {
settings: { [path: string]: Settings }
constructor() {
this.settings = {};
}
getSettings(workspaceFolder: WorkspaceFolder) {
if (!this.settings[workspaceFolder.uri.fsPath]) {
this.settings[workspaceFolder.uri.fsPath] = {
environments: [],
secrets: [],
variables: [],
inputs: [],
runners: [],
containerEngines: [
{
key: 'DOCKER_HOST',
value: '',
selected: false
}
]
}
}
return this.settings[workspaceFolder.uri.fsPath];
}
getEnvironments(workflow: Workflow): Environment[] { getEnvironments(workflow: Workflow): Environment[] {
const environments: Environment[] = []; const environments: Environment[] = [];
if (!workflow.yaml) { if (!workflow.yaml) {
@@ -67,12 +119,32 @@ export class SettingsManager {
return this.findInWorkflow(workflow.fileContent, /\${{\s*(?:inputs|github\.event\.inputs)\.(.*?)(?:\s*==\s*(.*?))?\s*}}/g); return this.findInWorkflow(workflow.fileContent, /\${{\s*(?:inputs|github\.event\.inputs)\.(.*?)(?:\s*==\s*(.*?))?\s*}}/g);
} }
editSecret(workspaceFolder: WorkspaceFolder, secret: Secret, newValue: string) {
}
editVariable(workspaceFolder: WorkspaceFolder, variable: Variable, newValue: string) {
}
editInput(workspaceFolder: WorkspaceFolder, input: Input, newValue: string) {
}
addRunner(workspaceFolder: WorkspaceFolder, runner: Runner) {
}
editContainerEngine(workspaceFolder: WorkspaceFolder, containerEngine: ContainerEngine, newValue: string) {
}
private findInWorkflow(content: string, regExp: RegExp) { private findInWorkflow(content: string, regExp: RegExp) {
const results: (Secret | Variable | Input)[] = []; const results: (Secret | Variable | Input)[] = [];
const matches = content.matchAll(regExp); const matches = content.matchAll(regExp);
for (const match of matches) { for (const match of matches) {
results.push({ key: match[1] }); results.push({ key: match[1], value: '', selected: false });
} }
return results; return results;

View File

@@ -1,6 +1,8 @@
import { MarkdownString, TreeItem } from "vscode"; import { MarkdownString, TreeItem, WorkspaceFolder } from "vscode";
export interface GithubLocalActionsTreeItem extends TreeItem { export interface GithubLocalActionsTreeItem extends TreeItem {
workspaceFolder?: WorkspaceFolder;
getChildren: () => GithubLocalActionsTreeItem[] | Promise<GithubLocalActionsTreeItem[]>; getChildren: () => GithubLocalActionsTreeItem[] | Promise<GithubLocalActionsTreeItem[]>;
getToolTip?: () => Promise<MarkdownString | string | undefined>; getToolTip?: () => Promise<MarkdownString | string | undefined>;

View File

@@ -1,13 +1,13 @@
import { ThemeColor, ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode"; import { ThemeColor, ThemeIcon, TreeItem, TreeItemCollapsibleState, WorkspaceFolder } from "vscode";
import { History, HistoryStatus } from "../../act";
import { DateUtils } from "../../dateUtils"; import { DateUtils } from "../../dateUtils";
import { History, HistoryStatus } from "../../historyManager";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem"; import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
export default class HistoryTreeItem extends TreeItem implements GithubLocalActionsTreeItem { export default class HistoryTreeItem extends TreeItem implements GithubLocalActionsTreeItem {
static contextValue = 'githubLocalActions.history'; static contextValue = 'githubLocalActions.history';
history: History; history: History;
constructor(history: History) { constructor(public workspaceFolder: WorkspaceFolder, history: History) {
super(history.name, TreeItemCollapsibleState.None); super(history.name, TreeItemCollapsibleState.None);
this.history = history; this.history = history;

View File

@@ -1,8 +1,9 @@
import { CancellationToken, commands, EventEmitter, ExtensionContext, extensions, TreeDataProvider, TreeItem, workspace } from "vscode"; import { CancellationToken, commands, EventEmitter, ExtensionContext, extensions, TreeDataProvider, TreeItem, workspace } from "vscode";
import { HistoryStatus } from "../../act";
import { act } from "../../extension"; import { act } from "../../extension";
import { HistoryStatus } from "../../historyManager";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem"; import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
import HistoryTreeItem from "./history"; import HistoryTreeItem from "./history";
import WorkspaceFolderHistoryTreeItem from "./workspaceFolderHistory";
export default class HistoryTreeDataProvider implements TreeDataProvider<GithubLocalActionsTreeItem> { export default class HistoryTreeDataProvider implements TreeDataProvider<GithubLocalActionsTreeItem> {
private _onDidChangeTreeData = new EventEmitter<GithubLocalActionsTreeItem | undefined | null | void>(); private _onDidChangeTreeData = new EventEmitter<GithubLocalActionsTreeItem | undefined | null | void>();
@@ -16,22 +17,24 @@ export default class HistoryTreeDataProvider implements TreeDataProvider<GithubL
context.subscriptions.push( context.subscriptions.push(
commands.registerCommand('githubLocalActions.clearAll', async () => { commands.registerCommand('githubLocalActions.clearAll', async () => {
await act.clearAll(); await act.historyManager.clearAll();
}), }),
commands.registerCommand('githubLocalActions.refreshHistory', async () => { commands.registerCommand('githubLocalActions.refreshHistory', async () => {
this.refresh(); this.refresh();
}), }),
commands.registerCommand('githubLocalActions.viewOutput', async (historyTreeItem: HistoryTreeItem) => { commands.registerCommand('githubLocalActions.viewOutput', async (historyTreeItem: HistoryTreeItem) => {
await act.viewOutput(historyTreeItem.history); await act.historyManager.viewOutput(historyTreeItem.history);
}), }),
commands.registerCommand('githubLocalActions.restart', async (historyTreeItem: HistoryTreeItem) => { commands.registerCommand('githubLocalActions.restart', async (historyTreeItem: HistoryTreeItem) => {
await act.runCommand(historyTreeItem.history.commandArgs); await act.historyManager.restart(historyTreeItem.history);
}), }),
commands.registerCommand('githubLocalActions.stop', async (historyTreeItem: HistoryTreeItem) => { commands.registerCommand('githubLocalActions.stop', async (historyTreeItem: HistoryTreeItem) => {
await act.stop(historyTreeItem.history); await act.historyManager.stop(historyTreeItem.history);
this.refresh();
}), }),
commands.registerCommand('githubLocalActions.remove', async (historyTreeItem: HistoryTreeItem) => { commands.registerCommand('githubLocalActions.remove', async (historyTreeItem: HistoryTreeItem) => {
await act.remove(historyTreeItem.history); await act.historyManager.remove(historyTreeItem.history);
this.refresh();
}) })
); );
} }
@@ -57,25 +60,24 @@ export default class HistoryTreeDataProvider implements TreeDataProvider<GithubL
return element.getChildren(); return element.getChildren();
} else { } else {
const items: GithubLocalActionsTreeItem[] = []; const items: GithubLocalActionsTreeItem[] = [];
let isRunning: boolean = false;
let noHistory: boolean = true;
const workspaceFolders = workspace.workspaceFolders; const workspaceFolders = workspace.workspaceFolders;
let isRunning: boolean = false; if (workspaceFolders) {
if (workspaceFolders && workspaceFolders.length > 0) { for (const workspaceFolder of workspaceFolders) {
//TODO: Fix for multi workspace support items.push(new WorkspaceFolderHistoryTreeItem(workspaceFolder));
const workspaceHistory = act.workspaceHistory[workspaceFolders[0].uri.fsPath];
if (workspaceHistory) {
for (const history of workspaceHistory) {
items.push(new HistoryTreeItem(history));
if (history.status === HistoryStatus.Running) { const workspaceHistory = act.historyManager.workspaceHistory[workspaceFolders[0].uri.fsPath];
isRunning = true; if (workspaceHistory.length > 0) {
} isRunning = act.historyManager.workspaceHistory[workspaceFolders[0].uri.fsPath].find(workspaceHistory => workspaceHistory.status === HistoryStatus.Running) !== undefined;
noHistory = false;
} }
} }
} }
await commands.executeCommand('setContext', 'githubLocalActions:isRunning', isRunning); await commands.executeCommand('setContext', 'githubLocalActions:isRunning', isRunning);
await commands.executeCommand('setContext', 'githubLocalActions:noHistory', items.length == 0); await commands.executeCommand('setContext', 'githubLocalActions:noHistory', noHistory);
return items; return items;
} }
} }

View File

@@ -0,0 +1,26 @@
import { ThemeIcon, TreeItem, TreeItemCollapsibleState, WorkspaceFolder } from "vscode";
import { act } from "../../extension";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
import HistoryTreeItem from "./history";
export default class WorkspaceFolderHistoryTreeItem extends TreeItem implements GithubLocalActionsTreeItem {
static contextValue = 'githubLocalActions.workspaceFolderHistory';
constructor(public workspaceFolder: WorkspaceFolder) {
super(workspaceFolder.name, TreeItemCollapsibleState.Collapsed);
this.contextValue = WorkspaceFolderHistoryTreeItem.contextValue;
this.iconPath = new ThemeIcon('folder');
}
async getChildren(): Promise<GithubLocalActionsTreeItem[]> {
const items: GithubLocalActionsTreeItem[] = [];
const workspaceHistory = act.historyManager.workspaceHistory[this.workspaceFolder.uri.fsPath];
if (workspaceHistory) {
for (const history of workspaceHistory.slice().reverse()) {
items.push(new HistoryTreeItem(this.workspaceFolder, history));
}
}
return items;
}
}

View File

@@ -0,0 +1,18 @@
import { ThemeIcon, TreeItem, TreeItemCollapsibleState, WorkspaceFolder } from "vscode";
import { ContainerEngine } from "../../settingsManager";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
export default class ContainerEngineTreeItem extends TreeItem implements GithubLocalActionsTreeItem {
static contextValue = 'githubLocalActions.containerEngine';
constructor(public workspaceFolder: WorkspaceFolder, containerEngine: ContainerEngine) {
super(containerEngine.key, TreeItemCollapsibleState.None);
this.description = containerEngine.value;
this.contextValue = ContainerEngineTreeItem.contextValue;
this.iconPath = new ThemeIcon('code');
}
async getChildren(): Promise<GithubLocalActionsTreeItem[]> {
return [];
}
}

View File

@@ -1,16 +1,25 @@
import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode"; import { ThemeIcon, TreeItem, TreeItemCollapsibleState, WorkspaceFolder } from "vscode";
import { act } from "../../extension";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem"; import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
import ContainerEngineTreeItem from "./containerEngine";
export default class ContainerEnginesTreeItem extends TreeItem implements GithubLocalActionsTreeItem { export default class ContainerEnginesTreeItem extends TreeItem implements GithubLocalActionsTreeItem {
static contextValue = 'githubLocalActions.containerEngines'; static contextValue = 'githubLocalActions.containerEngines';
constructor() { constructor(public workspaceFolder: WorkspaceFolder) {
super('Container Engines', TreeItemCollapsibleState.Collapsed); super('Container Engines', TreeItemCollapsibleState.Collapsed);
this.contextValue = ContainerEnginesTreeItem.contextValue; this.contextValue = ContainerEnginesTreeItem.contextValue;
this.iconPath = new ThemeIcon('server-process'); this.iconPath = new ThemeIcon('server-process');
} }
async getChildren(): Promise<GithubLocalActionsTreeItem[]> { async getChildren(): Promise<GithubLocalActionsTreeItem[]> {
return []; const items: GithubLocalActionsTreeItem[] = [];
const containerEngines = act.settingsManager.getSettings(this.workspaceFolder).containerEngines;
for (const containerEngine of containerEngines) {
items.push(new ContainerEngineTreeItem(this.workspaceFolder, containerEngine));
}
return items;
} }
} }

View File

@@ -1,11 +1,11 @@
import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode"; import { ThemeIcon, TreeItem, TreeItemCollapsibleState, WorkspaceFolder } from "vscode";
import { Environment } from "../../settingsManager"; import { Environment } from "../../settingsManager";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem"; import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
export default class EnvironmentTreeItem extends TreeItem implements GithubLocalActionsTreeItem { export default class EnvironmentTreeItem extends TreeItem implements GithubLocalActionsTreeItem {
static contextValue = 'githubLocalActions.environment'; static contextValue = 'githubLocalActions.environment';
constructor(environment: Environment) { constructor(public workspaceFolder: WorkspaceFolder, environment: Environment) {
super(environment.name, TreeItemCollapsibleState.None); super(environment.name, TreeItemCollapsibleState.None);
this.contextValue = EnvironmentTreeItem.contextValue; this.contextValue = EnvironmentTreeItem.contextValue;
this.iconPath = new ThemeIcon('server'); this.iconPath = new ThemeIcon('server');

View File

@@ -1,4 +1,4 @@
import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode"; import { ThemeIcon, TreeItem, TreeItemCollapsibleState, WorkspaceFolder } from "vscode";
import { act } from "../../extension"; import { act } from "../../extension";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem"; import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
import EnvironmentTreeItem from "./environment"; import EnvironmentTreeItem from "./environment";
@@ -6,15 +6,15 @@ import EnvironmentTreeItem from "./environment";
export default class EnvironmentsTreeItem extends TreeItem implements GithubLocalActionsTreeItem { export default class EnvironmentsTreeItem extends TreeItem implements GithubLocalActionsTreeItem {
static contextValue = 'githubLocalActions.environments'; static contextValue = 'githubLocalActions.environments';
constructor() { constructor(public workspaceFolder: WorkspaceFolder) {
super('Environments', TreeItemCollapsibleState.Collapsed); super('Environments', TreeItemCollapsibleState.Collapsed);
this.contextValue = EnvironmentsTreeItem.contextValue; this.contextValue = EnvironmentsTreeItem.contextValue;
this.iconPath = new ThemeIcon('server-environment'); this.iconPath = new ThemeIcon('server-environment');
} }
async getChildren(): Promise<GithubLocalActionsTreeItem[]> { async getChildren(): Promise<GithubLocalActionsTreeItem[]> {
const workflows = await act.workflowsManager.getWorkflows(); const workflows = await act.workflowsManager.getWorkflows(this.workspaceFolder);
const environments = [...new Set(workflows.map(workflow => act.settingsManager.getEnvironments(workflow)).flat())]; const environments = [...new Set(workflows.map(workflow => act.settingsManager.getEnvironments(workflow)).flat())];
return environments.map(environment => new EnvironmentTreeItem(environment)); return environments.map(environment => new EnvironmentTreeItem(this.workspaceFolder, environment));
} }
} }

View File

@@ -1,11 +1,11 @@
import { ThemeIcon, TreeItem, TreeItemCheckboxState, TreeItemCollapsibleState } from "vscode"; import { ThemeIcon, TreeItem, TreeItemCheckboxState, TreeItemCollapsibleState, WorkspaceFolder } from "vscode";
import { Input } from "../../settingsManager"; import { Input } from "../../settingsManager";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem"; import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
export default class InputTreeItem extends TreeItem implements GithubLocalActionsTreeItem { export default class InputTreeItem extends TreeItem implements GithubLocalActionsTreeItem {
static contextValue = 'githubLocalActions.input'; static contextValue = 'githubLocalActions.input';
constructor(input: Input) { constructor(public workspaceFolder: WorkspaceFolder, input: Input) {
super(input.key, TreeItemCollapsibleState.None); super(input.key, TreeItemCollapsibleState.None);
this.description = input.value; this.description = input.value;
this.contextValue = InputTreeItem.contextValue; this.contextValue = InputTreeItem.contextValue;

View File

@@ -1,4 +1,4 @@
import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode"; import { ThemeIcon, TreeItem, TreeItemCollapsibleState, WorkspaceFolder } from "vscode";
import { act } from "../../extension"; import { act } from "../../extension";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem"; import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
import InputTreeItem from "./input"; import InputTreeItem from "./input";
@@ -6,15 +6,15 @@ import InputTreeItem from "./input";
export default class InputsTreeItem extends TreeItem implements GithubLocalActionsTreeItem { export default class InputsTreeItem extends TreeItem implements GithubLocalActionsTreeItem {
static contextValue = 'githubLocalActions.inputs'; static contextValue = 'githubLocalActions.inputs';
constructor() { constructor(public workspaceFolder: WorkspaceFolder) {
super('Inputs', TreeItemCollapsibleState.Collapsed); super('Inputs', TreeItemCollapsibleState.Collapsed);
this.contextValue = InputsTreeItem.contextValue; this.contextValue = InputsTreeItem.contextValue;
this.iconPath = new ThemeIcon('record-keys'); this.iconPath = new ThemeIcon('record-keys');
} }
async getChildren(): Promise<GithubLocalActionsTreeItem[]> { async getChildren(): Promise<GithubLocalActionsTreeItem[]> {
const workflows = await act.workflowsManager.getWorkflows(); const workflows = await act.workflowsManager.getWorkflows(this.workspaceFolder);
const inputs = [...new Set(workflows.map(workflow => act.settingsManager.getInputs(workflow)).flat())]; const inputs = [...new Set(workflows.map(workflow => act.settingsManager.getInputs(workflow)).flat())];
return inputs.map(input => new InputTreeItem(input)); return inputs.map(input => new InputTreeItem(this.workspaceFolder, input));
} }
} }

View File

@@ -1,10 +1,10 @@
import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode"; import { ThemeIcon, TreeItem, TreeItemCollapsibleState, WorkspaceFolder } from "vscode";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem"; import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
export default class RunnersTreeItem extends TreeItem implements GithubLocalActionsTreeItem { export default class RunnersTreeItem extends TreeItem implements GithubLocalActionsTreeItem {
static contextValue = 'githubLocalActions.runners'; static contextValue = 'githubLocalActions.runners';
constructor() { constructor(public workspaceFolder: WorkspaceFolder) {
super('Runners', TreeItemCollapsibleState.Collapsed); super('Runners', TreeItemCollapsibleState.Collapsed);
this.contextValue = RunnersTreeItem.contextValue; this.contextValue = RunnersTreeItem.contextValue;
this.iconPath = new ThemeIcon('database'); this.iconPath = new ThemeIcon('database');

View File

@@ -1,15 +1,13 @@
import { ThemeIcon, TreeItem, TreeItemCheckboxState, TreeItemCollapsibleState } from "vscode"; import { ThemeIcon, TreeItem, TreeItemCheckboxState, TreeItemCollapsibleState, WorkspaceFolder } from "vscode";
import { Secret } from "../../settingsManager"; import { Secret } from "../../settingsManager";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem"; import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
export default class SecretTreeItem extends TreeItem implements GithubLocalActionsTreeItem { export default class SecretTreeItem extends TreeItem implements GithubLocalActionsTreeItem {
static contextValue = 'githubLocalActions.secret'; static contextValue = 'githubLocalActions.secret';
constructor(secret: Secret) { constructor(public workspaceFolder: WorkspaceFolder, secret: Secret) {
super(secret.key, TreeItemCollapsibleState.None); super(secret.key, TreeItemCollapsibleState.None);
if (secret.value) { this.description = secret.value ? '••••••••' : '';
this.description = '••••••••'
}
this.contextValue = SecretTreeItem.contextValue; this.contextValue = SecretTreeItem.contextValue;
this.iconPath = new ThemeIcon('key'); this.iconPath = new ThemeIcon('key');
this.checkboxState = TreeItemCheckboxState.Unchecked; this.checkboxState = TreeItemCheckboxState.Unchecked;

View File

@@ -1,4 +1,4 @@
import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode"; import { ThemeIcon, TreeItem, TreeItemCollapsibleState, WorkspaceFolder } from "vscode";
import { act } from "../../extension"; import { act } from "../../extension";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem"; import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
import SecretTreeItem from "./secret"; import SecretTreeItem from "./secret";
@@ -6,15 +6,15 @@ import SecretTreeItem from "./secret";
export default class SecretsTreeItem extends TreeItem implements GithubLocalActionsTreeItem { export default class SecretsTreeItem extends TreeItem implements GithubLocalActionsTreeItem {
static contextValue = 'githubLocalActions.secrets'; static contextValue = 'githubLocalActions.secrets';
constructor() { constructor(public workspaceFolder: WorkspaceFolder) {
super('Secrets', TreeItemCollapsibleState.Collapsed); super('Secrets', TreeItemCollapsibleState.Collapsed);
this.contextValue = SecretsTreeItem.contextValue; this.contextValue = SecretsTreeItem.contextValue;
this.iconPath = new ThemeIcon('lock'); this.iconPath = new ThemeIcon('lock');
} }
async getChildren(): Promise<GithubLocalActionsTreeItem[]> { async getChildren(): Promise<GithubLocalActionsTreeItem[]> {
const workflows = await act.workflowsManager.getWorkflows(); const workflows = await act.workflowsManager.getWorkflows(this.workspaceFolder);
const secrets = [...new Set(workflows.map(workflow => act.settingsManager.getSecrets(workflow)).flat())]; const secrets = [...new Set(workflows.map(workflow => act.settingsManager.getSecrets(workflow)).flat())];
return secrets.map(secret => new SecretTreeItem(secret)); return secrets.map(secret => new SecretTreeItem(this.workspaceFolder, secret));
} }
} }

View File

@@ -1,12 +1,12 @@
import { CancellationToken, commands, EventEmitter, ExtensionContext, TreeDataProvider, TreeItem } from "vscode"; import { CancellationToken, commands, EventEmitter, ExtensionContext, TreeDataProvider, TreeItem, workspace } from "vscode";
import { act } from "../../extension"; import { act } from "../../extension";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem"; import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
import ContainerEnginesTreeItem from "./containerEngines"; import ContainerEngineTreeItem from "./containerEngine";
import EnvironmentsTreeItem from "./environments"; import InputTreeItem from "./input";
import InputsTreeItem from "./inputs";
import RunnersTreeItem from "./runners"; import RunnersTreeItem from "./runners";
import SecretsTreeItem from "./secrets"; import SecretTreeItem from "./secret";
import VariablesTreeItem from "./variables"; import VariableTreeItem from "./variable";
import WorkspaceFolderSettingsTreeItem from "./workspaceFolderSettings";
export default class SettingsTreeDataProvider implements TreeDataProvider<GithubLocalActionsTreeItem> { export default class SettingsTreeDataProvider implements TreeDataProvider<GithubLocalActionsTreeItem> {
private _onDidChangeTreeData = new EventEmitter<GithubLocalActionsTreeItem | undefined | null | void>(); private _onDidChangeTreeData = new EventEmitter<GithubLocalActionsTreeItem | undefined | null | void>();
@@ -17,6 +17,21 @@ export default class SettingsTreeDataProvider implements TreeDataProvider<Github
context.subscriptions.push( context.subscriptions.push(
commands.registerCommand('githubLocalActions.refreshSettings', async () => { commands.registerCommand('githubLocalActions.refreshSettings', async () => {
this.refresh(); this.refresh();
}),
commands.registerCommand('githubLocalActions.editSecret', async (secretTreeItem: SecretTreeItem) => {
//TODO: Implement
}),
commands.registerCommand('githubLocalActions.editVariable', async (variableTreeItem: VariableTreeItem) => {
//TODO: Implement
}),
commands.registerCommand('githubLocalActions.editInput', async (inputTreeItem: InputTreeItem) => {
//TODO: Implement
}),
commands.registerCommand('githubLocalActions.addRunner', async (runnersTreeItem: RunnersTreeItem) => {
//TODO: Implement
}),
commands.registerCommand('githubLocalActions.editContainerEngine', async (containerEngineTreeItem: ContainerEngineTreeItem) => {
//TODO: Implement
}) })
); );
} }
@@ -42,20 +57,21 @@ export default class SettingsTreeDataProvider implements TreeDataProvider<Github
return element.getChildren(); return element.getChildren();
} else { } else {
const items: GithubLocalActionsTreeItem[] = []; const items: GithubLocalActionsTreeItem[] = [];
let noSettings: boolean = true;
const workflows = await act.workflowsManager.getWorkflows(); const workspaceFolders = workspace.workspaceFolders;
if (workspaceFolders) {
for (const workspaceFolder of workspaceFolders) {
items.push(new WorkspaceFolderSettingsTreeItem(workspaceFolder));
const workflows = await act.workflowsManager.getWorkflows(workspaceFolder);
if (workflows.length > 0) { if (workflows.length > 0) {
items.push(...[ noSettings = false;
new EnvironmentsTreeItem(), }
new SecretsTreeItem(), }
new VariablesTreeItem(),
new InputsTreeItem(),
new RunnersTreeItem(),
new ContainerEnginesTreeItem()
]);
} }
await commands.executeCommand('setContext', 'githubLocalActions:noSettings', items.length == 0); await commands.executeCommand('setContext', 'githubLocalActions:noSettings', noSettings);
return items; return items;
} }
} }

View File

@@ -1,11 +1,11 @@
import { ThemeIcon, TreeItem, TreeItemCheckboxState, TreeItemCollapsibleState } from "vscode"; import { ThemeIcon, TreeItem, TreeItemCheckboxState, TreeItemCollapsibleState, WorkspaceFolder } from "vscode";
import { Variable } from "../../settingsManager"; import { Variable } from "../../settingsManager";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem"; import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
export default class VariableTreeItem extends TreeItem implements GithubLocalActionsTreeItem { export default class VariableTreeItem extends TreeItem implements GithubLocalActionsTreeItem {
static contextValue = 'githubLocalActions.variable'; static contextValue = 'githubLocalActions.variable';
constructor(variable: Variable) { constructor(public workspaceFolder: WorkspaceFolder, variable: Variable) {
super(variable.key, TreeItemCollapsibleState.None); super(variable.key, TreeItemCollapsibleState.None);
this.description = variable.value; this.description = variable.value;
this.contextValue = VariableTreeItem.contextValue; this.contextValue = VariableTreeItem.contextValue;

View File

@@ -1,4 +1,4 @@
import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode"; import { ThemeIcon, TreeItem, TreeItemCollapsibleState, WorkspaceFolder } from "vscode";
import { act } from "../../extension"; import { act } from "../../extension";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem"; import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
import VariableTreeItem from "./variable"; import VariableTreeItem from "./variable";
@@ -6,15 +6,15 @@ import VariableTreeItem from "./variable";
export default class VariablesTreeItem extends TreeItem implements GithubLocalActionsTreeItem { export default class VariablesTreeItem extends TreeItem implements GithubLocalActionsTreeItem {
static contextValue = 'githubLocalActions.variables'; static contextValue = 'githubLocalActions.variables';
constructor() { constructor(public workspaceFolder: WorkspaceFolder) {
super('Variables', TreeItemCollapsibleState.Collapsed); super('Variables', TreeItemCollapsibleState.Collapsed);
this.contextValue = VariablesTreeItem.contextValue; this.contextValue = VariablesTreeItem.contextValue;
this.iconPath = new ThemeIcon('symbol-key'); this.iconPath = new ThemeIcon('symbol-key');
} }
async getChildren(): Promise<GithubLocalActionsTreeItem[]> { async getChildren(): Promise<GithubLocalActionsTreeItem[]> {
const workflows = await act.workflowsManager.getWorkflows(); const workflows = await act.workflowsManager.getWorkflows(this.workspaceFolder);
const variables = [...new Set(workflows.map(workflow => act.settingsManager.getVariables(workflow)).flat())]; const variables = [...new Set(workflows.map(workflow => act.settingsManager.getVariables(workflow)).flat())];
return variables.map(variable => new VariableTreeItem(variable)); return variables.map(variable => new VariableTreeItem(this.workspaceFolder, variable));
} }
} }

View File

@@ -0,0 +1,33 @@
import { ThemeIcon, TreeItem, TreeItemCollapsibleState, WorkspaceFolder } from "vscode";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
import ContainerEnginesTreeItem from "./containerEngines";
import EnvironmentsTreeItem from "./environments";
import InputsTreeItem from "./inputs";
import RunnersTreeItem from "./runners";
import SecretsTreeItem from "./secrets";
import VariablesTreeItem from "./variables";
export default class WorkspaceFolderSettingsTreeItem extends TreeItem implements GithubLocalActionsTreeItem {
static contextValue = 'githubLocalActions.workspaceFolderSettings';
constructor(public workspaceFolder: WorkspaceFolder) {
super(workspaceFolder.name, TreeItemCollapsibleState.Collapsed);
this.contextValue = WorkspaceFolderSettingsTreeItem.contextValue;
this.iconPath = new ThemeIcon('folder');
}
async getChildren(): Promise<GithubLocalActionsTreeItem[]> {
const items: GithubLocalActionsTreeItem[] = [];
items.push(...[
new EnvironmentsTreeItem(this.workspaceFolder),
new SecretsTreeItem(this.workspaceFolder),
new VariablesTreeItem(this.workspaceFolder),
new InputsTreeItem(this.workspaceFolder),
new RunnersTreeItem(this.workspaceFolder),
new ContainerEnginesTreeItem(this.workspaceFolder)
]);
return items;
}
}

View File

@@ -1,4 +1,4 @@
import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode"; import { ThemeIcon, TreeItem, TreeItemCollapsibleState, WorkspaceFolder } from "vscode";
import { Job, Workflow } from "../../workflowsManager"; import { Job, Workflow } from "../../workflowsManager";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem"; import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
@@ -7,7 +7,7 @@ export default class JobTreeItem extends TreeItem implements GithubLocalActionsT
job: Job; job: Job;
workflow: Workflow; workflow: Workflow;
constructor(workflow: Workflow, job: Job) { constructor(public workspaceFolder: WorkspaceFolder, workflow: Workflow, job: Job) {
super(job.name, TreeItemCollapsibleState.None); super(job.name, TreeItemCollapsibleState.None);
this.workflow = workflow; this.workflow = workflow;
this.job = job; this.job = job;

View File

@@ -1,4 +1,4 @@
import { ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri } from "vscode"; import { ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri, WorkspaceFolder } from "vscode";
import { Workflow } from "../../workflowsManager"; import { Workflow } from "../../workflowsManager";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem"; import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
import JobTreeItem from "./job"; import JobTreeItem from "./job";
@@ -7,7 +7,7 @@ export default class WorkflowTreeItem extends TreeItem implements GithubLocalAct
static contextValue = 'githubLocalActions.workflow'; static contextValue = 'githubLocalActions.workflow';
workflow: Workflow; workflow: Workflow;
constructor(workflow: Workflow) { constructor(public workspaceFolder: WorkspaceFolder, workflow: Workflow) {
super(workflow.name, workflow.error ? TreeItemCollapsibleState.None : TreeItemCollapsibleState.Collapsed); super(workflow.name, workflow.error ? TreeItemCollapsibleState.None : TreeItemCollapsibleState.Collapsed);
this.workflow = workflow; this.workflow = workflow;
this.contextValue = WorkflowTreeItem.contextValue; this.contextValue = WorkflowTreeItem.contextValue;
@@ -27,7 +27,7 @@ export default class WorkflowTreeItem extends TreeItem implements GithubLocalAct
const jobs = this.workflow.yaml.jobs; const jobs = this.workflow.yaml.jobs;
if (jobs) { if (jobs) {
for (const [key, value] of Object.entries<any>(jobs)) { for (const [key, value] of Object.entries<any>(jobs)) {
items.push(new JobTreeItem(this.workflow, { name: value.name ? value.name : key, id: key })); items.push(new JobTreeItem(this.workspaceFolder, this.workflow, { name: value.name ? value.name : key, id: key }));
} }
} }

View File

@@ -3,6 +3,7 @@ import { Event } from "../../act";
import { act } from "../../extension"; import { act } from "../../extension";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem"; import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
import WorkflowTreeItem from "./workflow"; import WorkflowTreeItem from "./workflow";
import WorkspaceFolderWorkflowsTreeItem from "./workspaceFolderWorkflows";
export default class WorkflowsTreeDataProvider implements TreeDataProvider<GithubLocalActionsTreeItem> { export default class WorkflowsTreeDataProvider implements TreeDataProvider<GithubLocalActionsTreeItem> {
private _onDidChangeTreeData = new EventEmitter<GithubLocalActionsTreeItem | undefined | null | void>(); private _onDidChangeTreeData = new EventEmitter<GithubLocalActionsTreeItem | undefined | null | void>();
@@ -63,13 +64,22 @@ export default class WorkflowsTreeDataProvider implements TreeDataProvider<Githu
return element.getChildren(); return element.getChildren();
} else { } else {
const items: GithubLocalActionsTreeItem[] = []; const items: GithubLocalActionsTreeItem[] = [];
let noWorkflows: boolean = true;
const workflows = await act.workflowsManager.getWorkflows(); const workspaceFolders = workspace.workspaceFolders;
for (const workflow of workflows) { if (workspaceFolders) {
items.push(new WorkflowTreeItem(workflow)); for (const workspaceFolder of workspaceFolders) {
items.push(new WorkspaceFolderWorkflowsTreeItem(workspaceFolder));
const workflows = await act.workflowsManager.getWorkflows(workspaceFolder);
if (workflows.length > 0) {
noWorkflows = false;
}
} }
await commands.executeCommand('setContext', 'githubLocalActions:noWorkflows', items.length == 0); }
await commands.executeCommand('setContext', 'githubLocalActions:noWorkflows', noWorkflows);
return items; return items;
} }
} }

View File

@@ -0,0 +1,25 @@
import { ThemeIcon, TreeItem, TreeItemCollapsibleState, WorkspaceFolder } from "vscode";
import { act } from "../../extension";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
import WorkflowTreeItem from "./workflow";
export default class WorkspaceFolderWorkflowsTreeItem extends TreeItem implements GithubLocalActionsTreeItem {
static contextValue = 'githubLocalActions.workspaceFolderWorkflows';
constructor(public workspaceFolder: WorkspaceFolder) {
super(workspaceFolder.name, TreeItemCollapsibleState.Collapsed);
this.contextValue = WorkspaceFolderWorkflowsTreeItem.contextValue;
this.iconPath = new ThemeIcon('folder');
}
async getChildren(): Promise<GithubLocalActionsTreeItem[]> {
const items: GithubLocalActionsTreeItem[] = [];
const workflows = await act.workflowsManager.getWorkflows(this.workspaceFolder);
for (const workflow of workflows) {
items.push(new WorkflowTreeItem(this.workspaceFolder, workflow));
}
return items;
}
}

View File

@@ -1,6 +1,6 @@
import * as fs from "fs/promises"; import * as fs from "fs/promises";
import * as path from "path"; import * as path from "path";
import { Uri, workspace } from "vscode"; import { RelativePattern, Uri, workspace, WorkspaceFolder } from "vscode";
import * as yaml from "yaml"; import * as yaml from "yaml";
export interface Workflow { export interface Workflow {
@@ -17,13 +17,10 @@ export interface Job {
} }
export class WorkflowsManager { export class WorkflowsManager {
async getWorkflows(): Promise<Workflow[]> { async getWorkflows(workspaceFolder: WorkspaceFolder): Promise<Workflow[]> {
const workflows: Workflow[] = []; const workflows: Workflow[] = [];
const workspaceFolders = workspace.workspaceFolders; const workflowFileUris = await workspace.findFiles(new RelativePattern(workspaceFolder, `.github/workflows/*.{yml,yaml}`));
if (workspaceFolders && workspaceFolders.length > 0) {
const workflowFileUris = await workspace.findFiles(`.github/workflows/*.{yml,yaml}`);
for await (const workflowFileUri of workflowFileUris) { for await (const workflowFileUri of workflowFileUris) {
let yamlContent: any | undefined; let yamlContent: any | undefined;
@@ -45,7 +42,6 @@ export class WorkflowsManager {
}); });
} }
} }
}
return workflows; return workflows;
} }