feat: Add Gitea workflow support (.gitea/workflows) - Support for both .github/workflows and .gitea/workflows directories - Fixed workflow execution path resolution - Cleaned up debugging code - Updated to version 1.2.5
Some checks failed
Test Gitea Workflow / test (push) Has been cancelled
Some checks failed
Test Gitea Workflow / test (push) Has been cancelled
This commit is contained in:
21
.gitea/workflows/test-gitea.yml
Normal file
21
.gitea/workflows/test-gitea.yml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
name: Test Gitea Workflow
|
||||||
|
run-name: Test Gitea Workflow
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: echo "Testing Gitea workflow"
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: echo "Building project"
|
||||||
2935
src/Extension Host.log
Normal file
2935
src/Extension Host.log
Normal file
File diff suppressed because it is too large
Load Diff
2226
src/act.ts
2226
src/act.ts
File diff suppressed because it is too large
Load Diff
@@ -1,60 +1,70 @@
|
|||||||
import { ConfigurationTarget, workspace } from 'vscode';
|
import { ConfigurationTarget, workspace } from "vscode";
|
||||||
import { Act } from './act';
|
import { Act } from "./act";
|
||||||
import { WorkflowsManager } from './workflowsManager';
|
|
||||||
|
|
||||||
export enum Platform {
|
export enum Platform {
|
||||||
windows = 'win32',
|
windows = "win32",
|
||||||
mac = 'darwin',
|
mac = "darwin",
|
||||||
linux = 'linux'
|
linux = "linux",
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum Section {
|
export enum Section {
|
||||||
actCommand = 'actCommand',
|
actCommand = "actCommand",
|
||||||
workflowsDirectory = 'workflowsDirectory',
|
dockerDesktopPath = "dockerDesktopPath",
|
||||||
dockerDesktopPath = 'dockerDesktopPath'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace ConfigurationManager {
|
export namespace ConfigurationManager {
|
||||||
export const group: string = 'githubLocalActions';
|
export const group: string = "githubLocalActions";
|
||||||
export const searchPrefix: string = '@ext:sanjulaganepola.github-local-actions';
|
export const searchPrefix: string =
|
||||||
|
"@ext:sanjulaganepola.github-local-actions";
|
||||||
|
|
||||||
export async function initialize(): Promise<void> {
|
export async function initialize(): Promise<void> {
|
||||||
let actCommand = ConfigurationManager.get<string>(Section.actCommand);
|
let actCommand = ConfigurationManager.get<string>(Section.actCommand);
|
||||||
if (!actCommand) {
|
if (!actCommand) {
|
||||||
await ConfigurationManager.set(Section.actCommand, Act.defaultActCommand);
|
await ConfigurationManager.set(Section.actCommand, Act.defaultActCommand);
|
||||||
}
|
|
||||||
|
|
||||||
let workflowsDirectory = ConfigurationManager.get<string>(Section.workflowsDirectory);
|
|
||||||
if (!workflowsDirectory) {
|
|
||||||
await ConfigurationManager.set(Section.workflowsDirectory, WorkflowsManager.defaultWorkflowsDirectory);
|
|
||||||
}
|
|
||||||
|
|
||||||
let dockerDesktopPath = ConfigurationManager.get<string>(Section.dockerDesktopPath);
|
|
||||||
if (!dockerDesktopPath) {
|
|
||||||
switch (process.platform) {
|
|
||||||
case Platform.windows:
|
|
||||||
dockerDesktopPath = 'C:/Program Files/Docker/Docker/Docker Desktop.exe';
|
|
||||||
break;
|
|
||||||
case Platform.mac:
|
|
||||||
dockerDesktopPath = '/Applications/Docker.app';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await ConfigurationManager.set(Section.dockerDesktopPath, dockerDesktopPath);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getSearchTerm(section: Section): string {
|
// Don't set a default workflows directory to allow multi-directory support
|
||||||
return `${ConfigurationManager.searchPrefix} ${ConfigurationManager.group}.${section}`;
|
// let workflowsDirectory = ConfigurationManager.get<string>(Section.workflowsDirectory);
|
||||||
}
|
// if (!workflowsDirectory) {
|
||||||
|
// await ConfigurationManager.set(Section.workflowsDirectory, WorkflowsManager.defaultWorkflowsDirectory);
|
||||||
|
// }
|
||||||
|
|
||||||
export function get<T>(section: Section): T | undefined {
|
let dockerDesktopPath = ConfigurationManager.get<string>(
|
||||||
return workspace.getConfiguration(ConfigurationManager.group).get(section) as T;
|
Section.dockerDesktopPath
|
||||||
}
|
);
|
||||||
|
if (!dockerDesktopPath) {
|
||||||
|
switch (process.platform) {
|
||||||
|
case Platform.windows:
|
||||||
|
dockerDesktopPath =
|
||||||
|
"C:/Program Files/Docker/Docker/Docker Desktop.exe";
|
||||||
|
break;
|
||||||
|
case Platform.mac:
|
||||||
|
dockerDesktopPath = "/Applications/Docker.app";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
export async function set(section: Section, value: any): Promise<void> {
|
await ConfigurationManager.set(
|
||||||
return await workspace.getConfiguration(ConfigurationManager.group).update(section, value, ConfigurationTarget.Global);
|
Section.dockerDesktopPath,
|
||||||
|
dockerDesktopPath
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getSearchTerm(section: Section): string {
|
||||||
|
return `${ConfigurationManager.searchPrefix} ${ConfigurationManager.group}.${section}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function get<T>(section: Section): T | undefined {
|
||||||
|
return workspace
|
||||||
|
.getConfiguration(ConfigurationManager.group)
|
||||||
|
.get(section) as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function set(section: Section, value: any): Promise<void> {
|
||||||
|
return await workspace
|
||||||
|
.getConfiguration(ConfigurationManager.group)
|
||||||
|
.update(section, value, ConfigurationTarget.Global);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
201
src/extension.ts
201
src/extension.ts
@@ -1,15 +1,23 @@
|
|||||||
import { commands, env, ExtensionContext, TreeCheckboxChangeEvent, Uri, window, workspace } from 'vscode';
|
import {
|
||||||
import { Act } from './act';
|
commands,
|
||||||
import { ConfigurationManager, Section } from './configurationManager';
|
env,
|
||||||
import { IssueHandler } from './issueHandler';
|
ExtensionContext,
|
||||||
import ComponentsTreeDataProvider from './views/components/componentsTreeDataProvider';
|
TreeCheckboxChangeEvent,
|
||||||
import { DecorationProvider } from './views/decorationProvider';
|
Uri,
|
||||||
import { GithubLocalActionsTreeItem } from './views/githubLocalActionsTreeItem';
|
window,
|
||||||
import HistoryTreeDataProvider from './views/history/historyTreeDataProvider';
|
workspace,
|
||||||
import SettingTreeItem from './views/settings/setting';
|
} from "vscode";
|
||||||
import SettingsTreeDataProvider from './views/settings/settingsTreeDataProvider';
|
import { Act } from "./act";
|
||||||
import WorkflowsTreeDataProvider from './views/workflows/workflowsTreeDataProvider';
|
import { ConfigurationManager, Section } from "./configurationManager";
|
||||||
import { WorkflowsManager } from './workflowsManager';
|
import { IssueHandler } from "./issueHandler";
|
||||||
|
import ComponentsTreeDataProvider from "./views/components/componentsTreeDataProvider";
|
||||||
|
import { DecorationProvider } from "./views/decorationProvider";
|
||||||
|
import { GithubLocalActionsTreeItem } from "./views/githubLocalActionsTreeItem";
|
||||||
|
import HistoryTreeDataProvider from "./views/history/historyTreeDataProvider";
|
||||||
|
import SettingTreeItem from "./views/settings/setting";
|
||||||
|
import SettingsTreeDataProvider from "./views/settings/settingsTreeDataProvider";
|
||||||
|
import WorkflowsTreeDataProvider from "./views/workflows/workflowsTreeDataProvider";
|
||||||
|
import { WorkflowsManager } from "./workflowsManager";
|
||||||
|
|
||||||
export let act: Act;
|
export let act: Act;
|
||||||
export let componentsTreeDataProvider: ComponentsTreeDataProvider;
|
export let componentsTreeDataProvider: ComponentsTreeDataProvider;
|
||||||
@@ -18,83 +26,120 @@ export let historyTreeDataProvider: HistoryTreeDataProvider;
|
|||||||
export let settingsTreeDataProvider: SettingsTreeDataProvider;
|
export let settingsTreeDataProvider: SettingsTreeDataProvider;
|
||||||
|
|
||||||
export function activate(context: ExtensionContext) {
|
export function activate(context: ExtensionContext) {
|
||||||
console.log('Congratulations, your extension "github-local-actions" is now active!');
|
console.log(
|
||||||
|
'Congratulations, your extension "github-local-actions" is now active!'
|
||||||
|
);
|
||||||
|
|
||||||
act = new Act(context);
|
act = new Act(context);
|
||||||
|
|
||||||
// Create tree views
|
// Create tree views
|
||||||
const decorationProvider = new DecorationProvider();
|
const decorationProvider = new DecorationProvider();
|
||||||
componentsTreeDataProvider = new ComponentsTreeDataProvider(context);
|
componentsTreeDataProvider = new ComponentsTreeDataProvider(context);
|
||||||
const componentsTreeView = window.createTreeView(ComponentsTreeDataProvider.VIEW_ID, { treeDataProvider: componentsTreeDataProvider, showCollapseAll: true });
|
const componentsTreeView = window.createTreeView(
|
||||||
workflowsTreeDataProvider = new WorkflowsTreeDataProvider(context);
|
ComponentsTreeDataProvider.VIEW_ID,
|
||||||
const workflowsTreeView = window.createTreeView(WorkflowsTreeDataProvider.VIEW_ID, { treeDataProvider: workflowsTreeDataProvider, showCollapseAll: true });
|
{ treeDataProvider: componentsTreeDataProvider, showCollapseAll: true }
|
||||||
historyTreeDataProvider = new HistoryTreeDataProvider(context);
|
);
|
||||||
const historyTreeView = window.createTreeView(HistoryTreeDataProvider.VIEW_ID, { treeDataProvider: historyTreeDataProvider, showCollapseAll: true });
|
|
||||||
settingsTreeDataProvider = new SettingsTreeDataProvider(context);
|
|
||||||
const settingsTreeView = window.createTreeView(SettingsTreeDataProvider.VIEW_ID, { treeDataProvider: settingsTreeDataProvider, showCollapseAll: true });
|
|
||||||
settingsTreeView.onDidChangeCheckboxState(async (event: TreeCheckboxChangeEvent<GithubLocalActionsTreeItem>) => {
|
|
||||||
await settingsTreeDataProvider.onDidChangeCheckboxState(event as TreeCheckboxChangeEvent<SettingTreeItem>);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create file watcher
|
workflowsTreeDataProvider = new WorkflowsTreeDataProvider(context);
|
||||||
let workflowsFileWatcher = setupFileWatcher(context);
|
const workflowsTreeView = window.createTreeView(
|
||||||
|
WorkflowsTreeDataProvider.VIEW_ID,
|
||||||
|
{ treeDataProvider: workflowsTreeDataProvider, showCollapseAll: true }
|
||||||
|
);
|
||||||
|
|
||||||
// Initialize configurations
|
historyTreeDataProvider = new HistoryTreeDataProvider(context);
|
||||||
ConfigurationManager.initialize();
|
const historyTreeView = window.createTreeView(
|
||||||
workspace.onDidChangeConfiguration(async event => {
|
HistoryTreeDataProvider.VIEW_ID,
|
||||||
if (event.affectsConfiguration(ConfigurationManager.group)) {
|
{ treeDataProvider: historyTreeDataProvider, showCollapseAll: true }
|
||||||
await ConfigurationManager.initialize();
|
);
|
||||||
|
settingsTreeDataProvider = new SettingsTreeDataProvider(context);
|
||||||
|
const settingsTreeView = window.createTreeView(
|
||||||
|
SettingsTreeDataProvider.VIEW_ID,
|
||||||
|
{ treeDataProvider: settingsTreeDataProvider, showCollapseAll: true }
|
||||||
|
);
|
||||||
|
settingsTreeView.onDidChangeCheckboxState(
|
||||||
|
async (event: TreeCheckboxChangeEvent<GithubLocalActionsTreeItem>) => {
|
||||||
|
await settingsTreeDataProvider.onDidChangeCheckboxState(
|
||||||
|
event as TreeCheckboxChangeEvent<SettingTreeItem>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
if (event.affectsConfiguration(`${ConfigurationManager.group}.${Section.actCommand}`) ||
|
// Create file watcher
|
||||||
event.affectsConfiguration(`${ConfigurationManager.group}.${Section.dockerDesktopPath}`)) {
|
let workflowsFileWatcher = setupFileWatcher(context);
|
||||||
componentsTreeDataProvider.refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.affectsConfiguration(`${ConfigurationManager.group}.${Section.workflowsDirectory}`)) {
|
// Initialize configurations
|
||||||
workflowsTreeDataProvider.refresh();
|
ConfigurationManager.initialize();
|
||||||
settingsTreeDataProvider.refresh();
|
workspace.onDidChangeConfiguration(async (event) => {
|
||||||
|
if (event.affectsConfiguration(ConfigurationManager.group)) {
|
||||||
|
await ConfigurationManager.initialize();
|
||||||
|
|
||||||
if (workflowsFileWatcher) {
|
if (
|
||||||
workflowsFileWatcher.dispose();
|
event.affectsConfiguration(
|
||||||
workflowsFileWatcher = setupFileWatcher(context);
|
`${ConfigurationManager.group}.${Section.actCommand}`
|
||||||
}
|
) ||
|
||||||
}
|
event.affectsConfiguration(
|
||||||
}
|
`${ConfigurationManager.group}.${Section.dockerDesktopPath}`
|
||||||
});
|
)
|
||||||
|
) {
|
||||||
|
componentsTreeDataProvider.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
context.subscriptions.push(
|
context.subscriptions.push(
|
||||||
componentsTreeView,
|
componentsTreeView,
|
||||||
workflowsTreeView,
|
workflowsTreeView,
|
||||||
historyTreeView,
|
historyTreeView,
|
||||||
settingsTreeView,
|
settingsTreeView,
|
||||||
window.registerFileDecorationProvider(decorationProvider),
|
window.registerFileDecorationProvider(decorationProvider),
|
||||||
workflowsFileWatcher,
|
workflowsFileWatcher,
|
||||||
commands.registerCommand('githubLocalActions.viewDocumentation', async () => {
|
commands.registerCommand(
|
||||||
await env.openExternal(Uri.parse('https://sanjulaganepola.github.io/github-local-actions-docs'));
|
"githubLocalActions.viewDocumentation",
|
||||||
}),
|
async () => {
|
||||||
commands.registerCommand('githubLocalActions.reportAnIssue', async () => {
|
await env.openExternal(
|
||||||
await IssueHandler.openBugReport(context);
|
Uri.parse(
|
||||||
}),
|
"https://sanjulaganepola.github.io/github-local-actions-docs"
|
||||||
);
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
commands.registerCommand("githubLocalActions.reportAnIssue", async () => {
|
||||||
|
await IssueHandler.openBugReport(context);
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupFileWatcher(context: ExtensionContext) {
|
function setupFileWatcher(context: ExtensionContext) {
|
||||||
const workflowsDirectory = WorkflowsManager.getWorkflowsDirectory();
|
const workflowsDirectories = WorkflowsManager.getWorkflowsDirectories();
|
||||||
const workflowsFileWatcher = workspace.createFileSystemWatcher(`**/${workflowsDirectory}/*.{${WorkflowsManager.ymlExtension},${WorkflowsManager.yamlExtension}}`);
|
const fileWatchers: any[] = [];
|
||||||
workflowsFileWatcher.onDidCreate(() => {
|
|
||||||
workflowsTreeDataProvider.refresh();
|
|
||||||
settingsTreeDataProvider.refresh();
|
|
||||||
});
|
|
||||||
workflowsFileWatcher.onDidChange(() => {
|
|
||||||
workflowsTreeDataProvider.refresh();
|
|
||||||
settingsTreeDataProvider.refresh();
|
|
||||||
});
|
|
||||||
workflowsFileWatcher.onDidDelete(() => {
|
|
||||||
workflowsTreeDataProvider.refresh();
|
|
||||||
settingsTreeDataProvider.refresh();
|
|
||||||
});
|
|
||||||
|
|
||||||
return workflowsFileWatcher;
|
for (const workflowsDirectory of workflowsDirectories) {
|
||||||
|
const workflowsFileWatcher = workspace.createFileSystemWatcher(
|
||||||
|
`**/${workflowsDirectory}/*.{${WorkflowsManager.ymlExtension},${WorkflowsManager.yamlExtension}}`
|
||||||
|
);
|
||||||
|
|
||||||
|
workflowsFileWatcher.onDidCreate(() => {
|
||||||
|
workflowsTreeDataProvider.refresh();
|
||||||
|
settingsTreeDataProvider.refresh();
|
||||||
|
});
|
||||||
|
workflowsFileWatcher.onDidChange(() => {
|
||||||
|
workflowsTreeDataProvider.refresh();
|
||||||
|
settingsTreeDataProvider.refresh();
|
||||||
|
});
|
||||||
|
workflowsFileWatcher.onDidDelete(() => {
|
||||||
|
workflowsTreeDataProvider.refresh();
|
||||||
|
settingsTreeDataProvider.refresh();
|
||||||
|
});
|
||||||
|
|
||||||
|
fileWatchers.push(workflowsFileWatcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a disposable that disposes all watchers
|
||||||
|
return {
|
||||||
|
dispose: () => {
|
||||||
|
fileWatchers.forEach((watcher) => watcher.dispose());
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deactivate() { }
|
export function deactivate() {}
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
import { CancellationToken, commands, EventEmitter, ExtensionContext, TreeDataProvider, TreeItem, window, workspace } from "vscode";
|
import {
|
||||||
|
CancellationToken,
|
||||||
|
commands,
|
||||||
|
EventEmitter,
|
||||||
|
ExtensionContext,
|
||||||
|
TreeDataProvider,
|
||||||
|
TreeItem,
|
||||||
|
window,
|
||||||
|
workspace,
|
||||||
|
} from "vscode";
|
||||||
import { Event } from "../../act";
|
import { Event } from "../../act";
|
||||||
import { act } from "../../extension";
|
import { act } from "../../extension";
|
||||||
import { Utils } from "../../utils";
|
import { Utils } from "../../utils";
|
||||||
@@ -9,176 +18,276 @@ import JobTreeItem from "./job";
|
|||||||
import WorkflowTreeItem from "./workflow";
|
import WorkflowTreeItem from "./workflow";
|
||||||
import WorkspaceFolderWorkflowsTreeItem from "./workspaceFolderWorkflows";
|
import WorkspaceFolderWorkflowsTreeItem from "./workspaceFolderWorkflows";
|
||||||
|
|
||||||
export default class WorkflowsTreeDataProvider implements TreeDataProvider<GithubLocalActionsTreeItem> {
|
export default class WorkflowsTreeDataProvider
|
||||||
private _onDidChangeTreeData = new EventEmitter<GithubLocalActionsTreeItem | undefined | null | void>();
|
implements TreeDataProvider<GithubLocalActionsTreeItem>
|
||||||
readonly onDidChangeTreeData = this._onDidChangeTreeData.event;
|
{
|
||||||
static VIEW_ID = 'workflows';
|
private _onDidChangeTreeData = new EventEmitter<
|
||||||
|
GithubLocalActionsTreeItem | undefined | null | void
|
||||||
|
>();
|
||||||
|
readonly onDidChangeTreeData = this._onDidChangeTreeData.event;
|
||||||
|
static VIEW_ID = "workflows";
|
||||||
|
|
||||||
constructor(context: ExtensionContext) {
|
constructor(context: ExtensionContext) {
|
||||||
context.subscriptions.push(
|
context.subscriptions.push(
|
||||||
commands.registerCommand('githubLocalActions.runAllWorkflows', async (workspaceFolderWorkflowsTreeItem?: WorkspaceFolderWorkflowsTreeItem) => {
|
commands.registerCommand(
|
||||||
const workspaceFolder = await Utils.getWorkspaceFolder(workspaceFolderWorkflowsTreeItem?.workspaceFolder);
|
"githubLocalActions.runAllWorkflows",
|
||||||
if (workspaceFolder) {
|
async (
|
||||||
await act.runAllWorkflows(workspaceFolder);
|
workspaceFolderWorkflowsTreeItem?: WorkspaceFolderWorkflowsTreeItem
|
||||||
}
|
) => {
|
||||||
}),
|
const workspaceFolder = await Utils.getWorkspaceFolder(
|
||||||
commands.registerCommand('githubLocalActions.runEvent', async (workspaceFolderWorkflowsTreeItem?: WorkspaceFolderWorkflowsTreeItem) => {
|
workspaceFolderWorkflowsTreeItem?.workspaceFolder
|
||||||
const workspaceFolder = await Utils.getWorkspaceFolder(workspaceFolderWorkflowsTreeItem?.workspaceFolder);
|
);
|
||||||
if (workspaceFolder) {
|
if (workspaceFolder) {
|
||||||
const event = await window.showQuickPick(Object.values(Event), {
|
await act.runAllWorkflows(workspaceFolder);
|
||||||
title: 'Select the event to run',
|
}
|
||||||
placeHolder: 'Event'
|
|
||||||
});
|
|
||||||
|
|
||||||
if (event) {
|
|
||||||
await act.runEvent(workspaceFolder, event as Event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
commands.registerCommand('githubLocalActions.refreshWorkflows', async () => {
|
|
||||||
this.refresh();
|
|
||||||
}),
|
|
||||||
commands.registerCommand('githubLocalActions.openWorkflow', async (workflowTreeItem: WorkflowTreeItem) => {
|
|
||||||
try {
|
|
||||||
const document = await workspace.openTextDocument(workflowTreeItem.workflow.uri);
|
|
||||||
await window.showTextDocument(document);
|
|
||||||
} catch (error: any) {
|
|
||||||
try {
|
|
||||||
await workspace.fs.stat(workflowTreeItem.workflow.uri);
|
|
||||||
window.showErrorMessage(`Failed to open workflow. Error: ${error}`);
|
|
||||||
} catch (error: any) {
|
|
||||||
window.showErrorMessage(`Workflow ${path.parse(workflowTreeItem.workflow.uri.fsPath).base} not found.`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
commands.registerCommand('githubLocalActions.runWorkflow', async (workflowTreeItem: WorkflowTreeItem) => {
|
|
||||||
if (workflowTreeItem) {
|
|
||||||
await act.runWorkflow(workflowTreeItem.workspaceFolder, workflowTreeItem.workflow);
|
|
||||||
} else {
|
|
||||||
let errorMessage: string | undefined;
|
|
||||||
|
|
||||||
const activeTextEditor = window.activeTextEditor;
|
|
||||||
if (activeTextEditor) {
|
|
||||||
const uri = activeTextEditor.document.uri;
|
|
||||||
const fileName = path.parse(uri.fsPath).base;
|
|
||||||
const workflowsDirectory = WorkflowsManager.getWorkflowsDirectory();
|
|
||||||
if (uri.path.match(`.*/${workflowsDirectory}/.*\\.(${WorkflowsManager.yamlExtension}|${WorkflowsManager.ymlExtension})`)) {
|
|
||||||
const workspaceFolder = workspace.getWorkspaceFolder(uri);
|
|
||||||
if (workspaceFolder) {
|
|
||||||
const workflows = await act.workflowsManager.getWorkflows(workspaceFolder);
|
|
||||||
const workflow = workflows.find(workflow => workflow.uri.fsPath === uri.fsPath);
|
|
||||||
if (workflow) {
|
|
||||||
await act.runWorkflow(workspaceFolder, workflow);
|
|
||||||
} else {
|
|
||||||
errorMessage = `Workflow not found in workflow directory (${workflowsDirectory}).`;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
errorMessage = `${fileName} must be opened in a workspace folder to be executed locally.`;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
errorMessage = `${fileName} is not a workflow that can be executed locally.`;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
errorMessage = 'No workflow opened to execute locally.';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (errorMessage) {
|
|
||||||
window.showErrorMessage(errorMessage, 'View Workflows').then(async value => {
|
|
||||||
if (value === 'View Workflows') {
|
|
||||||
await commands.executeCommand('workflows.focus');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
commands.registerCommand('githubLocalActions.runJob', async (jobTreeItem: JobTreeItem) => {
|
|
||||||
await act.runJob(jobTreeItem.workspaceFolder, jobTreeItem.workflow, jobTreeItem.job);
|
|
||||||
}),
|
|
||||||
commands.registerCommand('githubLocalActions.runWorkflowEvent', async (workflowTreeItem: WorkflowTreeItem) => {
|
|
||||||
// Filter to only events that are registered on the workflow
|
|
||||||
const registeredEventsOnWorkflow = Object.keys(workflowTreeItem.workflow.yaml.on);
|
|
||||||
|
|
||||||
if (registeredEventsOnWorkflow.length === 0) {
|
|
||||||
window.showErrorMessage(`No events registered on the workflow (${workflowTreeItem.workflow.name}). Add an event to the \`on\` section of the workflow to trigger it.`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const event = await window.showQuickPick(registeredEventsOnWorkflow, {
|
|
||||||
title: 'Select the event to run',
|
|
||||||
placeHolder: 'Event',
|
|
||||||
});
|
|
||||||
|
|
||||||
if (event) {
|
|
||||||
await act.runEvent(workflowTreeItem.workspaceFolder, event as Event, { workflow: workflowTreeItem.workflow });
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
commands.registerCommand('githubLocalActions.runJobEvent', async (jobTreeItem: JobTreeItem) => {
|
|
||||||
// Filter to only events that are registered on the job's parent workflow
|
|
||||||
const registeredEventsOnJobParentWorkflow = Object.keys(jobTreeItem.workflow.yaml.on);
|
|
||||||
|
|
||||||
if (registeredEventsOnJobParentWorkflow.length === 0) {
|
|
||||||
window.showErrorMessage(`No events registered on the workflow (${jobTreeItem.workflow.name}). Add an event to the \`on\` section of the workflow to trigger it.`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const event = await window.showQuickPick(registeredEventsOnJobParentWorkflow, {
|
|
||||||
title: 'Select the event to run',
|
|
||||||
placeHolder: 'Event'
|
|
||||||
});
|
|
||||||
|
|
||||||
if (event) {
|
|
||||||
await act.runEvent(jobTreeItem.workspaceFolder, event as Event, { workflow: jobTreeItem.workflow, job: jobTreeItem.job });
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
),
|
||||||
|
commands.registerCommand(
|
||||||
|
"githubLocalActions.runEvent",
|
||||||
|
async (
|
||||||
|
workspaceFolderWorkflowsTreeItem?: WorkspaceFolderWorkflowsTreeItem
|
||||||
|
) => {
|
||||||
|
const workspaceFolder = await Utils.getWorkspaceFolder(
|
||||||
|
workspaceFolderWorkflowsTreeItem?.workspaceFolder
|
||||||
|
);
|
||||||
|
if (workspaceFolder) {
|
||||||
|
const event = await window.showQuickPick(Object.values(Event), {
|
||||||
|
title: "Select the event to run",
|
||||||
|
placeHolder: "Event",
|
||||||
|
});
|
||||||
|
|
||||||
return element;
|
if (event) {
|
||||||
}
|
await act.runEvent(workspaceFolder, event as Event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
commands.registerCommand(
|
||||||
|
"githubLocalActions.refreshWorkflows",
|
||||||
|
async () => {
|
||||||
|
this.refresh();
|
||||||
|
}
|
||||||
|
),
|
||||||
|
commands.registerCommand(
|
||||||
|
"githubLocalActions.openWorkflow",
|
||||||
|
async (workflowTreeItem: WorkflowTreeItem) => {
|
||||||
|
try {
|
||||||
|
const document = await workspace.openTextDocument(
|
||||||
|
workflowTreeItem.workflow.uri
|
||||||
|
);
|
||||||
|
await window.showTextDocument(document);
|
||||||
|
} catch (error: any) {
|
||||||
|
try {
|
||||||
|
await workspace.fs.stat(workflowTreeItem.workflow.uri);
|
||||||
|
window.showErrorMessage(
|
||||||
|
`Failed to open workflow. Error: ${error}`
|
||||||
|
);
|
||||||
|
} catch (error: any) {
|
||||||
|
window.showErrorMessage(
|
||||||
|
`Workflow ${
|
||||||
|
path.parse(workflowTreeItem.workflow.uri.fsPath).base
|
||||||
|
} not found.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
commands.registerCommand(
|
||||||
|
"githubLocalActions.runWorkflow",
|
||||||
|
async (workflowTreeItem: WorkflowTreeItem) => {
|
||||||
|
if (workflowTreeItem) {
|
||||||
|
await act.runWorkflow(
|
||||||
|
workflowTreeItem.workspaceFolder,
|
||||||
|
workflowTreeItem.workflow
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let errorMessage: string | undefined;
|
||||||
|
|
||||||
async getChildren(element?: GithubLocalActionsTreeItem): Promise<GithubLocalActionsTreeItem[]> {
|
const activeTextEditor = window.activeTextEditor;
|
||||||
if (element) {
|
if (activeTextEditor) {
|
||||||
return element.getChildren();
|
const uri = activeTextEditor.document.uri;
|
||||||
} else {
|
const fileName = path.parse(uri.fsPath).base;
|
||||||
const items: GithubLocalActionsTreeItem[] = [];
|
const workflowsDirectory =
|
||||||
let noWorkflows: boolean = true;
|
WorkflowsManager.getWorkflowsDirectory();
|
||||||
|
if (
|
||||||
const workspaceFolders = workspace.workspaceFolders;
|
uri.path.match(
|
||||||
if (workspaceFolders) {
|
`.*/${workflowsDirectory}/.*\\.(${WorkflowsManager.yamlExtension}|${WorkflowsManager.ymlExtension})`
|
||||||
if (workspaceFolders.length === 1) {
|
)
|
||||||
items.push(...await new WorkspaceFolderWorkflowsTreeItem(workspaceFolders[0]).getChildren());
|
) {
|
||||||
|
const workspaceFolder = workspace.getWorkspaceFolder(uri);
|
||||||
const workflows = await act.workflowsManager.getWorkflows(workspaceFolders[0]);
|
if (workspaceFolder) {
|
||||||
if (workflows && workflows.length > 0) {
|
const workflows = await act.workflowsManager.getWorkflows(
|
||||||
noWorkflows = false;
|
workspaceFolder
|
||||||
}
|
);
|
||||||
} else if (workspaceFolders.length > 1) {
|
const workflow = workflows.find(
|
||||||
for (const workspaceFolder of workspaceFolders) {
|
(workflow) => workflow.uri.fsPath === uri.fsPath
|
||||||
items.push(new WorkspaceFolderWorkflowsTreeItem(workspaceFolder));
|
);
|
||||||
|
if (workflow) {
|
||||||
const workflows = await act.workflowsManager.getWorkflows(workspaceFolder);
|
await act.runWorkflow(workspaceFolder, workflow);
|
||||||
if (workflows && workflows.length > 0) {
|
} else {
|
||||||
noWorkflows = false;
|
errorMessage = `Workflow not found in workflow directory (${workflowsDirectory}).`;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
errorMessage = `${fileName} must be opened in a workspace folder to be executed locally.`;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
errorMessage = `${fileName} is not a workflow that can be executed locally.`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
errorMessage = "No workflow opened to execute locally.";
|
||||||
}
|
}
|
||||||
|
|
||||||
await commands.executeCommand('setContext', 'githubLocalActions:noWorkflows', noWorkflows);
|
if (errorMessage) {
|
||||||
return items;
|
window
|
||||||
|
.showErrorMessage(errorMessage, "View Workflows")
|
||||||
|
.then(async (value) => {
|
||||||
|
if (value === "View Workflows") {
|
||||||
|
await commands.executeCommand("workflows.focus");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
),
|
||||||
|
commands.registerCommand(
|
||||||
|
"githubLocalActions.runJob",
|
||||||
|
async (jobTreeItem: JobTreeItem) => {
|
||||||
|
await act.runJob(
|
||||||
|
jobTreeItem.workspaceFolder,
|
||||||
|
jobTreeItem.workflow,
|
||||||
|
jobTreeItem.job
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
commands.registerCommand(
|
||||||
|
"githubLocalActions.runWorkflowEvent",
|
||||||
|
async (workflowTreeItem: WorkflowTreeItem) => {
|
||||||
|
// Filter to only events that are registered on the workflow
|
||||||
|
const registeredEventsOnWorkflow = Object.keys(
|
||||||
|
workflowTreeItem.workflow.yaml.on
|
||||||
|
);
|
||||||
|
|
||||||
|
if (registeredEventsOnWorkflow.length === 0) {
|
||||||
|
window.showErrorMessage(
|
||||||
|
`No events registered on the workflow (${workflowTreeItem.workflow.name}). Add an event to the \`on\` section of the workflow to trigger it.`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const event = await window.showQuickPick(registeredEventsOnWorkflow, {
|
||||||
|
title: "Select the event to run",
|
||||||
|
placeHolder: "Event",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (event) {
|
||||||
|
await act.runEvent(
|
||||||
|
workflowTreeItem.workspaceFolder,
|
||||||
|
event as Event,
|
||||||
|
{ workflow: workflowTreeItem.workflow }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
commands.registerCommand(
|
||||||
|
"githubLocalActions.runJobEvent",
|
||||||
|
async (jobTreeItem: JobTreeItem) => {
|
||||||
|
// Filter to only events that are registered on the job's parent workflow
|
||||||
|
const registeredEventsOnJobParentWorkflow = Object.keys(
|
||||||
|
jobTreeItem.workflow.yaml.on
|
||||||
|
);
|
||||||
|
|
||||||
|
if (registeredEventsOnJobParentWorkflow.length === 0) {
|
||||||
|
window.showErrorMessage(
|
||||||
|
`No events registered on the workflow (${jobTreeItem.workflow.name}). Add an event to the \`on\` section of the workflow to trigger it.`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const event = await window.showQuickPick(
|
||||||
|
registeredEventsOnJobParentWorkflow,
|
||||||
|
{
|
||||||
|
title: "Select the event to run",
|
||||||
|
placeHolder: "Event",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (event) {
|
||||||
|
await act.runEvent(jobTreeItem.workspaceFolder, event as Event, {
|
||||||
|
workflow: jobTreeItem.workflow,
|
||||||
|
job: jobTreeItem.job,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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[] = [];
|
||||||
|
let noWorkflows: boolean = true;
|
||||||
|
|
||||||
|
const workspaceFolders = workspace.workspaceFolders;
|
||||||
|
if (workspaceFolders) {
|
||||||
|
if (workspaceFolders.length === 1) {
|
||||||
|
items.push(
|
||||||
|
...(await new WorkspaceFolderWorkflowsTreeItem(
|
||||||
|
workspaceFolders[0]
|
||||||
|
).getChildren())
|
||||||
|
);
|
||||||
|
|
||||||
|
const workflows = await act.workflowsManager.getWorkflows(
|
||||||
|
workspaceFolders[0]
|
||||||
|
);
|
||||||
|
if (workflows && workflows.length > 0) {
|
||||||
|
noWorkflows = false;
|
||||||
|
}
|
||||||
|
} else if (workspaceFolders.length > 1) {
|
||||||
|
for (const workspaceFolder of workspaceFolders) {
|
||||||
|
items.push(new WorkspaceFolderWorkflowsTreeItem(workspaceFolder));
|
||||||
|
|
||||||
|
const workflows = await act.workflowsManager.getWorkflows(
|
||||||
|
workspaceFolder
|
||||||
|
);
|
||||||
|
if (workflows && workflows.length > 0) {
|
||||||
|
noWorkflows = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await commands.executeCommand(
|
||||||
|
"setContext",
|
||||||
|
"githubLocalActions:noWorkflows",
|
||||||
|
noWorkflows
|
||||||
|
);
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,54 +2,81 @@ import * as fs from "fs/promises";
|
|||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
import { RelativePattern, Uri, workspace, WorkspaceFolder } from "vscode";
|
import { RelativePattern, Uri, workspace, WorkspaceFolder } from "vscode";
|
||||||
import * as yaml from "yaml";
|
import * as yaml from "yaml";
|
||||||
import { ConfigurationManager, Section } from "./configurationManager";
|
|
||||||
|
|
||||||
export interface Workflow {
|
export interface Workflow {
|
||||||
name: string,
|
name: string;
|
||||||
uri: Uri,
|
uri: Uri;
|
||||||
fileContent?: string,
|
fileContent?: string;
|
||||||
yaml?: any,
|
yaml?: any;
|
||||||
error?: string
|
error?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Job {
|
export interface Job {
|
||||||
name: string
|
name: string;
|
||||||
id: string
|
id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WorkflowsManager {
|
export class WorkflowsManager {
|
||||||
static defaultWorkflowsDirectory: string = '.github/workflows';
|
static defaultWorkflowsDirectory: string = ".github/workflows";
|
||||||
static yamlExtension: string = 'yaml';
|
static giteaWorkflowsDirectory: string = ".gitea/workflows";
|
||||||
static ymlExtension: string = 'yml';
|
static yamlExtension: string = "yaml";
|
||||||
|
static ymlExtension: string = "yml";
|
||||||
|
|
||||||
|
static getWorkflowsDirectories(): string[] {
|
||||||
|
const directories = [
|
||||||
|
WorkflowsManager.defaultWorkflowsDirectory,
|
||||||
|
WorkflowsManager.giteaWorkflowsDirectory,
|
||||||
|
];
|
||||||
|
return directories;
|
||||||
|
}
|
||||||
|
|
||||||
static getWorkflowsDirectory(): string {
|
static getWorkflowsDirectory(): string {
|
||||||
return ConfigurationManager.get<string>(Section.workflowsDirectory) || WorkflowsManager.defaultWorkflowsDirectory;
|
return WorkflowsManager.defaultWorkflowsDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getWorkflows(workspaceFolder: WorkspaceFolder): Promise<Workflow[]> {
|
async getWorkflows(workspaceFolder: WorkspaceFolder): Promise<Workflow[]> {
|
||||||
const workflows: Workflow[] = [];
|
const workflows: Workflow[] = [];
|
||||||
|
|
||||||
const workflowsDirectory = WorkflowsManager.getWorkflowsDirectory();
|
const workflowsDirectories = WorkflowsManager.getWorkflowsDirectories();
|
||||||
const workflowFileUris = await workspace.findFiles(new RelativePattern(workspaceFolder, `${workflowsDirectory}/*.{${WorkflowsManager.yamlExtension},${WorkflowsManager.ymlExtension}}`));
|
|
||||||
for await (const workflowFileUri of workflowFileUris) {
|
|
||||||
let yamlContent: any | undefined;
|
|
||||||
|
|
||||||
|
for (const workflowsDirectory of workflowsDirectories) {
|
||||||
try {
|
try {
|
||||||
const fileContent = await fs.readFile(workflowFileUri.fsPath, 'utf8');
|
const workflowFileUris = await workspace.findFiles(
|
||||||
yamlContent = yaml.parse(fileContent);
|
new RelativePattern(
|
||||||
|
workspaceFolder,
|
||||||
|
`${workflowsDirectory}/*.{${WorkflowsManager.yamlExtension},${WorkflowsManager.ymlExtension}}`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
workflows.push({
|
for await (const workflowFileUri of workflowFileUris) {
|
||||||
name: yamlContent.name || path.parse(workflowFileUri.fsPath).name,
|
let yamlContent: any | undefined;
|
||||||
uri: workflowFileUri,
|
|
||||||
fileContent: fileContent,
|
try {
|
||||||
yaml: yaml.parse(fileContent)
|
const fileContent = await fs.readFile(
|
||||||
});
|
workflowFileUri.fsPath,
|
||||||
} catch (error: any) {
|
"utf8"
|
||||||
workflows.push({
|
);
|
||||||
name: (yamlContent ? yamlContent.name : undefined) || path.parse(workflowFileUri.fsPath).name,
|
yamlContent = yaml.parse(fileContent);
|
||||||
uri: workflowFileUri,
|
|
||||||
error: 'Failed to parse workflow'
|
workflows.push({
|
||||||
});
|
name: yamlContent.name || path.parse(workflowFileUri.fsPath).name,
|
||||||
|
uri: workflowFileUri,
|
||||||
|
fileContent: fileContent,
|
||||||
|
yaml: yaml.parse(fileContent),
|
||||||
|
});
|
||||||
|
} catch (error: any) {
|
||||||
|
workflows.push({
|
||||||
|
name:
|
||||||
|
(yamlContent ? yamlContent.name : undefined) ||
|
||||||
|
path.parse(workflowFileUri.fsPath).name,
|
||||||
|
uri: workflowFileUri,
|
||||||
|
error: "Failed to parse workflow",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// Directory doesn't exist, skip it
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user