diff --git a/package.json b/package.json index 71ef677dd..5a3bf542d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "activationEvents": [ "onLanguage:yaml", + "onLanguage:yml", "workspaceContains:tox-ansible.ini", "onWebviewPanel:ansible-home" ], @@ -444,6 +445,10 @@ { "command": "ansible.open-language-server-logs", "title": "Ansible: Open Language Server Logs" + }, + { + "command": "extension.buildExecutionEnvironment", + "title": "Build Ansible execution environment" } ], "configuration": [ @@ -795,6 +800,11 @@ "group": "2_main@1", "command": "ansible.lightspeed.playbookExplanation", "when": "redhat.ansible.lightspeedSuggestionsEnabled && editorLangId == ansible" + }, + { + "when": "resourceFilename == 'execution-environment.yml' || resourceFilename == 'execution-environment.yaml'", + "command": "extension.buildExecutionEnvironment", + "group": "navigation" } ], "explorer/context": [ @@ -802,6 +812,11 @@ "group": "2_main@1", "submenu": "ansible.playbook.run", "when": "isFileSystemResource && resourceLangId == ansible" + }, + { + "when": "resourceFilename == 'execution-environment.yml' || resourceFilename == 'execution-environment.yaml'", + "command": "extension.buildExecutionEnvironment", + "group": "navigation" } ], "view/title": [ diff --git a/src/extension.ts b/src/extension.ts index 2210b7ebe..7005770f9 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -75,6 +75,7 @@ import { PlaybookFeedbackEvent } from "./interfaces/lightspeed"; import { CreateDevfile } from "./features/contentCreator/createDevfilePage"; import { CreateSampleExecutionEnv } from "./features/contentCreator/createSampleExecutionEnvPage"; import { CreateDevcontainer } from "./features/contentCreator/createDevcontainerPage"; +import { rightClickEEBuildCommand } from "./features/utils/buildExecutionEnvironment"; export let client: LanguageClient; export let lightSpeedManager: LightSpeedManager; @@ -168,6 +169,10 @@ export async function activate(context: ExtensionContext): Promise { vscode.commands.executeCommand("setContext", "lightspeedConnectReady", true); + const eeBuilderCommand = rightClickEEBuildCommand( + "extension.buildExecutionEnvironment", + ); + context.subscriptions.push( vscode.commands.registerCommand( LightSpeedCommands.LIGHTSPEED_STATUS_BAR_CLICK, @@ -827,6 +832,7 @@ export async function activate(context: ExtensionContext): Promise { lsOutputChannel.show(); }), ); + context.subscriptions.push(eeBuilderCommand); } const startClient = async ( diff --git a/src/features/utils/buildExecutionEnvironment.ts b/src/features/utils/buildExecutionEnvironment.ts new file mode 100644 index 000000000..04c6faa11 --- /dev/null +++ b/src/features/utils/buildExecutionEnvironment.ts @@ -0,0 +1,70 @@ +import * as vscode from "vscode"; +import * as path from "path"; +import { withInterpreter } from "../utils/commandRunner"; +import { SettingsManager } from "../../settings"; +import { runCommand } from "../contentCreator/utils"; + +export function rightClickEEBuildCommand(commandId: string): vscode.Disposable { + return vscode.commands.registerCommand(commandId, async (uri: vscode.Uri) => { + if (!uri?.fsPath) { + const getFileFromEditor = vscode.window.activeTextEditor; + if (!getFileFromEditor) { + vscode.window.showErrorMessage( + "No file selected and no active file found!", + ); + return; + } + const filePath = getFileFromEditor.document.uri.fsPath; + if ( + !filePath.endsWith("execution-environment.yml") && + !filePath.endsWith("execution-environment.yaml") + ) { + vscode.window.showErrorMessage( + "Active file is not an execution environment file!", + ); + return; + } + uri = getFileFromEditor.document.uri; + } + + const filePath = uri.fsPath; + const dirPath = path.dirname(filePath); + + const builderCommand = `ansible-builder build -f ${filePath} -c ${dirPath}/context`; + + vscode.window.showInformationMessage(`Running: ${builderCommand}`); + + if (!dirPath) { + vscode.window.showErrorMessage("Could not determine workspace folder."); + return; + } + + try { + const extSettings = new SettingsManager(); + await extSettings.initialize(); + + const { command, env } = withInterpreter( + extSettings.settings, + builderCommand, + "", + ); + + const result = await runCommand(command, env); + + if (result.status === "failed") { + vscode.window.showErrorMessage( + `Build failed with status ${result.status}: \n${result.output.trim()}`, + ); + return; + } + + vscode.window.showInformationMessage( + `Build successful:\n${result.output.trim()}`, + ); + } catch (error) { + vscode.window.showErrorMessage( + `Unexpected error: ${(error as Error).message}`, + ); + } + }); +} diff --git a/test/ui-test/contentCreatorUiTest.ts b/test/ui-test/contentCreatorUiTest.ts index 54c2c5cf2..764bd2354 100644 --- a/test/ui-test/contentCreatorUiTest.ts +++ b/test/ui-test/contentCreatorUiTest.ts @@ -1,4 +1,10 @@ -import { By, EditorView, WebElement } from "vscode-extension-tester"; +import { + By, + EditorView, + WebElement, + Workbench, + InputBox, +} from "vscode-extension-tester"; import { getWebviewByLocator, sleep, @@ -180,6 +186,51 @@ describe("Test Ansible sample execution environment file scaffolding", () => { "Create Sample Ansible Execution Environment", ); }); + + it("Executes the build command from the right-click menu", async function () { + const workbench = new Workbench(); + + await workbenchExecuteCommand("Build Ansible execution environment"); + let notifications = await workbench.getNotifications(); + const errorNotification = notifications.find(async (notification) => { + return (await notification.getMessage()).includes( + "No file selected and no active file found!", + ); + }); + if (!errorNotification) throw new Error("Notification not found"); + + await workbenchExecuteCommand("File: New Untitled Text file"); + await workbenchExecuteCommand("Build Ansible execution environment"); + notifications = await workbench.getNotifications(); + const fileTypeError = notifications.find(async (notification) => { + return (await notification.getMessage()).includes( + "Active file is not an execution environment file!", + ); + }); + if (!fileTypeError) throw new Error("Notification not found"); + + await workbenchExecuteCommand("Go to File..."); + const inputBox = await InputBox.create(); + await inputBox.setText( + path.join(os.homedir(), "execution-environment.yml"), + ); + await inputBox.confirm(); + await workbenchExecuteCommand("Build Ansible execution environment"); + + await new Promise((resolve) => setTimeout(resolve, 3000)); + notifications = await workbench.getNotifications(); + const buildResultNotification = notifications.find(async (notification) => { + const message = await notification.getMessage(); + return ( + message.includes("Build successful") || message.includes("Build failed") + ); + }); + if (!buildResultNotification) throw new Error("Notification not found"); + + expect(await buildResultNotification.getMessage()).to.match( + /^Build (successful|failed)/, + ); + }); }); describe("Test collection plugins scaffolding", () => {