diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml index 66626481..807f05a5 100644 --- a/.github/workflows/coverage.yaml +++ b/.github/workflows/coverage.yaml @@ -54,11 +54,11 @@ jobs: - name: Coverage run: | set +e - xvfb-run --auto-servernum npm run ui-coverage + xvfb-run --auto-servernum npm run ui-test:coverage exit 0 - name: Upload Coverage Results uses: actions/upload-artifact@v4 if: always() with: - name: ui-coverage + name: ui-test-coverage path: ${{ github.workspace }}/coverage diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml new file mode 100644 index 00000000..eee852ab --- /dev/null +++ b/.github/workflows/deploy.yaml @@ -0,0 +1,96 @@ +name: Deploy to Kubernetes CI + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} + cancel-in-progress: true + +jobs: + deploy: + env: + CODE_VERSION: max + TEST_RESOURCES: test-resources + + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: 17 + distribution: "temurin" + + - name: Install JBang + run: | + curl -Ls https://sh.jbang.dev | bash -s - app setup + echo "$HOME/.jbang/bin" >> $GITHUB_PATH + - name: Setup JBang (trusted sources) + run: jbang trust add https://github.com/apache/ + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + + - name: Start Minikube + uses: medyagh/setup-minikube@latest + with: + driver: docker + addons: registry + + - name: Cluster info + run: | + kubectl cluster-info + kubectl get pods -n kube-system + echo "current-context:" $(kubectl config current-context) + echo "environment-kubeconfig:" ${KUBECONFIG} + + - name: Install + run: npm ci + + - name: Compile + run: npm run compile + + - name: UI Tests + run: | + eval $(minikube -p minikube docker-env) + xvfb-run --auto-servernum npm run ui-test:deploy + + - name: Upload Coverage Results + uses: actions/upload-artifact@v4 + if: always() + with: + name: ui-test-screenshots + path: test-resources/screenshots/*.png + + check: + if: always() + runs-on: ubuntu-latest + name: Status Check + needs: [ deploy ] + steps: + - name: Test Matrix Result + run: | + echo result = ${{ needs.deploy.result }} + - name: Status Check - success + if: ${{ needs.deploy.result == 'success' }} + run: | + echo "All tests successfully completed!" + exit 0 + - name: Status Check - failure + if: ${{ needs.deploy.result != 'success' }} + run: | + echo "Status Check failed!" + exit 1 \ No newline at end of file diff --git a/.gitignore b/.gitignore index 922e0d3f..b37426df 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ node_modules *.vsix jars/camel-dap-server.jar test-resources -.camel-jbang +.camel-jbang* .test-extensions *sbom.json coverage diff --git a/CHANGELOG.md b/CHANGELOG.md index c4ab2e68..53242e08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to the "vscode-debug-adapter-apache-camel" extension will be ## 1.4.0 - Update default Camel version used for Camel JBang from 4.7.0 to 4.8.1 +- Provide command for a deployment of Camel standalone file using Camel JBang Kubernetes plugin. It is available for Camel JBang version 4.8+. ## 1.3.0 diff --git a/README.md b/README.md index b082e34c..27b34b58 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,11 @@ This is the Visual Studio Code exte - Supports adding extra parameters provided by the `Run with JBang *` commands. (For both running and debugging the application) - Configuration snippets for Camel debugger launch configuration - Configuration snippets to launch Camel application ready to accept a Camel debugger connection using JBang, Maven with Camel maven plugin or Quarkus Devs +- Deploy Integration (standalone Camel file) with [Apache Camel Kubernetes](https://camel.apache.org/manual/camel-jbang-kubernetes.html) plugin. + - It allows **one-click deployment into OpenShift** by default + - to see logs or delete deployment see [Manage deployment lifecycle](./docs/content/kubernetes-deploy.md#manage-deployment-lifecycle) + - requires Camel JBang 4.8+ + - for deployment into Kubernetes cluster see [how to deploy into local Kubernetes cluster](./docs/content/kubernetes-deploy.md#how-to-deploy-into-local-kubernetes-cluster) ### Requirements @@ -92,7 +97,7 @@ Something is not working properly? In that case, feel free to [open issues, add ### Get Involved -If you'd like to help us get better, we appriciate it! Check out our [Contribution Guide](Contributing.md) on how to do that. +If you'd like to help us get better, we appreciate it! Check out our [Contribution Guide](Contributing.md) on how to do that. ### Data and Telemetry diff --git a/docs/content/kubernetes-deploy.md b/docs/content/kubernetes-deploy.md new file mode 100644 index 00000000..ee88ddb0 --- /dev/null +++ b/docs/content/kubernetes-deploy.md @@ -0,0 +1,52 @@ +# Deployment into cluster using Camel JBang Kubernetes plugin + +## Manage deployment lifecycle + +There are extensions which allows you to manage your deployments (which are part of an [Extension Pack for Apache Camel](https://marketplace.visualstudio.com/items?itemName=redhat.apache-camel-extension-pack)): + +- [OpenShift Toolkit](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-openshift-connector) +- [Kubernetes](https://marketplace.visualstudio.com/items?itemName=ms-kubernetes-tools.vscode-kubernetes-tools) + +or you can use a power of Camel CLI described below. + +### Follow logs + +You can use Camel CLI to obtain logs of current running integration. In terminal window execute: + +```shell +jbang camel@apache/camel kubernetes logs --name= +``` + +### Remove deployment + +To remove current integration, you can use also Camel CLI. In this case the command is: + +```shell +jbang camel@apache/camel kubernetes delete --name= +``` + +#### Troubleshooting + +For a latest releases of Camel (4.8.1+) there could be problem when deleting deployments using Camel Jbang CLI, for details you can see reported upstream issue [CAMEL-21388](https://issues.apache.org/jira/browse/CAMEL-21388). + +In that case please try with previous version which was working better. + +```shell +jbang -Dcamel.jbang.version=4.8.0 camel@apache/camel kubernetes delete --name= +``` + +## How to deploy into local Kubernetes cluster + +By default, the deployment aims OpenShift cluster. In case you need to deploy into Kubernetes, there is a small modification needed: + +1) open Settings UI in VS Code + - Linux/Windows - `File > Preferences > Settings` + - macOS - `Code > Settings... > Settings` +2) navigate to `Extensions > Debug Adapter for Apache Camel` +3) modify setting `Camel > Debug Adapter: Kubernetes Run Parameters` as you can see on picture below + +![Deploy to Kubernetes cluster with Minikube](../images/kubernetes-run-params.png) + +The picture describes how to deploy to local Kubernetes cluster using Minikube. You can use eg. also `Kind`. In that case, just change to `--cluster-type=kind`. + +For more information see [Camel Kubernetes plugin official documentation](https://camel.apache.org/manual/camel-jbang-kubernetes.html). diff --git a/docs/images/kubernetes-run-params.png b/docs/images/kubernetes-run-params.png new file mode 100644 index 00000000..994605e9 Binary files /dev/null and b/docs/images/kubernetes-run-params.png differ diff --git a/docs/index.md b/docs/index.md index 04212e91..5d7e549c 100644 --- a/docs/index.md +++ b/docs/index.md @@ -51,6 +51,11 @@ This extension adds Came - JBang - or Maven with Camel maven plugin - or Quarkus Devs +- Deploy Integration (standalone Camel file) with [Apache Camel Kubernetes](https://camel.apache.org/manual/camel-jbang-kubernetes.html) plugin. + - It allows **one-click deployment into OpenShift** by default + - to see logs or delete deployment see [Manage deployment lifecycle](./content/kubernetes-deploy.md#manage-deployment-lifecycle) + - requires Camel JBang 4.8+ + - for deployment into Kubernetes cluster see [how to deploy into local Kubernetes cluster](./content/kubernetes-deploy.md#how-to-deploy-into-local-kubernetes-cluster) ### Advanced diff --git a/package.json b/package.json index ca9c7418..4e573a99 100644 --- a/package.json +++ b/package.json @@ -111,6 +111,18 @@ "default": [ "--local-kamelet-dir=." ] + }, + "camel.debugAdapter.KubernetesRunParameters": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + }, + "additionalProperties": false, + "markdownDescription": "User defined parameters to be applied at every deploy (See [Camel JBang Kubernetes](https://camel.apache.org/manual/camel-jbang-kubernetes.html)). In case of spaces, the values needs to be enclosed with quotes. Default value is `[\"--cluster-type=openshift\"]`\n\n**Note**: Excluding `--camel-version` which is already being set in `#camel.debugAdapter.CamelVersion#`.\n\nFor more possible values see: `camel kubernetes run --help` or `jbang camel@apache/camel kubernetes run --help`", + "default": [ + "--cluster-type=openshift" + ] } } }, @@ -247,6 +259,11 @@ "title": "Run with JBang All Camel Integrations from containing folder", "icon": "$(camel-run)", "enablement": "resourceFilename =~ /\\.(java|xml|yaml)$/" + }, + { + "command": "apache.camel.kubernetes.deploy", + "title": "Deploy Integration with Apache Camel Kubernetes Run", + "icon": "$(rocket)" } ], "menus": { @@ -293,6 +310,13 @@ "when": "resourceFilename =~ /\\.(java|xml|yaml)$/", "group": "3_camelrun@3" } + ], + "editor/title": [ + { + "command": "apache.camel.kubernetes.deploy", + "when": "resourceFilename =~ /\\.(java|xml|yaml)$/", + "group": "navigation" + } ] } }, @@ -306,7 +330,8 @@ "lint": "eslint src", "test": "node ./out/test/runTest.js", "ui-test": "node ./out/ui-test/uitest_runner.js", - "ui-coverage": "npm run ui-test -- coverage" + "ui-test:deploy": "npm run ui-test -- deploy", + "ui-test:coverage": "npm run ui-test -- coverage" }, "devDependencies": { "@stylistic/eslint-plugin": "^2.9.0", diff --git a/src/extension.ts b/src/extension.ts index bc85b7d0..33e869fc 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -20,6 +20,7 @@ import { getRedHatService, TelemetryEvent, TelemetryService } from "@redhat-deve import { CamelApplicationLauncherTasksCompletionItemProvider } from './completion/CamelApplicationLauncherTasksCompletionItemProvider'; import { CamelJBangTaskProvider } from './task/CamelJBangTaskProvider'; import { CamelJBangCodelens } from './codelenses/CamelJBangCodelens'; +import { execSync } from 'child_process'; let telemetryService: TelemetryService; @@ -30,6 +31,7 @@ export const CAMEL_RUN_AND_DEBUG_WITH_JBANG_ROOT_COMMAND_ID = 'apache.camel.debu export const CAMEL_RUN_WITH_JBANG_ROOT_COMMAND_ID = 'apache.camel.run.jbang.all.root'; export const CAMEL_RUN_AND_DEBUG_WITH_JBANG_CONTAININGFOLDER_COMMAND_ID = 'apache.camel.debug.jbang.all.containingfolder'; export const CAMEL_RUN_WITH_JBANG_CONTAININGFOLDER_COMMAND_ID = 'apache.camel.run.jbang.all.containingfolder'; +export const CAMEL_JBANG_KUBERNETES_DEPLOY_COMMAND_ID = 'apache.camel.kubernetes.deploy'; export const WORKSPACE_WARNING_MESSAGE = `The action requires an opened folder/workspace to complete successfully.`; export async function activate(context: vscode.ExtensionContext) { @@ -53,6 +55,19 @@ export async function activate(context: vscode.ExtensionContext) { registerRunCommand(CAMEL_RUN_WITH_JBANG_ROOT_COMMAND_ID, CamelJBangTaskProvider.labelProvidedRunAllTask, taskProvider); registerRunCommand(CAMEL_RUN_WITH_JBANG_CONTAININGFOLDER_COMMAND_ID, CamelJBangTaskProvider.labelProvidedRunAllFromContainingFolderTask, taskProvider); + vscode.commands.registerCommand(CAMEL_JBANG_KUBERNETES_DEPLOY_COMMAND_ID, async function () { + const camelAddKubernetesPluginTask = taskProvider.createTask(CamelJBangTaskProvider.labelAddKubernetesPluginTask); + if (camelAddKubernetesPluginTask && !(await isCamelPluginInstalled('kubernetes'))) { + await vscode.tasks.executeTask(camelAddKubernetesPluginTask); + await taskProvider.waitForTaskEnd(CamelJBangTaskProvider.labelAddKubernetesPluginTask); + } + const camelDeployTask = taskProvider.createTask(CamelJBangTaskProvider.labelProvidedDeployTask); + if (camelDeployTask) { + await vscode.tasks.executeTask(camelDeployTask); + await sendCommandTrackingEvent(telemetryService, CAMEL_JBANG_KUBERNETES_DEPLOY_COMMAND_ID); + } + }); + vscode.debug.registerDebugAdapterTrackerFactory(CAMEL_DEBUG_ADAPTER_ID, { createDebugAdapterTracker(_session: vscode.DebugSession) { return { @@ -80,7 +95,7 @@ export async function activate(context: vscode.ExtensionContext) { vscode.languages.registerCodeLensProvider(docSelector, new CamelJBangCodelens()); } -function registerDebugCommand(commandId :string, taskLabel :string) { +function registerDebugCommand(commandId: string, taskLabel: string) { vscode.commands.registerCommand(commandId, async (uri: vscode.Uri) => { if (!vscode.workspace.workspaceFolders) { await vscode.window.showWarningMessage(WORKSPACE_WARNING_MESSAGE); @@ -100,7 +115,7 @@ function registerDebugCommand(commandId :string, taskLabel :string) { }); } -function registerRunCommand(commandId :string, taskLabel :string, taskProvider :CamelJBangTaskProvider) { +function registerRunCommand(commandId: string, taskLabel: string, taskProvider: CamelJBangTaskProvider) { vscode.commands.registerCommand(commandId, async function () { if (!vscode.workspace.workspaceFolders) { await vscode.window.showWarningMessage(WORKSPACE_WARNING_MESSAGE); @@ -128,3 +143,19 @@ async function sendCommandTrackingEvent(telemetryService: TelemetryService, comm }; await telemetryService.send(telemetryEvent); } + +async function isCamelPluginInstalled(plugin: string): Promise { + let output = ''; + // it takes always few seconds to compute after click on deploy button + // - can be confusing for user without any UI feedback, it looks like nothing is happening after click on a button.. + await vscode.window.withProgress({ + location: vscode.ProgressLocation.Window, + cancellable: false, + title: 'Checking Camel JBang Kubernetes plugin...' + }, async (progress) => { + progress.report({ increment: 0 }); + output = execSync('jbang camel@apache/camel plugin get', { stdio: 'pipe' }).toString(); + progress.report({ increment: 100 }); + }); + return output.includes(plugin); +} diff --git a/src/task/CamelJBangTaskProvider.ts b/src/task/CamelJBangTaskProvider.ts index 0ed04452..989aadad 100644 --- a/src/task/CamelJBangTaskProvider.ts +++ b/src/task/CamelJBangTaskProvider.ts @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { CancellationToken, ProviderResult, ShellExecution, ShellExecutionOptions, ShellQuoting, Task, TaskDefinition, TaskProvider, TaskRevealKind, TaskScope, workspace } from 'vscode'; +import { CancellationToken, ProviderResult, ShellExecution, ShellExecutionOptions, ShellQuoting, Task, TaskDefinition, TaskProvider, TaskRevealKind, tasks, TaskScope, workspace } from 'vscode'; export class CamelJBangTaskProvider implements TaskProvider { @@ -24,6 +24,8 @@ export class CamelJBangTaskProvider implements TaskProvider { public static readonly labelProvidedRunAllTask: string = "Run with JBang All Camel Applications"; public static readonly labelProvidedRunAllFromContainingFolderWithDebugActivatedTask: string = "Start All Camel applications from containing folder with debug enabled with JBang"; public static readonly labelProvidedRunAllFromContainingFolderTask: string = "Run with JBang All Camel Applications from containing folder"; + public static readonly labelProvidedDeployTask: string = "Deploy Integration with Apache Camel Kubernetes Run"; + public static readonly labelAddKubernetesPluginTask: string = "Camel JBang add Kubernetes plugin"; provideTasks(_token: CancellationToken): ProviderResult { const tasks: Task[] = []; @@ -34,10 +36,12 @@ export class CamelJBangTaskProvider implements TaskProvider { tasks.push(this.createTask(CamelJBangTaskProvider.labelProvidedRunAllTask)); tasks.push(this.createTask(CamelJBangTaskProvider.labelProvidedRunAllFromContainingFolderWithDebugActivatedTask)); tasks.push(this.createTask(CamelJBangTaskProvider.labelProvidedRunAllFromContainingFolderTask)); + tasks.push(this.createTask(CamelJBangTaskProvider.labelProvidedDeployTask)); + tasks.push(this.createTask(CamelJBangTaskProvider.labelAddKubernetesPluginTask)); return tasks; } - createTask(taskLabel: string) :Task{ + createTask(taskLabel: string): Task { switch (taskLabel) { case CamelJBangTaskProvider.labelProvidedRunWithDebugActivatedTask: return this.createRunWithDebugTask(CamelJBangTaskProvider.labelProvidedRunWithDebugActivatedTask, '${relativeFile}', undefined); @@ -51,13 +55,87 @@ export class CamelJBangTaskProvider implements TaskProvider { return this.createRunWithDebugTask(CamelJBangTaskProvider.labelProvidedRunAllFromContainingFolderWithDebugActivatedTask, '*','${fileDirname}'); case CamelJBangTaskProvider.labelProvidedRunAllFromContainingFolderTask: return this.createRunTask(CamelJBangTaskProvider.labelProvidedRunAllFromContainingFolderTask, '*', '${fileDirname}'); + case CamelJBangTaskProvider.labelProvidedDeployTask: + return this.createDeployTask(CamelJBangTaskProvider.labelProvidedDeployTask, '${relativeFile}', undefined); + case CamelJBangTaskProvider.labelAddKubernetesPluginTask: + return this.createAddKubernetesPluginTask('kubernetes', CamelJBangTaskProvider.labelAddKubernetesPluginTask); default: break; } throw new Error('Method not implemented.'); } - private createRunTask(taskLabel :string, patternForCamelFiles :string, cwd :string | undefined) { + private createDeployTask(taskLabel: string, patternForCamelFiles: string, cwd: string | undefined) { + const shellExecOptions: ShellExecutionOptions = { + cwd: cwd + }; + const deployTask = new Task( + { + "label": taskLabel, + "type": "shell" + }, + TaskScope.Workspace, + taskLabel, + 'camel', + new ShellExecution( + 'jbang', + [ + { + "value": `-Dcamel.jbang.version=${this.getCamelJBangCLIVersion()}`, + "quoting": ShellQuoting.Strong + }, + 'camel@apache/camel', + 'kubernetes', + 'run', + patternForCamelFiles, + this.getCamelVersion(), + ...this.getKubernetesExtraParameters() + ].filter(function (arg) { return arg; }), // remove ALL empty values ("", null, undefined and 0) + shellExecOptions + ) + ); + deployTask.isBackground = true; + return deployTask; + } + + private createAddKubernetesPluginTask(plugin: string, taskLabel: string) { + const addPluginTask = new Task( + { + "label": taskLabel, + "type": "shell" + }, + TaskScope.Workspace, + taskLabel, + 'camel', + new ShellExecution( + 'jbang', + [ + { + "value": `-Dcamel.jbang.version=${this.getCamelJBangCLIVersion()}`, + "quoting": ShellQuoting.Strong + }, + 'camel@apache/camel', + 'plugin', + 'add', + plugin + ] + ) + ); + return addPluginTask; + } + + async waitForTaskEnd(label: string): Promise { + await new Promise(resolve => { + const disposable = tasks.onDidEndTask((e) => { + if (e.execution.task.name === label) { + disposable.dispose(); + resolve(); + } + }); + }); + } + + private createRunTask(taskLabel: string, patternForCamelFiles: string, cwd: string | undefined) { const shellExecOptions: ShellExecutionOptions = { cwd: cwd }; @@ -92,7 +170,7 @@ export class CamelJBangTaskProvider implements TaskProvider { return runTask; } - private createRunWithDebugTask(taskLabel :string, patternForCamelFiles :string, cwd : string | undefined) { + private createRunWithDebugTask(taskLabel: string, patternForCamelFiles: string, cwd: string | undefined) { console.log(`cwd : ${cwd}`); const taskDefinition: TaskDefinition = { "label": taskLabel, @@ -189,4 +267,13 @@ export class CamelJBangTaskProvider implements TaskProvider { return []; } } + + private getKubernetesExtraParameters(): string[] { + const extraParameters = workspace.getConfiguration().get('camel.debugAdapter.KubernetesRunParameters') as string[]; + if (extraParameters) { + return extraParameters; + } else { + return []; + } + } } diff --git a/src/ui-test/resources/vscode-settings.json b/src/ui-test/resources/vscode-settings.json index dbd670d9..2c5e1b00 100644 --- a/src/ui-test/resources/vscode-settings.json +++ b/src/ui-test/resources/vscode-settings.json @@ -14,5 +14,9 @@ "window.title": "${dirty}${activeEditorLong}${separator}${rootPath}${separator}${appName}", "redhat.telemetry.enabled": false, "terminal.integrated.sendKeybindingsToShell": true, - "git.autoRepositoryDetection": false + "git.autoRepositoryDetection": false, + "camel.debugAdapter.KubernetesRunParameters": [ + "--cluster-type=minikube", + "--build-property=quarkus.kubernetes.image-pull-policy=Never" + ] } diff --git a/src/ui-test/tests/camel.settings.test.ts b/src/ui-test/tests/camel.settings.test.ts index cdd8931a..7aa0ed1e 100644 --- a/src/ui-test/tests/camel.settings.test.ts +++ b/src/ui-test/tests/camel.settings.test.ts @@ -132,7 +132,7 @@ describe('Camel User Settings', function () { it('Should add another parameter', async function () { this.timeout(20000); - const arraySetting = await (await new Workbench().openSettings()).findSetting('Extra Launch Parameter', 'Camel', 'Debug Adapter') as ArraySetting; + const arraySetting = await (await new Workbench().openSettings()).findSettingByID("camel.debugAdapter.ExtraLaunchParameter") as ArraySetting; const add1 = await arraySetting.add(); await add1.setValue(newParameter); await add1.ok(); @@ -156,7 +156,7 @@ describe('Camel User Settings', function () { it('Should remove parameter', async function () { this.timeout(15000); - const arraySetting = await (await new Workbench().openSettings()).findSetting('Extra Launch Parameter', 'Camel', 'Debug Adapter') as ArraySetting; + const arraySetting = await (await new Workbench().openSettings()).findSettingByID("camel.debugAdapter.ExtraLaunchParameter") as ArraySetting; const toRemove = await arraySetting.getItem(newParameter); await toRemove?.remove(); await waitUntilItemNotExists(newParameter, arraySetting); diff --git a/src/ui-test/tests/deploy.kubernetes.run.test.ts b/src/ui-test/tests/deploy.kubernetes.run.test.ts new file mode 100644 index 00000000..8048c04e --- /dev/null +++ b/src/ui-test/tests/deploy.kubernetes.run.test.ts @@ -0,0 +1,91 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License", destination); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { resolve } from 'node:path'; +import { CAMEL_ROUTE_YAML_WITH_SPACE } from '../variables'; +import { + ActivityBar, + after, + before, + BottomBarPanel, + EditorAction, + EditorView, + repeat, + SideBarView, + VSBrowser, + Workbench, +} from 'vscode-uitests-tooling'; +import { killTerminal, waitUntilTerminalHasText } from '../utils'; +import { execSync } from 'child_process'; + +describe('Camel standalone file deployment using Camel JBang Kubernetes Run', function () { + this.timeout(180_000); + + let editorView: EditorView; + let jbangVersion: string; + const RESOURCES_PATH: string = resolve('src', 'ui-test', 'resources'); + + before(async function () { + jbangVersion = await getJBangVersion(); + await VSBrowser.instance.openResources(RESOURCES_PATH); + await (await new ActivityBar().getViewControl('Explorer')).openView(); + const section = await new SideBarView().getContent().getSection('resources'); + await section.openItem(CAMEL_ROUTE_YAML_WITH_SPACE); + + editorView = new EditorView(); + await repeat(async function () { + return (await editorView.getOpenEditorTitles()).find(title => title === CAMEL_ROUTE_YAML_WITH_SPACE); + }, { + timeout: 10_000, + message: `The test file ${CAMEL_ROUTE_YAML_WITH_SPACE} was not opened` + }); + }); + + after(async function () { + await killTerminal(); + await editorView.closeAllEditors(); + // remove deployed integration from a local cluster + execSync(`jbang -Dcamel.jbang.version=${jbangVersion} camel@apache/camel kubernetes delete --name=demoroute`, { stdio: 'inherit', cwd: RESOURCES_PATH }); + }); + + it('Deploy integration to Kubernetes (Minikube)', async function () { + const action = (await editorView.getAction('Deploy Integration with Apache Camel Kubernetes Run')) as EditorAction; + await action.click(); + + // using some additional steps for CAMEL 4.9.0-SNAPSHOT / 4.8.1 version + // because the '--dev' parameter is not working for a deployment to Kubernetes + await waitUntilTerminalHasText(action.getDriver(), ['BUILD SUCCESS'], 3_000, 120_000); + await killTerminal(); + + const terminalView = await new BottomBarPanel().openTerminalView(); + await terminalView.getDriver().wait(async () => { + const found = (await terminalView.getText()).match(/[A-Za-z]/g); + return found; + }, 10_000, 'New terminal shell was not opened properly.', 2_000); + // skip 'await' for async function to allow continue test after terminal command execution which would be blocking thread for infinity + // eslint-disable-next-line @typescript-eslint/no-floating-promises + terminalView.executeCommand(`jbang -Dcamel.jbang.version=${jbangVersion} camel@apache/camel kubernetes logs --name=demoroute`); + await waitUntilTerminalHasText(action.getDriver(), ['Hello Camel from'], 3_000, 120_000); + }); + + async function getJBangVersion(): Promise { + const textField = await (await new Workbench().openSettings()).findSetting('JBang Version', 'Camel', 'Debug Adapter'); + const value = await textField.getValue() as string; + await new EditorView().closeEditor('Settings'); + return value; + } + +}); diff --git a/src/ui-test/uitest_runner.ts b/src/ui-test/uitest_runner.ts index f8b3a797..ce3dd9a8 100644 --- a/src/ui-test/uitest_runner.ts +++ b/src/ui-test/uitest_runner.ts @@ -26,15 +26,18 @@ const releaseType: ReleaseQuality = process.env.CODE_TYPE === 'insider' ? Releas export const projectPath = path.resolve(__dirname, '..', '..'); const extensionFolder = variables.EXTENSION_DIR; const coverage = process.argv[2] === 'coverage'; +const deploy = process.argv[2] === 'deploy'; async function main(): Promise { const tester = new ExTester(storageFolder, releaseType, extensionFolder, coverage); + const tests = deploy ? 'out/ui-test/tests/deploy*.test.js' : [ + 'out/ui-test/env/set.camel.version.js', + 'out/ui-test/tests/!(deploy)*.test.js', // run everything, except deployment tests + 'out/ui-test/env/check.camel.version.js' + ]; + await tester.setupAndRunTests( - [ - 'out/ui-test/env/set.camel.version.js', - 'out/ui-test/tests/*.test.js', - 'out/ui-test/env/check.camel.version.js' - ], + tests, process.env.CODE_VERSION, { 'installDependencies': true