From b71464ad0252ee33fa75a4997b663b37e0db4426 Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Wed, 10 Sep 2025 16:48:39 -0400 Subject: [PATCH 01/46] Initialize container docs --- .../vs-code-designer/src/container/Dockerfile | 1 + .../src/container/devcontainer.json | 55 +++++++++++++++++++ .../src/container/docker-compose.yml | 14 +++++ 3 files changed, 70 insertions(+) create mode 100644 apps/vs-code-designer/src/container/Dockerfile create mode 100644 apps/vs-code-designer/src/container/devcontainer.json create mode 100644 apps/vs-code-designer/src/container/docker-compose.yml diff --git a/apps/vs-code-designer/src/container/Dockerfile b/apps/vs-code-designer/src/container/Dockerfile new file mode 100644 index 00000000000..05ac6273594 --- /dev/null +++ b/apps/vs-code-designer/src/container/Dockerfile @@ -0,0 +1 @@ +FROM mcr.microsoft.com/devcontainers/javascript-node:1-22-bookworm \ No newline at end of file diff --git a/apps/vs-code-designer/src/container/devcontainer.json b/apps/vs-code-designer/src/container/devcontainer.json new file mode 100644 index 00000000000..b134518b078 --- /dev/null +++ b/apps/vs-code-designer/src/container/devcontainer.json @@ -0,0 +1,55 @@ +{ + "name": "Logic Apps Standard Development", + "dockerComposeFile": "docker-compose.yml", + "service": "app", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + "features": { + "ghcr.io/devcontainers/features/azure-cli:1": { + "version": "latest" + }, + "ghcr.io/devcontainers/features/dotnet:2": { + "version": "8.0", + "additionalVersions": "6.0", + "installUsingApt": true, + "globalTools": "" + }, + "ghcr.io/jlaundry/devcontainer-features/azure-functions-core-tools:1": { + "version": "4" + }, + "ghcr.io/devcontainers/features/powershell:1": { + "version": "latest", + "modules": "Az" + }, + "ghcr.io/devcontainers/features/java:1": { + "version": "17", + "jdkDistro": "ms", + "gradleVersion": "latest", + "mavenVersion": "latest", + "installAnt": false + } + }, + "customizations": { + "vscode": { + "extensions": [ + "ms-azuretools.vscode-azurelogicapps", + "ms-azuretools.vscode-azurefunctions", + "ms-azuretools.vscode-docker", + "azurite.azurite", + "ms-azuretools.vscode-azureresourcegroups", + "ms-dotnettools.csharp", + "ms-dotnettools.csdevkit" + ], + "settings": { + "terminal.integrated.defaultProfile.linux": "bash", + "files.exclude": { + "**/bin": true, + "**/obj": true + } + } + } + }, + + "otherPortsAttributes": { + "onAutoForward": "silent" + } +} diff --git a/apps/vs-code-designer/src/container/docker-compose.yml b/apps/vs-code-designer/src/container/docker-compose.yml new file mode 100644 index 00000000000..2c23cdcc078 --- /dev/null +++ b/apps/vs-code-designer/src/container/docker-compose.yml @@ -0,0 +1,14 @@ +services: + app: + build: + context: . + dockerfile: Dockerfile + platform: linux/amd64 + volumes: + - ../..:/workspaces:cached + command: sleep infinity + network_mode: service:azurite + + azurite: + image: mcr.microsoft.com/azure-storage/azurite + restart: unless-stopped From 93c78c2329602a44641d0d612d7ad034ffb5f5d4 Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Wed, 10 Sep 2025 19:19:42 -0400 Subject: [PATCH 02/46] Remove unused files --- .../resetValidateAndInstallBinaries.ts | 73 --- .../binaries/validateAndInstallBinaries.ts | 122 ----- .../initCustomCodeProjectStep.ts | 6 +- .../initCustomCodeScriptProjectStep.ts | 6 +- .../src/app/commands/dotnet/installDotNet.ts | 21 - .../dotnet/validateDotNetInstalled.ts | 74 --- .../commands/dotnet/validateDotNetIsLatest.ts | 45 -- .../funcCoreTools/installFuncCoreTools.ts | 75 --- .../funcCoreTools/uninstallFuncCoreTools.ts | 11 - .../funcCoreTools/updateFuncCoreTools.ts | 40 -- .../validateFuncCoreToolsInstalled.ts | 123 ----- .../validateFuncCoreToolsIsLatest.ts | 149 ------ .../initDotnetProjectStep.ts | 5 +- .../initProjectForVSCode/initProjectStep.ts | 6 +- .../initScriptProjectStep.ts | 6 +- .../src/app/commands/nodeJs/installNodeJs.ts | 44 -- .../nodeJs/validateNodeJsInstalled.ts | 76 --- .../commands/nodeJs/validateNodeJsIsLatest.ts | 62 --- .../src/app/commands/registerCommands.ts | 5 - .../workflows/switchToDotnetProject.ts | 15 +- .../src/app/debug/validatePreDebug.ts | 6 - .../src/app/utils/__test__/binaries.test.ts | 406 ---------------- .../src/app/utils/binaries.ts | 440 ------------------ .../src/app/utils/bundleFeed.ts | 49 +- .../src/app/utils/dotnet/dotnet.ts | 107 +---- .../dotnet/executeDotnetTemplateCommand.ts | 21 +- .../app/utils/funcCoreTools/funcVersion.ts | 30 +- .../utils/funcCoreTools/getBrewPackageName.ts | 54 --- .../funcCoreTools/getFuncPackageManagers.ts | 61 --- .../app/utils/funcCoreTools/getNpmDistTag.ts | 34 -- .../src/app/utils/nodeJs/nodeJsVersion.ts | 97 ---- apps/vs-code-designer/src/constants.ts | 12 +- .../src/container/devcontainer.json | 100 ++-- apps/vs-code-designer/src/main.ts | 17 +- apps/vs-code-designer/src/onboarding.ts | 56 --- apps/vs-code-designer/src/package.json | 15 - .../panel/nodeDetailsPanel/usePanelTabs.tsx | 4 +- 37 files changed, 97 insertions(+), 2376 deletions(-) delete mode 100644 apps/vs-code-designer/src/app/commands/binaries/resetValidateAndInstallBinaries.ts delete mode 100644 apps/vs-code-designer/src/app/commands/binaries/validateAndInstallBinaries.ts delete mode 100644 apps/vs-code-designer/src/app/commands/dotnet/installDotNet.ts delete mode 100644 apps/vs-code-designer/src/app/commands/dotnet/validateDotNetInstalled.ts delete mode 100644 apps/vs-code-designer/src/app/commands/dotnet/validateDotNetIsLatest.ts delete mode 100644 apps/vs-code-designer/src/app/commands/funcCoreTools/installFuncCoreTools.ts delete mode 100644 apps/vs-code-designer/src/app/commands/funcCoreTools/uninstallFuncCoreTools.ts delete mode 100644 apps/vs-code-designer/src/app/commands/funcCoreTools/updateFuncCoreTools.ts delete mode 100644 apps/vs-code-designer/src/app/commands/funcCoreTools/validateFuncCoreToolsInstalled.ts delete mode 100644 apps/vs-code-designer/src/app/commands/funcCoreTools/validateFuncCoreToolsIsLatest.ts delete mode 100644 apps/vs-code-designer/src/app/commands/nodeJs/installNodeJs.ts delete mode 100644 apps/vs-code-designer/src/app/commands/nodeJs/validateNodeJsInstalled.ts delete mode 100644 apps/vs-code-designer/src/app/commands/nodeJs/validateNodeJsIsLatest.ts delete mode 100644 apps/vs-code-designer/src/app/utils/__test__/binaries.test.ts delete mode 100644 apps/vs-code-designer/src/app/utils/binaries.ts delete mode 100644 apps/vs-code-designer/src/app/utils/funcCoreTools/getBrewPackageName.ts delete mode 100644 apps/vs-code-designer/src/app/utils/funcCoreTools/getFuncPackageManagers.ts delete mode 100644 apps/vs-code-designer/src/app/utils/funcCoreTools/getNpmDistTag.ts delete mode 100644 apps/vs-code-designer/src/app/utils/nodeJs/nodeJsVersion.ts delete mode 100644 apps/vs-code-designer/src/onboarding.ts diff --git a/apps/vs-code-designer/src/app/commands/binaries/resetValidateAndInstallBinaries.ts b/apps/vs-code-designer/src/app/commands/binaries/resetValidateAndInstallBinaries.ts deleted file mode 100644 index 85c05faf0d2..00000000000 --- a/apps/vs-code-designer/src/app/commands/binaries/resetValidateAndInstallBinaries.ts +++ /dev/null @@ -1,73 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See LICENSE.md in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import { - autoRuntimeDependenciesPathSettingKey, - autoRuntimeDependenciesValidationAndInstallationSetting, - dotNetBinaryPathSettingKey, - funcCoreToolsBinaryPathSettingKey, - nodeJsBinaryPathSettingKey, -} from '../../../constants'; -import { localize } from '../../../localize'; -import { updateGlobalSetting } from '../../utils/vsCodeConfig/settings'; -import type { IActionContext } from '@microsoft/vscode-azext-utils'; -import * as vscode from 'vscode'; - -/** - * Resets the auto validation and installation of binaries dependencies. - * @param {IActionContext} context The action context. - */ -export async function resetValidateAndInstallBinaries(context: IActionContext): Promise { - await vscode.window.withProgress( - { - location: vscode.ProgressLocation.Notification, // Location of the progress indicator - title: localize('resetBinariesDependencies', 'Resetting binaries dependencies settings'), // Title displayed in the progress notification - cancellable: false, // Allow the user to cancel the task - }, - async (progress) => { - await updateGlobalSetting(autoRuntimeDependenciesValidationAndInstallationSetting, true); - progress.report({ increment: 20, message: localize('resetValidation', 'Reset auto runtime validation and installation') }); - await resetBinariesPathSettings(progress); - context.telemetry.properties.resetBinariesDependencies = 'true'; - } - ); -} - -/** - * Disables the auto validation and installation of binaries dependencies. - * @param {IActionContext} context The action context. - */ -export async function disableValidateAndInstallBinaries(context: IActionContext): Promise { - await vscode.window.withProgress( - { - location: vscode.ProgressLocation.Notification, // Location of the progress indicator - title: localize('disableBinariesDependencies', 'Disabling binaries dependencies settings'), // Title displayed in the progress notification - cancellable: false, // Allow the user to cancel the task - }, - async (progress) => { - await updateGlobalSetting(autoRuntimeDependenciesValidationAndInstallationSetting, false); - progress.report({ increment: 20, message: localize('disableValidation', 'Disable auto runtime validation and installation') }); - await resetBinariesPathSettings(progress); - context.telemetry.properties.disableBinariesDependencies = 'true'; - } - ); -} - -/** - * Resets the path settings for auto runtime dependencies, dotnet binary, node js binary, and func core tools binary. - * @param {vscode.Progress} progress - The progress object to report the progress of the reset operation. - */ -async function resetBinariesPathSettings(progress: vscode.Progress<{ message?: string; increment?: number }>): Promise { - await updateGlobalSetting(autoRuntimeDependenciesPathSettingKey, undefined); - progress.report({ increment: 40, message: localize('resetDependenciesPath', 'Reset auto runtime dependencies path') }); - - await updateGlobalSetting(dotNetBinaryPathSettingKey, undefined); - progress.report({ increment: 60, message: localize('resetDotnet', 'Reset dotnet binary path') }); - - await updateGlobalSetting(nodeJsBinaryPathSettingKey, undefined); - progress.report({ increment: 80, message: localize('resetNodeJs', 'Reset node js binary path') }); - - await updateGlobalSetting(funcCoreToolsBinaryPathSettingKey, undefined); - progress.report({ increment: 100, message: localize('resetFuncCoreTools', 'Reset func core tools binary path') }); -} diff --git a/apps/vs-code-designer/src/app/commands/binaries/validateAndInstallBinaries.ts b/apps/vs-code-designer/src/app/commands/binaries/validateAndInstallBinaries.ts deleted file mode 100644 index c72accda5ec..00000000000 --- a/apps/vs-code-designer/src/app/commands/binaries/validateAndInstallBinaries.ts +++ /dev/null @@ -1,122 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See LICENSE.md in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import { autoRuntimeDependenciesPathSettingKey, defaultDependencyPathValue } from '../../../constants'; -import { ext } from '../../../extensionVariables'; -import { localize } from '../../../localize'; -import { getDependencyTimeout } from '../../utils/binaries'; -import { getDependenciesVersion } from '../../utils/bundleFeed'; -import { setDotNetCommand } from '../../utils/dotnet/dotnet'; -import { executeCommand } from '../../utils/funcCoreTools/cpUtils'; -import { setFunctionsCommand } from '../../utils/funcCoreTools/funcVersion'; -import { setNodeJsCommand } from '../../utils/nodeJs/nodeJsVersion'; -import { runWithDurationTelemetry } from '../../utils/telemetry'; -import { timeout } from '../../utils/timeout'; -import { getGlobalSetting, updateGlobalSetting } from '../../utils/vsCodeConfig/settings'; -import { validateDotNetIsLatest } from '../dotnet/validateDotNetIsLatest'; -import { validateFuncCoreToolsIsLatest } from '../funcCoreTools/validateFuncCoreToolsIsLatest'; -import { validateNodeJsIsLatest } from '../nodeJs/validateNodeJsIsLatest'; -import type { IActionContext } from '@microsoft/vscode-azext-utils'; -import type { IBundleDependencyFeed } from '@microsoft/vscode-extension-logic-apps'; -import * as vscode from 'vscode'; - -export async function validateAndInstallBinaries(context: IActionContext) { - const helpLink = 'https://aka.ms/lastandard/onboarding/troubleshoot'; - - await vscode.window.withProgress( - { - location: vscode.ProgressLocation.Notification, // Location of the progress indicator - title: localize('validateRuntimeDependency', 'Validating Runtime Dependency'), // Title displayed in the progress notification - cancellable: false, // Allow the user to cancel the task - }, - async (progress, token) => { - token.onCancellationRequested(() => { - // Handle cancellation logic - executeCommand(ext.outputChannel, undefined, 'echo', 'validateAndInstallBinaries was canceled'); - }); - - context.telemetry.properties.lastStep = 'getGlobalSetting'; - progress.report({ increment: 10, message: 'Get Settings' }); - - const dependencyTimeout = getDependencyTimeout() * 1000; - - context.telemetry.properties.dependencyTimeout = `${dependencyTimeout} milliseconds`; - if (!getGlobalSetting(autoRuntimeDependenciesPathSettingKey)) { - await updateGlobalSetting(autoRuntimeDependenciesPathSettingKey, defaultDependencyPathValue); - context.telemetry.properties.dependencyPath = defaultDependencyPathValue; - } - - context.telemetry.properties.lastStep = 'getDependenciesVersion'; - progress.report({ increment: 10, message: 'Get dependency version from CDN' }); - let dependenciesVersions: IBundleDependencyFeed; - try { - dependenciesVersions = await getDependenciesVersion(context); - context.telemetry.properties.dependenciesVersions = JSON.stringify(dependenciesVersions); - } catch (error) { - // Unable to get dependency.json, will default to fallback versions - console.log(error); - } - - context.telemetry.properties.lastStep = 'validateNodeJsIsLatest'; - - try { - await runWithDurationTelemetry(context, 'azureLogicAppsStandard.validateNodeJsIsLatest', async () => { - progress.report({ increment: 20, message: 'NodeJS' }); - await timeout( - validateNodeJsIsLatest, - 'NodeJs', - dependencyTimeout, - 'https://github.com/nodesource/distributions', - dependenciesVersions?.nodejs - ); - await setNodeJsCommand(); - }); - - context.telemetry.properties.lastStep = 'validateFuncCoreToolsIsLatest'; - await runWithDurationTelemetry(context, 'azureLogicAppsStandard.validateFuncCoreToolsIsLatest', async () => { - progress.report({ increment: 20, message: 'Functions Runtime' }); - await timeout( - validateFuncCoreToolsIsLatest, - 'Functions Runtime', - dependencyTimeout, - 'https://github.com/Azure/azure-functions-core-tools/releases', - dependenciesVersions?.funcCoreTools - ); - await setFunctionsCommand(); - }); - - context.telemetry.properties.lastStep = 'validateDotNetIsLatest'; - await runWithDurationTelemetry(context, 'azureLogicAppsStandard.validateDotNetIsLatest', async () => { - progress.report({ increment: 20, message: '.NET SDK' }); - const dotnetDependencies = dependenciesVersions?.dotnetVersions ?? dependenciesVersions?.dotnet; - await timeout( - validateDotNetIsLatest, - '.NET SDK', - dependencyTimeout, - 'https://dotnet.microsoft.com/en-us/download/dotnet', - dotnetDependencies - ); - await setDotNetCommand(); - }); - ext.outputChannel.appendLog( - localize( - 'azureLogicApsBinariesSucessfull', - 'Azure Logic Apps Standard Runtime Dependencies validation and installation completed successfully.' - ) - ); - } catch (error) { - ext.outputChannel.appendLog( - localize('azureLogicApsBinariesError', 'Error in dependencies validation and installation: "{0}"...', error?.message) - ); - context.telemetry.properties.dependenciesError = error?.message; - vscode.window.showErrorMessage( - localize( - 'binariesTroubleshoot', - `The Validation and Installation of Runtime Dependencies encountered an error. To resolve this issue, please click [here](${helpLink}) to access our troubleshooting documentation for step-by-step instructions.` - ) - ); - } - } - ); -} diff --git a/apps/vs-code-designer/src/app/commands/createProject/createCustomCodeProjectSteps/initCustomCodeProjectStep.ts b/apps/vs-code-designer/src/app/commands/createProject/createCustomCodeProjectSteps/initCustomCodeProjectStep.ts index b892312a4d7..74bc22542fe 100644 --- a/apps/vs-code-designer/src/app/commands/createProject/createCustomCodeProjectSteps/initCustomCodeProjectStep.ts +++ b/apps/vs-code-designer/src/app/commands/createProject/createCustomCodeProjectSteps/initCustomCodeProjectStep.ts @@ -2,15 +2,15 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { binariesExist } from '../../../utils/binaries'; -import { extensionCommand, func, funcDependencyName, funcWatchProblemMatcher, hostStartCommand } from '../../../../constants'; +import { extensionCommand, func, funcWatchProblemMatcher, hostStartCommand } from '../../../../constants'; import { InitCustomCodeScriptProjectStep } from './initCustomCodeScriptProjectStep'; import type { ITaskInputs, ISettingToAdd } from '@microsoft/vscode-extension-logic-apps'; import type { TaskDefinition } from 'vscode'; export class InitCustomCodeProjectStep extends InitCustomCodeScriptProjectStep { protected getTasks(): TaskDefinition[] { - const funcBinariesExist = binariesExist(funcDependencyName); + // TODO (ccastrotrejo) - remove + const funcBinariesExist = true; const binariesOptions = funcBinariesExist ? { options: { diff --git a/apps/vs-code-designer/src/app/commands/createProject/createCustomCodeProjectSteps/initCustomCodeScriptProjectStep.ts b/apps/vs-code-designer/src/app/commands/createProject/createCustomCodeProjectSteps/initCustomCodeScriptProjectStep.ts index 08f854a1933..ecdb9d12bec 100644 --- a/apps/vs-code-designer/src/app/commands/createProject/createCustomCodeProjectSteps/initCustomCodeScriptProjectStep.ts +++ b/apps/vs-code-designer/src/app/commands/createProject/createCustomCodeProjectSteps/initCustomCodeScriptProjectStep.ts @@ -2,8 +2,7 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { binariesExist } from '../../../utils/binaries'; -import { extInstallTaskName, func, funcDependencyName, funcWatchProblemMatcher, hostStartCommand } from '../../../../constants'; +import { extInstallTaskName, func, funcWatchProblemMatcher, hostStartCommand } from '../../../../constants'; import { getLocalFuncCoreToolsVersion } from '../../../utils/funcCoreTools/funcVersion'; import { InitCustomCodeProjectStepBase } from './initCustomCodeProjectStepBase'; import type { IProjectWizardContext } from '@microsoft/vscode-extension-logic-apps'; @@ -48,7 +47,8 @@ export class InitCustomCodeScriptProjectStep extends InitCustomCodeProjectStepBa } protected getTasks(): TaskDefinition[] { - const funcBinariesExist = binariesExist(funcDependencyName); + // TODO (ccastrotrejo) - remove + const funcBinariesExist = true; const binariesOptions = funcBinariesExist ? { options: { diff --git a/apps/vs-code-designer/src/app/commands/dotnet/installDotNet.ts b/apps/vs-code-designer/src/app/commands/dotnet/installDotNet.ts deleted file mode 100644 index f14a890055b..00000000000 --- a/apps/vs-code-designer/src/app/commands/dotnet/installDotNet.ts +++ /dev/null @@ -1,21 +0,0 @@ -/*------------------p--------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import { autoRuntimeDependenciesPathSettingKey, dotnetDependencyName } from '../../../constants'; -import { ext } from '../../../extensionVariables'; -import { downloadAndExtractDependency, getDotNetBinariesReleaseUrl } from '../../utils/binaries'; -import { getGlobalSetting } from '../../utils/vsCodeConfig/settings'; -import type { IActionContext } from '@microsoft/vscode-azext-utils'; - -export async function installDotNet(context: IActionContext, majorVersion?: string): Promise { - ext.outputChannel.show(); - context.telemetry.properties.majorVersion = majorVersion; - const targetDirectory = getGlobalSetting(autoRuntimeDependenciesPathSettingKey); - - context.telemetry.properties.lastStep = 'getDotNetBinariesReleaseUrl'; - const scriptUrl = getDotNetBinariesReleaseUrl(); - - context.telemetry.properties.lastStep = 'downloadAndExtractBinaries'; - await downloadAndExtractDependency(context, scriptUrl, targetDirectory, dotnetDependencyName, null, majorVersion); -} diff --git a/apps/vs-code-designer/src/app/commands/dotnet/validateDotNetInstalled.ts b/apps/vs-code-designer/src/app/commands/dotnet/validateDotNetInstalled.ts deleted file mode 100644 index eef69e112e3..00000000000 --- a/apps/vs-code-designer/src/app/commands/dotnet/validateDotNetInstalled.ts +++ /dev/null @@ -1,74 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import { validateDotNetSDKSetting } from '../../../constants'; -import { localize } from '../../../localize'; -import { getDotNetCommand } from '../../utils/dotnet/dotnet'; -import { executeCommand } from '../../utils/funcCoreTools/cpUtils'; -import { getWorkspaceSetting } from '../../utils/vsCodeConfig/settings'; -import { installDotNet } from './installDotNet'; -import { callWithTelemetryAndErrorHandling, DialogResponses, openUrl } from '@microsoft/vscode-azext-utils'; -import type { IActionContext } from '@microsoft/vscode-azext-utils'; -import type { MessageItem } from 'vscode'; - -/** - * Checks if dotnet 6 is installed, and installs it if needed. - * @param {IActionContext} context - Workflow file path. - * @param {string} fsPath - Workspace file system path. - * @returns {Promise} Returns true if it is installed or was sucessfully installed, otherwise returns false. - */ -export async function validateDotNetIsInstalled(context: IActionContext, fsPath: string): Promise { - let input: MessageItem | undefined; - let installed = false; - const install: MessageItem = { title: localize('install', 'Install') }; - const message: string = localize('installDotnetSDK', 'You must have the .NET SDK installed. Would you like to install it now?'); - await callWithTelemetryAndErrorHandling('azureLogicAppsStandard.validateDotNetIsInstalled', async (innerContext: IActionContext) => { - innerContext.errorHandling.suppressDisplay = true; - - if (!getWorkspaceSetting(validateDotNetSDKSetting, fsPath)) { - innerContext.telemetry.properties.validateDotNet = 'false'; - installed = true; - } else if (await isDotNetInstalled()) { - installed = true; - } else { - const items: MessageItem[] = [install, DialogResponses.learnMore]; - input = await innerContext.ui.showWarningMessage(message, { modal: true }, ...items); - innerContext.telemetry.properties.dialogResult = input.title; - - if (input === install) { - await installDotNet(innerContext); - installed = true; - } else if (input === DialogResponses.learnMore) { - await openUrl('https://dotnet.microsoft.com/download/dotnet/6.0'); - } - } - }); - - // validate that DotNet was installed only if user confirmed - if (input === install && !installed) { - if ( - (await context.ui.showWarningMessage( - localize('failedInstallDotNet', 'The .NET SDK installation failed. Please manually install instead.'), - DialogResponses.learnMore - )) === DialogResponses.learnMore - ) { - await openUrl('https://dotnet.microsoft.com/download/dotnet/6.0'); - } - } - - return installed; -} - -/** - * Check is dotnet is installed. - * @returns {Promise} Returns true if installed, otherwise returns false. - */ -async function isDotNetInstalled(): Promise { - try { - await executeCommand(undefined, undefined, getDotNetCommand(), '--version'); - return true; - } catch (_error) { - return false; - } -} diff --git a/apps/vs-code-designer/src/app/commands/dotnet/validateDotNetIsLatest.ts b/apps/vs-code-designer/src/app/commands/dotnet/validateDotNetIsLatest.ts deleted file mode 100644 index af263dd69b7..00000000000 --- a/apps/vs-code-designer/src/app/commands/dotnet/validateDotNetIsLatest.ts +++ /dev/null @@ -1,45 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import { isNullOrUndefined } from '@microsoft/logic-apps-shared'; -import { dotnetDependencyName } from '../../../constants'; -import { binariesExist, getLatestDotNetVersion } from '../../utils/binaries'; -import { getDotNetCommand, getLocalDotNetVersionFromBinaries } from '../../utils/dotnet/dotnet'; -import { installDotNet } from './installDotNet'; -import { callWithTelemetryAndErrorHandling } from '@microsoft/vscode-azext-utils'; -import type { IActionContext } from '@microsoft/vscode-azext-utils'; -import * as semver from 'semver'; - -export async function validateDotNetIsLatest(majorVersion?: string): Promise { - await callWithTelemetryAndErrorHandling('azureLogicAppsStandard.validateDotNetIsLatest', async (context: IActionContext) => { - context.errorHandling.suppressDisplay = true; - context.telemetry.properties.isActivationEvent = 'true'; - const majorVersions = majorVersion.split(','); - - const binaries = binariesExist(dotnetDependencyName); - context.telemetry.properties.binariesExist = `${binaries}`; - - if (binaries) { - for (const version of majorVersions) { - const localVersion: string | null = await getLocalDotNetVersionFromBinaries(version); - if (isNullOrUndefined(localVersion)) { - await installDotNet(context, version); - } else { - context.telemetry.properties.localVersion = localVersion; - const newestVersion: string | undefined = await getLatestDotNetVersion(context, version); - - if (semver.major(newestVersion) === semver.major(localVersion) && semver.gt(newestVersion, localVersion)) { - context.telemetry.properties.outOfDateDotNet = 'true'; - await installDotNet(context, version); - } - } - } - } else { - for (const version of majorVersions) { - await installDotNet(context, version); - } - } - context.telemetry.properties.binaryCommand = `${getDotNetCommand()}`; - }); -} diff --git a/apps/vs-code-designer/src/app/commands/funcCoreTools/installFuncCoreTools.ts b/apps/vs-code-designer/src/app/commands/funcCoreTools/installFuncCoreTools.ts deleted file mode 100644 index 722d41f28c8..00000000000 --- a/apps/vs-code-designer/src/app/commands/funcCoreTools/installFuncCoreTools.ts +++ /dev/null @@ -1,75 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import { PackageManager, Platform, autoRuntimeDependenciesPathSettingKey, funcDependencyName, funcPackageName } from '../../../constants'; -import { ext } from '../../../extensionVariables'; -import { - downloadAndExtractDependency, - getCpuArchitecture, - getFunctionCoreToolsBinariesReleaseUrl, - getLatestFunctionCoreToolsVersion, -} from '../../utils/binaries'; -import { executeCommand } from '../../utils/funcCoreTools/cpUtils'; -import { getBrewPackageName } from '../../utils/funcCoreTools/getBrewPackageName'; -import { getNpmDistTag } from '../../utils/funcCoreTools/getNpmDistTag'; -import { getGlobalSetting, promptForFuncVersion } from '../../utils/vsCodeConfig/settings'; -import type { IActionContext } from '@microsoft/vscode-azext-utils'; -import type { FuncVersion, INpmDistTag } from '@microsoft/vscode-extension-logic-apps'; -import { localize } from 'vscode-nls'; - -export async function installFuncCoreToolsBinaries(context: IActionContext, majorVersion?: string): Promise { - ext.outputChannel.show(); - const arch = getCpuArchitecture(); - const targetDirectory = getGlobalSetting(autoRuntimeDependenciesPathSettingKey); - context.telemetry.properties.lastStep = 'getLatestFunctionCoreToolsVersion'; - const version = await getLatestFunctionCoreToolsVersion(context, majorVersion); - let azureFunctionCoreToolsReleasesUrl: string; - - context.telemetry.properties.lastStep = 'getFunctionCoreToolsBinariesReleaseUrl'; - switch (process.platform) { - case Platform.windows: { - azureFunctionCoreToolsReleasesUrl = getFunctionCoreToolsBinariesReleaseUrl(version, 'win', arch); - break; - } - - case Platform.linux: { - azureFunctionCoreToolsReleasesUrl = getFunctionCoreToolsBinariesReleaseUrl(version, 'linux', arch); - break; - } - - case Platform.mac: { - azureFunctionCoreToolsReleasesUrl = getFunctionCoreToolsBinariesReleaseUrl(version, 'osx', arch); - break; - } - } - context.telemetry.properties.lastStep = 'downloadAndExtractBinaries'; - await downloadAndExtractDependency(context, azureFunctionCoreToolsReleasesUrl, targetDirectory, funcDependencyName); -} - -export async function installFuncCoreToolsSystem( - context: IActionContext, - packageManagers: PackageManager[], - version?: FuncVersion -): Promise { - version = version || (await promptForFuncVersion(context, localize('selectVersion', 'Select the version of the runtime to install'))); - - ext.outputChannel.show(); - - const distTag: INpmDistTag = await getNpmDistTag(context, version); - const brewPackageName: string = getBrewPackageName(version); - - switch (packageManagers[0]) { - case PackageManager.npm: { - await executeCommand(ext.outputChannel, undefined, 'npm', 'install', '-g', `${funcPackageName}@${distTag.tag}`); - break; - } - case PackageManager.brew: { - await executeCommand(ext.outputChannel, undefined, 'brew', 'tap', 'azure/functions'); - await executeCommand(ext.outputChannel, undefined, 'brew', 'install', brewPackageName); - break; - } - default: - throw new RangeError(localize('invalidPackageManager', 'Invalid package manager "{0}".', packageManagers[0])); - } -} diff --git a/apps/vs-code-designer/src/app/commands/funcCoreTools/uninstallFuncCoreTools.ts b/apps/vs-code-designer/src/app/commands/funcCoreTools/uninstallFuncCoreTools.ts deleted file mode 100644 index 529026ad88f..00000000000 --- a/apps/vs-code-designer/src/app/commands/funcCoreTools/uninstallFuncCoreTools.ts +++ /dev/null @@ -1,11 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import { extensionCommand } from '../../../constants'; -import type { PackageManager } from '../../../constants'; -import { commands } from 'vscode'; - -export async function uninstallFuncCoreTools(packageManagers?: PackageManager[]): Promise { - await commands.executeCommand(extensionCommand.azureFunctionsUninstallFuncCoreTools, packageManagers); -} diff --git a/apps/vs-code-designer/src/app/commands/funcCoreTools/updateFuncCoreTools.ts b/apps/vs-code-designer/src/app/commands/funcCoreTools/updateFuncCoreTools.ts deleted file mode 100644 index 35cfe265f22..00000000000 --- a/apps/vs-code-designer/src/app/commands/funcCoreTools/updateFuncCoreTools.ts +++ /dev/null @@ -1,40 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import { PackageManager, funcPackageName } from '../../../constants'; -import { ext } from '../../../extensionVariables'; -import { localize } from '../../../localize'; -import { executeCommand } from '../../utils/funcCoreTools/cpUtils'; -import { getBrewPackageName, tryGetInstalledBrewPackageName } from '../../utils/funcCoreTools/getBrewPackageName'; -import { getNpmDistTag } from '../../utils/funcCoreTools/getNpmDistTag'; -import type { IActionContext } from '@microsoft/vscode-azext-utils'; -import { nonNullValue } from '@microsoft/vscode-azext-utils'; -import type { FuncVersion, INpmDistTag } from '@microsoft/vscode-extension-logic-apps'; - -export async function updateFuncCoreTools(context: IActionContext, packageManager: PackageManager, version: FuncVersion): Promise { - ext.outputChannel.show(); - const distTag: INpmDistTag = await getNpmDistTag(context, version); - - switch (packageManager) { - case PackageManager.npm: { - await executeCommand(ext.outputChannel, undefined, 'npm', 'install', '-g', `${funcPackageName}@${distTag.tag}`); - break; - } - case PackageManager.brew: { - const brewPackageName: string = getBrewPackageName(version); - const installedBrewPackageName: string = nonNullValue(await tryGetInstalledBrewPackageName(version), 'brewPackageName'); - if (brewPackageName !== installedBrewPackageName) { - await executeCommand(ext.outputChannel, undefined, 'brew', 'uninstall', installedBrewPackageName); - await executeCommand(ext.outputChannel, undefined, 'brew', 'install', brewPackageName); - } else { - await executeCommand(ext.outputChannel, undefined, 'brew', 'upgrade', brewPackageName); - } - break; - } - - default: { - throw new RangeError(localize('invalidPackageManager', 'Invalid package manager "{0}".', packageManager)); - } - } -} diff --git a/apps/vs-code-designer/src/app/commands/funcCoreTools/validateFuncCoreToolsInstalled.ts b/apps/vs-code-designer/src/app/commands/funcCoreTools/validateFuncCoreToolsInstalled.ts deleted file mode 100644 index 9b1ed5c5be2..00000000000 --- a/apps/vs-code-designer/src/app/commands/funcCoreTools/validateFuncCoreToolsInstalled.ts +++ /dev/null @@ -1,123 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import { type PackageManager, funcVersionSetting, validateFuncCoreToolsSetting } from '../../../constants'; -import { localize } from '../../../localize'; -import { useBinariesDependencies } from '../../utils/binaries'; -import { executeCommand } from '../../utils/funcCoreTools/cpUtils'; -import { getFunctionsCommand, tryParseFuncVersion } from '../../utils/funcCoreTools/funcVersion'; -import { getFuncPackageManagers } from '../../utils/funcCoreTools/getFuncPackageManagers'; -import { getWorkspaceSetting } from '../../utils/vsCodeConfig/settings'; -import { installFuncCoreToolsBinaries, installFuncCoreToolsSystem } from './installFuncCoreTools'; -import { callWithTelemetryAndErrorHandling, DialogResponses, openUrl } from '@microsoft/vscode-azext-utils'; -import type { IActionContext } from '@microsoft/vscode-azext-utils'; -import type { FuncVersion } from '@microsoft/vscode-extension-logic-apps'; -import type { MessageItem } from 'vscode'; - -/** - * Checks if functions core tools is installed, and installs it if needed. - * @param {IActionContext} context - Workflow file path. - * @param {string} message - Message for warning. - * @param {string} fsPath - Workspace file system path. - * @returns {Promise} Returns true if it is installed or was sucessfully installed, otherwise returns false. - */ -export async function validateFuncCoreToolsInstalled(context: IActionContext, message: string, fsPath: string): Promise { - let input: MessageItem | undefined; - let installed = false; - const install: MessageItem = { title: localize('install', 'Install') }; - - await callWithTelemetryAndErrorHandling('azureLogicAppsStandard.validateFuncCoreToolsInstalled', async (innerContext: IActionContext) => { - innerContext.errorHandling.suppressDisplay = true; - - if (!getWorkspaceSetting(validateFuncCoreToolsSetting, fsPath)) { - innerContext.telemetry.properties.validateFuncCoreTools = 'false'; - installed = true; - } else if (await isFuncToolsInstalled()) { - installed = true; - } else if (useBinariesDependencies()) { - installed = await validateFuncCoreToolsInstalledBinaries(innerContext, message, install, input, installed); - } else { - installed = await validateFuncCoreToolsInstalledSystem(innerContext, message, install, input, installed, fsPath); - } - }); - - // validate that Func Tools was installed only if user confirmed - if (input === install && !installed) { - if ( - (await context.ui.showWarningMessage( - localize('failedInstallFuncTools', 'The Azure Functions Core Tools installion has failed and will have to be installed manually.'), - DialogResponses.learnMore - )) === DialogResponses.learnMore - ) { - await openUrl('https://aka.ms/Dqur4e'); - } - } - - return installed; -} - -/** - * Check is functions core tools is installed. - * @returns {Promise} Returns true if installed, otherwise returns false. - */ -async function isFuncToolsInstalled(): Promise { - const funcCommand = getFunctionsCommand(); - try { - await executeCommand(undefined, undefined, funcCommand, '--version'); - return true; - } catch { - return false; - } -} - -async function validateFuncCoreToolsInstalledBinaries( - innerContext: IActionContext, - message: string, - install: MessageItem, - input: MessageItem | undefined, - installed: boolean -): Promise { - const items: MessageItem[] = [install, DialogResponses.learnMore]; - input = await innerContext.ui.showWarningMessage(message, { modal: true }, ...items); - innerContext.telemetry.properties.dialogResult = input.title; - - if (input === install) { - await installFuncCoreToolsBinaries(innerContext); - installed = true; - } else if (input === DialogResponses.learnMore) { - await openUrl('https://aka.ms/Dqur4e'); - } - - return installed; -} - -async function validateFuncCoreToolsInstalledSystem( - innerContext: IActionContext, - message: string, - install: MessageItem, - input: MessageItem | undefined, - installed: boolean, - fsPath: string -): Promise { - const items: MessageItem[] = []; - const packageManagers: PackageManager[] = await getFuncPackageManagers(false /* isFuncInstalled */); - if (packageManagers.length > 0) { - items.push(install); - } else { - items.push(DialogResponses.learnMore); - } - - input = await innerContext.ui.showWarningMessage(message, { modal: true }, ...items); - - innerContext.telemetry.properties.dialogResult = input.title; - - if (input === install) { - const version: FuncVersion | undefined = tryParseFuncVersion(getWorkspaceSetting(funcVersionSetting, fsPath)); - await installFuncCoreToolsSystem(innerContext, packageManagers, version); - installed = true; - } else if (input === DialogResponses.learnMore) { - await openUrl('https://aka.ms/Dqur4e'); - } - return installed; -} diff --git a/apps/vs-code-designer/src/app/commands/funcCoreTools/validateFuncCoreToolsIsLatest.ts b/apps/vs-code-designer/src/app/commands/funcCoreTools/validateFuncCoreToolsIsLatest.ts deleted file mode 100644 index b25f036e12b..00000000000 --- a/apps/vs-code-designer/src/app/commands/funcCoreTools/validateFuncCoreToolsIsLatest.ts +++ /dev/null @@ -1,149 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import { PackageManager, funcDependencyName } from '../../../constants'; -import { localize } from '../../../localize'; -import { executeOnFunctions } from '../../functionsExtension/executeOnFunctionsExt'; -import { binariesExist, getLatestFunctionCoreToolsVersion, useBinariesDependencies } from '../../utils/binaries'; -import { startAllDesignTimeApis, stopAllDesignTimeApis } from '../../utils/codeless/startDesignTimeApi'; -import { getFunctionsCommand, getLocalFuncCoreToolsVersion, tryParseFuncVersion } from '../../utils/funcCoreTools/funcVersion'; -import { getBrewPackageName } from '../../utils/funcCoreTools/getBrewPackageName'; -import { getFuncPackageManagers } from '../../utils/funcCoreTools/getFuncPackageManagers'; -import { getNpmDistTag } from '../../utils/funcCoreTools/getNpmDistTag'; -import { sendRequestWithExtTimeout } from '../../utils/requestUtils'; -import { getWorkspaceSetting, updateGlobalSetting } from '../../utils/vsCodeConfig/settings'; -import { installFuncCoreToolsBinaries } from './installFuncCoreTools'; -import { uninstallFuncCoreTools } from './uninstallFuncCoreTools'; -import { updateFuncCoreTools } from './updateFuncCoreTools'; -import { HTTP_METHODS } from '@microsoft/logic-apps-shared'; -import { callWithTelemetryAndErrorHandling, DialogResponses, parseError } from '@microsoft/vscode-azext-utils'; -import type { IActionContext } from '@microsoft/vscode-azext-utils'; -import type { FuncVersion } from '@microsoft/vscode-extension-logic-apps'; -import * as semver from 'semver'; -import type { MessageItem } from 'vscode'; - -export async function validateFuncCoreToolsIsLatest(majorVersion?: string): Promise { - if (useBinariesDependencies()) { - await validateFuncCoreToolsIsLatestBinaries(majorVersion); - } else { - await validateFuncCoreToolsIsLatestSystem(); - } -} - -async function validateFuncCoreToolsIsLatestBinaries(majorVersion?: string): Promise { - await callWithTelemetryAndErrorHandling('azureLogicAppsStandard.validateFuncCoreToolsIsLatest', async (context: IActionContext) => { - context.errorHandling.suppressDisplay = true; - context.telemetry.properties.isActivationEvent = 'true'; - - const binaries = binariesExist(funcDependencyName); - context.telemetry.properties.binariesExist = `${binaries}`; - - const localVersion: string | null = binaries ? await getLocalFuncCoreToolsVersion() : null; - context.telemetry.properties.localVersion = localVersion ?? 'null'; - - const newestVersion: string | undefined = binaries ? await getLatestFunctionCoreToolsVersion(context, majorVersion) : undefined; - const isOutdated = binaries && localVersion && newestVersion && semver.gt(newestVersion, localVersion); - - const shouldInstall = !binaries || localVersion === null || isOutdated; - - if (shouldInstall) { - if (isOutdated) { - context.telemetry.properties.outOfDateFunc = 'true'; - stopAllDesignTimeApis(); - } - - await installFuncCoreToolsBinaries(context, majorVersion); - await startAllDesignTimeApis(); - } - - context.telemetry.properties.binaryCommand = getFunctionsCommand(); - }); -} - -async function validateFuncCoreToolsIsLatestSystem(): Promise { - await callWithTelemetryAndErrorHandling('azureLogicAppsStandard.validateFuncCoreToolsIsLatest', async (context: IActionContext) => { - context.errorHandling.suppressDisplay = true; - context.telemetry.properties.isActivationEvent = 'true'; - - const showMultiCoreToolsWarningKey = 'showMultiCoreToolsWarning'; - const showMultiCoreToolsWarning = !!getWorkspaceSetting(showMultiCoreToolsWarningKey); - - if (showMultiCoreToolsWarning) { - const packageManagers: PackageManager[] = await getFuncPackageManagers(true /* isFuncInstalled */); - let packageManager: PackageManager; - - if (packageManagers.length === 0) { - return; - } - if (packageManagers.length === 1) { - packageManager = packageManagers[0]; - context.telemetry.properties.packageManager = packageManager; - } else { - context.telemetry.properties.multiFunc = 'true'; - - if (showMultiCoreToolsWarning) { - const message: string = localize('multipleInstalls', 'Detected multiple installs of the func cli.'); - const selectUninstall: MessageItem = { title: localize('selectUninstall', 'Select version to uninstall') }; - const result: MessageItem = await context.ui.showWarningMessage(message, selectUninstall, DialogResponses.dontWarnAgain); - - if (result === selectUninstall) { - await executeOnFunctions(uninstallFuncCoreTools, context, packageManagers); - } else if (result === DialogResponses.dontWarnAgain) { - await updateGlobalSetting(showMultiCoreToolsWarningKey, false); - } - } - - return; - } - const localVersion: string | null = await getLocalFuncCoreToolsVersion(); - if (!localVersion) { - return; - } - context.telemetry.properties.localVersion = localVersion; - - const versionFromSetting: FuncVersion | undefined = tryParseFuncVersion(localVersion); - if (versionFromSetting === undefined) { - return; - } - - const newestVersion: string | undefined = await getNewestFunctionRuntimeVersion(packageManager, versionFromSetting, context); - if (!newestVersion) { - return; - } - - if (semver.major(newestVersion) === semver.major(localVersion) && semver.gt(newestVersion, localVersion)) { - context.telemetry.properties.outOfDateFunc = 'true'; - stopAllDesignTimeApis(); - await updateFuncCoreTools(context, packageManager, versionFromSetting); - await startAllDesignTimeApis(); - } - } - }); -} - -async function getNewestFunctionRuntimeVersion( - packageManager: PackageManager | undefined, - versionFromSetting: FuncVersion, - context: IActionContext -): Promise { - try { - if (packageManager === PackageManager.brew) { - const packageName: string = getBrewPackageName(versionFromSetting); - const brewRegistryUri = `https://raw.githubusercontent.com/Azure/homebrew-functions/master/Formula/${packageName}.rb`; - const response = await sendRequestWithExtTimeout(context, { url: brewRegistryUri, method: HTTP_METHODS.GET }); - const brewInfo: string = response.bodyAsText; - const matches: RegExpMatchArray | null = brewInfo.match(/version\s+["']([^"']+)["']/i); - - if (matches && matches.length > 1) { - return matches[1]; - } - } else { - return (await getNpmDistTag(context, versionFromSetting)).value; - } - } catch (error) { - context.telemetry.properties.latestRuntimeError = parseError(error).message; - } - - return undefined; -} diff --git a/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initDotnetProjectStep.ts b/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initDotnetProjectStep.ts index 683af87986b..47ae9e4eb89 100644 --- a/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initDotnetProjectStep.ts +++ b/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initDotnetProjectStep.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { dotnetPublishTaskLabel, - funcDependencyName, dotnetExtensionId, func, funcWatchProblemMatcher, @@ -12,7 +11,6 @@ import { show64BitWarningSetting, } from '../../../constants'; import { localize } from '../../../localize'; -import { binariesExist } from '../../utils/binaries'; import { getProjFiles, getTargetFramework, getDotnetDebugSubpath, tryGetFuncVersion } from '../../utils/dotnet/dotnet'; import type { ProjectFile } from '../../utils/dotnet/dotnet'; import { tryParseFuncVersion } from '../../utils/funcCoreTools/funcVersion'; @@ -108,7 +106,8 @@ export class InitDotnetProjectStep extends InitProjectStepBase { protected getTasks(): TaskDefinition[] { const commonArgs: string[] = ['/property:GenerateFullPaths=true', '/consoleloggerparameters:NoSummary']; const releaseArgs: string[] = ['--configuration', 'Release']; - const funcBinariesExist = binariesExist(funcDependencyName); + // TODO (ccastrotrejo)-remove + const funcBinariesExist = true; const binariesOptions = funcBinariesExist ? { options: { diff --git a/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initProjectStep.ts b/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initProjectStep.ts index 1805ac02d39..94b30801edd 100644 --- a/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initProjectStep.ts +++ b/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initProjectStep.ts @@ -2,15 +2,15 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { binariesExist } from '../../utils/binaries'; -import { extensionCommand, func, funcDependencyName, funcWatchProblemMatcher, hostStartCommand } from '../../../constants'; +import { extensionCommand, func, funcWatchProblemMatcher, hostStartCommand } from '../../../constants'; import { InitScriptProjectStep } from './initScriptProjectStep'; import type { ITaskInputs, ISettingToAdd } from '@microsoft/vscode-extension-logic-apps'; import type { TaskDefinition } from 'vscode'; export class InitProjectStep extends InitScriptProjectStep { protected getTasks(): TaskDefinition[] { - const funcBinariesExist = binariesExist(funcDependencyName); + // TODO (ccastrotrejo) - Remove + const funcBinariesExist = true; const binariesOptions = funcBinariesExist ? { options: { diff --git a/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initScriptProjectStep.ts b/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initScriptProjectStep.ts index 2d958275bfb..de2e5697dcb 100644 --- a/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initScriptProjectStep.ts +++ b/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initScriptProjectStep.ts @@ -2,8 +2,7 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { extInstallTaskName, func, funcDependencyName, funcWatchProblemMatcher, hostStartCommand } from '../../../constants'; -import { binariesExist } from '../../utils/binaries'; +import { extInstallTaskName, func, funcWatchProblemMatcher, hostStartCommand } from '../../../constants'; import { getLocalFuncCoreToolsVersion } from '../../utils/funcCoreTools/funcVersion'; import { InitProjectStepBase } from './initProjectStepBase'; import type { IProjectWizardContext } from '@microsoft/vscode-extension-logic-apps'; @@ -50,7 +49,8 @@ export class InitScriptProjectStep extends InitProjectStepBase { } protected getTasks(): TaskDefinition[] { - const funcBinariesExist = binariesExist(funcDependencyName); + // TODO (ccastrotrejo) - Remoce + const funcBinariesExist = true; const binariesOptions = funcBinariesExist ? { options: { diff --git a/apps/vs-code-designer/src/app/commands/nodeJs/installNodeJs.ts b/apps/vs-code-designer/src/app/commands/nodeJs/installNodeJs.ts deleted file mode 100644 index 2002276747f..00000000000 --- a/apps/vs-code-designer/src/app/commands/nodeJs/installNodeJs.ts +++ /dev/null @@ -1,44 +0,0 @@ -/*------------------p--------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import { Platform, autoRuntimeDependenciesPathSettingKey, nodeJsDependencyName } from '../../../constants'; -import { ext } from '../../../extensionVariables'; -import { - downloadAndExtractDependency, - getCpuArchitecture, - getLatestNodeJsVersion, - getNodeJsBinariesReleaseUrl, -} from '../../utils/binaries'; -import { getGlobalSetting } from '../../utils/vsCodeConfig/settings'; -import type { IActionContext } from '@microsoft/vscode-azext-utils'; - -export async function installNodeJs(context: IActionContext, majorVersion?: string): Promise { - ext.outputChannel.show(); - const arch = getCpuArchitecture(); - const targetDirectory = getGlobalSetting(autoRuntimeDependenciesPathSettingKey); - context.telemetry.properties.lastStep = 'getLatestNodeJsVersion'; - const version = await getLatestNodeJsVersion(context, majorVersion); - let nodeJsReleaseUrl: string; - - context.telemetry.properties.lastStep = 'getNodeJsBinariesReleaseUrl'; - switch (process.platform) { - case Platform.windows: { - nodeJsReleaseUrl = getNodeJsBinariesReleaseUrl(version, 'win', arch); - break; - } - - case Platform.linux: { - nodeJsReleaseUrl = getNodeJsBinariesReleaseUrl(version, 'linux', arch); - break; - } - - case Platform.mac: { - nodeJsReleaseUrl = getNodeJsBinariesReleaseUrl(version, 'darwin', arch); - break; - } - } - - context.telemetry.properties.lastStep = 'downloadAndExtractBinaries'; - await downloadAndExtractDependency(context, nodeJsReleaseUrl, targetDirectory, nodeJsDependencyName); -} diff --git a/apps/vs-code-designer/src/app/commands/nodeJs/validateNodeJsInstalled.ts b/apps/vs-code-designer/src/app/commands/nodeJs/validateNodeJsInstalled.ts deleted file mode 100644 index 7a092c0fc9b..00000000000 --- a/apps/vs-code-designer/src/app/commands/nodeJs/validateNodeJsInstalled.ts +++ /dev/null @@ -1,76 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import { validateNodeJsSetting } from '../../../constants'; -import { localize } from '../../../localize'; -import { executeCommand } from '../../utils/funcCoreTools/cpUtils'; -import { getNodeJsCommand } from '../../utils/nodeJs/nodeJsVersion'; -import { getWorkspaceSetting } from '../../utils/vsCodeConfig/settings'; -import { installNodeJs } from './installNodeJs'; -import { callWithTelemetryAndErrorHandling, DialogResponses, openUrl } from '@microsoft/vscode-azext-utils'; -import type { IActionContext } from '@microsoft/vscode-azext-utils'; -import type { MessageItem } from 'vscode'; - -/** - * Checks if node is installed, and installs it if needed. - * TODO(aeldridge): Unused - * @param {IActionContext} context - Workflow file path. - * @param {string} message - Message for warning. - * @param {string} fsPath - Workspace file system path. - * @returns {Promise} Returns true if it is installed or was sucessfully installed, otherwise returns false. - */ -export async function validateNodeJsInstalled(context: IActionContext, message: string, fsPath: string): Promise { - let input: MessageItem | undefined; - let installed = false; - const install: MessageItem = { title: localize('install', 'Install') }; - - await callWithTelemetryAndErrorHandling('azureLogicAppsStandard.validateNodeJsIsInstalled', async (innerContext: IActionContext) => { - innerContext.errorHandling.suppressDisplay = true; - - if (!getWorkspaceSetting(validateNodeJsSetting, fsPath)) { - innerContext.telemetry.properties.validateDotNet = 'false'; - installed = true; - } else if (await isNodeJsInstalled()) { - installed = true; - } else { - const items: MessageItem[] = [install, DialogResponses.learnMore]; - input = await innerContext.ui.showWarningMessage(message, { modal: true }, ...items); - innerContext.telemetry.properties.dialogResult = input.title; - - if (input === install) { - await installNodeJs(innerContext); - installed = true; - } else if (input === DialogResponses.learnMore) { - await openUrl('https://nodejs.org/en/download'); - } - } - }); - - // validate that DotNet was installed only if user confirmed - if (input === install && !installed) { - if ( - (await context.ui.showWarningMessage( - localize('failedInstallDotNet', 'The Node JS installation failed. Please manually install instead.'), - DialogResponses.learnMore - )) === DialogResponses.learnMore - ) { - await openUrl('https://nodejs.org/en/download'); - } - } - - return installed; -} - -/** - * Check is dotnet is installed. - * @returns {Promise} Returns true if installed, otherwise returns false. - */ -export async function isNodeJsInstalled(): Promise { - try { - await executeCommand(undefined, undefined, getNodeJsCommand(), '--version'); - return true; - } catch { - return false; - } -} diff --git a/apps/vs-code-designer/src/app/commands/nodeJs/validateNodeJsIsLatest.ts b/apps/vs-code-designer/src/app/commands/nodeJs/validateNodeJsIsLatest.ts deleted file mode 100644 index 853a313418c..00000000000 --- a/apps/vs-code-designer/src/app/commands/nodeJs/validateNodeJsIsLatest.ts +++ /dev/null @@ -1,62 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import { nodeJsDependencyName } from '../../../constants'; -import { localize } from '../../../localize'; -import { binariesExist, getLatestNodeJsVersion } from '../../utils/binaries'; -import { getLocalNodeJsVersion, getNodeJsCommand } from '../../utils/nodeJs/nodeJsVersion'; -import { getWorkspaceSetting, updateGlobalSetting } from '../../utils/vsCodeConfig/settings'; -import { installNodeJs } from './installNodeJs'; -import { callWithTelemetryAndErrorHandling, DialogResponses, openUrl } from '@microsoft/vscode-azext-utils'; -import type { IActionContext } from '@microsoft/vscode-azext-utils'; -import * as semver from 'semver'; -import type { MessageItem } from 'vscode'; - -export async function validateNodeJsIsLatest(majorVersion?: string): Promise { - await callWithTelemetryAndErrorHandling('azureLogicAppsStandard.validateNodeJsIsLatest', async (context: IActionContext) => { - context.errorHandling.suppressDisplay = true; - context.telemetry.properties.isActivationEvent = 'true'; - const showNodeJsWarningKey = 'showNodeJsWarning'; - const showNodeJsWarning = !!getWorkspaceSetting(showNodeJsWarningKey); - const binaries = binariesExist(nodeJsDependencyName); - context.telemetry.properties.binariesExist = `${binaries}`; - - if (!binaries) { - await installNodeJs(context, majorVersion); - context.telemetry.properties.binaryCommand = `${getNodeJsCommand()}`; - } else if (showNodeJsWarning) { - context.telemetry.properties.binaryCommand = `${getNodeJsCommand()}`; - const localVersion: string | null = await getLocalNodeJsVersion(context); - context.telemetry.properties.localVersion = localVersion; - const newestVersion: string | undefined = await getLatestNodeJsVersion(context, majorVersion); - - if (localVersion === null) { - await installNodeJs(context, majorVersion); - } else if (semver.major(newestVersion) === semver.major(localVersion) && semver.gt(newestVersion, localVersion)) { - context.telemetry.properties.outOfDateDotNet = 'true'; - const message: string = localize( - 'outdatedNodeJsRuntime', - 'Update your local Node JS version ({0}) to the latest version ({1}) for the best experience.', - localVersion, - newestVersion - ); - const update: MessageItem = { title: 'Update' }; - let result: MessageItem; - do { - result = - newestVersion !== undefined - ? await context.ui.showWarningMessage(message, update, DialogResponses.learnMore, DialogResponses.dontWarnAgain) - : await context.ui.showWarningMessage(message, DialogResponses.learnMore, DialogResponses.dontWarnAgain); - if (result === DialogResponses.learnMore) { - await openUrl('https://nodejs.org/en/download'); - } else if (result === update) { - await installNodeJs(context, majorVersion); - } else if (result === DialogResponses.dontWarnAgain) { - await updateGlobalSetting(showNodeJsWarningKey, false); - } - } while (result === DialogResponses.learnMore); - } - } - }); -} diff --git a/apps/vs-code-designer/src/app/commands/registerCommands.ts b/apps/vs-code-designer/src/app/commands/registerCommands.ts index 11aa264deb5..8de0b690741 100644 --- a/apps/vs-code-designer/src/app/commands/registerCommands.ts +++ b/apps/vs-code-designer/src/app/commands/registerCommands.ts @@ -11,8 +11,6 @@ import { editAppSetting } from './appSettings/editAppSetting'; import { renameAppSetting } from './appSettings/renameAppSetting'; import { toggleSlotSetting } from './appSettings/toggleSlotSetting'; import { uploadAppSettings } from './appSettings/uploadAppSettings'; -import { disableValidateAndInstallBinaries, resetValidateAndInstallBinaries } from './binaries/resetValidateAndInstallBinaries'; -import { validateAndInstallBinaries } from './binaries/validateAndInstallBinaries'; import { browseWebsite } from './browseWebsite'; import { buildCustomCodeFunctionsProject } from './buildCustomCodeFunctionsProject'; import { configureDeploymentSource } from './configureDeploymentSource'; @@ -155,9 +153,6 @@ export function registerCommands(): void { registerCommandWithTreeNodeUnwrapping(extensionCommand.configureDeploymentSource, configureDeploymentSource); registerCommandWithTreeNodeUnwrapping(extensionCommand.startRemoteDebug, startRemoteDebug); registerCommand(extensionCommand.parameterizeConnections, parameterizeConnections); - registerCommandWithTreeNodeUnwrapping(extensionCommand.validateAndInstallBinaries, validateAndInstallBinaries); - registerCommandWithTreeNodeUnwrapping(extensionCommand.resetValidateAndInstallBinaries, resetValidateAndInstallBinaries); - registerCommandWithTreeNodeUnwrapping(extensionCommand.disableValidateAndInstallBinaries, disableValidateAndInstallBinaries); // Data Mapper Commands registerCommand(extensionCommand.createNewDataMap, (context: IActionContext) => createNewDataMapCmd(context)); registerCommand(extensionCommand.loadDataMapFile, (context: IActionContext, uri: Uri) => loadDataMapFileCmd(context, uri)); diff --git a/apps/vs-code-designer/src/app/commands/workflows/switchToDotnetProject.ts b/apps/vs-code-designer/src/app/commands/workflows/switchToDotnetProject.ts index 122a0ad99cc..0f7a6cb2705 100644 --- a/apps/vs-code-designer/src/app/commands/workflows/switchToDotnetProject.ts +++ b/apps/vs-code-designer/src/app/commands/workflows/switchToDotnetProject.ts @@ -16,7 +16,6 @@ import { import { localize } from '../../../localize'; import { initProjectForVSCode } from '../../commands/initProjectForVSCode/initProjectForVSCode'; import { DotnetTemplateProvider } from '../../templates/dotnet/DotnetTemplateProvider'; -import { useBinariesDependencies } from '../../utils/binaries'; import { getDotnetBuildFile, addNugetPackagesToBuildFile, @@ -29,7 +28,7 @@ import { allowLocalSettingsToPublishDirectory, addNugetPackagesToBuildFileByName, } from '../../utils/codeless/updateBuildFile'; -import { getLocalDotNetVersionFromBinaries, getProjFiles, getTemplateKeyFromProjFile } from '../../utils/dotnet/dotnet'; +import { getProjFiles, getTemplateKeyFromProjFile } from '../../utils/dotnet/dotnet'; import { getFramework, executeDotnetTemplateCommand } from '../../utils/dotnet/executeDotnetTemplateCommand'; import { wrapArgInQuotes } from '../../utils/funcCoreTools/cpUtils'; import { tryGetMajorVersion, tryParseFuncVersion } from '../../utils/funcCoreTools/funcVersion'; @@ -43,7 +42,6 @@ import { FuncVersion, ProjectLanguage } from '@microsoft/vscode-extension-logic- import * as fse from 'fs-extra'; import * as path from 'path'; import * as vscode from 'vscode'; -import { validateDotNetIsInstalled } from '../dotnet/validateDotNetInstalled'; import { tryGetLogicAppProjectRoot } from '../../utils/verifyIsProject'; import { ext } from '../../../extensionVariables'; @@ -63,11 +61,6 @@ export async function switchToDotnetProject( target = vscode.Uri.file(projectPath); } - const isDotNetInstalled = await validateDotNetIsInstalled(context, target.fsPath); - if (!isDotNetInstalled) { - return; - } - let version: FuncVersion | undefined = tryParseFuncVersion(getWorkspaceSetting(funcVersionSetting, target.fsPath)); if (isCodeful) { version = FuncVersion.v4; @@ -134,8 +127,6 @@ export async function switchToDotnetProject( const projectPath: string = target.fsPath; const projTemplateKey = await getTemplateKeyFromProjFile(context, projectPath, version, ProjectLanguage.CSharp); const dotnetVersion = await getFramework(context, projectPath, isCodeful); - const useBinaries = useBinariesDependencies(); - const dotnetLocalVersion = useBinaries ? await getLocalDotNetVersionFromBinaries(localDotNetMajorVersion) : ''; await deleteBundleProjectFiles(target); await renameBundleProjectFiles(target); @@ -156,9 +147,7 @@ export async function switchToDotnetProject( await copyBundleProjectFiles(target); await updateBuildFile(context, target, dotnetVersion, isCodeful); - if (useBinaries) { - await createGlobalJsonFile(dotnetLocalVersion, target.fsPath); - } + await createGlobalJsonFile(localDotNetMajorVersion, target.fsPath); const workspaceFolder: vscode.WorkspaceFolder | undefined = getContainingWorkspace(target.fsPath); diff --git a/apps/vs-code-designer/src/app/debug/validatePreDebug.ts b/apps/vs-code-designer/src/app/debug/validatePreDebug.ts index 5aa0bec8079..da7e7127785 100644 --- a/apps/vs-code-designer/src/app/debug/validatePreDebug.ts +++ b/apps/vs-code-designer/src/app/debug/validatePreDebug.ts @@ -11,7 +11,6 @@ import { Platform, } from '../../constants'; import { localize } from '../../localize'; -import { validateFuncCoreToolsInstalled } from '../commands/funcCoreTools/validateFuncCoreToolsInstalled'; import { getAzureWebJobsStorage, setLocalAppSetting } from '../utils/appSettings/localSettings'; import { getDebugConfigs, isDebugConfigEqual } from '../utils/vsCodeConfig/launch'; import { getWorkspaceSetting, getFunctionsWorkerRuntime } from '../utils/vsCodeConfig/settings'; @@ -38,11 +37,6 @@ export async function preDebugValidate( try { context.telemetry.properties.lastValidateStep = 'funcInstalled'; - const message: string = localize( - 'installFuncTools', - 'You must have the Azure Functions Core Tools installed to debug your local functions.' - ); - shouldContinue = await validateFuncCoreToolsInstalled(context, message, projectPath); if (shouldContinue) { const projectLanguage: string | undefined = getWorkspaceSetting(projectLanguageSetting, projectPath); diff --git a/apps/vs-code-designer/src/app/utils/__test__/binaries.test.ts b/apps/vs-code-designer/src/app/utils/__test__/binaries.test.ts deleted file mode 100644 index e3b086ead7d..00000000000 --- a/apps/vs-code-designer/src/app/utils/__test__/binaries.test.ts +++ /dev/null @@ -1,406 +0,0 @@ -import { describe, it, expect, vi, beforeEach, afterEach, Mock } from 'vitest'; -import * as fs from 'fs'; -import axios from 'axios'; -import * as vscode from 'vscode'; -import { - downloadAndExtractDependency, - binariesExist, - getLatestDotNetVersion, - getLatestFunctionCoreToolsVersion, - getLatestNodeJsVersion, - getNodeJsBinariesReleaseUrl, - getFunctionCoreToolsBinariesReleaseUrl, - getDotNetBinariesReleaseUrl, - getCpuArchitecture, - getDependencyTimeout, - installBinaries, - useBinariesDependencies, -} from '../binaries'; -import { ext } from '../../../extensionVariables'; -import { DependencyVersion, Platform } from '../../../constants'; -import { executeCommand } from '../funcCoreTools/cpUtils'; -import { getNpmCommand } from '../nodeJs/nodeJsVersion'; -import { getGlobalSetting, getWorkspaceSetting } from '../vsCodeConfig/settings'; -import type { IActionContext } from '@microsoft/vscode-azext-utils'; -import { isNodeJsInstalled } from '../../commands/nodeJs/validateNodeJsInstalled'; - -vi.mock('../funcCoreTools/cpUtils'); -vi.mock('../nodeJs/nodeJsVersion'); -vi.mock('../../../onboarding'); -vi.mock('../vsCodeConfig/settings'); -vi.mock('../../commands/nodeJs/validateNodeJsInstalled'); - -describe('binaries', () => { - describe('downloadAndExtractDependency', () => { - let context: IActionContext; - - beforeEach(() => { - context = { - telemetry: { - properties: {}, - }, - } as IActionContext; - }); - - it('should download and extract dependency', async () => { - const downloadUrl = 'https://example.com/dependency.zip'; - const targetFolder = 'targetFolder'; - const dependencyName = 'dependency'; - const folderName = 'folderName'; - const dotNetVersion = '6.0'; - - const writer = { - on: vi.fn(), - } as any; - - (axios.get as Mock).mockResolvedValue({ - data: { - pipe: vi.fn().mockImplementation((writer) => { - writer.on('finish'); - }), - }, - }); - - (fs.createWriteStream as Mock).mockReturnValue(writer); - - await downloadAndExtractDependency(context, downloadUrl, targetFolder, dependencyName, folderName, dotNetVersion); - - expect(fs.mkdirSync).toHaveBeenCalledWith(expect.any(String), { recursive: true }); - expect(fs.chmodSync).toHaveBeenCalledWith(expect.any(String), 0o777); - expect(executeCommand).toHaveBeenCalledWith(ext.outputChannel, undefined, 'echo', `Downloading dependency from: ${downloadUrl}`); - }); - - it('should throw error when the compression file extension is not supported', async () => { - const downloadUrl = 'https://example.com/dependency.zip222'; - const targetFolder = 'targetFolder'; - const dependencyName = 'dependency'; - const folderName = 'folderName'; - const dotNetVersion = '6.0'; - - await expect( - downloadAndExtractDependency(context, downloadUrl, targetFolder, dependencyName, folderName, dotNetVersion) - ).rejects.toThrowError(); - }); - }); - - describe('binariesExist', () => { - beforeEach(() => { - (getGlobalSetting as Mock).mockReturnValue('binariesLocation'); - }); - it('should return true if binaries exist', () => { - (fs.existsSync as Mock).mockReturnValue(true); - - const result = binariesExist('dependencyName'); - - expect(result).toBe(true); - }); - - it('should return false if binaries do not exist', () => { - (fs.existsSync as Mock).mockReturnValue(false); - - const result = binariesExist('dependencyName'); - - expect(result).toBe(false); - }); - - it('should return false if useBinariesDependencies returns false', () => { - (fs.existsSync as Mock).mockReturnValue(false); - (getGlobalSetting as Mock).mockReturnValue(false); - const result = binariesExist('dependencyName'); - - expect(result).toBe(false); - }); - }); - - describe('getLatestDotNetVersion', () => { - let context: IActionContext; - let majorVersion: string; - - beforeEach(() => { - context = { - telemetry: { - properties: {}, - }, - } as IActionContext; - majorVersion = '6'; - }); - - it('should return the latest .NET version', async () => { - const response = [{ tag_name: 'v6.0.0' }]; - - (axios.get as Mock).mockResolvedValue({ data: response, status: 200 }); - - const result = await getLatestDotNetVersion(context, majorVersion); - - expect(result).toBe('6.0.0'); - }); - - it('should throw error when api call to get dotnet version fails and return fallback version', async () => { - const showErrorMessage = vi.fn(); - (axios.get as Mock).mockResolvedValue({ data: [], status: 500 }); - - vscode.window.showErrorMessage = showErrorMessage; - - const result = await getLatestDotNetVersion(context, majorVersion); - expect(result).toBe(DependencyVersion.dotnet6); - expect(showErrorMessage).toHaveBeenCalled(); - }); - - it('should return fallback dotnet version when no major version is sent', async () => { - const result = await getLatestDotNetVersion(context); - - expect(result).toBe(DependencyVersion.dotnet6); - }); - }); - - describe('getLatestFunctionCoreToolsVersion', () => { - let context: IActionContext; - let majorVersion: string; - - beforeEach(() => { - context = { - telemetry: { - properties: {}, - }, - } as IActionContext; - majorVersion = '3'; - }); - - it('should return the latest Function Core Tools version from npm', async () => { - const npmVersion = '3.0.0'; - (isNodeJsInstalled as Mock).mockResolvedValue(true); - (getNpmCommand as Mock).mockReturnValue('npm'); - (executeCommand as Mock).mockResolvedValue(npmVersion); - - const result = await getLatestFunctionCoreToolsVersion(context, majorVersion); - - expect(result).toBe(npmVersion); - expect(context.telemetry.properties.latestVersionSource).toBe('node'); - }); - - it('should return the latest Function Core Tools version from GitHub', async () => { - const githubVersion = '3.0.0'; - (isNodeJsInstalled as Mock).mockResolvedValue(false); - (axios.get as Mock).mockResolvedValue({ data: { tag_name: `v${githubVersion}` }, status: 200 }); - - const result = await getLatestFunctionCoreToolsVersion(context, majorVersion); - - expect(result).toBe(githubVersion); - expect(context.telemetry.properties.latestVersionSource).toBe('github'); - }); - - it('should return the fallback Function Core Tools version', async () => { - const showErrorMessage = vi.fn(); - (isNodeJsInstalled as Mock).mockResolvedValue(false); - (axios.get as Mock).mockResolvedValue({ data: [], status: 500 }); - - vscode.window.showErrorMessage = showErrorMessage; - - const result = await getLatestFunctionCoreToolsVersion(context, majorVersion); - - expect(result).toBe(DependencyVersion.funcCoreTools); - expect(showErrorMessage).toHaveBeenCalled(); - expect(context.telemetry.properties.latestVersionSource).toBe('fallback'); - }); - - it('should return the fallback Function Core Tools version when no major version is sent', async () => { - (isNodeJsInstalled as Mock).mockResolvedValue(false); - const result = await getLatestFunctionCoreToolsVersion(context); - - expect(result).toBe(DependencyVersion.funcCoreTools); - expect(context.telemetry.properties.latestVersionSource).toBe('fallback'); - }); - }); - - describe('getLatestNodeJsVersion', () => { - let context: IActionContext; - let majorVersion: string; - - beforeEach(() => { - context = { - telemetry: { - properties: {}, - }, - } as IActionContext; - majorVersion = '14'; - }); - - it('should return the latest Node.js version', async () => { - const response = [{ tag_name: 'v14.0.0' }]; - (axios.get as any).mockResolvedValue({ data: response, status: 200 }); - const result = await getLatestNodeJsVersion(context, majorVersion); - - expect(result).toBe('14.0.0'); - }); - - it('should throw error when api call to get dotnet version fails', async () => { - const showErrorMessage = vi.fn(); - (axios.get as Mock).mockResolvedValue({ data: [], status: 500 }); - - vscode.window.showErrorMessage = showErrorMessage; - - const result = await getLatestNodeJsVersion(context, majorVersion); - expect(result).toBe(DependencyVersion.nodeJs); - expect(showErrorMessage).toHaveBeenCalled(); - }); - - it('should return fallback nodejs version when no major version is sent', async () => { - const result = await getLatestNodeJsVersion(context); - expect(result).toBe(DependencyVersion.nodeJs); - }); - }); - - describe('getNodeJsBinariesReleaseUrl', () => { - const version = '14.0.0'; - const arch = 'x64'; - - it('should return the correct Node.js binaries release URL for windows', () => { - const osPlatform = 'win'; - - const result = getNodeJsBinariesReleaseUrl(version, osPlatform, arch); - console.log(result); - - expect(result).toStrictEqual('https://nodejs.org/dist/v14.0.0/node-v14.0.0-win-x64.zip'); - }); - it('should return the correct Node.js binaries release URL for non windows', () => { - const osPlatform = 'darwin'; - const result = getNodeJsBinariesReleaseUrl(version, osPlatform, arch); - - expect(result).toStrictEqual('https://nodejs.org/dist/v14.0.0/node-v14.0.0-darwin-x64.tar.gz'); - }); - }); - - describe('getFunctionCoreToolsBinariesReleaseUrl', () => { - it('should return the correct Function Core Tools binaries release URL', () => { - const version = '3.0.0'; - const osPlatform = 'win-x64'; - const arch = 'x64'; - const result = getFunctionCoreToolsBinariesReleaseUrl(version, osPlatform, arch); - - expect(result).toStrictEqual( - `https://github.com/Azure/azure-functions-core-tools/releases/download/${version}/Azure.Functions.Cli.${osPlatform}-${arch}.${version}.zip` - ); - }); - }); - - describe('getDotNetBinariesReleaseUrl', () => { - const originalPlatform = process.platform; - - afterEach(() => { - vi.restoreAllMocks(); - Object.defineProperty(process, 'platform', { - value: originalPlatform, - }); - }); - - it('should return the correct .NET binaries release URL for windows', () => { - vi.stubGlobal('process', { - ...process, - platform: Platform.windows, - }); - const result = getDotNetBinariesReleaseUrl(); - - expect(result).toBe('https://dot.net/v1/dotnet-install.ps1'); - }); - - it('should return the correct .NET binaries release URL for non windows', () => { - vi.stubGlobal('process', { - ...process, - platform: Platform.mac, - }); - const result = getDotNetBinariesReleaseUrl(); - - expect(result).toBe('https://dot.net/v1/dotnet-install.sh'); - }); - }); - - describe('getCpuArchitecture', () => { - const originalArch = process.arch; - - afterEach(() => { - vi.restoreAllMocks(); - Object.defineProperty(process, 'arch', { - value: originalArch, - }); - }); - - it('should return the correct CPU architecture', () => { - vi.stubGlobal('process', { - ...process, - arch: 'x64', - }); - const result = getCpuArchitecture(); - - expect(result).toBe('x64'); - }); - - it('should throw an error for unsupported CPU architecture', () => { - (process as any).arch = vi.stubGlobal('process', { - ...process, - arch: 'unsupported', - }); - expect(() => getCpuArchitecture()).toThrowError('Unsupported CPU architecture: unsupported'); - }); - }); - - describe('getDependencyTimeout', () => { - it('should return the dependency timeout value', () => { - (getWorkspaceSetting as Mock).mockReturnValue(60); - - const result = getDependencyTimeout(); - - expect(result).toBe(60); - }); - - it('should throw an error for invalid timeout value', () => { - (getWorkspaceSetting as Mock).mockReturnValue('invalid'); - - expect(() => getDependencyTimeout()).toThrowError('The setting "invalid" must be a number, but instead found "invalid".'); - }); - }); - - describe('installBinaries', () => { - let context: IActionContext; - - beforeEach(() => { - context = { - telemetry: { - properties: {}, - }, - } as IActionContext; - }); - it('should install binaries', async () => { - (getGlobalSetting as Mock).mockReturnValue(true); - - await installBinaries(context); - - expect(context.telemetry.properties.autoRuntimeDependenciesValidationAndInstallationSetting).toBe('true'); - }); - - it('should not install binaries', async () => { - (getGlobalSetting as Mock).mockReturnValue(false); - - await installBinaries(context); - - expect(context.telemetry.properties.autoRuntimeDependenciesValidationAndInstallationSetting).toBe('false'); - }); - }); - - describe('useBinariesDependencies', () => { - it('should return true if binaries dependencies are used', () => { - (getGlobalSetting as Mock).mockReturnValue(true); - - const result = useBinariesDependencies(); - - expect(result).toBe(true); - }); - - it('should return false if binaries dependencies are not used', () => { - (getGlobalSetting as Mock).mockReturnValue(false); - - const result = useBinariesDependencies(); - - expect(result).toBe(false); - }); - }); -}); diff --git a/apps/vs-code-designer/src/app/utils/binaries.ts b/apps/vs-code-designer/src/app/utils/binaries.ts deleted file mode 100644 index f13a4e3e961..00000000000 --- a/apps/vs-code-designer/src/app/utils/binaries.ts +++ /dev/null @@ -1,440 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See LICENSE.md in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import { - DependencyVersion, - Platform, - autoRuntimeDependenciesValidationAndInstallationSetting, - autoRuntimeDependenciesPathSettingKey, - dependencyTimeoutSettingKey, - dotnetDependencyName, - funcPackageName, - defaultLogicAppsFolder, - dotNetBinaryPathSettingKey, - DependencyDefaultPath, - nodeJsBinaryPathSettingKey, - funcCoreToolsBinaryPathSettingKey, - funcDependencyName, - extensionBundleId, -} from '../../constants'; -import { ext } from '../../extensionVariables'; -import { localize } from '../../localize'; -import { onboardBinaries } from '../../onboarding'; -import { isNodeJsInstalled } from '../commands/nodeJs/validateNodeJsInstalled'; -import { executeCommand } from './funcCoreTools/cpUtils'; -import { getNpmCommand } from './nodeJs/nodeJsVersion'; -import { getGlobalSetting, getWorkspaceSetting, updateGlobalSetting } from './vsCodeConfig/settings'; -import type { IActionContext } from '@microsoft/vscode-azext-utils'; -import type { IGitHubReleaseInfo } from '@microsoft/vscode-extension-logic-apps'; -import axios from 'axios'; -import * as fs from 'fs'; -import * as os from 'os'; -import * as path from 'path'; -import * as semver from 'semver'; -import * as vscode from 'vscode'; - -import AdmZip = require('adm-zip'); -import { isNullOrUndefined, isString } from '@microsoft/logic-apps-shared'; -import { setFunctionsCommand } from './funcCoreTools/funcVersion'; -import { startAllDesignTimeApis, stopAllDesignTimeApis } from './codeless/startDesignTimeApi'; - -/** - * Download and Extracts dependency zip. - * @param {string} downloadUrl - download url. - * @param {string} targetFolder - Module name to check. - * @param {string} dependencyName - The Dedependency name. - * @param {string} folderName - Optional Folder name. Will default to dependency name if empty. - * @param {string} dotNetVersion - The .NET Major Version from CDN. - */ - -export async function downloadAndExtractDependency( - context: IActionContext, - downloadUrl: string, - targetFolder: string, - dependencyName: string, - folderName?: string, - dotNetVersion?: string -): Promise { - folderName = folderName || dependencyName; - const tempFolderPath = path.join(os.tmpdir(), defaultLogicAppsFolder, folderName); - targetFolder = path.join(targetFolder, folderName); - fs.mkdirSync(targetFolder, { recursive: true }); - - // Read and write permissions - fs.chmodSync(targetFolder, 0o777); - - const dependencyFileExtension = getCompressionFileExtension(downloadUrl); - const dependencyFilePath = path.join(tempFolderPath, `${dependencyName}${dependencyFileExtension}`); - - executeCommand(ext.outputChannel, undefined, 'echo', `Downloading dependency from: ${downloadUrl}`); - - axios.get(downloadUrl, { responseType: 'stream' }).then((response) => { - executeCommand(ext.outputChannel, undefined, 'echo', `Creating temporary folder... ${tempFolderPath}`); - fs.mkdirSync(tempFolderPath, { recursive: true }); - fs.chmodSync(tempFolderPath, 0o777); - - const writer = fs.createWriteStream(dependencyFilePath); - response.data.pipe(writer); - - writer.on('finish', async () => { - executeCommand(ext.outputChannel, undefined, 'echo', `Successfully downloaded ${dependencyName} dependency.`); - fs.chmodSync(dependencyFilePath, 0o777); - - // Extract to targetFolder - if (dependencyName === dotnetDependencyName) { - const version = dotNetVersion ?? semver.major(DependencyVersion.dotnet6); - process.platform === Platform.windows - ? await executeCommand( - ext.outputChannel, - undefined, - 'powershell -ExecutionPolicy Bypass -File', - dependencyFilePath, - '-InstallDir', - targetFolder, - '-Channel', - `${version}.0` - ) - : await executeCommand(ext.outputChannel, undefined, dependencyFilePath, '-InstallDir', targetFolder, '-Channel', `${version}.0`); - } else { - if (dependencyName === funcDependencyName || dependencyName === extensionBundleId) { - stopAllDesignTimeApis(); - } - await extractDependency(dependencyFilePath, targetFolder, dependencyName); - vscode.window.showInformationMessage(localize('successInstall', `Successfully installed ${dependencyName}`)); - if (dependencyName === funcDependencyName) { - // Add execute permissions for func and gozip binaries - if (process.platform !== Platform.windows) { - fs.chmodSync(`${targetFolder}/func`, 0o755); - fs.chmodSync(`${targetFolder}/gozip`, 0o755); - fs.chmodSync(`${targetFolder}/in-proc8/func`, 0o755); - fs.chmodSync(`${targetFolder}/in-proc6/func`, 0o755); - } - await setFunctionsCommand(); - await startAllDesignTimeApis(); - } else if (dependencyName === extensionBundleId) { - await startAllDesignTimeApis(); - } - } - // remove the temp folder. - fs.rmSync(tempFolderPath, { recursive: true }); - executeCommand(ext.outputChannel, undefined, 'echo', `Removed ${tempFolderPath}`); - }); - writer.on('error', async (error) => { - // log the error message the VSCode window and to telemetry. - const errorMessage = `Error downloading and extracting the ${dependencyName} zip file: ${error.message}`; - vscode.window.showErrorMessage(errorMessage); - context.telemetry.properties.error = errorMessage; - - // remove the target folder. - fs.rmSync(targetFolder, { recursive: true }); - await executeCommand(ext.outputChannel, undefined, 'echo', `[ExtractError]: Removed ${targetFolder}`); - }); - }); -} - -const getFunctionCoreToolVersionFromGithub = async (context: IActionContext, majorVersion: string): Promise => { - try { - const response: IGitHubReleaseInfo = await readJsonFromUrl( - 'https://api.github.com/repos/Azure/azure-functions-core-tools/releases/latest' - ); - const latestVersion = semver.valid(semver.coerce(response.tag_name)); - context.telemetry.properties.latestVersionSource = 'github'; - context.telemetry.properties.latestGithubVersion = response.tag_name; - if (checkMajorVersion(latestVersion, majorVersion)) { - return latestVersion; - } - throw new Error( - localize( - 'latestVersionNotFound', - 'Latest version of Azure Functions Core Tools not found for major version {0}. Latest version is {1}.', - majorVersion, - latestVersion - ) - ); - } catch (error) { - const errorMessage = error instanceof Error ? error.message : isString(error) ? error : 'Unknown error'; - context.telemetry.properties.latestVersionSource = 'fallback'; - context.telemetry.properties.errorLatestFunctionCoretoolsVersion = `Error getting latest function core tools version from github: ${errorMessage}`; - return DependencyVersion.funcCoreTools; - } -}; - -export async function getLatestFunctionCoreToolsVersion(context: IActionContext, majorVersion?: string): Promise { - context.telemetry.properties.funcCoreTools = majorVersion; - - if (!majorVersion) { - context.telemetry.properties.latestVersionSource = 'fallback'; - return DependencyVersion.funcCoreTools; - } - - // Use npm to find newest func core tools version - const hasNodeJs = await isNodeJsInstalled(); - if (hasNodeJs) { - context.telemetry.properties.latestVersionSource = 'node'; - try { - const npmCommand = getNpmCommand(); - const latestVersion = (await executeCommand(undefined, undefined, `${npmCommand}`, 'view', funcPackageName, 'version'))?.trim(); - if (checkMajorVersion(latestVersion, majorVersion)) { - return latestVersion; - } - } catch (error) { - context.telemetry.properties.errorLatestFunctionCoretoolsVersion = `Error executing npm command to get latest function core tools version: ${error}`; - } - } - return await getFunctionCoreToolVersionFromGithub(context, majorVersion); -} - -/** - * Retrieves the latest version of .NET SDK. - * @param {IActionContext} context - The action context. - * @param {string} majorVersion - The major version of .NET SDK to retrieve. (optional) - * @returns A promise that resolves to the latest version of .NET SDK. - * @throws An error if there is an issue retrieving the latest .NET SDK version. - */ -export async function getLatestDotNetVersion(context: IActionContext, majorVersion?: string): Promise { - context.telemetry.properties.dotNetMajorVersion = majorVersion; - - if (majorVersion) { - return await readJsonFromUrl('https://api.github.com/repos/dotnet/sdk/releases') - .then((response: IGitHubReleaseInfo[]) => { - context.telemetry.properties.latestVersionSource = 'github'; - let latestVersion: string | null; - for (const releaseInfo of response) { - const releaseVersion: string | null = semver.valid(semver.coerce(releaseInfo.tag_name)); - context.telemetry.properties.latestGithubVersion = releaseInfo.tag_name; - if ( - checkMajorVersion(releaseVersion, majorVersion) && - (isNullOrUndefined(latestVersion) || semver.gt(releaseVersion, latestVersion)) - ) { - latestVersion = releaseVersion; - } - } - return latestVersion; - }) - .catch((error) => { - context.telemetry.properties.latestVersionSource = 'fallback'; - context.telemetry.properties.errorNewestDotNetVersion = `Error getting latest .NET SDK version: ${error}`; - return DependencyVersion.dotnet6; - }); - } - - context.telemetry.properties.latestVersionSource = 'fallback'; - return DependencyVersion.dotnet6; -} - -export async function getLatestNodeJsVersion(context: IActionContext, majorVersion?: string): Promise { - context.telemetry.properties.nodeMajorVersion = majorVersion; - - if (majorVersion) { - return await readJsonFromUrl('https://api.github.com/repos/nodejs/node/releases') - .then((response: IGitHubReleaseInfo[]) => { - context.telemetry.properties.latestVersionSource = 'github'; - for (const releaseInfo of response) { - const releaseVersion = semver.valid(semver.coerce(releaseInfo.tag_name)); - context.telemetry.properties.latestGithubVersion = releaseInfo.tag_name; - if (checkMajorVersion(releaseVersion, majorVersion)) { - return releaseVersion; - } - } - }) - .catch((error) => { - context.telemetry.properties.latestNodeJSVersion = 'fallback'; - context.telemetry.properties.errorLatestNodeJsVersion = `Error getting latest Node JS version: ${error}`; - return DependencyVersion.nodeJs; - }); - } - - context.telemetry.properties.latestNodeJSVersion = 'fallback'; - return DependencyVersion.nodeJs; -} - -export function getNodeJsBinariesReleaseUrl(version: string, osPlatform: string, arch: string): string { - if (osPlatform === 'win') { - return `https://nodejs.org/dist/v${version}/node-v${version}-${osPlatform}-${arch}.zip`; - } - - return `https://nodejs.org/dist/v${version}/node-v${version}-${osPlatform}-${arch}.tar.gz`; -} - -export function getFunctionCoreToolsBinariesReleaseUrl(version: string, osPlatform: string, arch: string): string { - return `https://github.com/Azure/azure-functions-core-tools/releases/download/${version}/Azure.Functions.Cli.${osPlatform}-${arch}.${version}.zip`; -} - -export function getDotNetBinariesReleaseUrl(): string { - return process.platform === Platform.windows ? 'https://dot.net/v1/dotnet-install.ps1' : 'https://dot.net/v1/dotnet-install.sh'; -} - -export function getCpuArchitecture() { - switch (process.arch) { - case 'x64': - case 'arm64': - return process.arch; - - default: - throw new Error(localize('UnsupportedCPUArchitecture', `Unsupported CPU architecture: ${process.arch}`)); - } -} - -/** - * Checks if binaries folder directory path exists. - * @param dependencyName The name of the dependency. - * @returns true if expected binaries folder directory path exists - */ -export function binariesExist(dependencyName: string): boolean { - if (!useBinariesDependencies()) { - return false; - } - const binariesLocation = getGlobalSetting(autoRuntimeDependenciesPathSettingKey); - const binariesPath = path.join(binariesLocation, dependencyName); - const binariesExist = fs.existsSync(binariesPath); - - executeCommand(ext.outputChannel, undefined, 'echo', `${dependencyName} Binaries: ${binariesPath}`); - return binariesExist; -} - -async function readJsonFromUrl(url: string): Promise { - try { - const response = await axios.get(url); - if (response.status === 200) { - return response.data; - } - throw new Error(`Request failed with status: ${response.status}`); - } catch (error) { - vscode.window.showErrorMessage(`Error reading JSON from URL ${url} : ${error.message}`); - throw error; - } -} - -function getCompressionFileExtension(binariesUrl: string): string { - if (binariesUrl.endsWith('.zip')) { - return '.zip'; - } - - if (binariesUrl.endsWith('.tar.gz')) { - return '.tar.gz'; - } - - if (binariesUrl.endsWith('.tar.xz')) { - return '.tar.xz'; - } - - if (binariesUrl.endsWith('.ps1')) { - return '.ps1'; - } - - if (binariesUrl.endsWith('.sh')) { - return '.sh'; - } - - throw new Error(localize('UnsupportedCompressionFileExtension', `Unsupported compression file extension: ${binariesUrl}`)); -} - -function cleanDirectory(targetFolder: string): void { - // Read all files/folders in targetFolder - const entries = fs.readdirSync(targetFolder); - for (const entry of entries) { - const entryPath = path.join(targetFolder, entry); - // Remove files or directories recursively - fs.rmSync(entryPath, { recursive: true, force: true }); - } -} - -async function extractDependency(dependencyFilePath: string, targetFolder: string, dependencyName: string): Promise { - // Clear targetFolder's contents without deleting the folder itself - // TODO(aeldridge): It is possible there is a lock on a file in targetFolder, should be handled. - cleanDirectory(targetFolder); - await executeCommand(ext.outputChannel, undefined, 'echo', `Extracting ${dependencyFilePath}`); - try { - if (dependencyFilePath.endsWith('.zip')) { - const zip = new AdmZip(dependencyFilePath); - await zip.extractAllTo(targetFolder, /* overwrite */ true, /* Permissions */ true); - } else { - await executeCommand(ext.outputChannel, undefined, 'tar', '-xzvf', dependencyFilePath, '-C', targetFolder); - } - extractContainerFolder(targetFolder); - await executeCommand(ext.outputChannel, undefined, 'echo', `Extraction ${dependencyName} successfully completed.`); - } catch (error) { - throw new Error(`Error extracting ${dependencyName}: ${error}`); - } -} - -/** - * Checks if the major version of a given version string matches the specified major version. - * @param {string} version - The version string to check. - * @param {string} majorVersion - The major version to compare against. - * @returns A boolean indicating whether the major version matches. - */ -function checkMajorVersion(version: string, majorVersion: string): boolean { - return semver.major(version) === Number(majorVersion); -} - -/** - * Cleans up by removing Container Folder: - * path/to/folder/container/files --> /path/to/folder/files - * @param targetFolder - */ -function extractContainerFolder(targetFolder: string) { - const extractedContents = fs.readdirSync(targetFolder); - if (extractedContents.length === 1 && fs.statSync(path.join(targetFolder, extractedContents[0])).isDirectory()) { - const containerFolderPath = path.join(targetFolder, extractedContents[0]); - const containerContents = fs.readdirSync(containerFolderPath); - containerContents.forEach((content) => { - const contentPath = path.join(containerFolderPath, content); - const destinationPath = path.join(targetFolder, content); - fs.renameSync(contentPath, destinationPath); - }); - - if (fs.readdirSync(containerFolderPath).length === 0) { - fs.rmSync(containerFolderPath, { recursive: true }); - } - } -} - -/** - * Gets dependency timeout setting value from workspace settings. - * @param {IActionContext} context - Command context. - * @returns {number} Timeout value in seconds. - */ -export function getDependencyTimeout(): number { - const dependencyTimeoutValue: number | undefined = getWorkspaceSetting(dependencyTimeoutSettingKey); - const timeoutInSeconds = Number(dependencyTimeoutValue); - if (Number.isNaN(timeoutInSeconds)) { - throw new Error( - localize( - 'invalidSettingValue', - 'The setting "{0}" must be a number, but instead found "{1}".', - dependencyTimeoutValue, - dependencyTimeoutValue - ) - ); - } - - return timeoutInSeconds; -} - -/** - * Prompts warning message to decide the auto validation/installation of dependency binaries. - * @param {IActionContext} context - Activation context. - */ -export async function installBinaries(context: IActionContext) { - const useBinaries = useBinariesDependencies(); - - if (useBinaries) { - await onboardBinaries(context); - context.telemetry.properties.autoRuntimeDependenciesValidationAndInstallationSetting = 'true'; - } else { - await updateGlobalSetting(dotNetBinaryPathSettingKey, DependencyDefaultPath.dotnet); - await updateGlobalSetting(nodeJsBinaryPathSettingKey, DependencyDefaultPath.node); - await updateGlobalSetting(funcCoreToolsBinaryPathSettingKey, DependencyDefaultPath.funcCoreTools); - context.telemetry.properties.autoRuntimeDependenciesValidationAndInstallationSetting = 'false'; - } -} - -/** - * Returns boolean to determine if workspace uses binaries dependencies. - */ -export const useBinariesDependencies = (): boolean => { - const binariesInstallation = getGlobalSetting(autoRuntimeDependenciesValidationAndInstallationSetting); - return !!binariesInstallation; -}; diff --git a/apps/vs-code-designer/src/app/utils/bundleFeed.ts b/apps/vs-code-designer/src/app/utils/bundleFeed.ts index 7be952b9eb3..afb0f73b014 100644 --- a/apps/vs-code-designer/src/app/utils/bundleFeed.ts +++ b/apps/vs-code-designer/src/app/utils/bundleFeed.ts @@ -4,10 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import { defaultVersionRange, extensionBundleId, localSettingsFileName, defaultExtensionBundlePathValue } from '../../constants'; import { getLocalSettingsJson } from './appSettings/localSettings'; -import { downloadAndExtractDependency } from './binaries'; import { getJsonFeed } from './feed'; import type { IActionContext } from '@microsoft/vscode-azext-utils'; -import type { IBundleDependencyFeed, IBundleFeed, IBundleMetadata, IHostJsonV2 } from '@microsoft/vscode-extension-logic-apps'; +import type { IBundleFeed, IBundleMetadata, IHostJsonV2 } from '@microsoft/vscode-extension-logic-apps'; import * as path from 'path'; import * as semver from 'semver'; import * as vscode from 'vscode'; @@ -52,29 +51,6 @@ async function getWorkflowBundleFeed(context: IActionContext): Promise} Returns bundle extension object. - */ -async function getBundleDependencyFeed( - context: IActionContext, - bundleMetadata: IBundleMetadata | undefined -): Promise { - const bundleId: string = (bundleMetadata && bundleMetadata?.id) || extensionBundleId; - const projectPath: string | undefined = vscode.workspace.workspaceFolders ? vscode.workspace.workspaceFolders[0].uri.fsPath : null; - let envVarUri: string | undefined = process.env.FUNCTIONS_EXTENSIONBUNDLE_SOURCE_URI; - if (projectPath) { - envVarUri = (await getLocalSettingsJson(context, path.join(projectPath, localSettingsFileName)))?.Values - ?.FUNCTIONS_EXTENSIONBUNDLE_SOURCE_URI; - } - - const baseUrl: string = envVarUri || 'https://cdn.functions.azure.com/public'; - const url = `${baseUrl}/ExtensionBundles/${bundleId}/dependency.json`; - return getJsonFeed(context, url); -} - /** * Gets latest bundle extension version range. * @param {IActionContext} context - Command context. @@ -85,16 +61,6 @@ export async function getLatestVersionRange(context: IActionContext): Promise} Returns dependency versions. - */ -export async function getDependenciesVersion(context: IActionContext): Promise { - const feed: IBundleDependencyFeed = await getBundleDependencyFeed(context, undefined); - return feed; -} - /** * Add bundle extension version to host.json configuration. * @param {IActionContext} context - Command context. @@ -183,7 +149,9 @@ export async function downloadExtensionBundle(context: IActionContext): Promise< } const extensionBundleUrl = await getExtensionBundleZip(context, envVarVer); - await downloadAndExtractDependency(context, extensionBundleUrl, defaultExtensionBundlePathValue, extensionBundleId, envVarVer); + + //TODO (ccastrotrejo): Get the bundle in the container + console.log(extensionBundleUrl); context.telemetry.measurements.downloadExtensionBundleDuration = (Date.now() - downloadExtensionBundleStartTime) / 1000; context.telemetry.properties.didUpdateExtensionBundle = 'true'; return true; @@ -205,13 +173,8 @@ export async function downloadExtensionBundle(context: IActionContext): Promise< if (semver.gt(latestFeedBundleVersion, latestLocalBundleVersion)) { const extensionBundleUrl = await getExtensionBundleZip(context, latestFeedBundleVersion); - await downloadAndExtractDependency( - context, - extensionBundleUrl, - defaultExtensionBundlePathValue, - extensionBundleId, - latestFeedBundleVersion - ); + //TODO (ccastrotrejo): Get the bundle in the container + console.log(extensionBundleUrl); context.telemetry.measurements.downloadExtensionBundleDuration = (Date.now() - downloadExtensionBundleStartTime) / 1000; context.telemetry.properties.didUpdateExtensionBundle = 'true'; diff --git a/apps/vs-code-designer/src/app/utils/dotnet/dotnet.ts b/apps/vs-code-designer/src/app/utils/dotnet/dotnet.ts index ae6576953aa..5b2bd240a98 100644 --- a/apps/vs-code-designer/src/app/utils/dotnet/dotnet.ts +++ b/apps/vs-code-designer/src/app/utils/dotnet/dotnet.ts @@ -1,29 +1,12 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import { isNullOrUndefined } from '@microsoft/logic-apps-shared'; -import { - DotnetVersion, - Platform, - autoRuntimeDependenciesPathSettingKey, - dotNetBinaryPathSettingKey, - dotnetDependencyName, - isolatedSdkName, -} from '../../../constants'; -import { ext } from '../../../extensionVariables'; +import { DotnetVersion, isolatedSdkName } from '../../../constants'; import { localize } from '../../../localize'; -import { executeCommand } from '../funcCoreTools/cpUtils'; import { runWithDurationTelemetry } from '../telemetry'; -import { getGlobalSetting, updateGlobalSetting, updateWorkspaceSetting } from '../vsCodeConfig/settings'; -import { findFiles, getWorkspaceLogicAppFolders } from '../workspace'; +import { findFiles } from '../workspace'; import type { IActionContext } from '@microsoft/vscode-azext-utils'; import { AzExtFsExtra } from '@microsoft/vscode-azext-utils'; import type { IWorkerRuntime } from '@microsoft/vscode-extension-logic-apps'; import { FuncVersion, ProjectLanguage } from '@microsoft/vscode-extension-logic-apps'; -import * as fs from 'fs'; import * as path from 'path'; -import * as semver from 'semver'; export class ProjectFile { public name: string; @@ -186,89 +169,3 @@ export function getTemplateKeyFromFeedEntry(runtimeInfo: IWorkerRuntime): string const isIsolated = runtimeInfo.sdk.name.toLowerCase() === isolatedSdkName.toLowerCase(); return getProjectTemplateKey(runtimeInfo.targetFramework, isIsolated); } - -export async function getLocalDotNetVersionFromBinaries(majorVersion?: string): Promise { - const binariesLocation = getGlobalSetting(autoRuntimeDependenciesPathSettingKey); - const sdkVersionFolder = path.join(binariesLocation, dotnetDependencyName, 'sdk'); - - if (isNullOrUndefined(majorVersion)) { - try { - const output: string = await executeCommand(ext.outputChannel, undefined, getDotNetCommand(), '--version'); - const version: string | null = semver.clean(output); - if (version) { - return version; - } - } catch { - return null; - } - } - - const files = fs.existsSync(sdkVersionFolder) ? fs.readdirSync(sdkVersionFolder, { withFileTypes: true }) : null; - if (Array.isArray(files)) { - const sdkFolders = files.filter((file) => file.isDirectory()).map((file) => file.name); - const version = semver.maxSatisfying(sdkFolders, `~${majorVersion}`); - if (version !== null) { - await executeCommand(ext.outputChannel, undefined, 'echo', 'Local binary .NET SDK version', version); - return version; - } - } - - return null; -} - -/** - * Get the nodejs binaries executable or use the system nodejs executable. - */ -export function getDotNetCommand(): string { - const command = getGlobalSetting(dotNetBinaryPathSettingKey); - return command; -} - -export async function setDotNetCommand(): Promise { - const binariesLocation = getGlobalSetting(autoRuntimeDependenciesPathSettingKey); - const dotNetBinariesPath = path.join(binariesLocation, dotnetDependencyName); - const binariesExist = fs.existsSync(dotNetBinariesPath); - let command = ext.dotNetCliPath; - if (binariesExist) { - // Explicit executable for tasks.json - command = - process.platform === Platform.windows - ? path.join(dotNetBinariesPath, `${ext.dotNetCliPath}.exe`) - : path.join(dotNetBinariesPath, `${ext.dotNetCliPath}`); - const newPath = `${dotNetBinariesPath}${path.delimiter}\${env:PATH}`; - fs.chmodSync(dotNetBinariesPath, 0o777); - - try { - const workspaceLogicAppFolders = await getWorkspaceLogicAppFolders(); - for (const projectPath of workspaceLogicAppFolders) { - const pathEnv = { - PATH: newPath, - }; - - // Required for dotnet cli in VSCode Terminal - switch (process.platform) { - case Platform.windows: { - await updateWorkspaceSetting('integrated.env.windows', pathEnv, projectPath, 'terminal'); - break; - } - - case Platform.linux: { - await updateWorkspaceSetting('integrated.env.linux', pathEnv, projectPath, 'terminal'); - break; - } - - case Platform.mac: { - await updateWorkspaceSetting('integrated.env.osx', pathEnv, projectPath, 'terminal'); - break; - } - } - // Required for CoreClr - await updateWorkspaceSetting('dotNetCliPaths', [dotNetBinariesPath], projectPath, 'omnisharp'); - } - } catch (error) { - console.log(error); - } - } - - await updateGlobalSetting(dotNetBinaryPathSettingKey, command); -} diff --git a/apps/vs-code-designer/src/app/utils/dotnet/executeDotnetTemplateCommand.ts b/apps/vs-code-designer/src/app/utils/dotnet/executeDotnetTemplateCommand.ts index be483db6b21..ef00d7224c5 100644 --- a/apps/vs-code-designer/src/app/utils/dotnet/executeDotnetTemplateCommand.ts +++ b/apps/vs-code-designer/src/app/utils/dotnet/executeDotnetTemplateCommand.ts @@ -4,9 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { ext } from '../../../extensionVariables'; import { localize } from '../../../localize'; -import { useBinariesDependencies } from '../binaries'; import { executeCommand, wrapArgInQuotes } from '../funcCoreTools/cpUtils'; -import { getDotNetCommand, getLocalDotNetVersionFromBinaries } from './dotnet'; import type { IActionContext } from '@microsoft/vscode-azext-utils'; import type { FuncVersion } from '@microsoft/vscode-extension-logic-apps'; import * as path from 'path'; @@ -41,7 +39,7 @@ export async function executeDotnetTemplateCommand( return await executeCommand( undefined, workingDirectory, - getDotNetCommand(), + 'dotnet', wrapArgInQuotes(jsonDllPath), '--templateDir', wrapArgInQuotes(getDotnetTemplateDir(version, projTemplateKey)), @@ -86,22 +84,7 @@ export async function validateDotnetInstalled(context: IActionContext): Promise< */ export async function getFramework(context: IActionContext, workingDirectory: string | undefined, isCodeful = false): Promise { if (!cachedFramework || isCodeful) { - let versions = ''; - const dotnetBinariesLocation = getDotNetCommand(); - - versions = useBinariesDependencies() ? await getLocalDotNetVersionFromBinaries() : versions; - - try { - versions += await executeCommand(undefined, workingDirectory, dotnetBinariesLocation, '--version'); - } catch { - // ignore - } - - try { - versions += await executeCommand(undefined, workingDirectory, dotnetBinariesLocation, '--list-sdks'); - } catch { - // ignore - } + const versions = '8'; // Prioritize "LTS", then "Current", then "Preview" const netVersions: string[] = ['8', '6', '3', '2', '9', '10']; diff --git a/apps/vs-code-designer/src/app/utils/funcCoreTools/funcVersion.ts b/apps/vs-code-designer/src/app/utils/funcCoreTools/funcVersion.ts index 92160c5d7b5..e2d013b2ab9 100644 --- a/apps/vs-code-designer/src/app/utils/funcCoreTools/funcVersion.ts +++ b/apps/vs-code-designer/src/app/utils/funcCoreTools/funcVersion.ts @@ -2,21 +2,13 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { - autoRuntimeDependenciesPathSettingKey, - funcCoreToolsBinaryPathSettingKey, - funcDependencyName, - funcVersionSetting, -} from '../../../constants'; -import { ext } from '../../../extensionVariables'; +import { funcCoreToolsBinaryPathSettingKey, funcVersionSetting } from '../../../constants'; import { localize } from '../../../localize'; -import { getGlobalSetting, getWorkspaceSettingFromAnyFolder, updateGlobalSetting } from '../vsCodeConfig/settings'; +import { getGlobalSetting, getWorkspaceSettingFromAnyFolder } from '../vsCodeConfig/settings'; import { executeCommand } from './cpUtils'; import { isNullOrUndefined } from '@microsoft/logic-apps-shared'; import type { IActionContext } from '@microsoft/vscode-azext-utils'; import { FuncVersion, latestGAVersion } from '@microsoft/vscode-extension-logic-apps'; -import * as fs from 'fs'; -import * as path from 'path'; import * as semver from 'semver'; /** @@ -155,21 +147,3 @@ export function getFunctionsCommand(): string { } return command; } - -export async function setFunctionsCommand(): Promise { - const binariesLocation = getGlobalSetting(autoRuntimeDependenciesPathSettingKey); - const funcBinariesPath = path.join(binariesLocation, funcDependencyName); - const binariesExist = fs.existsSync(funcBinariesPath); - let command = ext.funcCliPath; - if (binariesExist) { - command = path.join(funcBinariesPath, ext.funcCliPath); - fs.chmodSync(funcBinariesPath, 0o777); - - const funcExist = await fs.existsSync(command); - if (funcExist) { - fs.chmodSync(command, 0o777); - } - } - - await updateGlobalSetting(funcCoreToolsBinaryPathSettingKey, command); -} diff --git a/apps/vs-code-designer/src/app/utils/funcCoreTools/getBrewPackageName.ts b/apps/vs-code-designer/src/app/utils/funcCoreTools/getBrewPackageName.ts deleted file mode 100644 index 61d7bc4e03e..00000000000 --- a/apps/vs-code-designer/src/app/utils/funcCoreTools/getBrewPackageName.ts +++ /dev/null @@ -1,54 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import { funcPackageName } from '../../../constants'; -import { executeCommand } from './cpUtils'; -import { tryGetMajorVersion } from './funcVersion'; -import { FuncVersion } from '@microsoft/vscode-extension-logic-apps'; - -/** - * Gets functions core tools brew package name. - * @param {FuncVersion} version - Package version. - * @returns {string} Returns full package name for brew. - */ -export function getBrewPackageName(version: FuncVersion): string { - return `${funcPackageName}@${tryGetMajorVersion(version)}`; -} - -/** - * Gets installed functions core tools brew package. - * @param {FuncVersion} version - Package version. - * @returns {Promise} Returns installed full package name for brew. - */ -export async function tryGetInstalledBrewPackageName(version: FuncVersion): Promise { - const brewPackageName: string = getBrewPackageName(version); - if (await isBrewPackageInstalled(brewPackageName)) { - return brewPackageName; - } - let oldPackageName: string | undefined; - if (version === FuncVersion.v2) { - oldPackageName = funcPackageName; - } else if (version === FuncVersion.v3) { - oldPackageName = `${funcPackageName}-v3-preview`; - } - - if (oldPackageName && (await isBrewPackageInstalled(oldPackageName))) { - return oldPackageName; - } - return undefined; -} - -/** - * Checks if the package is installed via brew. - * @param {string} packageName - Package name. - * @returns {Promise} Returns true if the package is installed, otherwise returns false. - */ -async function isBrewPackageInstalled(packageName: string): Promise { - try { - await executeCommand(undefined, undefined, 'brew', 'ls', packageName); - return true; - } catch { - return false; - } -} diff --git a/apps/vs-code-designer/src/app/utils/funcCoreTools/getFuncPackageManagers.ts b/apps/vs-code-designer/src/app/utils/funcCoreTools/getFuncPackageManagers.ts deleted file mode 100644 index 816a369509f..00000000000 --- a/apps/vs-code-designer/src/app/utils/funcCoreTools/getFuncPackageManagers.ts +++ /dev/null @@ -1,61 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import { funcPackageName, PackageManager, Platform } from '../../../constants'; -import { executeCommand } from './cpUtils'; -import { tryGetInstalledBrewPackageName } from './getBrewPackageName'; -import { FuncVersion } from '@microsoft/vscode-extension-logic-apps'; - -/** - * Gets package managers installed in the system. - * @param {boolean} isFuncInstalled - Is functions core tools installed. - * @returns {Promise} Returns array of package managers. - */ -export async function getFuncPackageManagers(isFuncInstalled: boolean): Promise { - const result: PackageManager[] = []; - if (process.platform === Platform.mac) { - if (await hasBrew(isFuncInstalled)) { - result.push(PackageManager.brew); - } - } - // https://github.com/Microsoft/vscode-azurefunctions/issues/311 - if (process.platform !== Platform.linux) { - try { - isFuncInstalled - ? await executeCommand(undefined, undefined, 'npm', 'ls', '-g', funcPackageName) - : await executeCommand(undefined, undefined, 'npm', '--version'); - result.push(PackageManager.npm); - } catch { - // an error indicates no npm - } - } - return result; -} - -/** - * Checks if the system has brew installed. - * @param {boolean} isFuncInstalled - Is functions core tools installed. - * @returns {Promise} Returns true if the system has brew installed, otherwise returns false. - */ -async function hasBrew(isFuncInstalled: boolean): Promise { - for (const version of Object.values(FuncVersion)) { - if (version !== FuncVersion.v1) { - if (isFuncInstalled) { - const packageName: string | undefined = await tryGetInstalledBrewPackageName(version); - if (packageName) { - return true; - } - } else { - try { - await executeCommand(undefined, undefined, 'brew', '--version'); - return true; - } catch { - // an error indicates no brew - } - } - } - } - - return false; -} diff --git a/apps/vs-code-designer/src/app/utils/funcCoreTools/getNpmDistTag.ts b/apps/vs-code-designer/src/app/utils/funcCoreTools/getNpmDistTag.ts deleted file mode 100644 index a56561fd58c..00000000000 --- a/apps/vs-code-designer/src/app/utils/funcCoreTools/getNpmDistTag.ts +++ /dev/null @@ -1,34 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import { localize } from '../../../localize'; -import { parseJson } from '../parseJson'; -import { sendRequestWithExtTimeout } from '../requestUtils'; -import { tryGetMajorVersion } from './funcVersion'; -import { HTTP_METHODS } from '@microsoft/logic-apps-shared'; -import type { IActionContext } from '@microsoft/vscode-azext-utils'; -import type { FuncVersion, INpmDistTag, IPackageMetadata } from '@microsoft/vscode-extension-logic-apps'; -import * as semver from 'semver'; - -/** - * Gets distribution tag of functions core tools npm package. - * @param {IActionContext} context - Command context. - * @param {FuncVersion} version - Functions core tools version. - * @returns {Promise} Returns core tools version to install. - */ -export async function getNpmDistTag(context: IActionContext, version: FuncVersion): Promise { - const npmRegistryUri = 'https://aka.ms/AA2qmnu'; - const response = await sendRequestWithExtTimeout(context, { url: npmRegistryUri, method: HTTP_METHODS.GET }); - - const packageMetadata: IPackageMetadata = parseJson(response.bodyAsText); - const majorVersion: string = tryGetMajorVersion(version); - - const validVersions: string[] = Object.keys(packageMetadata.versions).filter((v: string) => !!semver.valid(v)); - const maxVersion: string | null = semver.maxSatisfying(validVersions, majorVersion); - - if (!maxVersion) { - throw new Error(localize('noDistTag', 'Failed to retrieve NPM tag for version "{0}".', version)); - } - return { tag: majorVersion, value: maxVersion }; -} diff --git a/apps/vs-code-designer/src/app/utils/nodeJs/nodeJsVersion.ts b/apps/vs-code-designer/src/app/utils/nodeJs/nodeJsVersion.ts deleted file mode 100644 index c741e02d520..00000000000 --- a/apps/vs-code-designer/src/app/utils/nodeJs/nodeJsVersion.ts +++ /dev/null @@ -1,97 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import type { IActionContext } from '@microsoft/vscode-azext-utils'; -import { Platform, autoRuntimeDependenciesPathSettingKey, nodeJsBinaryPathSettingKey, nodeJsDependencyName } from '../../../constants'; -import { ext } from '../../../extensionVariables'; -import { executeCommand } from '../funcCoreTools/cpUtils'; -import { getGlobalSetting, updateGlobalSetting } from '../vsCodeConfig/settings'; -import * as fs from 'fs'; -import * as path from 'path'; -import * as semver from 'semver'; -import { isString } from '@microsoft/logic-apps-shared'; -import { binariesExist } from '../binaries'; - -/** - * Executes nodejs version command and gets it from cli. - * @returns {Promise} Functions core tools version. - */ -export async function getLocalNodeJsVersion(context: IActionContext): Promise { - try { - const output: string = await executeCommand(undefined, undefined, `${getNodeJsCommand()}`, '--version'); - const version: string | null = semver.clean(output); - if (version) { - return version; - } - return null; - } catch (error) { - const errorMessage = error instanceof Error ? error.message : isString(error) ? error : 'Unknown error'; - context.telemetry.properties.error = errorMessage; - return null; - } -} - -/** - * Get the npm binaries executable or use the system npm executable. - */ -export function getNpmCommand(): string { - const binariesLocation = getGlobalSetting(autoRuntimeDependenciesPathSettingKey); - const nodeJsBinariesPath = path.join(binariesLocation, nodeJsDependencyName); - const binaries = binariesExist(nodeJsDependencyName); - let command = ext.npmCliPath; - if (binaries) { - // windows the executable is at root folder, linux & macos its in the bin - command = path.join(nodeJsBinariesPath, ext.npmCliPath); - if (process.platform !== Platform.windows) { - const nodeSubFolder = getNodeSubFolder(command); - command = path.join(nodeJsBinariesPath, nodeSubFolder, 'bin', ext.npmCliPath); - } - } - return command; -} - -/** - * Get the nodejs binaries executable or use the system nodejs executable. - */ -export function getNodeJsCommand(): string { - const command = getGlobalSetting(nodeJsBinaryPathSettingKey); - return command; -} - -export async function setNodeJsCommand(): Promise { - const binariesLocation = getGlobalSetting(autoRuntimeDependenciesPathSettingKey); - const nodeJsBinariesPath = path.join(binariesLocation, nodeJsDependencyName); - const binariesExist = fs.existsSync(nodeJsBinariesPath); - let command = ext.nodeJsCliPath; - if (binariesExist) { - // windows the executable is at root folder, linux & macos its in the bin - command = path.join(nodeJsBinariesPath, ext.nodeJsCliPath); - if (process.platform !== Platform.windows) { - const nodeSubFolder = getNodeSubFolder(command); - command = path.join(nodeJsBinariesPath, nodeSubFolder, 'bin', ext.nodeJsCliPath); - - fs.chmodSync(nodeJsBinariesPath, 0o777); - } - } - await updateGlobalSetting(nodeJsBinaryPathSettingKey, command); -} - -function getNodeSubFolder(directoryPath: string): string | null { - try { - const items = fs.readdirSync(directoryPath); - - for (const item of items) { - const itemPath = path.join(directoryPath, item); - const stats = fs.statSync(itemPath); - - if (stats.isDirectory() && item.includes('node')) { - return item; - } - } - } catch (error) { - console.error('Error:', error.message); - } - - return ''; // No 'node' subfolders found -} diff --git a/apps/vs-code-designer/src/constants.ts b/apps/vs-code-designer/src/constants.ts index 208b6190fb5..f2add4d3484 100644 --- a/apps/vs-code-designer/src/constants.ts +++ b/apps/vs-code-designer/src/constants.ts @@ -185,9 +185,6 @@ export const extensionCommand = { startRemoteDebug: 'azureLogicAppsStandard.startRemoteDebug', validateLogicAppProjects: 'azureLogicAppsStandard.validateFunctionProjects', reportIssue: 'azureLogicAppsStandard.reportIssue', - validateAndInstallBinaries: 'azureLogicAppsStandard.validateAndInstallBinaries', - resetValidateAndInstallBinaries: 'azureLogicAppsStandard.resetValidateAndInstallBinaries', - disableValidateAndInstallBinaries: 'azureLogicAppsStandard.disableValidateAndInstallBinaries', azureAzuriteStart: 'azurite.start', parameterizeConnections: 'azureLogicAppsStandard.parameterizeConnections', loadDataMapFile: 'azureLogicAppsStandard.dataMap.loadDataMapFile', @@ -240,13 +237,11 @@ export const showProjectWarningSetting = 'showProjectWarning'; export const showTargetFrameworkWarningSetting = 'showTargetFrameworkWarning'; export const showStartDesignTimeMessageSetting = 'showStartDesignTimeMessage'; export const autoStartDesignTimeSetting = 'autoStartDesignTime'; -export const autoRuntimeDependenciesValidationAndInstallationSetting = 'autoRuntimeDependenciesValidationAndInstallation'; export const azuriteBinariesLocationSetting = 'azuriteLocationSetting'; export const driveLetterSMBSetting = 'driveLetterSMB'; export const parameterizeConnectionsInProjectLoadSetting = 'parameterizeConnectionsInProjectLoad'; export const showAutoStartAzuriteWarning = 'showAutoStartAzuriteWarning'; export const autoStartAzuriteSetting = 'autoStartAzurite'; -export const autoRuntimeDependenciesPathSettingKey = 'autoRuntimeDependenciesPath'; export const dotNetBinaryPathSettingKey = 'dotnetBinaryPath'; export const nodeJsBinaryPathSettingKey = 'nodeJsBinaryPath'; export const funcCoreToolsBinaryPathSettingKey = 'funcCoreToolsBinaryPath'; @@ -255,6 +250,11 @@ export const unitTestExplorer = 'unitTestExplorer'; export const verifyConnectionKeysSetting = 'verifyConnectionKeys'; export const useSmbDeployment = 'useSmbDeploymentForHybrid'; +// TODO (ccastrotrejo): To be removed +export const autoRuntimeDependenciesPathSettingKey = 'autoRuntimeDependenciesPath'; +export const defaultLogicAppsFolder = '.azurelogicapps'; +export const defaultDependencyPathValue = path.join(os.homedir(), defaultLogicAppsFolder, 'dependencies'); + // host.json export const extensionBundleId = 'Microsoft.Azure.Functions.ExtensionBundle.Workflows'; export const targetBundleKey = 'FUNCTIONS_EXTENSIONBUNDLE_SOURCE_URI'; @@ -277,10 +277,8 @@ export const extInstallTaskName = `${func}: ${extInstallCommand}`; export const tasksVersion = '2.0.0'; export const launchVersion = '0.2.0'; export const dotnetPublishTaskLabel = 'publish'; -export const defaultLogicAppsFolder = '.azurelogicapps'; export const defaultFunctionCoreToolsFolder = '.azure-functions-core-tools'; export const defaultAzuritePathValue = path.join(os.homedir(), defaultLogicAppsFolder, '.azurite'); -export const defaultDependencyPathValue = path.join(os.homedir(), defaultLogicAppsFolder, 'dependencies'); export const defaultExtensionBundlePathValue = path.join( os.homedir(), defaultFunctionCoreToolsFolder, diff --git a/apps/vs-code-designer/src/container/devcontainer.json b/apps/vs-code-designer/src/container/devcontainer.json index b134518b078..bd4cfd98ed6 100644 --- a/apps/vs-code-designer/src/container/devcontainer.json +++ b/apps/vs-code-designer/src/container/devcontainer.json @@ -1,55 +1,55 @@ { - "name": "Logic Apps Standard Development", - "dockerComposeFile": "docker-compose.yml", - "service": "app", - "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", - "features": { - "ghcr.io/devcontainers/features/azure-cli:1": { - "version": "latest" - }, - "ghcr.io/devcontainers/features/dotnet:2": { - "version": "8.0", - "additionalVersions": "6.0", - "installUsingApt": true, - "globalTools": "" - }, - "ghcr.io/jlaundry/devcontainer-features/azure-functions-core-tools:1": { - "version": "4" - }, - "ghcr.io/devcontainers/features/powershell:1": { - "version": "latest", - "modules": "Az" - }, - "ghcr.io/devcontainers/features/java:1": { - "version": "17", - "jdkDistro": "ms", - "gradleVersion": "latest", - "mavenVersion": "latest", - "installAnt": false - } + "name": "Logic Apps Standard Development", + "dockerComposeFile": "docker-compose.yml", + "service": "app", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + "features": { + "ghcr.io/devcontainers/features/azure-cli:1": { + "version": "latest" }, - "customizations": { - "vscode": { - "extensions": [ - "ms-azuretools.vscode-azurelogicapps", - "ms-azuretools.vscode-azurefunctions", - "ms-azuretools.vscode-docker", - "azurite.azurite", - "ms-azuretools.vscode-azureresourcegroups", - "ms-dotnettools.csharp", - "ms-dotnettools.csdevkit" - ], - "settings": { - "terminal.integrated.defaultProfile.linux": "bash", - "files.exclude": { - "**/bin": true, - "**/obj": true - } - } - } + "ghcr.io/devcontainers/features/dotnet:2": { + "version": "8.0", + "additionalVersions": "6.0", + "installUsingApt": true, + "globalTools": "" + }, + "ghcr.io/jlaundry/devcontainer-features/azure-functions-core-tools:1": { + "version": "4" }, - - "otherPortsAttributes": { - "onAutoForward": "silent" + "ghcr.io/devcontainers/features/powershell:1": { + "version": "latest", + "modules": "Az" + }, + "ghcr.io/devcontainers/features/java:1": { + "version": "17", + "jdkDistro": "ms", + "gradleVersion": "latest", + "mavenVersion": "latest", + "installAnt": false + } + }, + "customizations": { + "vscode": { + "extensions": [ + "ms-azuretools.vscode-azurelogicapps", + "ms-azuretools.vscode-azurefunctions", + "ms-azuretools.vscode-docker", + "azurite.azurite", + "ms-azuretools.vscode-azureresourcegroups", + "ms-dotnettools.csharp", + "ms-dotnettools.csdevkit" + ], + "settings": { + "terminal.integrated.defaultProfile.linux": "bash", + "files.exclude": { + "**/bin": true, + "**/obj": true + } + } } + }, + + "otherPortsAttributes": { + "onAutoForward": "silent" + } } diff --git a/apps/vs-code-designer/src/main.ts b/apps/vs-code-designer/src/main.ts index 8fca45f0ca1..5af32566f20 100644 --- a/apps/vs-code-designer/src/main.ts +++ b/apps/vs-code-designer/src/main.ts @@ -11,14 +11,13 @@ import { registerCommands } from './app/commands/registerCommands'; import { getResourceGroupsApi } from './app/resourcesExtension/getExtensionApi'; import type { AzureAccountTreeItemWithProjects } from './app/tree/AzureAccountTreeItemWithProjects'; import { downloadExtensionBundle } from './app/utils/bundleFeed'; -import { stopAllDesignTimeApis } from './app/utils/codeless/startDesignTimeApi'; +import { promptStartDesignTimeOption, stopAllDesignTimeApis } from './app/utils/codeless/startDesignTimeApi'; import { UriHandler } from './app/utils/codeless/urihandler'; import { getExtensionVersion } from './app/utils/extension'; import { registerFuncHostTaskEvents } from './app/utils/funcCoreTools/funcHostTask'; import { verifyVSCodeConfigOnActivate } from './app/utils/vsCodeConfig/verifyVSCodeConfigOnActivate'; -import { extensionCommand, logicAppFilter } from './constants'; +import { autoStartDesignTimeSetting, extensionCommand, logicAppFilter, showStartDesignTimeMessageSetting } from './constants'; import { ext } from './extensionVariables'; -import { startOnboarding } from './onboarding'; import { registerAppServiceExtensionVariables } from '@microsoft/vscode-azext-azureappservice'; import { verifyLocalConnectionKeys } from './app/utils/appSettings/connectionKeys'; import { @@ -33,9 +32,10 @@ import { convertToWorkspace } from './app/commands/convertToWorkspace'; import TelemetryReporter from '@vscode/extension-telemetry'; import { getAllCustomCodeFunctionsProjects } from './app/utils/customCodeUtils'; import { createVSCodeAzureSubscriptionProvider } from './app/utils/services/VSCodeAzureSubscriptionProvider'; -import { logExtensionSettings, logSubscriptions } from './app/utils/telemetry'; +import { logExtensionSettings, logSubscriptions, runWithDurationTelemetry } from './app/utils/telemetry'; import { registerAzureUtilsExtensionVariables } from '@microsoft/vscode-azext-azureutils'; import { getAzExtResourceType, getAzureResourcesExtensionApi } from '@microsoft/vscode-azureresources-api'; +import { validateTasksJson } from './app/utils/vsCodeConfig/tasks'; const perfStats = { loadStartTime: Date.now(), @@ -112,7 +112,14 @@ export async function activate(context: vscode.ExtensionContext) { downloadExtensionBundle(activateContext); promptParameterizeConnections(activateContext, false); verifyLocalConnectionKeys(activateContext); - await startOnboarding(activateContext); + + // TODO (ccastrotrjeo): Move to somewhere else + await callWithTelemetryAndErrorHandling(autoStartDesignTimeSetting, async (actionContext: IActionContext) => { + await runWithDurationTelemetry(actionContext, showStartDesignTimeMessageSetting, async () => { + await validateTasksJson(actionContext, vscode.workspace.workspaceFolders); + await promptStartDesignTimeOption(activateContext); + }); + }); // Removed for unit test codefull experience standby //await prepareTestExplorer(context, activateContext); diff --git a/apps/vs-code-designer/src/onboarding.ts b/apps/vs-code-designer/src/onboarding.ts deleted file mode 100644 index fea9929e37f..00000000000 --- a/apps/vs-code-designer/src/onboarding.ts +++ /dev/null @@ -1,56 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import { validateAndInstallBinaries } from './app/commands/binaries/validateAndInstallBinaries'; -import { installBinaries, useBinariesDependencies } from './app/utils/binaries'; -import { promptStartDesignTimeOption } from './app/utils/codeless/startDesignTimeApi'; -import { runWithDurationTelemetry } from './app/utils/telemetry'; -import { validateTasksJson } from './app/utils/vsCodeConfig/tasks'; -import { - extensionCommand, - autoRuntimeDependenciesValidationAndInstallationSetting, - autoStartDesignTimeSetting, - showStartDesignTimeMessageSetting, -} from './constants'; -import { callWithTelemetryAndErrorHandling, type IActionContext } from '@microsoft/vscode-azext-utils'; -import * as vscode from 'vscode'; - -/** - * Prompts warning message for installing the installing/validate binaries and taks.json. - * @param {IActionContext} activateContext - Activation context. - */ -export const onboardBinaries = async (activateContext: IActionContext) => { - await callWithTelemetryAndErrorHandling(extensionCommand.validateAndInstallBinaries, async (actionContext: IActionContext) => { - await runWithDurationTelemetry(actionContext, extensionCommand.validateAndInstallBinaries, async () => { - const binariesInstallation = useBinariesDependencies(); - if (binariesInstallation) { - activateContext.telemetry.properties.lastStep = extensionCommand.validateAndInstallBinaries; - await validateAndInstallBinaries(actionContext); - await validateTasksJson(actionContext, vscode.workspace.workspaceFolders); - } - }); - }); -}; - -/** - * Start onboarding experience prompting inputs for user. - * This function will propmpt/install dependencies binaries, start design time api and start azurite. - * @param {IActionContext} activateContext - Activation context. - */ -export const startOnboarding = async (activateContext: IActionContext) => { - callWithTelemetryAndErrorHandling(autoRuntimeDependenciesValidationAndInstallationSetting, async (actionContext: IActionContext) => { - const binariesInstallStartTime = Date.now(); - await runWithDurationTelemetry(actionContext, autoRuntimeDependenciesValidationAndInstallationSetting, async () => { - activateContext.telemetry.properties.lastStep = autoRuntimeDependenciesValidationAndInstallationSetting; - await installBinaries(actionContext); - }); - activateContext.telemetry.measurements.binariesInstallDuration = Date.now() - binariesInstallStartTime; - }); - - await callWithTelemetryAndErrorHandling(autoStartDesignTimeSetting, async (actionContext: IActionContext) => { - await runWithDurationTelemetry(actionContext, showStartDesignTimeMessageSetting, async () => { - await promptStartDesignTimeOption(activateContext); - }); - }); -}; diff --git a/apps/vs-code-designer/src/package.json b/apps/vs-code-designer/src/package.json index 6d9882b2156..bfe35843f45 100644 --- a/apps/vs-code-designer/src/package.json +++ b/apps/vs-code-designer/src/package.json @@ -335,21 +335,6 @@ "title": "Report issue...", "category": "Azure Logic Apps" }, - { - "command": "azureLogicAppsStandard.validateAndInstallBinaries", - "title": "Validate and install dependency binaries", - "category": "Azure Logic Apps" - }, - { - "command": "azureLogicAppsStandard.resetValidateAndInstallBinaries", - "title": "Reset binaries dependency settings", - "category": "Azure Logic Apps" - }, - { - "command": "azureLogicAppsStandard.disableValidateAndInstallBinaries", - "title": "Disable binaries dependency settings", - "category": "Azure Logic Apps" - }, { "command": "azureLogicAppsStandard.dataMap.createNewDataMap", "title": "Create Data Map", diff --git a/libs/designer/src/lib/ui/panel/nodeDetailsPanel/usePanelTabs.tsx b/libs/designer/src/lib/ui/panel/nodeDetailsPanel/usePanelTabs.tsx index d62317ee9aa..aa5244e2166 100644 --- a/libs/designer/src/lib/ui/panel/nodeDetailsPanel/usePanelTabs.tsx +++ b/libs/designer/src/lib/ui/panel/nodeDetailsPanel/usePanelTabs.tsx @@ -115,9 +115,9 @@ export const usePanelTabs = ({ nodeId }: { nodeId: string }) => { const testingTabItem = useMemo( () => ({ ...testingTab(intl, tabProps), - visible: !isTrigger && hasSchema && !isMonitoringView, + visible: !isTrigger && hasSchema && !isMonitoringView, }), - [intl, isTrigger, hasSchema, isMonitoringView, tabProps] + [intl, isTrigger, hasSchema, isMonitoringView, tabProps] ); const aboutTabItem = useMemo(() => aboutTab(intl, tabProps), [intl, tabProps]); From 2a63e52b071a5120264625cadd14339ecf312e0e Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Wed, 10 Sep 2025 19:31:30 -0400 Subject: [PATCH 03/46] Update dependencies settings --- .../functionAppFilesStep.ts | 2 +- .../initCustomCodeProjectStep.ts | 4 +- .../initCustomCodeProjectStepBase.ts | 4 +- .../initCustomCodeScriptProjectStep.ts | 2 +- .../initDotnetProjectStep.ts | 10 ++-- .../initProjectForVSCode/initProjectStep.ts | 4 +- .../initScriptProjectStep.ts | 2 +- .../app/utils/__test__/reportAnIssue.test.ts | 6 --- .../app/utils/funcCoreTools/funcHostTask.ts | 2 +- .../app/utils/funcCoreTools/funcVersion.ts | 17 ++---- .../src/app/utils/reportAnIssue.ts | 8 +-- .../src/app/utils/telemetry.ts | 2 - .../src/app/utils/unitTests.ts | 8 ++- .../src/app/utils/vsCodeConfig/tasks.ts | 16 +++--- apps/vs-code-designer/src/constants.ts | 7 --- apps/vs-code-designer/src/package.json | 53 ------------------- 16 files changed, 30 insertions(+), 117 deletions(-) diff --git a/apps/vs-code-designer/src/app/commands/createProject/createCustomCodeProjectSteps/functionAppFilesStep.ts b/apps/vs-code-designer/src/app/commands/createProject/createCustomCodeProjectSteps/functionAppFilesStep.ts index 4b426177f27..8027162828b 100644 --- a/apps/vs-code-designer/src/app/commands/createProject/createCustomCodeProjectSteps/functionAppFilesStep.ts +++ b/apps/vs-code-designer/src/app/commands/createProject/createCustomCodeProjectSteps/functionAppFilesStep.ts @@ -287,7 +287,7 @@ export class FunctionAppFilesStep extends AzureWizardPromptStep { get: vi.fn((key: string) => { const settings = { dataMapperVersion: '1.0.0', - validateFuncCoreTools: true, - autoRuntimeDependenciesPath: '/path/to/deps', - autoRuntimeDependenciesValidationAndInstallation: false, parameterizeConnectionsInProjectLoad: true, }; return settings[key as keyof typeof settings]; @@ -222,9 +219,6 @@ describe('reportAnIssue', () => { expect(decodedLink).toContain('Settings'); expect(decodedLink).toContain('dataMapperVersion'); - expect(decodedLink).toContain('validateFuncCoreTools'); - expect(decodedLink).toContain('autoRuntimeDependenciesPath'); - expect(decodedLink).toContain('autoRuntimeDependenciesValidationAndInstallation'); expect(decodedLink).toContain('parameterizeConnectionsInProjectLoad'); }); diff --git a/apps/vs-code-designer/src/app/utils/funcCoreTools/funcHostTask.ts b/apps/vs-code-designer/src/app/utils/funcCoreTools/funcHostTask.ts index 4e487ae8d08..8b054e4c14c 100644 --- a/apps/vs-code-designer/src/app/utils/funcCoreTools/funcHostTask.ts +++ b/apps/vs-code-designer/src/app/utils/funcCoreTools/funcHostTask.ts @@ -29,7 +29,7 @@ export function isFuncHostTask(task: vscode.Task): boolean { const commandLine: string | undefined = task.execution && (task.execution as vscode.ShellExecution).commandLine; if (task.definition.type === 'shell') { const command = (task.execution as vscode.ShellExecution).command?.toString(); - const funcRegex = /\$\{config:azureLogicAppsStandard\.funcCoreToolsBinaryPath\}/; + const funcRegex = /func/; // check for args? return funcRegex.test(command); } diff --git a/apps/vs-code-designer/src/app/utils/funcCoreTools/funcVersion.ts b/apps/vs-code-designer/src/app/utils/funcCoreTools/funcVersion.ts index e2d013b2ab9..d1aff34e984 100644 --- a/apps/vs-code-designer/src/app/utils/funcCoreTools/funcVersion.ts +++ b/apps/vs-code-designer/src/app/utils/funcCoreTools/funcVersion.ts @@ -2,9 +2,9 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { funcCoreToolsBinaryPathSettingKey, funcVersionSetting } from '../../../constants'; +import { funcVersionSetting } from '../../../constants'; import { localize } from '../../../localize'; -import { getGlobalSetting, getWorkspaceSettingFromAnyFolder } from '../vsCodeConfig/settings'; +import { getWorkspaceSettingFromAnyFolder } from '../vsCodeConfig/settings'; import { executeCommand } from './cpUtils'; import { isNullOrUndefined } from '@microsoft/logic-apps-shared'; import type { IActionContext } from '@microsoft/vscode-azext-utils'; @@ -82,7 +82,7 @@ export async function tryGetLocalFuncVersion(): Promise */ export async function getLocalFuncCoreToolsVersion(): Promise { try { - const output: string = await executeCommand(undefined, undefined, `${getFunctionsCommand()}`, '--version'); + const output: string = await executeCommand(undefined, undefined, 'func', '--version'); const version: string | null = semver.clean(output); if (version) { return version; @@ -136,14 +136,3 @@ export function checkSupportedFuncVersion(version: FuncVersion) { ); } } - -/** - * Get the functions binaries executable or use the system functions executable. - */ -export function getFunctionsCommand(): string { - const command = getGlobalSetting(funcCoreToolsBinaryPathSettingKey); - if (!command) { - throw Error('Functions Core Tools Binary Path Setting is empty'); - } - return command; -} diff --git a/apps/vs-code-designer/src/app/utils/reportAnIssue.ts b/apps/vs-code-designer/src/app/utils/reportAnIssue.ts index 8be3f02f658..d73205e2ba7 100644 --- a/apps/vs-code-designer/src/app/utils/reportAnIssue.ts +++ b/apps/vs-code-designer/src/app/utils/reportAnIssue.ts @@ -21,13 +21,7 @@ const MAX_INLINE_MESSAGE_CHARS = 1000; const MAX_ISSUE_BODY_CHARS = 4000; // Whitelisted extension configuration settings -const SETTINGS_WHITELIST: string[] = [ - 'dataMapperVersion', - 'validateFuncCoreTools', - 'autoRuntimeDependenciesPath', - 'autoRuntimeDependenciesValidationAndInstallation', - 'parameterizeConnectionsInProjectLoad', -]; +const SETTINGS_WHITELIST: string[] = ['dataMapperVersion', 'parameterizeConnectionsInProjectLoad']; /** * Generates a "Report an Issue" link from the provided error context and opens it in the user's browser. diff --git a/apps/vs-code-designer/src/app/utils/telemetry.ts b/apps/vs-code-designer/src/app/utils/telemetry.ts index de51387291a..55e44d06819 100644 --- a/apps/vs-code-designer/src/app/utils/telemetry.ts +++ b/apps/vs-code-designer/src/app/utils/telemetry.ts @@ -53,12 +53,10 @@ export const logSubscriptions = async (context: IActionContext) => { export const logExtensionSettings = async (context: IActionContext) => { const settingsToLog = [ - 'autoRuntimeDependenciesValidationAndInstallation', 'autoStartAzurite', 'autoStartDesignTime', 'parameterizeConnectionsInProjectLoad', 'showStartDesignTimeMessage', - 'validateDotNetSDK', 'stopFuncTaskPostDebug', ]; try { diff --git a/apps/vs-code-designer/src/app/utils/unitTests.ts b/apps/vs-code-designer/src/app/utils/unitTests.ts index 21eb037b7c4..391727e5b94 100644 --- a/apps/vs-code-designer/src/app/utils/unitTests.ts +++ b/apps/vs-code-designer/src/app/utils/unitTests.ts @@ -12,7 +12,6 @@ import type { UnitTestResult } from '@microsoft/vscode-extension-logic-apps'; import { toPascalCase } from '@microsoft/logic-apps-shared'; import { assetsFolderName, - dotNetBinaryPathSettingKey, saveUnitTestEvent, testMockOutputsDirectory, testsDirectoryName, @@ -23,7 +22,6 @@ import { ext } from '../../extensionVariables'; import { localize } from '../../localize'; import { getWorkflowsInLocalProject } from './codeless/common'; import { executeCommand } from './funcCoreTools/cpUtils'; -import { getGlobalSetting } from './vsCodeConfig/settings'; /** * Saves a unit test definition for a workflow to the file system. @@ -1301,7 +1299,7 @@ export async function isMockableHttp(type: string): Promise { export async function updateTestsSln(testsDirectory: string, logicAppCsprojPath: string): Promise { const solutionName = 'Tests'; // This will create "Tests.sln" const solutionFile = path.join(testsDirectory, `${solutionName}.sln`); - const dotnetBinaryPath = getGlobalSetting(dotNetBinaryPathSettingKey); + const dotnetCommand = 'dotnet'; try { // Create a new solution file if it doesn't already exist. @@ -1309,14 +1307,14 @@ export async function updateTestsSln(testsDirectory: string, logicAppCsprojPath: ext.outputChannel.appendLog(`Solution file already exists at ${solutionFile}.`); } else { ext.outputChannel.appendLog(`Creating new solution file at ${solutionFile}...`); - await executeCommand(ext.outputChannel, testsDirectory, `${dotnetBinaryPath} new sln -n ${solutionName}`); + await executeCommand(ext.outputChannel, testsDirectory, `${dotnetCommand} new sln -n ${solutionName}`); ext.outputChannel.appendLog(`Solution file created: ${solutionFile}`); } // Compute the relative path from the tests directory to the Logic App .csproj. const relativeProjectPath = path.relative(testsDirectory, logicAppCsprojPath); ext.outputChannel.appendLog(`Adding project '${relativeProjectPath}' to solution '${solutionFile}'...`); - await executeCommand(ext.outputChannel, testsDirectory, `${dotnetBinaryPath} sln "${solutionFile}" add "${relativeProjectPath}"`); + await executeCommand(ext.outputChannel, testsDirectory, `${dotnetCommand} sln "${solutionFile}" add "${relativeProjectPath}"`); ext.outputChannel.appendLog('Project added to solution successfully.'); } catch (err) { ext.outputChannel.appendLog(`Error updating solution: ${err}`); diff --git a/apps/vs-code-designer/src/app/utils/vsCodeConfig/tasks.ts b/apps/vs-code-designer/src/app/utils/vsCodeConfig/tasks.ts index cd9e0724283..9121765263b 100644 --- a/apps/vs-code-designer/src/app/utils/vsCodeConfig/tasks.ts +++ b/apps/vs-code-designer/src/app/utils/vsCodeConfig/tasks.ts @@ -183,21 +183,21 @@ async function overwriteTasksJson(context: IActionContext, projectPath: string): tasks: [ { label: 'generateDebugSymbols', - command: '${config:azureLogicAppsStandard.dotnetBinaryPath}', + command: 'dotnet', args: ['${input:getDebugSymbolDll}'], type: 'process', problemMatcher: '$msCompile', }, { label: 'clean', - command: '${config:azureLogicAppsStandard.dotnetBinaryPath}', + command: 'dotnet', args: ['clean', ...commonArgs], type: 'process', problemMatcher: '$msCompile', }, { label: 'build', - command: '${config:azureLogicAppsStandard.dotnetBinaryPath}', + command: 'dotnet', args: ['build', ...commonArgs], type: 'process', dependsOn: 'clean', @@ -209,14 +209,14 @@ async function overwriteTasksJson(context: IActionContext, projectPath: string): }, { label: 'clean release', - command: '${config:azureLogicAppsStandard.dotnetBinaryPath}', + command: 'dotnet', args: [...releaseArgs, ...commonArgs], type: 'process', problemMatcher: '$msCompile', }, { label: 'publish', - command: '${config:azureLogicAppsStandard.dotnetBinaryPath}', + command: 'dotnet', args: ['publish', ...releaseArgs, ...commonArgs], type: 'process', dependsOn: 'clean release', @@ -226,7 +226,7 @@ async function overwriteTasksJson(context: IActionContext, projectPath: string): label: 'func: host start', dependsOn: 'build', type: 'shell', - command: '${config:azureLogicAppsStandard.funcCoreToolsBinaryPath}', + command: 'func', args: ['host', 'start'], options: { cwd: debugSubpath, @@ -253,14 +253,14 @@ async function overwriteTasksJson(context: IActionContext, projectPath: string): tasks: [ { label: 'generateDebugSymbols', - command: '${config:azureLogicAppsStandard.dotnetBinaryPath}', + command: 'dotnet', args: ['${input:getDebugSymbolDll}'], type: 'process', problemMatcher: '$msCompile', }, { type: 'shell', - command: '${config:azureLogicAppsStandard.funcCoreToolsBinaryPath}', + command: 'func', args: ['host', 'start'], options: { env: { diff --git a/apps/vs-code-designer/src/constants.ts b/apps/vs-code-designer/src/constants.ts index f2add4d3484..212be6eb734 100644 --- a/apps/vs-code-designer/src/constants.ts +++ b/apps/vs-code-designer/src/constants.ts @@ -225,9 +225,6 @@ export const projectSubpathSetting = 'projectSubpath'; export const projectTemplateKeySetting = 'projectTemplateKey'; export const projectOpenBehaviorSetting = 'projectOpenBehavior'; export const stopFuncTaskPostDebugSetting = 'stopFuncTaskPostDebug'; -export const validateFuncCoreToolsSetting = 'validateFuncCoreTools'; -export const validateDotNetSDKSetting = 'validateDotNetSDK'; -export const validateNodeJsSetting = 'validateNodeJs'; export const showDeployConfirmationSetting = 'showDeployConfirmation'; export const deploySubpathSetting = 'deploySubpath'; export const preDeployTaskSetting = 'preDeployTask'; @@ -242,10 +239,6 @@ export const driveLetterSMBSetting = 'driveLetterSMB'; export const parameterizeConnectionsInProjectLoadSetting = 'parameterizeConnectionsInProjectLoad'; export const showAutoStartAzuriteWarning = 'showAutoStartAzuriteWarning'; export const autoStartAzuriteSetting = 'autoStartAzurite'; -export const dotNetBinaryPathSettingKey = 'dotnetBinaryPath'; -export const nodeJsBinaryPathSettingKey = 'nodeJsBinaryPath'; -export const funcCoreToolsBinaryPathSettingKey = 'funcCoreToolsBinaryPath'; -export const dependencyTimeoutSettingKey = 'dependencyTimeout'; export const unitTestExplorer = 'unitTestExplorer'; export const verifyConnectionKeysSetting = 'verifyConnectionKeys'; export const useSmbDeployment = 'useSmbDeploymentForHybrid'; diff --git a/apps/vs-code-designer/src/package.json b/apps/vs-code-designer/src/package.json index bfe35843f45..ffa833fa49f 100644 --- a/apps/vs-code-designer/src/package.json +++ b/apps/vs-code-designer/src/package.json @@ -809,34 +809,11 @@ "type": "string", "description": "The default subpath for the workspace folder to use during deployment. If you set this value, you won't get a prompt for the folder path during deployment." }, - "azureLogicAppsStandard.dependencyTimeout": { - "type": "number", - "description": "The timeout (in seconds) to be used when validating and installing dependencies.", - "default": 300 - }, "azureLogicAppsStandard.autoRuntimeDependenciesPath": { "scope": "resource", "type": "string", "description": "The path for Azure Logic Apps extension runtime dependencies." }, - "azureLogicAppsStandard.dotnetBinaryPath": { - "scope": "resource", - "type": "string", - "description": "The path for Azure Logic Apps extension .NET SDK dependency binary.", - "default": "dotnet" - }, - "azureLogicAppsStandard.nodeJsBinaryPath": { - "scope": "resource", - "type": "string", - "description": "The path for Azure Logic Apps extension Node JS dependency binary.", - "default": "node" - }, - "azureLogicAppsStandard.funcCoreToolsBinaryPath": { - "scope": "resource", - "type": "string", - "description": "The path for Azure Logic Apps extension Azure Function Core Tools dependency binary.", - "default": "func" - }, "azureLogicAppsStandard.projectSubpath": { "scope": "resource", "type": "string", @@ -852,36 +829,11 @@ "description": "Automatically stop the task running the Azure Functions host when a debug sessions ends.", "default": true }, - "azureLogicAppsStandard.validateFuncCoreTools": { - "type": "boolean", - "description": "Make sure that Azure Functions Core Tools is installed before you start debugging.", - "default": true - }, - "azureLogicAppsStandard.validateDotNetSDK": { - "type": "boolean", - "description": "Make sure that the .NET SDK is installed before you start debugging.", - "default": true - }, - "azureLogicAppsStandard.validateNodeJs": { - "type": "boolean", - "description": "Make sure that Node JS is installed before you start debugging.", - "default": true - }, "azureLogicAppsStandard.showDeployConfirmation": { "type": "boolean", "description": "Ask to confirm before deploying to a function app in Azure. Deployment overwrites any previous deployment and can't be undone.", "default": true }, - "azureLogicAppsStandard.showNodeJsWarning": { - "type": "boolean", - "description": "Show a warning when your installed version of Node JS is outdated.", - "default": true - }, - "azureLogicAppsStandard.showMultiCoreToolsWarning": { - "type": "boolean", - "description": "Show a warning when multiple installations of the Azure Functions Core Tools are found.", - "default": true - }, "azureLogicAppsStandard.requestTimeout": { "type": "number", "description": "The timeout (in seconds) to be used when making requests, for example getting the latest templates.", @@ -937,11 +889,6 @@ "description": "Start background design-time process at project load time.", "default": true }, - "azureLogicAppsStandard.autoRuntimeDependenciesValidationAndInstallation": { - "type": "boolean", - "description": "Enable automatic validation and installation for runtime dependencies at the configured path.", - "default": true - }, "azureLogicAppsStandard.showAutoStartAzuriteWarning": { "type": "boolean", "description": "Show a warning asking if user's would like to configure Azurite auto start.", From 260258a9856ff8305da31548436c6e778e2f97f2 Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Thu, 11 Sep 2025 11:22:36 -0400 Subject: [PATCH 04/46] Delete more code --- .../src/app/commands/dataMapper/FxWorkflowRuntime.ts | 3 +-- .../src/app/utils/codeless/startDesignTimeApi.ts | 3 +-- apps/vs-code-designer/src/constants.ts | 2 -- apps/vs-code-designer/src/extensionVariables.ts | 11 ----------- 4 files changed, 2 insertions(+), 17 deletions(-) diff --git a/apps/vs-code-designer/src/app/commands/dataMapper/FxWorkflowRuntime.ts b/apps/vs-code-designer/src/app/commands/dataMapper/FxWorkflowRuntime.ts index ad869db7f3c..01d9ad4a13e 100644 --- a/apps/vs-code-designer/src/app/commands/dataMapper/FxWorkflowRuntime.ts +++ b/apps/vs-code-designer/src/app/commands/dataMapper/FxWorkflowRuntime.ts @@ -24,7 +24,6 @@ import { startDesignTimeProcess, waitForDesignTimeStartUp, } from '../../utils/codeless/startDesignTimeApi'; -import { getFunctionsCommand } from '../../utils/funcCoreTools/funcVersion'; import { backendRuntimeBaseUrl } from './extensionConfig'; import type { IActionContext } from '@microsoft/vscode-azext-utils'; import * as portfinder from 'portfinder'; @@ -75,7 +74,7 @@ export async function startBackendRuntime(context: IActionContext, projectPath: ); const cwd: string = designTimeDirectory.fsPath; const portArgs = `--port ${designTimeInst.port}`; - startDesignTimeProcess(ext.outputChannel, cwd, getFunctionsCommand(), 'host', 'start', portArgs); + startDesignTimeProcess(ext.outputChannel, cwd, 'func', 'host', 'start', portArgs); await waitForDesignTimeStartUp(context, projectPath, url, true); } else { diff --git a/apps/vs-code-designer/src/app/utils/codeless/startDesignTimeApi.ts b/apps/vs-code-designer/src/app/utils/codeless/startDesignTimeApi.ts index ac566cfcce3..07b2a7c372b 100644 --- a/apps/vs-code-designer/src/app/utils/codeless/startDesignTimeApi.ts +++ b/apps/vs-code-designer/src/app/utils/codeless/startDesignTimeApi.ts @@ -24,7 +24,6 @@ import { localize } from '../../../localize'; import { addOrUpdateLocalAppSettings, getLocalSettingsSchema } from '../appSettings/localSettings'; import { updateFuncIgnore } from '../codeless/common'; import { writeFormattedJson } from '../fs'; -import { getFunctionsCommand } from '../funcCoreTools/funcVersion'; import { getWorkspaceSetting, updateGlobalSetting } from '../vsCodeConfig/settings'; import { getWorkspaceLogicAppFolders } from '../workspace'; import { delay } from '../delay'; @@ -118,7 +117,7 @@ export async function startDesignTimeApi(projectPath: string): Promise { const cwd: string = designTimeDirectory.fsPath; const portArgs = `--port ${designTimeInst.port}`; - startDesignTimeProcess(ext.outputChannel, cwd, getFunctionsCommand(), 'host', 'start', portArgs); + startDesignTimeProcess(ext.outputChannel, cwd, 'func', 'host', 'start', portArgs); await waitForDesignTimeStartUp(actionContext, projectPath, url, true); actionContext.telemetry.properties.isDesignTimeUp = 'true'; diff --git a/apps/vs-code-designer/src/constants.ts b/apps/vs-code-designer/src/constants.ts index 212be6eb734..89b273632c5 100644 --- a/apps/vs-code-designer/src/constants.ts +++ b/apps/vs-code-designer/src/constants.ts @@ -67,8 +67,6 @@ export const dotnetDependencyName = 'DotNetSDK'; // Node export const node = 'node'; -export const npm = 'npm'; -export const nodeJsDependencyName = 'NodeJs'; // Workflow export const workflowLocationKey = 'WORKFLOWS_LOCATION_NAME'; diff --git a/apps/vs-code-designer/src/extensionVariables.ts b/apps/vs-code-designer/src/extensionVariables.ts index d371c54d082..d059315ba8a 100644 --- a/apps/vs-code-designer/src/extensionVariables.ts +++ b/apps/vs-code-designer/src/extensionVariables.ts @@ -6,7 +6,6 @@ import type { VSCodeAzureSubscriptionProvider } from '@microsoft/vscode-azext-az import type DataMapperPanel from './app/commands/dataMapper/DataMapperPanel'; import type { AzureAccountTreeItemWithProjects } from './app/tree/AzureAccountTreeItemWithProjects'; import type { TestData } from './app/tree/unitTestTree'; -import { dotnet, func, node, npm } from './constants'; import type { ContainerApp, Site } from '@azure/arm-appservice'; import type { IActionContext, IAzExtOutputChannel } from '@microsoft/vscode-azext-utils'; import type { AzureHostExtensionApi } from '@microsoft/vscode-azext-utils/hostapi'; @@ -74,16 +73,6 @@ export namespace ext { // Data Mapper panel export const dataMapPanelManagers: DataMapperPanelDictionary = {}; - // Functions - export const funcCliPath: string = func; - - // DotNet - export const dotNetCliPath: string = dotnet; - - // Node Js - export const nodeJsCliPath: string = node; - export const npmCliPath: string = npm; - // WebViews export const webViewKey = { designerLocal: 'designerLocal', From 73d8bf0dc85de6f7a903bb1452831487a76eb035 Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Thu, 11 Sep 2025 11:53:59 -0400 Subject: [PATCH 05/46] Remove constants --- .../src/app/utils/__test__/bundleFeed.test.ts | 5 ---- .../app/utils/__test__/unitTestUtils.test.ts | 9 +++--- .../src/app/utils/bundleFeed.ts | 3 +- apps/vs-code-designer/src/constants.ts | 30 ++----------------- 4 files changed, 7 insertions(+), 40 deletions(-) diff --git a/apps/vs-code-designer/src/app/utils/__test__/bundleFeed.test.ts b/apps/vs-code-designer/src/app/utils/__test__/bundleFeed.test.ts index 8a9f9064ec2..a4ae9d01b62 100644 --- a/apps/vs-code-designer/src/app/utils/__test__/bundleFeed.test.ts +++ b/apps/vs-code-designer/src/app/utils/__test__/bundleFeed.test.ts @@ -10,11 +10,6 @@ vi.mock('../../localize', () => ({ localize: vi.fn((key: string, defaultValue: string) => defaultValue), })); -// Mock funcVersion -vi.mock('../funcCoreTools/funcVersion', () => ({ - getFunctionsCommand: vi.fn(() => 'func'), -})); - const mockedFse = vi.mocked(fse); const mockedExecSync = vi.mocked(cp.execSync); diff --git a/apps/vs-code-designer/src/app/utils/__test__/unitTestUtils.test.ts b/apps/vs-code-designer/src/app/utils/__test__/unitTestUtils.test.ts index 3f645589e88..fbf16c2c284 100644 --- a/apps/vs-code-designer/src/app/utils/__test__/unitTestUtils.test.ts +++ b/apps/vs-code-designer/src/app/utils/__test__/unitTestUtils.test.ts @@ -1928,14 +1928,13 @@ namespace <%= LogicAppName %>.Tests }); describe('updateSolutionWithProject', () => { - const testDotnetBinaryPath = path.join('test', 'path', 'to', 'dotnet'); let pathExistsSpy: any; let executeCommandSpy: any; beforeEach(() => { vi.spyOn(ext.outputChannel, 'appendLog').mockImplementation(() => {}); vi.spyOn(util, 'promisify').mockImplementation((fn) => fn); - vi.spyOn(vscodeConfigSettings, 'getGlobalSetting').mockReturnValue(testDotnetBinaryPath); + vi.spyOn(vscodeConfigSettings, 'getGlobalSetting').mockReturnValue('dotnet'); executeCommandSpy = vi.spyOn(cpUtils, 'executeCommand').mockResolvedValue(''); }); @@ -1955,7 +1954,7 @@ namespace <%= LogicAppName %>.Tests expect(executeCommandSpy).toHaveBeenCalledWith( ext.outputChannel, testsDirectory, - `${testDotnetBinaryPath} sln "${path.join(testsDirectory, 'Tests.sln')}" add "${fakeLogicAppName}.csproj"` + `${'dotnet'} sln "${path.join(testsDirectory, 'Tests.sln')}" add "${fakeLogicAppName}.csproj"` ); }); @@ -1968,11 +1967,11 @@ namespace <%= LogicAppName %>.Tests await updateTestsSln(testsDirectory, logicAppCsprojPath); expect(executeCommandSpy).toHaveBeenCalledTimes(2); - expect(executeCommandSpy).toHaveBeenCalledWith(ext.outputChannel, testsDirectory, `${testDotnetBinaryPath} new sln -n Tests`); + expect(executeCommandSpy).toHaveBeenCalledWith(ext.outputChannel, testsDirectory, `${'dotnet'} new sln -n Tests`); expect(executeCommandSpy).toHaveBeenCalledWith( ext.outputChannel, testsDirectory, - `${testDotnetBinaryPath} sln "${path.join(testsDirectory, 'Tests.sln')}" add "${fakeLogicAppName}.csproj"` + `${'dotnet'} sln "${path.join(testsDirectory, 'Tests.sln')}" add "${fakeLogicAppName}.csproj"` ); }); }); diff --git a/apps/vs-code-designer/src/app/utils/bundleFeed.ts b/apps/vs-code-designer/src/app/utils/bundleFeed.ts index afb0f73b014..723d261bd15 100644 --- a/apps/vs-code-designer/src/app/utils/bundleFeed.ts +++ b/apps/vs-code-designer/src/app/utils/bundleFeed.ts @@ -12,7 +12,6 @@ import * as semver from 'semver'; import * as vscode from 'vscode'; import { localize } from '../../localize'; import { ext } from '../../extensionVariables'; -import { getFunctionsCommand } from './funcCoreTools/funcVersion'; import * as cp from 'child_process'; import * as fse from 'fs-extra'; /** @@ -290,7 +289,7 @@ export async function getBundleVersionNumber(): Promise { * @returns {string} Extension bundle folder path. */ export async function getExtensionBundleFolder(): Promise { - const command = `${getFunctionsCommand()} GetExtensionBundlePath`; + const command = 'func GetExtensionBundlePath'; const outputChannel = ext.outputChannel; if (outputChannel) { diff --git a/apps/vs-code-designer/src/constants.ts b/apps/vs-code-designer/src/constants.ts index 89b273632c5..a82d73ad07d 100644 --- a/apps/vs-code-designer/src/constants.ts +++ b/apps/vs-code-designer/src/constants.ts @@ -241,11 +241,6 @@ export const unitTestExplorer = 'unitTestExplorer'; export const verifyConnectionKeysSetting = 'verifyConnectionKeys'; export const useSmbDeployment = 'useSmbDeploymentForHybrid'; -// TODO (ccastrotrejo): To be removed -export const autoRuntimeDependenciesPathSettingKey = 'autoRuntimeDependenciesPath'; -export const defaultLogicAppsFolder = '.azurelogicapps'; -export const defaultDependencyPathValue = path.join(os.homedir(), defaultLogicAppsFolder, 'dependencies'); - // host.json export const extensionBundleId = 'Microsoft.Azure.Functions.ExtensionBundle.Workflows'; export const targetBundleKey = 'FUNCTIONS_EXTENSIONBUNDLE_SOURCE_URI'; @@ -263,13 +258,12 @@ export const isZipDeployEnabledSetting = 'IS_ZIP_DEPLOY_ENABLED'; // Project export const defaultVersionRange = '[1.*, 2.0.0)'; // Might need to be changed export const funcWatchProblemMatcher = '$func-watch'; -export const extInstallCommand = 'extensions install'; -export const extInstallTaskName = `${func}: ${extInstallCommand}`; +export const extInstallTaskName = `${func}: extensions install`; export const tasksVersion = '2.0.0'; export const launchVersion = '0.2.0'; export const dotnetPublishTaskLabel = 'publish'; export const defaultFunctionCoreToolsFolder = '.azure-functions-core-tools'; -export const defaultAzuritePathValue = path.join(os.homedir(), defaultLogicAppsFolder, '.azurite'); +export const defaultAzuritePathValue = path.join(os.homedir(), '.azurite'); export const defaultExtensionBundlePathValue = path.join( os.homedir(), defaultFunctionCoreToolsFolder, @@ -279,14 +273,6 @@ export const defaultExtensionBundlePathValue = path.join( ); export const defaultDataMapperVersion = 2; -// Fallback Dependency Versions -export const DependencyVersion = { - dotnet6: '6.0.413', - funcCoreTools: '4.0.7030', - nodeJs: '18.17.1', -} as const; -export type DependencyVersion = (typeof DependencyVersion)[keyof typeof DependencyVersion]; - export const hostFileContent = { version: '2.0', extensionBundle: { @@ -302,12 +288,6 @@ export const hostFileContent = { }, }; -export const DependencyDefaultPath = { - dotnet: 'dotnet', - funcCoreTools: 'func', - node: 'node', -} as const; -export type DependencyDefaultPath = (typeof DependencyDefaultPath)[keyof typeof DependencyDefaultPath]; // .NET export const DotnetVersion = { net8: 'net8.0', @@ -320,12 +300,6 @@ export type DotnetVersion = (typeof DotnetVersion)[keyof typeof DotnetVersion]; export const dotnetExtensionId = 'ms-dotnettools.csharp'; -// Packages Manager -export const PackageManager = { - npm: 'npm', - brew: 'brew', -} as const; -export type PackageManager = (typeof PackageManager)[keyof typeof PackageManager]; // Operating System Platforms export const Platform = { windows: 'win32', From 87a84cd564e45d2883da26b78c994063036ec2a3 Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Fri, 12 Sep 2025 18:50:23 -0400 Subject: [PATCH 06/46] Remove extension bundle installation --- .../workflows/unitTest/runUnitTest.ts | 3 +- .../src/app/utils/bundleFeed.ts | 262 +----------------- apps/vs-code-designer/src/main.ts | 2 - 3 files changed, 4 insertions(+), 263 deletions(-) diff --git a/apps/vs-code-designer/src/app/commands/workflows/unitTest/runUnitTest.ts b/apps/vs-code-designer/src/app/commands/workflows/unitTest/runUnitTest.ts index 74a07bc1ead..f6d33b8b192 100644 --- a/apps/vs-code-designer/src/app/commands/workflows/unitTest/runUnitTest.ts +++ b/apps/vs-code-designer/src/app/commands/workflows/unitTest/runUnitTest.ts @@ -11,7 +11,6 @@ import * as vscode from 'vscode'; import * as cp from 'child_process'; import * as path from 'path'; import { getWorkspacePath, isMultiRootWorkspace } from '../../../utils/workspace'; -import { getLatestBundleVersion } from '../../../utils/bundleFeed'; import { activateAzurite } from '../../../utils/azurite/activateAzurite'; import { TestFile } from '../../../tree/unitTestTree/testFile'; import type { UnitTestExecutionResult } from '@microsoft/vscode-extension-logic-apps'; @@ -104,7 +103,7 @@ export async function runUnitTestFromPath(context: IActionContext, unitTestPath: const logicAppName = path.relative(testDirectory, unitTestPath).split(path.sep)[0]; const workflowName = path.basename(path.dirname(unitTestPath)); const unitTestName = getUnitTestName(path.basename(unitTestPath)); - const bundleVersionNumber = await getLatestBundleVersion(defaultExtensionBundlePathValue); + const bundleVersionNumber = '1.138.54'; // TODO (ccastrotrejo): Need to get the value from the docker container const pathToExe = path.join( defaultExtensionBundlePathValue, bundleVersionNumber, diff --git a/apps/vs-code-designer/src/app/utils/bundleFeed.ts b/apps/vs-code-designer/src/app/utils/bundleFeed.ts index 723d261bd15..e83c26213ed 100644 --- a/apps/vs-code-designer/src/app/utils/bundleFeed.ts +++ b/apps/vs-code-designer/src/app/utils/bundleFeed.ts @@ -2,63 +2,12 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { defaultVersionRange, extensionBundleId, localSettingsFileName, defaultExtensionBundlePathValue } from '../../constants'; -import { getLocalSettingsJson } from './appSettings/localSettings'; -import { getJsonFeed } from './feed'; +import { defaultVersionRange, extensionBundleId } from '../../constants'; import type { IActionContext } from '@microsoft/vscode-azext-utils'; -import type { IBundleFeed, IBundleMetadata, IHostJsonV2 } from '@microsoft/vscode-extension-logic-apps'; -import * as path from 'path'; -import * as semver from 'semver'; -import * as vscode from 'vscode'; import { localize } from '../../localize'; import { ext } from '../../extensionVariables'; import * as cp from 'child_process'; -import * as fse from 'fs-extra'; -/** - * Gets bundle extension feed. - * @param {IActionContext} context - Command context. - * @param {IBundleMetadata | undefined} bundleMetadata - Bundle meta data. - * @returns {Promise} Returns bundle extension object. - */ -async function getBundleFeed(context: IActionContext, bundleMetadata: IBundleMetadata | undefined): Promise { - const bundleId: string = (bundleMetadata && bundleMetadata.id) || extensionBundleId; - - const envVarUri: string | undefined = process.env.FUNCTIONS_EXTENSIONBUNDLE_SOURCE_URI; - // Only use an aka.ms link for the most common case, otherwise we will dynamically construct the url - let url: string; - if (!envVarUri && bundleId === extensionBundleId) { - url = 'https://aka.ms/AAqvc78'; - } else { - const baseUrl: string = envVarUri || 'https://cdn.functions.azure.com/public'; - url = `${baseUrl}/ExtensionBundles/${bundleId}/index-v2.json`; - } - - return getJsonFeed(context, url); -} - -/** - * Gets Workflow bundle extension feed. - * @param {IActionContext} context - Command context. - * @param {IBundleMetadata | undefined} bundleMetadata - Bundle meta data. - * @returns {Promise} Returns bundle extension object. - */ -async function getWorkflowBundleFeed(context: IActionContext): Promise { - const envVarUri: string | undefined = process.env.FUNCTIONS_EXTENSIONBUNDLE_SOURCE_URI; - const baseUrl: string = envVarUri || 'https://cdn.functions.azure.com/public'; - const url = `${baseUrl}/ExtensionBundles/${extensionBundleId}/index-v2.json`; - - return getJsonFeed(context, url); -} - -/** - * Gets latest bundle extension version range. - * @param {IActionContext} context - Command context. - * @returns {Promise} Returns lates version range. - */ -export async function getLatestVersionRange(context: IActionContext): Promise { - const feed: IBundleFeed = await getBundleFeed(context, undefined); - return feed.defaultVersionRange; -} +import type { IHostJsonV2 } from '@microsoft/vscode-extension-logic-apps'; /** * Add bundle extension version to host.json configuration. @@ -68,7 +17,7 @@ export async function getLatestVersionRange(context: IActionContext): Promise { let versionRange: string; try { - versionRange = await getLatestVersionRange(context); + versionRange = '[1.*, 2.0.0)'; // TODO (ccastrotrejo): Set the range from defaul } catch { versionRange = defaultVersionRange; } @@ -79,211 +28,6 @@ export async function addDefaultBundle(context: IActionContext, hostJson: IHostJ }; } -/** - * Gets bundle extension zip. Microsoft.Azure.Functions.ExtensionBundle.Workflows.. - * @param {IActionContext} context - Command context. - * @param {string} extensionVersion - Bundle Extension Version. - * @returns {string} Returns bundle extension zip url. - */ -async function getExtensionBundleZip(context: IActionContext, extensionVersion: string): Promise { - let envVarUri: string | undefined = process.env.FUNCTIONS_EXTENSIONBUNDLE_SOURCE_URI; - const projectPath: string | undefined = vscode.workspace.workspaceFolders ? vscode.workspace.workspaceFolders[0].uri.fsPath : null; - if (projectPath) { - envVarUri = (await getLocalSettingsJson(context, path.join(projectPath, localSettingsFileName)))?.Values - ?.FUNCTIONS_EXTENSIONBUNDLE_SOURCE_URI; - } - const baseUrl: string = envVarUri || 'https://cdn.functions.azure.com/public'; - const url = `${baseUrl}/ExtensionBundles/${extensionBundleId}/${extensionVersion}/${extensionBundleId}.${extensionVersion}_any-any.zip`; - - return url; -} - -/** - * Gets the Extension Bundle Versions iterating through the default extension bundle path directory. - * @param {string} directoryPath - extension bundle path directory. - * @returns {string[]} Returns the list of versions. - */ -async function getExtensionBundleVersionFolders(directoryPath: string): Promise { - if (!(await fse.pathExists(directoryPath))) { - return []; - } - const directoryContents = fse.readdirSync(directoryPath); - - // Filter only the folders with valid version names. - const folders = directoryContents.filter((item) => { - const itemPath = path.join(directoryPath, item); - return fse.statSync(itemPath).isDirectory() && semver.valid(item); - }); - - return folders; -} - -/** - * Download Microsoft.Azure.Functions.ExtensionBundle.Workflows. - * Destination: C:\Users\\.azure-functions-core-tools\Functions\ExtensionBundles\ - * @param {IActionContext} context - Command context. - * @returns {Promise} A boolean indicating whether the bundle was updated. - */ -export async function downloadExtensionBundle(context: IActionContext): Promise { - try { - const downloadExtensionBundleStartTime = Date.now(); - let envVarVer: string | undefined = process.env.AzureFunctionsJobHost_extensionBundle_version; - const projectPath: string | undefined = vscode.workspace.workspaceFolders ? vscode.workspace.workspaceFolders[0].uri.fsPath : null; - if (projectPath) { - envVarVer = (await getLocalSettingsJson(context, path.join(projectPath, localSettingsFileName)))?.Values - ?.AzureFunctionsJobHost_extensionBundle_version; - } - - // Check for latest version at directory. - let latestLocalBundleVersion = '1.0.0'; - const localVersions = await getExtensionBundleVersionFolders(defaultExtensionBundlePathValue); - for (const localVersion of localVersions) { - latestLocalBundleVersion = semver.gt(latestLocalBundleVersion, localVersion) ? latestLocalBundleVersion : localVersion; - } - - context.telemetry.properties.envVariableExtensionBundleVersion = envVarVer; - if (envVarVer) { - if (semver.eq(envVarVer, latestLocalBundleVersion)) { - return false; - } - - const extensionBundleUrl = await getExtensionBundleZip(context, envVarVer); - - //TODO (ccastrotrejo): Get the bundle in the container - console.log(extensionBundleUrl); - context.telemetry.measurements.downloadExtensionBundleDuration = (Date.now() - downloadExtensionBundleStartTime) / 1000; - context.telemetry.properties.didUpdateExtensionBundle = 'true'; - return true; - } - - // Check the latest from feed. - let latestFeedBundleVersion = '1.0.0'; - const feed: IBundleFeed = await getWorkflowBundleFeed(context); - for (const bundleVersion in feed.bundleVersions) { - latestFeedBundleVersion = semver.gt(latestFeedBundleVersion, bundleVersion) ? latestFeedBundleVersion : bundleVersion; - } - - context.telemetry.properties.latestBundleVersion = semver.gt(latestFeedBundleVersion, latestLocalBundleVersion) - ? latestFeedBundleVersion - : latestLocalBundleVersion; - - ext.defaultBundleVersion = context.telemetry.properties.latestBundleVersion; - ext.latestBundleVersion = context.telemetry.properties.latestBundleVersion; - - if (semver.gt(latestFeedBundleVersion, latestLocalBundleVersion)) { - const extensionBundleUrl = await getExtensionBundleZip(context, latestFeedBundleVersion); - //TODO (ccastrotrejo): Get the bundle in the container - console.log(extensionBundleUrl); - - context.telemetry.measurements.downloadExtensionBundleDuration = (Date.now() - downloadExtensionBundleStartTime) / 1000; - context.telemetry.properties.didUpdateExtensionBundle = 'true'; - return true; - } - - context.telemetry.measurements.downloadExtensionBundleDuration = (Date.now() - downloadExtensionBundleStartTime) / 1000; - context.telemetry.properties.didUpdateExtensionBundle = 'false'; - return false; - } catch (error) { - const errorMessage = `Error downloading and extracting the Logic Apps Standard extension bundle: ${error.message}`; - context.telemetry.properties.errorMessage = errorMessage; - return false; - } -} - -/** - * Retrieves the latest version number of a bundle from the specified folder. - * @param {string} bundleFolder - The path to the folder containing the bundle. - * @returns The latest version number of the bundle. - * @throws An error if the bundle folder is empty. - */ -export const getLatestBundleVersion = async (bundleFolder: string) => { - let bundleVersionNumber = '0.0.0'; - - const bundleFolders = await fse.readdir(bundleFolder); - if (bundleFolders.length === 0) { - throw new Error(localize('bundleMissingError', 'Extension bundle could not be found.')); - } - - for (const file of bundleFolders) { - const filePath: string = path.join(bundleFolder, file); - if (await (await fse.stat(filePath)).isDirectory()) { - bundleVersionNumber = getMaxVersion(bundleVersionNumber, file); - } - } - - return bundleVersionNumber; -}; - -/** - * Compares and gets biggest extension bundle version. - * @param version1 - Extension bundle version. - * @param version2 - Extension bundle version. - * @returns {string} Biggest extension bundle version. - */ -function getMaxVersion(version1, version2): string { - let maxVersion = ''; - let arr1 = version1.split('.'); - let arr2 = version2.split('.'); - - arr1 = arr1.map(Number); - arr2 = arr2.map(Number); - - const arr1Size = arr1.length; - const arr2Size = arr2.length; - - if (arr1Size > arr2Size) { - for (let i = arr2Size; i < arr1Size; i++) { - arr2.push(0); - } - } else { - for (let i = arr1Size; i < arr2Size; i++) { - arr1.push(0); - } - } - - for (let i = 0; i < arr1.length; i++) { - if (arr1[i] > arr2[i]) { - maxVersion = version1; - break; - } - if (arr2[i] > arr1[i]) { - maxVersion = version2; - break; - } - } - return maxVersion; -} - -/** - * Retrieves the highest version number of the extension bundle available in the bundle folder. - * - * This function locates the extension bundle folder, enumerates its subdirectories, - * and determines the maximum version number present among them. If no bundle is found, - * it throws an error. - * - * @returns {Promise} A promise that resolves to the highest bundle version number as a string (e.g., "1.2.3"). - * @throws {Error} If the extension bundle folder is missing or contains no subdirectories. - */ -export async function getBundleVersionNumber(): Promise { - const bundleFolderRoot = await getExtensionBundleFolder(); - const bundleFolder = path.join(bundleFolderRoot, extensionBundleId); - let bundleVersionNumber = '0.0.0'; - - const bundleFolders = await fse.readdir(bundleFolder); - if (bundleFolders.length === 0) { - throw new Error(localize('bundleMissingError', 'Extension bundle could not be found.')); - } - - for (const file of bundleFolders) { - const filePath: string = path.join(bundleFolder, file); - if (await (await fse.stat(filePath)).isDirectory()) { - bundleVersionNumber = getMaxVersion(bundleVersionNumber, file); - } - } - - return bundleVersionNumber; -} - /** * Gets extension bundle folder path. * @returns {string} Extension bundle folder path. diff --git a/apps/vs-code-designer/src/main.ts b/apps/vs-code-designer/src/main.ts index d6a8652f1ef..61fc3ef49be 100644 --- a/apps/vs-code-designer/src/main.ts +++ b/apps/vs-code-designer/src/main.ts @@ -10,7 +10,6 @@ import { promptParameterizeConnections } from './app/commands/parameterizeConnec import { registerCommands } from './app/commands/registerCommands'; import { getResourceGroupsApi } from './app/resourcesExtension/getExtensionApi'; import type { AzureAccountTreeItemWithProjects } from './app/tree/AzureAccountTreeItemWithProjects'; -import { downloadExtensionBundle } from './app/utils/bundleFeed'; import { promptStartDesignTimeOption, stopAllDesignTimeApis } from './app/utils/codeless/startDesignTimeApi'; import { UriHandler } from './app/utils/codeless/urihandler'; import { getExtensionVersion } from './app/utils/extension'; @@ -109,7 +108,6 @@ export async function activate(context: vscode.ExtensionContext) { await convertToWorkspace(activateContext); } - downloadExtensionBundle(activateContext); promptParameterizeConnections(activateContext, false); verifyLocalConnectionKeys(activateContext); From 32f58b5e795f573362de4c3fd4f5c867ff186f70 Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Mon, 15 Sep 2025 10:11:01 -0400 Subject: [PATCH 07/46] Add extension bundle download --- apps/vs-code-designer/src/container/Dockerfile | 16 +++++++++++++++- .../src/container/devcontainer.json | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/apps/vs-code-designer/src/container/Dockerfile b/apps/vs-code-designer/src/container/Dockerfile index 05ac6273594..3edd4269c58 100644 --- a/apps/vs-code-designer/src/container/Dockerfile +++ b/apps/vs-code-designer/src/container/Dockerfile @@ -1 +1,15 @@ -FROM mcr.microsoft.com/devcontainers/javascript-node:1-22-bookworm \ No newline at end of file +FROM mcr.microsoft.com/devcontainers/javascript-node:1-22-bookworm + +ARG EXTENSION_BUNDLE_VERSION=1.131.9 +ARG EXTENSION_BUNDLE_CDN_URL=https://functionscdn.azureedge.net/public +ARG EXTENSION_BUNDLE_FOLDER_PATH=.azure-functions-core-tools/Functions/ExtensionBundles + +RUN apt-get update && apt-get install -y curl jq gnupg wget unzip +RUN echo "Using version: $EXTENSION_BUNDLE_VERSION" && \ + EXTENSION_BUNDLE_FILENAME_V4=Microsoft.Azure.Functions.ExtensionBundle.Workflows.${EXTENSION_BUNDLE_VERSION}_any-any.zip && \ + wget $EXTENSION_BUNDLE_CDN_URL/ExtensionBundles/Microsoft.Azure.Functions.ExtensionBundle.Workflows/$EXTENSION_BUNDLE_VERSION/$EXTENSION_BUNDLE_FILENAME_V4 && \ + mkdir -p /.${EXTENSION_BUNDLE_FOLDER_PATH}/Microsoft.Azure.Functions.ExtensionBundle.Workflows/$EXTENSION_BUNDLE_VERSION && \ + unzip /$EXTENSION_BUNDLE_FILENAME_V4 -d /.${EXTENSION_BUNDLE_FOLDER_PATH}/Microsoft.Azure.Functions.ExtensionBundle.Workflows/$EXTENSION_BUNDLE_VERSION && \ + rm -f /$EXTENSION_BUNDLE_FILENAME_V4 + +RUN find /.${EXTENSION_BUNDLE_FOLDER_PATH}/ -type f -exec chmod 644 {} \; \ No newline at end of file diff --git a/apps/vs-code-designer/src/container/devcontainer.json b/apps/vs-code-designer/src/container/devcontainer.json index bd4cfd98ed6..fa20747822b 100644 --- a/apps/vs-code-designer/src/container/devcontainer.json +++ b/apps/vs-code-designer/src/container/devcontainer.json @@ -48,7 +48,7 @@ } } }, - + "postStartCommand": "azurite --silent --location /home/vscode/.azurite --debug /home/vscode/.azurite/debug.log &", "otherPortsAttributes": { "onAutoForward": "silent" } From 544e9cc5a13d21f846d8819c7052597ee2bfed4d Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Mon, 15 Sep 2025 10:27:55 -0400 Subject: [PATCH 08/46] Add Azure Functions Core Tools download to container Dockerfile --- apps/vs-code-designer/src/container/Dockerfile | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/apps/vs-code-designer/src/container/Dockerfile b/apps/vs-code-designer/src/container/Dockerfile index 3edd4269c58..794d68be9b7 100644 --- a/apps/vs-code-designer/src/container/Dockerfile +++ b/apps/vs-code-designer/src/container/Dockerfile @@ -12,4 +12,19 @@ RUN echo "Using version: $EXTENSION_BUNDLE_VERSION" && \ unzip /$EXTENSION_BUNDLE_FILENAME_V4 -d /.${EXTENSION_BUNDLE_FOLDER_PATH}/Microsoft.Azure.Functions.ExtensionBundle.Workflows/$EXTENSION_BUNDLE_VERSION && \ rm -f /$EXTENSION_BUNDLE_FILENAME_V4 -RUN find /.${EXTENSION_BUNDLE_FOLDER_PATH}/ -type f -exec chmod 644 {} \; \ No newline at end of file +RUN find /.${EXTENSION_BUNDLE_FOLDER_PATH}/ -type f -exec chmod 755 {} \; + +ARG FUNCTIONS_CORE_TOOLS_VERSION=4.2.2 +ARG FUNCTIONS_CORE_TOOLS_OS_PLATFORM=linux +ARG FUNCTIONS_CORE_TOOLS_ARCH=x64 +ARG FUNCTIONS_CORE_TOOLS_FOLDER_PATH=.azurelogicapps/dependencies/FuncCoreTools + +RUN echo "Downloading Azure Functions Core Tools version: $FUNCTIONS_CORE_TOOLS_VERSION" && \ + FUNCTIONS_CORE_TOOLS_FILENAME=Azure.Functions.Cli.${FUNCTIONS_CORE_TOOLS_OS_PLATFORM}-${FUNCTIONS_CORE_TOOLS_ARCH}.${FUNCTIONS_CORE_TOOLS_VERSION}.zip && \ + wget https://github.com/Azure/azure-functions-core-tools/releases/download/${FUNCTIONS_CORE_TOOLS_VERSION}/$FUNCTIONS_CORE_TOOLS_FILENAME && \ + mkdir -p /.${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/ && \ + unzip /$FUNCTIONS_CORE_TOOLS_FILENAME -d /.${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/ && \ + rm -f /$FUNCTIONS_CORE_TOOLS_FILENAME + +RUN chmod -R 755 /.${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/ && \ + chmod 755 /.${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/func \ No newline at end of file From 4984fab849e0c45921551344715bd5ff8e0a2002 Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Mon, 15 Sep 2025 10:41:21 -0400 Subject: [PATCH 09/46] Complete container integration with func binary linking --- LESS_FILES_MIGRATION_ANALYSIS.md | 2 +- LESS_TO_MAKESTYLES_DETAILED_MIGRATION_PLAN.md | 4 +-- LESS_TO_MAKESTYLES_MIGRATION_PLAN.md | 6 ++-- MIGRATION_DEPENDENCY_GRAPH.md | 2 +- .../initCustomCodeProjectStep.ts | 20 +++---------- .../initCustomCodeScriptProjectStep.ts | 20 +++---------- .../initDotnetProjectStep.ts | 28 +++---------------- .../initProjectForVSCode/initProjectStep.ts | 20 +++---------- .../initScriptProjectStep.ts | 20 +++---------- .../vs-code-designer/src/container/Dockerfile | 3 +- apps/vs-code-react/src/state/DesignerSlice.ts | 1 - 11 files changed, 29 insertions(+), 97 deletions(-) diff --git a/LESS_FILES_MIGRATION_ANALYSIS.md b/LESS_FILES_MIGRATION_ANALYSIS.md index f3c06063231..5020167f9ee 100644 --- a/LESS_FILES_MIGRATION_ANALYSIS.md +++ b/LESS_FILES_MIGRATION_ANALYSIS.md @@ -15,7 +15,7 @@ This document provides a detailed analysis of all 124 LESS files in the LogicApp - ✅ **reviewList styles.less (32 lines) - REMOVED ENTIRELY** - apps/vs-code-react → reviewListStyles.ts (PR #7907) - ✅ **VS Code styles.less (5 lines) - REMOVED ENTIRELY** - apps/vs-code-react → inline HTML styles - ✅ SVG icon migration (3 files removed) - apps/vs-code-react -- ✅ **nodeSearchPanel** - NEW makeStyles implementation with Tabster focus management (branch: ccastrotrejo/panelSearchMigration) +- ✅ **nodeSearchPanel** - NEW makeStyles implementation with Tabster focus management - ✅ **Fluent UI v8 to v9 Component Migrations**: - SearchableDropdown: Complete migration with proper key handling and Fluent UI v9 patterns - ShimmeredDetailsList → Table: Native Fluent UI v9 table with column resizing diff --git a/LESS_TO_MAKESTYLES_DETAILED_MIGRATION_PLAN.md b/LESS_TO_MAKESTYLES_DETAILED_MIGRATION_PLAN.md index 9200369da61..8f0e20f3a0e 100644 --- a/LESS_TO_MAKESTYLES_DETAILED_MIGRATION_PLAN.md +++ b/LESS_TO_MAKESTYLES_DETAILED_MIGRATION_PLAN.md @@ -426,7 +426,7 @@ This document provides a detailed, granular breakdown of the LESS to makeStyles - In Progress: 5 - Blocked: 0 -### Recently Completed (PRs #7588, #7797, #7820, #7907, Branch: ccastrotrejo/panelSearchMigration) +### Recently Completed (PRs #7588, #7797, #7820, #7907) - ✅ VS Code React export.less → exportStyles.ts (PR #7588, #7797) - ✅ VS Code React overview.less → overviewStyles.ts (PR #7588) - ✅ VS Code React reviewList component styles → reviewListStyles.ts (PR #7907) - **COMPLEX MIGRATION** @@ -437,7 +437,7 @@ This document provides a detailed, granular breakdown of the LESS to makeStyles - Updated all consuming components (validation.tsx, review/index.tsx) - Enhanced accessibility with proper ARIA labels and tree navigation - ✅ SVG icon migration to Fluent UI icons (PR #7820) -- ✅ **nodeSearchPanel component**: New makeStyles implementation with Tabster focus management (Branch: ccastrotrejo/panelSearchMigration) +- ✅ **nodeSearchPanel component**: New makeStyles implementation with Tabster focus management - Migrated from Fluent UI v8 `FocusTrapZone` to Tabster for better accessibility - Added new dependency: `tabster: 8.5.6` - Created `nodeSearchPanelStyles.ts` with makeStyles for SearchBox styling diff --git a/LESS_TO_MAKESTYLES_MIGRATION_PLAN.md b/LESS_TO_MAKESTYLES_MIGRATION_PLAN.md index 6679a2167b8..5b61b7eb8ab 100644 --- a/LESS_TO_MAKESTYLES_MIGRATION_PLAN.md +++ b/LESS_TO_MAKESTYLES_MIGRATION_PLAN.md @@ -33,11 +33,11 @@ This document outlines a comprehensive plan to migrate 124 .less files in the Lo - ✅ flyout component (flyout.less - 50 lines) - already had makeStyles, verified - ✅ pager component (pager.less - 84 lines) - ✅ staticResult component (staticResult.less - 146 lines) - styles created -- ✅ **nodeSearchPanel** - NEW makeStyles implementation with Tabster focus management (branch: ccastrotrejo/panelSearchMigration) +- ✅ **nodeSearchPanel** - NEW makeStyles implementation with Tabster focus management - ✅ **VS CODE**: export component (export.less - 120 lines) → exportStyles.ts (PR #7588/#7797) - ✅ **VS CODE**: overview app (overview.less - 4 lines) → overviewStyles.ts (PR #7588) - ✅ **VS CODE**: reviewList component (styles.less - 32 lines) → reviewListStyles.ts (PR #7907) - **COMPLEX MIGRATION** -- ✅ **VS CODE**: root styles.less (5 lines) → **REMOVED ENTIRELY** - inline HTML styles (ccastrotrejo/FinalMigration) +- ✅ **VS CODE**: root styles.less (5 lines) → **REMOVED ENTIRELY** - inline HTML styles - ✅ **SVG MIGRATION**: 3 SVG files removed, replaced with Fluent UI icons (PR #7820) - ✅ **FLUENT UI v8 TO v9 MIGRATIONS** : - ✅ SearchableDropdown: Complete v8→v9 migration with enhanced key handling and Fluent UI v9 patterns @@ -638,7 +638,7 @@ Alongside the LESS to makeStyles migration, we're also migrating from Fluent UI - Removed validationItems parameter, simplified component API - Complete removal of styles.less file (not just migration) -7. **NodeSearchPanel Component** (✅ COMPLETED - Branch: ccastrotrejo/panelSearchMigration) +7. **NodeSearchPanel Component** (✅ COMPLETED) - v8: `FocusTrapZone` → Tabster focus management system - v8: `SearchBox` → v9: `SearchBox` with updated event handlers - Location: `/libs/designer/src/lib/ui/panel/nodeSearchPanel/` diff --git a/MIGRATION_DEPENDENCY_GRAPH.md b/MIGRATION_DEPENDENCY_GRAPH.md index 3345b46e00f..65afe2719cc 100644 --- a/MIGRATION_DEPENDENCY_GRAPH.md +++ b/MIGRATION_DEPENDENCY_GRAPH.md @@ -227,7 +227,7 @@ These patterns can accelerate the remaining designer-ui and designer library mig - ✓ **MAJOR**: ReviewList complete architecture migration (GroupedList → Tree) with file removal - ✓ Fluent UI v8 → v9 migration patterns established and refined - ✓ SVG → Fluent UI icon migration completed for VS Code -- ✓ **NEW**: NodeSearchPanel migration with Tabster focus management (Branch: ccastrotrejo/panelSearchMigration) +- ✓ **NEW**: NodeSearchPanel migration with Tabster focus management - ✓ Added `tabster: 8.5.6` dependency for advanced accessibility features - ✓ Complex component migration patterns validated (Tree, Skeleton components) - ⚠️ Performance validation in progress diff --git a/apps/vs-code-designer/src/app/commands/createProject/createCustomCodeProjectSteps/initCustomCodeProjectStep.ts b/apps/vs-code-designer/src/app/commands/createProject/createCustomCodeProjectSteps/initCustomCodeProjectStep.ts index 25333793765..9dc24650c4a 100644 --- a/apps/vs-code-designer/src/app/commands/createProject/createCustomCodeProjectSteps/initCustomCodeProjectStep.ts +++ b/apps/vs-code-designer/src/app/commands/createProject/createCustomCodeProjectSteps/initCustomCodeProjectStep.ts @@ -2,24 +2,13 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { extensionCommand, func, funcWatchProblemMatcher, hostStartCommand } from '../../../../constants'; +import { extensionCommand, funcWatchProblemMatcher } from '../../../../constants'; import { InitCustomCodeScriptProjectStep } from './initCustomCodeScriptProjectStep'; import type { ITaskInputs, ISettingToAdd } from '@microsoft/vscode-extension-logic-apps'; import type { TaskDefinition } from 'vscode'; export class InitCustomCodeProjectStep extends InitCustomCodeScriptProjectStep { protected getTasks(): TaskDefinition[] { - // TODO (ccastrotrejo) - remove - const funcBinariesExist = true; - const binariesOptions = funcBinariesExist - ? { - options: { - env: { - PATH: '${config:azureLogicAppsStandard.autoRuntimeDependenciesPath}\\NodeJs;${config:azureLogicAppsStandard.autoRuntimeDependenciesPath}\\DotNetSDK;$env:PATH', - }, - }, - } - : {}; return [ { label: 'generateDebugSymbols', @@ -29,10 +18,9 @@ export class InitCustomCodeProjectStep extends InitCustomCodeScriptProjectStep { problemMatcher: '$msCompile', }, { - type: funcBinariesExist ? 'shell' : func, - command: funcBinariesExist ? 'func' : hostStartCommand, - args: funcBinariesExist ? ['host', 'start'] : undefined, - ...binariesOptions, + type: 'shell', + command: 'func', + args: ['host', 'start'], problemMatcher: funcWatchProblemMatcher, isBackground: true, label: 'func: host start', diff --git a/apps/vs-code-designer/src/app/commands/createProject/createCustomCodeProjectSteps/initCustomCodeScriptProjectStep.ts b/apps/vs-code-designer/src/app/commands/createProject/createCustomCodeProjectSteps/initCustomCodeScriptProjectStep.ts index bccfe5e7f85..0c982020811 100644 --- a/apps/vs-code-designer/src/app/commands/createProject/createCustomCodeProjectSteps/initCustomCodeScriptProjectStep.ts +++ b/apps/vs-code-designer/src/app/commands/createProject/createCustomCodeProjectSteps/initCustomCodeScriptProjectStep.ts @@ -2,7 +2,7 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { extInstallTaskName, func, funcWatchProblemMatcher, hostStartCommand } from '../../../../constants'; +import { extInstallTaskName, funcWatchProblemMatcher } from '../../../../constants'; import { getLocalFuncCoreToolsVersion } from '../../../utils/funcCoreTools/funcVersion'; import { InitCustomCodeProjectStepBase } from './initCustomCodeProjectStepBase'; import type { IProjectWizardContext } from '@microsoft/vscode-extension-logic-apps'; @@ -47,24 +47,12 @@ export class InitCustomCodeScriptProjectStep extends InitCustomCodeProjectStepBa } protected getTasks(): TaskDefinition[] { - // TODO (ccastrotrejo) - remove - const funcBinariesExist = true; - const binariesOptions = funcBinariesExist - ? { - options: { - env: { - PATH: '${config:azureLogicAppsStandard.autoRuntimeDependenciesPath}\\NodeJs;${config:azureLogicAppsStandard.autoRuntimeDependenciesPath}\\DotNetSDK;$env:PATH', - }, - }, - } - : {}; return [ { label: 'func: host start', - type: funcBinariesExist ? 'shell' : func, - command: funcBinariesExist ? 'func' : hostStartCommand, - args: funcBinariesExist ? ['host', 'start'] : undefined, - ...binariesOptions, + type: 'shell', + command: 'func', + args: ['host', 'start'], problemMatcher: funcWatchProblemMatcher, dependsOn: this.useFuncExtensionsInstall ? extInstallTaskName : undefined, isBackground: true, diff --git a/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initDotnetProjectStep.ts b/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initDotnetProjectStep.ts index dfb7aafd60f..f09306b773b 100644 --- a/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initDotnetProjectStep.ts +++ b/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initDotnetProjectStep.ts @@ -2,14 +2,7 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { - dotnetPublishTaskLabel, - dotnetExtensionId, - func, - funcWatchProblemMatcher, - hostStartCommand, - show64BitWarningSetting, -} from '../../../constants'; +import { dotnetPublishTaskLabel, dotnetExtensionId, funcWatchProblemMatcher, show64BitWarningSetting } from '../../../constants'; import { localize } from '../../../localize'; import { getProjFiles, getTargetFramework, getDotnetDebugSubpath, tryGetFuncVersion } from '../../utils/dotnet/dotnet'; import type { ProjectFile } from '../../utils/dotnet/dotnet'; @@ -106,18 +99,6 @@ export class InitDotnetProjectStep extends InitProjectStepBase { protected getTasks(): TaskDefinition[] { const commonArgs: string[] = ['/property:GenerateFullPaths=true', '/consoleloggerparameters:NoSummary']; const releaseArgs: string[] = ['--configuration', 'Release']; - // TODO (ccastrotrejo)-remove - const funcBinariesExist = true; - const binariesOptions = funcBinariesExist - ? { - options: { - cwd: this.debugSubpath, - env: { - PATH: '${config:azureLogicAppsStandard.autoRuntimeDependenciesPath}\\NodeJs;${config:azureLogicAppsStandard.autoRuntimeDependenciesPath}\\DotNetSDK;$env:PATH', - }, - }, - } - : {}; return [ { label: 'clean', @@ -155,11 +136,10 @@ export class InitDotnetProjectStep extends InitProjectStepBase { }, { label: 'func: host start', - type: funcBinariesExist ? 'shell' : func, + type: 'shell', dependsOn: 'build', - ...binariesOptions, - command: funcBinariesExist ? 'func' : hostStartCommand, - args: funcBinariesExist ? ['host', 'start'] : undefined, + command: 'func', + args: ['host', 'start'], isBackground: true, problemMatcher: funcWatchProblemMatcher, }, diff --git a/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initProjectStep.ts b/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initProjectStep.ts index 9809707c262..951f7eb471d 100644 --- a/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initProjectStep.ts +++ b/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initProjectStep.ts @@ -2,24 +2,13 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { extensionCommand, func, funcWatchProblemMatcher, hostStartCommand } from '../../../constants'; +import { extensionCommand, funcWatchProblemMatcher } from '../../../constants'; import { InitScriptProjectStep } from './initScriptProjectStep'; import type { ITaskInputs, ISettingToAdd } from '@microsoft/vscode-extension-logic-apps'; import type { TaskDefinition } from 'vscode'; export class InitProjectStep extends InitScriptProjectStep { protected getTasks(): TaskDefinition[] { - // TODO (ccastrotrejo) - Remove - const funcBinariesExist = true; - const binariesOptions = funcBinariesExist - ? { - options: { - env: { - PATH: '${config:azureLogicAppsStandard.autoRuntimeDependenciesPath}\\NodeJs;${config:azureLogicAppsStandard.autoRuntimeDependenciesPath}\\DotNetSDK;$env:PATH', - }, - }, - } - : {}; return [ { label: 'generateDebugSymbols', @@ -29,10 +18,9 @@ export class InitProjectStep extends InitScriptProjectStep { problemMatcher: '$msCompile', }, { - type: funcBinariesExist ? 'shell' : func, - command: funcBinariesExist ? 'func' : hostStartCommand, - args: funcBinariesExist ? ['host', 'start'] : undefined, - ...binariesOptions, + type: 'shell', + command: 'func', + args: ['host', 'start'], problemMatcher: funcWatchProblemMatcher, isBackground: true, label: 'func: host start', diff --git a/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initScriptProjectStep.ts b/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initScriptProjectStep.ts index b4a30e740b7..927043d97cb 100644 --- a/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initScriptProjectStep.ts +++ b/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initScriptProjectStep.ts @@ -2,7 +2,7 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { extInstallTaskName, func, funcWatchProblemMatcher, hostStartCommand } from '../../../constants'; +import { extInstallTaskName, funcWatchProblemMatcher } from '../../../constants'; import { getLocalFuncCoreToolsVersion } from '../../utils/funcCoreTools/funcVersion'; import { InitProjectStepBase } from './initProjectStepBase'; import type { IProjectWizardContext } from '@microsoft/vscode-extension-logic-apps'; @@ -49,24 +49,12 @@ export class InitScriptProjectStep extends InitProjectStepBase { } protected getTasks(): TaskDefinition[] { - // TODO (ccastrotrejo) - Remoce - const funcBinariesExist = true; - const binariesOptions = funcBinariesExist - ? { - options: { - env: { - PATH: '${config:azureLogicAppsStandard.autoRuntimeDependenciesPath}\\NodeJs;${config:azureLogicAppsStandard.autoRuntimeDependenciesPath}\\DotNetSDK;$env:PATH', - }, - }, - } - : {}; return [ { label: 'func: host start', - type: funcBinariesExist ? 'shell' : func, - command: funcBinariesExist ? 'func' : hostStartCommand, - args: funcBinariesExist ? ['host', 'start'] : undefined, - ...binariesOptions, + type: 'shell', + command: 'func', + args: ['host', 'start'], problemMatcher: funcWatchProblemMatcher, dependsOn: this.useFuncExtensionsInstall ? extInstallTaskName : undefined, isBackground: true, diff --git a/apps/vs-code-designer/src/container/Dockerfile b/apps/vs-code-designer/src/container/Dockerfile index 794d68be9b7..f57e08714fd 100644 --- a/apps/vs-code-designer/src/container/Dockerfile +++ b/apps/vs-code-designer/src/container/Dockerfile @@ -27,4 +27,5 @@ RUN echo "Downloading Azure Functions Core Tools version: $FUNCTIONS_CORE_TOOLS_ rm -f /$FUNCTIONS_CORE_TOOLS_FILENAME RUN chmod -R 755 /.${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/ && \ - chmod 755 /.${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/func \ No newline at end of file + chmod 755 /.${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/func && \ + ln -s /.${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/func /usr/local/bin/func \ No newline at end of file diff --git a/apps/vs-code-react/src/state/DesignerSlice.ts b/apps/vs-code-react/src/state/DesignerSlice.ts index 5b9c9a428ff..3d270d0c141 100644 --- a/apps/vs-code-react/src/state/DesignerSlice.ts +++ b/apps/vs-code-react/src/state/DesignerSlice.ts @@ -63,7 +63,6 @@ export const designerSlice = createSlice({ name: 'designer', initialState, reducers: { - /// TODO(ccastrotrejo): Update missing types initializeDesigner: (state, action: PayloadAction) => { const { panelMetadata, From 6014306f914334e990e925af54c959bf3b36b9a9 Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Tue, 16 Sep 2025 17:22:44 -0400 Subject: [PATCH 10/46] Remove extension bundle func --- .../createProjectSteps/projectCreateStep.ts | 13 +- .../commands/pickCustomCodeNetHostProcess.ts | 19 ++- .../openDesignerForLocalProject.ts | 6 +- .../openMonitoringViewForLocal.ts | 6 +- .../src/app/utils/__test__/bundleFeed.test.ts | 116 ------------------ .../app/utils/__test__/reportAnIssue.test.ts | 4 - .../src/app/utils/bundleFeed.ts | 22 ---- .../app/utils/codeless/startDesignTimeApi.ts | 4 +- apps/vs-code-designer/src/app/utils/debug.ts | 8 +- .../src/app/utils/reportAnIssue.ts | 1 - apps/vs-code-designer/src/constants.ts | 4 +- .../src/extensionVariables.ts | 2 - 12 files changed, 35 insertions(+), 170 deletions(-) delete mode 100644 apps/vs-code-designer/src/app/utils/__test__/bundleFeed.test.ts diff --git a/apps/vs-code-designer/src/app/commands/createProject/createProjectSteps/projectCreateStep.ts b/apps/vs-code-designer/src/app/commands/createProject/createProjectSteps/projectCreateStep.ts index 028777acb9c..95c0b33ec65 100644 --- a/apps/vs-code-designer/src/app/commands/createProject/createProjectSteps/projectCreateStep.ts +++ b/apps/vs-code-designer/src/app/commands/createProject/createProjectSteps/projectCreateStep.ts @@ -6,6 +6,8 @@ import { ProjectDirectoryPathKey, appKindSetting, azureWebJobsStorageKey, + defaultVersionRange, + extensionBundleId, funcIgnoreFileName, functionsInprocNet8Enabled, functionsInprocNet8EnabledTrue, @@ -17,11 +19,9 @@ import { vscodeFolderName, workerRuntimeKey, } from '../../../../constants'; -import { addDefaultBundle } from '../../../utils/bundleFeed'; import { confirmOverwriteFile, writeFormattedJson } from '../../../utils/fs'; import { ProjectCreateStepBase } from './projectCreateStepBase'; import { nonNullProp } from '@microsoft/vscode-azext-utils'; -import type { IActionContext } from '@microsoft/vscode-azext-utils'; import type { IHostJsonV1, IHostJsonV2, ILocalSettingsJson, IProjectWizardContext } from '@microsoft/vscode-extension-logic-apps'; import { FuncVersion, WorkerRuntime } from '@microsoft/vscode-extension-logic-apps'; import * as fse from 'fs-extra'; @@ -61,7 +61,7 @@ export class ProjectCreateStep extends ProjectCreateStepBase { const hostJsonPath: string = path.join(context.projectPath, hostFileName); if (await confirmOverwriteFile(context, hostJsonPath)) { - const hostJson: IHostJsonV2 | IHostJsonV1 = version === FuncVersion.v1 ? {} : await this.getHostContent(context); + const hostJson: IHostJsonV2 | IHostJsonV1 = version === FuncVersion.v1 ? {} : await this.getHostContent(); await writeFormattedJson(hostJsonPath, hostJson); } @@ -82,7 +82,7 @@ export class ProjectCreateStep extends ProjectCreateStepBase { } } - protected async getHostContent(context: IActionContext): Promise { + protected async getHostContent(): Promise { const hostJson: IHostJsonV2 = { version: '2.0', logging: { @@ -95,7 +95,10 @@ export class ProjectCreateStep extends ProjectCreateStepBase { }, }; - await addDefaultBundle(context, hostJson); + hostJson.extensionBundle = { + id: extensionBundleId, + version: defaultVersionRange, + }; return hostJson; } diff --git a/apps/vs-code-designer/src/app/commands/pickCustomCodeNetHostProcess.ts b/apps/vs-code-designer/src/app/commands/pickCustomCodeNetHostProcess.ts index 250a541da0f..0f28da7df7b 100644 --- a/apps/vs-code-designer/src/app/commands/pickCustomCodeNetHostProcess.ts +++ b/apps/vs-code-designer/src/app/commands/pickCustomCodeNetHostProcess.ts @@ -6,7 +6,7 @@ import { Platform } from '../../constants'; import { getMatchingWorkspaceFolder } from '../debug/validatePreDebug'; import { runningFuncTaskMap } from '../utils/funcCoreTools/funcHostTask'; import type { IRunningFuncTask } from '../utils/funcCoreTools/funcHostTask'; -import type { IActionContext } from '@microsoft/vscode-azext-utils'; +import { parseError, type IActionContext } from '@microsoft/vscode-azext-utils'; import type * as vscode from 'vscode'; import * as path from 'path'; import { getUnixChildren, getWindowsChildren, pickChildProcess } from './pickFuncProcess'; @@ -66,7 +66,13 @@ export async function pickCustomCodeNetHostProcess( context.telemetry.properties.lastStep = 'pickNetHostChildProcess'; let customCodeNetHostProcess: string | undefined; for (let i = 0; i < maxRetries; i++) { - customCodeNetHostProcess = await pickNetHostChildProcess(taskInfo, debugConfig.isCodeless); + try { + customCodeNetHostProcess = await pickNetHostChildProcess(taskInfo, debugConfig.isCodeless); + } catch (error) { + context.telemetry.properties.result = 'Failed'; + context.telemetry.properties.error = parseError(error).message; + throw error; + } if (customCodeNetHostProcess) { break; } @@ -109,7 +115,14 @@ export async function pickCustomCodeNetHostProcessInternal( } context.telemetry.properties.lastStep = 'pickNetHostChildProcess'; - const customCodeNetHostProcess = await pickNetHostChildProcess(taskInfo, isCodeless); + let customCodeNetHostProcess: string | undefined; + try { + customCodeNetHostProcess = await pickNetHostChildProcess(taskInfo, isCodeless); + } catch (error) { + context.telemetry.properties.result = 'Failed'; + context.telemetry.properties.error = parseError(error).message; + throw error; + } if (!customCodeNetHostProcess) { const errorMessage = 'Failed to find the .NET host child process for the functions project for logic app "{0}".'; context.telemetry.properties.result = 'Failed'; diff --git a/apps/vs-code-designer/src/app/commands/workflows/openDesigner/openDesignerForLocalProject.ts b/apps/vs-code-designer/src/app/commands/workflows/openDesigner/openDesignerForLocalProject.ts index 019d2d9a744..33e1b0b569b 100644 --- a/apps/vs-code-designer/src/app/commands/workflows/openDesigner/openDesignerForLocalProject.ts +++ b/apps/vs-code-designer/src/app/commands/workflows/openDesigner/openDesignerForLocalProject.ts @@ -1,4 +1,4 @@ -import { localSettingsFileName, managementApiPrefix, workflowAppApiVersion } from '../../../../constants'; +import { EXTENSION_BUNDLE_VERSION, localSettingsFileName, managementApiPrefix, workflowAppApiVersion } from '../../../../constants'; import { ext } from '../../../../extensionVariables'; import { localize } from '../../../../localize'; import { getLocalSettingsJson } from '../../../utils/appSettings/localSettings'; @@ -45,7 +45,6 @@ import { env, ProgressLocation, Uri, ViewColumn, window, workspace } from 'vscod import type { WebviewPanel, ProgressOptions } from 'vscode'; import { saveBlankUnitTest } from '../unitTest/saveBlankUnitTest'; import { createHttpHeaders } from '@azure/core-rest-pipeline'; -import { getBundleVersionNumber } from '../../../utils/bundleFeed'; import { pickFuncProcess } from '../../pickFuncProcess'; export default class OpenDesignerForLocalProject extends OpenDesignerBase { @@ -531,7 +530,6 @@ export default class OpenDesignerForLocalProject extends OpenDesignerBase { const customCodeData: Record = await getCustomCodeFromFiles(this.workflowFilePath); const workflowDetails = await getManualWorkflowsInLocalProject(projectPath, this.workflowName); const artifacts = await getArtifactsInLocalProject(projectPath); - const bundleVersionNumber = await getBundleVersionNumber(); let localSettings: Record; let azureDetails: AzureConnectorDetails; @@ -559,7 +557,7 @@ export default class OpenDesignerForLocalProject extends OpenDesignerBase { artifacts, schemaArtifacts: this.schemaArtifacts, mapArtifacts: this.mapArtifacts, - extensionBundleVersion: bundleVersionNumber, + extensionBundleVersion: EXTENSION_BUNDLE_VERSION, }; } diff --git a/apps/vs-code-designer/src/app/commands/workflows/openMonitoringView/openMonitoringViewForLocal.ts b/apps/vs-code-designer/src/app/commands/workflows/openMonitoringView/openMonitoringViewForLocal.ts index ae10b51ebb7..dec4ee6f32f 100644 --- a/apps/vs-code-designer/src/app/commands/workflows/openMonitoringView/openMonitoringViewForLocal.ts +++ b/apps/vs-code-designer/src/app/commands/workflows/openMonitoringView/openMonitoringViewForLocal.ts @@ -2,7 +2,7 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { localSettingsFileName, managementApiPrefix } from '../../../../constants'; +import { EXTENSION_BUNDLE_VERSION, localSettingsFileName, managementApiPrefix } from '../../../../constants'; import { ext } from '../../../../extensionVariables'; import { localize } from '../../../../localize'; import { getLocalSettingsJson } from '../../../utils/appSettings/localSettings'; @@ -32,7 +32,6 @@ import type { WebviewPanel } from 'vscode'; import { Uri, ViewColumn } from 'vscode'; import { getArtifactsInLocalProject } from '../../../utils/codeless/artifacts'; import { saveBlankUnitTest } from '../unitTest/saveBlankUnitTest'; -import { getBundleVersionNumber } from '../../../utils/bundleFeed'; export default class OpenMonitoringViewForLocal extends OpenMonitoringViewBase { private projectPath: string | undefined; @@ -192,7 +191,6 @@ export default class OpenMonitoringViewForLocal extends OpenMonitoringViewBase { const workflowContent: any = JSON.parse(readFileSync(this.workflowFilePath, 'utf8')); const parametersData: Record = await getParametersFromFile(this.context, this.workflowFilePath); const customCodeData: Record = await getCustomCodeFromFiles(this.workflowFilePath); - const bundleVersionNumber = await getBundleVersionNumber(); let localSettings: Record; let azureDetails: AzureConnectorDetails; @@ -219,7 +217,7 @@ export default class OpenMonitoringViewForLocal extends OpenMonitoringViewBase { standardApp: getStandardAppData(this.workflowName, { ...workflowContent, definition: {} }), schemaArtifacts: this.schemaArtifacts, mapArtifacts: this.mapArtifacts, - extensionBundleVersion: bundleVersionNumber, + extensionBundleVersion: EXTENSION_BUNDLE_VERSION, }; } } diff --git a/apps/vs-code-designer/src/app/utils/__test__/bundleFeed.test.ts b/apps/vs-code-designer/src/app/utils/__test__/bundleFeed.test.ts deleted file mode 100644 index a4ae9d01b62..00000000000 --- a/apps/vs-code-designer/src/app/utils/__test__/bundleFeed.test.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { getBundleVersionNumber } from '../bundleFeed'; -import { describe, it, expect, vi, beforeEach } from 'vitest'; -import * as fse from 'fs-extra'; -import * as path from 'path'; -import * as cp from 'child_process'; -import { extensionBundleId } from '../../../constants'; - -// Mock localize -vi.mock('../../localize', () => ({ - localize: vi.fn((key: string, defaultValue: string) => defaultValue), -})); - -const mockedFse = vi.mocked(fse); -const mockedExecSync = vi.mocked(cp.execSync); - -describe('getBundleVersionNumber', () => { - const mockBundleFolderRoot = '/mock/bundle/root'; - const mockBundleFolder = path.join(mockBundleFolderRoot, extensionBundleId); - - beforeEach(() => { - vi.clearAllMocks(); - mockedExecSync.mockReturnValue(`${mockBundleFolderRoot}Microsoft.Azure.Functions.ExtensionBundle\n`); - }); - - it('should return the highest version number from available bundle folders', async () => { - const mockFolders = ['1.0.0', '2.1.0', '1.5.0', 'some-file.txt']; - mockedFse.readdir.mockResolvedValue(mockFolders as any); - mockedFse.stat.mockImplementation((filePath: any) => { - const fileName = path.basename(filePath.toString()); - return Promise.resolve({ - isDirectory: () => fileName !== 'some-file.txt', - } as any); - }); - - const result = await getBundleVersionNumber(); - - expect(result).toBe('2.1.0'); - expect(mockedFse.readdir).toHaveBeenCalledWith(mockBundleFolder); - }); - - it('should handle version numbers with different digit counts', async () => { - const mockFolders = ['1.0.0', '10.2.1', '2.15.3']; - mockedFse.readdir.mockResolvedValue(mockFolders as any); - mockedFse.stat.mockImplementation(() => { - return Promise.resolve({ - isDirectory: () => true, - } as any); - }); - - const result = await getBundleVersionNumber(); - - expect(result).toBe('10.2.1'); - }); - - it('should return default version when only non-directory files exist', async () => { - const mockFolders = ['file1.txt', 'file2.log']; - mockedFse.readdir.mockResolvedValue(mockFolders as any); - mockedFse.stat.mockImplementation(() => { - return Promise.resolve({ - isDirectory: () => false, - } as any); - }); - - const result = await getBundleVersionNumber(); - - expect(result).toBe('0.0.0'); - }); - - it('should handle single version folder', async () => { - const mockFolders = ['1.2.3']; - mockedFse.readdir.mockResolvedValue(mockFolders as any); - mockedFse.stat.mockImplementation(() => { - return Promise.resolve({ - isDirectory: () => true, - } as any); - }); - - const result = await getBundleVersionNumber(); - - expect(result).toBe('1.2.3'); - }); - - it('should throw error when no bundle folders found', async () => { - mockedFse.readdir.mockResolvedValue([] as any); - - await expect(getBundleVersionNumber()).rejects.toThrow('Extension bundle could not be found.'); - }); - - it('should handle mixed version formats correctly', async () => { - const mockFolders = ['1.0', '1.0.0', '1.0.0.1']; - mockedFse.readdir.mockResolvedValue(mockFolders as any); - mockedFse.stat.mockImplementation(() => { - return Promise.resolve({ - isDirectory: () => true, - } as any); - }); - - const result = await getBundleVersionNumber(); - - expect(result).toBe('1.0.0.1'); - }); - - it('should call execSync to get the bundle root path', async () => { - const mockFolders = ['1.0.0']; - mockedFse.readdir.mockResolvedValue(mockFolders as any); - mockedFse.stat.mockImplementation(() => { - return Promise.resolve({ - isDirectory: () => true, - } as any); - }); - - await getBundleVersionNumber(); - - expect(mockedExecSync).toHaveBeenCalledWith('func GetExtensionBundlePath', { encoding: 'utf8' }); - }); -}); diff --git a/apps/vs-code-designer/src/app/utils/__test__/reportAnIssue.test.ts b/apps/vs-code-designer/src/app/utils/__test__/reportAnIssue.test.ts index b2238ee4d1d..7a081ac8029 100644 --- a/apps/vs-code-designer/src/app/utils/__test__/reportAnIssue.test.ts +++ b/apps/vs-code-designer/src/app/utils/__test__/reportAnIssue.test.ts @@ -186,7 +186,6 @@ describe('reportAnIssue', () => { const decodedLink = decodeURIComponent(link); expect(decodedLink).toContain('Extension version: 1.0.0'); - expect(decodedLink).toContain('Extension bundle version: 1.2.3'); expect(decodedLink).toContain('OS: darwin'); expect(decodedLink).toContain('Product: Visual Studio Code'); expect(decodedLink).toContain('Product version: 1.85.0'); @@ -350,7 +349,6 @@ describe('reportAnIssue', () => { test('should handle missing extension versions', async () => { const originalExtensionVersion = ext.extensionVersion; - const originalBundleVersion = ext.latestBundleVersion; (ext as any).extensionVersion = undefined; (ext as any).latestBundleVersion = undefined; @@ -359,11 +357,9 @@ describe('reportAnIssue', () => { const decodedLink = decodeURIComponent(link); expect(decodedLink).toContain('Extension version: unknown'); - expect(decodedLink).toContain('Extension bundle version: unknown'); // Restore original values (ext as any).extensionVersion = originalExtensionVersion; - (ext as any).latestBundleVersion = originalBundleVersion; }); test('should handle different OS platforms', async () => { diff --git a/apps/vs-code-designer/src/app/utils/bundleFeed.ts b/apps/vs-code-designer/src/app/utils/bundleFeed.ts index e83c26213ed..e50a3322867 100644 --- a/apps/vs-code-designer/src/app/utils/bundleFeed.ts +++ b/apps/vs-code-designer/src/app/utils/bundleFeed.ts @@ -2,31 +2,9 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { defaultVersionRange, extensionBundleId } from '../../constants'; -import type { IActionContext } from '@microsoft/vscode-azext-utils'; import { localize } from '../../localize'; import { ext } from '../../extensionVariables'; import * as cp from 'child_process'; -import type { IHostJsonV2 } from '@microsoft/vscode-extension-logic-apps'; - -/** - * Add bundle extension version to host.json configuration. - * @param {IActionContext} context - Command context. - * @param {IHostJsonV2} hostJson - Host.json configuration. - */ -export async function addDefaultBundle(context: IActionContext, hostJson: IHostJsonV2): Promise { - let versionRange: string; - try { - versionRange = '[1.*, 2.0.0)'; // TODO (ccastrotrejo): Set the range from defaul - } catch { - versionRange = defaultVersionRange; - } - - hostJson.extensionBundle = { - id: extensionBundleId, - version: versionRange, - }; -} /** * Gets extension bundle folder path. diff --git a/apps/vs-code-designer/src/app/utils/codeless/startDesignTimeApi.ts b/apps/vs-code-designer/src/app/utils/codeless/startDesignTimeApi.ts index 07b2a7c372b..f8c27067bfb 100644 --- a/apps/vs-code-designer/src/app/utils/codeless/startDesignTimeApi.ts +++ b/apps/vs-code-designer/src/app/utils/codeless/startDesignTimeApi.ts @@ -127,9 +127,7 @@ export async function startDesignTimeApi(projectPath: string): Promise { if (data.extensionBundle) { const versionWithoutSpaces = data.extensionBundle.version.replace(/\s+/g, ''); const rangeWithoutSpaces = defaultVersionRange.replace(/\s+/g, ''); - if (data.extensionBundle.id === extensionBundleId && versionWithoutSpaces === rangeWithoutSpaces) { - ext.currentBundleVersion.set(projectPath, ext.latestBundleVersion); - } else if (data.extensionBundle.id === extensionBundleId && versionWithoutSpaces !== rangeWithoutSpaces) { + if (data.extensionBundle.id === extensionBundleId && versionWithoutSpaces !== rangeWithoutSpaces) { ext.currentBundleVersion.set(projectPath, extractPinnedVersion(data.extensionBundle.version) ?? data.extensionBundle.version); ext.pinnedBundleVersion.set(projectPath, true); } diff --git a/apps/vs-code-designer/src/app/utils/debug.ts b/apps/vs-code-designer/src/app/utils/debug.ts index e77826cce74..0d1450e011d 100644 --- a/apps/vs-code-designer/src/app/utils/debug.ts +++ b/apps/vs-code-designer/src/app/utils/debug.ts @@ -4,17 +4,15 @@ *--------------------------------------------------------------------------------------------*/ import { FuncVersion, TargetFramework } from '@microsoft/vscode-extension-logic-apps'; import type { DebugConfiguration } from 'vscode'; -import { debugSymbolDll, extensionBundleId, extensionCommand } from '../../constants'; - +import { debugSymbolDll, EXTENSION_BUNDLE_VERSION, extensionBundleId, extensionCommand } from '../../constants'; import * as path from 'path'; -import { getBundleVersionNumber, getExtensionBundleFolder } from './bundleFeed'; +import { getExtensionBundleFolder } from './bundleFeed'; export async function getDebugSymbolDll(): Promise { const bundleFolderRoot = await getExtensionBundleFolder(); const bundleFolder = path.join(bundleFolderRoot, extensionBundleId); - const bundleVersionNumber = await getBundleVersionNumber(); - return path.join(bundleFolder, bundleVersionNumber, 'bin', debugSymbolDll); + return path.join(bundleFolder, EXTENSION_BUNDLE_VERSION, 'bin', debugSymbolDll); } /** diff --git a/apps/vs-code-designer/src/app/utils/reportAnIssue.ts b/apps/vs-code-designer/src/app/utils/reportAnIssue.ts index d73205e2ba7..fd1f0a74d5f 100644 --- a/apps/vs-code-designer/src/app/utils/reportAnIssue.ts +++ b/apps/vs-code-designer/src/app/utils/reportAnIssue.ts @@ -88,7 +88,6 @@ function buildIssueBody(errorContext: IErrorHandlerContext, issue: IParsedError, body += `\nSession id: ${vscode.env.sessionId}`; } body += `\nExtension version: ${ext.extensionVersion ?? 'unknown'}`; - body += `\nExtension bundle version: ${ext.latestBundleVersion ?? 'unknown'}`; body += `\nOS: ${process.platform} (${os.type()} ${os.release()})`; body += `\nOS arch: ${os.arch()}`; body += `\nProduct: ${vscode.env.appName}`; diff --git a/apps/vs-code-designer/src/constants.ts b/apps/vs-code-designer/src/constants.ts index 124b5b6e5dd..f44fd9381a2 100644 --- a/apps/vs-code-designer/src/constants.ts +++ b/apps/vs-code-designer/src/constants.ts @@ -256,8 +256,10 @@ export const ProjectDirectoryPathKey = 'ProjectDirectoryPath'; export const extensionVersionKey = 'FUNCTIONS_EXTENSION_VERSION'; export const azureStorageTypeSetting = 'Files'; export const isZipDeployEnabledSetting = 'IS_ZIP_DEPLOY_ENABLED'; + // Project -export const defaultVersionRange = '[1.*, 2.0.0)'; // Might need to be changed +export const EXTENSION_BUNDLE_VERSION = '1.131.9'; +export const defaultVersionRange = '[1.*, 2.0.0)'; export const funcWatchProblemMatcher = '$func-watch'; export const extInstallTaskName = `${func}: extensions install`; export const tasksVersion = '2.0.0'; diff --git a/apps/vs-code-designer/src/extensionVariables.ts b/apps/vs-code-designer/src/extensionVariables.ts index d059315ba8a..c0fef3faa23 100644 --- a/apps/vs-code-designer/src/extensionVariables.ts +++ b/apps/vs-code-designer/src/extensionVariables.ts @@ -53,8 +53,6 @@ export namespace ext { export const prefix = 'azureLogicAppsStandard'; export const currentBundleVersion: Map = new Map(); export const pinnedBundleVersion: Map = new Map(); - export let defaultBundleVersion: string; - export let latestBundleVersion: string; // Services export let subscriptionProvider: VSCodeAzureSubscriptionProvider; From 0652615060c2f3045883a4b05da5829f0a0919e4 Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Tue, 16 Sep 2025 17:30:49 -0400 Subject: [PATCH 11/46] Add script to update the extension bundle reference --- apps/vs-code-designer/package.json | 5 ++- .../{ => scripts}/extension-copy-svgs.js | 2 +- .../update-extension-bundle-version.js | 41 +++++++++++++++++++ 3 files changed, 45 insertions(+), 3 deletions(-) rename apps/vs-code-designer/{ => scripts}/extension-copy-svgs.js (89%) create mode 100644 apps/vs-code-designer/scripts/update-extension-bundle-version.js diff --git a/apps/vs-code-designer/package.json b/apps/vs-code-designer/package.json index 3180cc14e0f..93e12158dcb 100644 --- a/apps/vs-code-designer/package.json +++ b/apps/vs-code-designer/package.json @@ -57,13 +57,14 @@ "scripts": { "build:extension": "tsup && pnpm run copyFiles", "build:ui": "tsup --config tsup.e2e.test.config.ts", - "copyFiles": "node extension-copy-svgs.js", + "copyFiles": "node scripts/extension-copy-svgs.js", "vscode:designer:pack": "pnpm run vscode:designer:pack:step1 && pnpm run vscode:designer:pack:step2", "vscode:designer:pack:step1": "cd ./dist && npm install", "vscode:designer:pack:step2": "cd ./dist && vsce package", "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", "test:extension-unit": "vitest run --retry=3", "vscode:designer:e2e:ui": "pnpm run build:ui && cd dist && extest setup-and-run ../out/test/**/*.js --coverage", - "vscode:designer:e2e:headless": "pnpm run build:ui && cd dist && extest setup-and-run ../out/test/**/*.js --coverage" + "vscode:designer:e2e:headless": "pnpm run build:ui && cd dist && extest setup-and-run ../out/test/**/*.js --coverage", + "update:extension-bundle-version": "node scripts/update-extension-bundle-version.js" } } diff --git a/apps/vs-code-designer/extension-copy-svgs.js b/apps/vs-code-designer/scripts/extension-copy-svgs.js similarity index 89% rename from apps/vs-code-designer/extension-copy-svgs.js rename to apps/vs-code-designer/scripts/extension-copy-svgs.js index 7fa2bdcc4a6..df14d45bde3 100644 --- a/apps/vs-code-designer/extension-copy-svgs.js +++ b/apps/vs-code-designer/scripts/extension-copy-svgs.js @@ -6,7 +6,7 @@ const copyDoc = async (projectPath) => { await copy('./src', `${projectPath}`, { filter: ['LICENSE.md', 'package.json', 'README.md', 'assets/**'], }); - await copy(path.resolve(__dirname, '..', '..'), `${projectPath}`, { + await copy(path.resolve(__dirname, '..'), `${projectPath}`, { filter: ['CHANGELOG.md'], }); }; diff --git a/apps/vs-code-designer/scripts/update-extension-bundle-version.js b/apps/vs-code-designer/scripts/update-extension-bundle-version.js new file mode 100644 index 00000000000..cecb76a63a0 --- /dev/null +++ b/apps/vs-code-designer/scripts/update-extension-bundle-version.js @@ -0,0 +1,41 @@ +#!/usr/bin/env node +/* eslint-disable no-undef */ +const fs = require('fs/promises'); +const path = require('path'); + +async function main() { + const version = process.argv[2]; + if (!version) { + console.error('Usage: node scripts/update-extension-bundle-version.js '); + process.exitCode = 1; + return; + } + + const constantsPath = path.resolve(__dirname, '../src/constants.ts'); + const dockerfilePath = path.resolve(__dirname, '../src/container/Dockerfile'); + + await updateFile( + constantsPath, + /export const EXTENSION_BUNDLE_VERSION = ['"][^'"]+['"];\s*/, + `export const EXTENSION_BUNDLE_VERSION = '${version}';\n` + ); + await updateFile(dockerfilePath, /ARG EXTENSION_BUNDLE_VERSION=[^\s]+/, `ARG EXTENSION_BUNDLE_VERSION=${version}`); + + console.log(`Updated extension bundle version to ${version}`); +} + +async function updateFile(filePath, regex, replacement) { + const original = await fs.readFile(filePath, 'utf8'); + if (!regex.test(original)) { + throw new Error(`Could not find target pattern in ${filePath}`); + } + const updated = original.replace(regex, replacement); + if (updated !== original) { + await fs.writeFile(filePath, updated); + } +} + +main().catch((err) => { + console.error(err.message || err); + process.exitCode = 1; +}); From 6b98a581209dba304769e0fe2d3a61b3d397816f Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Tue, 16 Sep 2025 17:33:14 -0400 Subject: [PATCH 12/46] Add scripts --- .../generateDeploymentScripts/generateDeploymentScripts.ts | 3 ++- .../GenerateADODeploymentScriptsStep.ts | 4 ++-- apps/vs-code-designer/src/app/commands/registerCommands.ts | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/vs-code-designer/src/app/commands/generateDeploymentScripts/generateDeploymentScripts.ts b/apps/vs-code-designer/src/app/commands/generateDeploymentScripts/generateDeploymentScripts.ts index 6d4bcd278b9..6b7d3770e3e 100644 --- a/apps/vs-code-designer/src/app/commands/generateDeploymentScripts/generateDeploymentScripts.ts +++ b/apps/vs-code-designer/src/app/commands/generateDeploymentScripts/generateDeploymentScripts.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { + EXTENSION_BUNDLE_VERSION, localSettingsFileName, workflowLocationKey, workflowResourceGroupNameKey, @@ -93,7 +94,7 @@ export async function generateDeploymentScripts(context: IActionContext, node?: : 'false'; context.telemetry.properties.currentWorkflowBundleVersion = ext.currentBundleVersion.has(projectPath) ? ext.currentBundleVersion.get(projectPath) - : ext.defaultBundleVersion; + : EXTENSION_BUNDLE_VERSION; if (error instanceof UserCancelledError) { context.telemetry.properties.result = 'Canceled'; diff --git a/apps/vs-code-designer/src/app/commands/generateDeploymentScripts/generateDeploymentScriptsSteps/adoDeploymentScriptsSteps/GenerateADODeploymentScriptsStep.ts b/apps/vs-code-designer/src/app/commands/generateDeploymentScripts/generateDeploymentScriptsSteps/adoDeploymentScriptsSteps/GenerateADODeploymentScriptsStep.ts index f400e0215b8..310a29f0ee1 100644 --- a/apps/vs-code-designer/src/app/commands/generateDeploymentScripts/generateDeploymentScriptsSteps/adoDeploymentScriptsSteps/GenerateADODeploymentScriptsStep.ts +++ b/apps/vs-code-designer/src/app/commands/generateDeploymentScripts/generateDeploymentScriptsSteps/adoDeploymentScriptsSteps/GenerateADODeploymentScriptsStep.ts @@ -17,7 +17,7 @@ import { ext } from '../../../../../extensionVariables'; import { localize } from '../../../../../localize'; import { parameterizeConnections } from '../../../parameterizeConnections'; import { FileManagement } from '../../iacGestureHelperFunctions'; -import { deploymentDirectory, managementApiPrefix, workflowFileName } from '../../../../../constants'; +import { deploymentDirectory, EXTENSION_BUNDLE_VERSION, managementApiPrefix, workflowFileName } from '../../../../../constants'; import { unzipLogicAppArtifacts } from '../../../../utils/taskUtils'; import { startDesignTimeApi } from '../../../../utils/codeless/startDesignTimeApi'; import { getAuthorizationToken, getCloudHost } from '../../../../utils/codeless/getAuthorizationToken'; @@ -151,7 +151,7 @@ export class GenerateADODeploymentScriptsStep extends AzureWizardExecuteStep Date: Tue, 16 Sep 2025 17:47:56 -0400 Subject: [PATCH 13/46] Update DOCKERFIle --- .../vs-code-designer/src/container/Dockerfile | 69 ++++++++++++++----- 1 file changed, 50 insertions(+), 19 deletions(-) diff --git a/apps/vs-code-designer/src/container/Dockerfile b/apps/vs-code-designer/src/container/Dockerfile index f57e08714fd..9965f3704f0 100644 --- a/apps/vs-code-designer/src/container/Dockerfile +++ b/apps/vs-code-designer/src/container/Dockerfile @@ -1,31 +1,62 @@ FROM mcr.microsoft.com/devcontainers/javascript-node:1-22-bookworm +# ----------------------------- +# Extension bundle (Workflows) +# ----------------------------- ARG EXTENSION_BUNDLE_VERSION=1.131.9 ARG EXTENSION_BUNDLE_CDN_URL=https://functionscdn.azureedge.net/public +# NOTE: this folder name intentionally begins with a dot; don't prefix with "/." ARG EXTENSION_BUNDLE_FOLDER_PATH=.azure-functions-core-tools/Functions/ExtensionBundles -RUN apt-get update && apt-get install -y curl jq gnupg wget unzip -RUN echo "Using version: $EXTENSION_BUNDLE_VERSION" && \ - EXTENSION_BUNDLE_FILENAME_V4=Microsoft.Azure.Functions.ExtensionBundle.Workflows.${EXTENSION_BUNDLE_VERSION}_any-any.zip && \ - wget $EXTENSION_BUNDLE_CDN_URL/ExtensionBundles/Microsoft.Azure.Functions.ExtensionBundle.Workflows/$EXTENSION_BUNDLE_VERSION/$EXTENSION_BUNDLE_FILENAME_V4 && \ - mkdir -p /.${EXTENSION_BUNDLE_FOLDER_PATH}/Microsoft.Azure.Functions.ExtensionBundle.Workflows/$EXTENSION_BUNDLE_VERSION && \ - unzip /$EXTENSION_BUNDLE_FILENAME_V4 -d /.${EXTENSION_BUNDLE_FOLDER_PATH}/Microsoft.Azure.Functions.ExtensionBundle.Workflows/$EXTENSION_BUNDLE_VERSION && \ - rm -f /$EXTENSION_BUNDLE_FILENAME_V4 - -RUN find /.${EXTENSION_BUNDLE_FOLDER_PATH}/ -type f -exec chmod 755 {} \; - +# ----------------------------- +# Azure Functions Core Tools +# ----------------------------- ARG FUNCTIONS_CORE_TOOLS_VERSION=4.2.2 ARG FUNCTIONS_CORE_TOOLS_OS_PLATFORM=linux ARG FUNCTIONS_CORE_TOOLS_ARCH=x64 ARG FUNCTIONS_CORE_TOOLS_FOLDER_PATH=.azurelogicapps/dependencies/FuncCoreTools -RUN echo "Downloading Azure Functions Core Tools version: $FUNCTIONS_CORE_TOOLS_VERSION" && \ - FUNCTIONS_CORE_TOOLS_FILENAME=Azure.Functions.Cli.${FUNCTIONS_CORE_TOOLS_OS_PLATFORM}-${FUNCTIONS_CORE_TOOLS_ARCH}.${FUNCTIONS_CORE_TOOLS_VERSION}.zip && \ - wget https://github.com/Azure/azure-functions-core-tools/releases/download/${FUNCTIONS_CORE_TOOLS_VERSION}/$FUNCTIONS_CORE_TOOLS_FILENAME && \ - mkdir -p /.${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/ && \ - unzip /$FUNCTIONS_CORE_TOOLS_FILENAME -d /.${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/ && \ - rm -f /$FUNCTIONS_CORE_TOOLS_FILENAME +# ----------------------------- +# OS deps + install everything +# ----------------------------- +RUN set -eux; \ + apt-get update; \ + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + ca-certificates curl jq gnupg wget unzip \ + libc6 libicu72 libgssapi-krb5-2 libkrb5-3 zlib1g; \ + rm -rf /var/lib/apt/lists/* + +# ----------------------------- +# Download & unpack extension bundle +# ----------------------------- +RUN set -eux; \ + echo "Using extension bundle version: ${EXTENSION_BUNDLE_VERSION}"; \ + EXTENSION_BUNDLE_FILENAME="Microsoft.Azure.Functions.ExtensionBundle.Workflows.${EXTENSION_BUNDLE_VERSION}_any-any.zip"; \ + wget "${EXTENSION_BUNDLE_CDN_URL}/ExtensionBundles/Microsoft.Azure.Functions.ExtensionBundle.Workflows/${EXTENSION_BUNDLE_VERSION}/${EXTENSION_BUNDLE_FILENAME}" -O "/tmp/${EXTENSION_BUNDLE_FILENAME}"; \ + mkdir -p "/${EXTENSION_BUNDLE_FOLDER_PATH}/Microsoft.Azure.Functions.ExtensionBundle.Workflows/${EXTENSION_BUNDLE_VERSION}"; \ + unzip -q "/tmp/${EXTENSION_BUNDLE_FILENAME}" -d "/${EXTENSION_BUNDLE_FOLDER_PATH}/Microsoft.Azure.Functions.ExtensionBundle.Workflows/${EXTENSION_BUNDLE_VERSION}"; \ + rm -f "/tmp/${EXTENSION_BUNDLE_FILENAME}"; \ + find "/${EXTENSION_BUNDLE_FOLDER_PATH}/" -type f -exec chmod 644 {} \; ; \ + # ensure scripts/binaries inside the bundle stay executable if any + find "/${EXTENSION_BUNDLE_FOLDER_PATH}/" -type f -name "*.sh" -exec chmod 755 {} \; || true + +# ----------------------------- +# Download & install Core Tools (func) +# ----------------------------- +RUN set -eux; \ + echo "Downloading Azure Functions Core Tools version: ${FUNCTIONS_CORE_TOOLS_VERSION}"; \ + FILENAME="Azure.Functions.Cli.${FUNCTIONS_CORE_TOOLS_OS_PLATFORM}-${FUNCTIONS_CORE_TOOLS_ARCH}.${FUNCTIONS_CORE_TOOLS_VERSION}.zip"; \ + wget "https://github.com/Azure/azure-functions-core-tools/releases/download/${FUNCTIONS_CORE_TOOLS_VERSION}/${FILENAME}" -O "/tmp/${FILENAME}"; \ + mkdir -p "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}"; \ + unzip -q "/tmp/${FILENAME}" -d "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}"; \ + rm -f "/tmp/${FILENAME}"; \ + chmod -R a+rX "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}"; \ + chmod 755 "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/func"; \ + ln -sf "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/func" /usr/local/bin/func -RUN chmod -R 755 /.${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/ && \ - chmod 755 /.${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/func && \ - ln -s /.${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/func /usr/local/bin/func \ No newline at end of file +# ----------------------------- +# Verify CLI is on PATH +# ----------------------------- +RUN set -eux; \ + which func; \ + func --version From 28e201086a61a3fe470b09cea9edbdb29dfcecc1 Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Wed, 17 Sep 2025 12:06:23 -0400 Subject: [PATCH 14/46] Update docker file --- apps/vs-code-designer/src/app/utils/debug.ts | 7 ++++--- apps/vs-code-designer/src/container/Dockerfile | 16 ++++++++++++++-- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/apps/vs-code-designer/src/app/utils/debug.ts b/apps/vs-code-designer/src/app/utils/debug.ts index 0d1450e011d..a40e11cfb4e 100644 --- a/apps/vs-code-designer/src/app/utils/debug.ts +++ b/apps/vs-code-designer/src/app/utils/debug.ts @@ -2,7 +2,8 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { FuncVersion, TargetFramework } from '@microsoft/vscode-extension-logic-apps'; +import type { FuncVersion } from '@microsoft/vscode-extension-logic-apps'; +import { TargetFramework } from '@microsoft/vscode-extension-logic-apps'; import type { DebugConfiguration } from 'vscode'; import { debugSymbolDll, EXTENSION_BUNDLE_VERSION, extensionBundleId, extensionCommand } from '../../constants'; import * as path from 'path'; @@ -35,7 +36,7 @@ export const getDebugConfiguration = ( name: `Run/Debug logic app with local function ${logicAppName}`, type: 'logicapp', request: 'launch', - funcRuntime: version === FuncVersion.v1 ? 'clr' : 'coreclr', + funcRuntime: 'coreclr', customCodeRuntime: customCodeTargetFramework === TargetFramework.Net8 ? 'coreclr' : 'clr', isCodeless: true, }; @@ -43,7 +44,7 @@ export const getDebugConfiguration = ( return { name: `Run/Debug logic app ${logicAppName}`, - type: version === FuncVersion.v1 ? 'clr' : 'coreclr', + type: 'coreclr', request: 'attach', processId: `\${command:${extensionCommand.pickProcess}}`, }; diff --git a/apps/vs-code-designer/src/container/Dockerfile b/apps/vs-code-designer/src/container/Dockerfile index 9965f3704f0..35e4380a77b 100644 --- a/apps/vs-code-designer/src/container/Dockerfile +++ b/apps/vs-code-designer/src/container/Dockerfile @@ -51,8 +51,17 @@ RUN set -eux; \ unzip -q "/tmp/${FILENAME}" -d "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}"; \ rm -f "/tmp/${FILENAME}"; \ chmod -R a+rX "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}"; \ - chmod 755 "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/func"; \ - ln -sf "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/func" /usr/local/bin/func + for executable in \ + "func" \ + "gozip" \ + "in-proc8/func" \ + "in-proc6/func"; do \ + if [ -f "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/${executable}" ]; then \ + chmod 755 "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/${executable}"; \ + fi; \ + done; \ + ln -sf "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/func" /usr/local/bin/func; \ + ln -sf "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/func" /usr/bin/func # ----------------------------- # Verify CLI is on PATH @@ -60,3 +69,6 @@ RUN set -eux; \ RUN set -eux; \ which func; \ func --version + +# Ensure Core Tools are discoverable for all users +ENV PATH=/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}:$PATH From d984fc8138f4c21028f07354e4471be944c14925 Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Thu, 18 Sep 2025 11:19:45 -0400 Subject: [PATCH 15/46] Remove unused func versions --- .../createLogicAppSteps/logicAppCreateStep.ts | 15 +--- .../initCustomCodeScriptProjectStep.ts | 8 -- .../createProjectSteps/projectCreateStep.ts | 8 +- .../createCodelessWorkflow.ts | 4 +- .../commands/createWorkflow/createWorkflow.ts | 4 +- .../initDotnetProjectStep.ts | 38 +-------- .../initScriptProjectStep.ts | 8 -- .../src/app/funcConfig/host.ts | 26 +----- .../src/app/templates/TemplateProviderBase.ts | 26 +----- .../src/app/tree/LogicAppResourceTree.ts | 3 +- .../subscriptionTree/subscriptionTreeItem.ts | 13 ++- .../src/app/utils/__test__/debug.test.ts | 83 ------------------- .../src/app/utils/dotnet/dotnet.ts | 12 --- .../app/utils/funcCoreTools/funcVersion.ts | 18 ---- .../src/app/utils/vsCodeConfig/settings.ts | 9 +- apps/vs-code-designer/src/constants.ts | 1 - apps/vs-code-designer/src/package.json | 14 +--- .../src/lib/models/functions.ts | 11 --- libs/vscode-extension/src/lib/models/host.ts | 6 -- 19 files changed, 28 insertions(+), 279 deletions(-) diff --git a/apps/vs-code-designer/src/app/commands/createLogicApp/createLogicAppSteps/logicAppCreateStep.ts b/apps/vs-code-designer/src/app/commands/createLogicApp/createLogicAppSteps/logicAppCreateStep.ts index 36c5d9c9210..5f46ea39219 100644 --- a/apps/vs-code-designer/src/app/commands/createLogicApp/createLogicAppSteps/logicAppCreateStep.ts +++ b/apps/vs-code-designer/src/app/commands/createLogicApp/createLogicAppSteps/logicAppCreateStep.ts @@ -30,7 +30,7 @@ import type { CustomLocation } from '@microsoft/vscode-azext-azureappservice'; import { LocationListStep } from '@microsoft/vscode-azext-azureutils'; import { AzureWizardExecuteStep, nonNullOrEmptyValue, nonNullProp } from '@microsoft/vscode-azext-utils'; import type { ILogicAppWizardContext, ConnectionStrings } from '@microsoft/vscode-extension-logic-apps'; -import { StorageOptions, FuncVersion, WorkerRuntime } from '@microsoft/vscode-extension-logic-apps'; +import { StorageOptions, WorkerRuntime } from '@microsoft/vscode-extension-logic-apps'; import type { Progress } from 'vscode'; export class LogicAppCreateStep extends AzureWizardExecuteStep { @@ -191,18 +191,7 @@ export class LogicAppCreateStep extends AzureWizardExecuteStep ): Promise { - const version: FuncVersion = nonNullProp(context, 'version'); const hostJsonPath: string = path.join(context.projectPath, hostFileName); if (await confirmOverwriteFile(context, hostJsonPath)) { - const hostJson: IHostJsonV2 | IHostJsonV1 = version === FuncVersion.v1 ? {} : await this.getHostContent(); + const hostJson: IHostJsonV2 = await this.getHostContent(); await writeFormattedJson(hostJsonPath, hostJson); } diff --git a/apps/vs-code-designer/src/app/commands/createWorkflow/createCodelessWorkflow/createCodelessWorkflow.ts b/apps/vs-code-designer/src/app/commands/createWorkflow/createCodelessWorkflow/createCodelessWorkflow.ts index a15f2c2cfa4..f956ea28309 100644 --- a/apps/vs-code-designer/src/app/commands/createWorkflow/createCodelessWorkflow/createCodelessWorkflow.ts +++ b/apps/vs-code-designer/src/app/commands/createWorkflow/createCodelessWorkflow/createCodelessWorkflow.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { projectTemplateKeySetting } from '../../../../constants'; import { getProjFiles } from '../../../utils/dotnet/dotnet'; -import { addLocalFuncTelemetry, checkSupportedFuncVersion } from '../../../utils/funcCoreTools/funcVersion'; +import { addLocalFuncTelemetry } from '../../../utils/funcCoreTools/funcVersion'; import { verifyAndPromptToCreateProject } from '../../../utils/verifyIsProject'; import { getWorkspaceSetting } from '../../../utils/vsCodeConfig/settings'; import { verifyInitForVSCode } from '../../../utils/vsCodeConfig/verifyInitForVSCode'; @@ -55,8 +55,6 @@ export async function createCodelessWorkflow( [language, version] = await verifyInitForVSCode(context, projectPath, language, version); - checkSupportedFuncVersion(version); - const projectTemplateKey: string | undefined = getWorkspaceSetting(projectTemplateKeySetting, projectPath); const wizardContext: IFunctionWizardContext = Object.assign(context, { projectPath, diff --git a/apps/vs-code-designer/src/app/commands/createWorkflow/createWorkflow.ts b/apps/vs-code-designer/src/app/commands/createWorkflow/createWorkflow.ts index f359e04d4d9..31a6684f393 100644 --- a/apps/vs-code-designer/src/app/commands/createWorkflow/createWorkflow.ts +++ b/apps/vs-code-designer/src/app/commands/createWorkflow/createWorkflow.ts @@ -5,7 +5,7 @@ import { projectTemplateKeySetting } from '../../../constants'; import { ext } from '../../../extensionVariables'; import { getProjFiles } from '../../utils/dotnet/dotnet'; -import { addLocalFuncTelemetry, checkSupportedFuncVersion } from '../../utils/funcCoreTools/funcVersion'; +import { addLocalFuncTelemetry } from '../../utils/funcCoreTools/funcVersion'; import { verifyAndPromptToCreateProject } from '../../utils/verifyIsProject'; import { getWorkspaceSetting } from '../../utils/vsCodeConfig/settings'; import { verifyInitForVSCode } from '../../utils/vsCodeConfig/verifyInitForVSCode'; @@ -56,8 +56,6 @@ export async function createWorkflow( [language, version] = await verifyInitForVSCode(context, projectPath, language, version); - checkSupportedFuncVersion(version); - const projectTemplateKey: string | undefined = getWorkspaceSetting(projectTemplateKeySetting, projectPath); const wizardContext: IFunctionWizardContext = Object.assign(context, { projectPath, diff --git a/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initDotnetProjectStep.ts b/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initDotnetProjectStep.ts index f09306b773b..ff1633e2350 100644 --- a/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initDotnetProjectStep.ts +++ b/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initDotnetProjectStep.ts @@ -2,18 +2,17 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { dotnetPublishTaskLabel, dotnetExtensionId, funcWatchProblemMatcher, show64BitWarningSetting } from '../../../constants'; +import { dotnetPublishTaskLabel, dotnetExtensionId, funcWatchProblemMatcher } from '../../../constants'; import { localize } from '../../../localize'; import { getProjFiles, getTargetFramework, getDotnetDebugSubpath, tryGetFuncVersion } from '../../utils/dotnet/dotnet'; import type { ProjectFile } from '../../utils/dotnet/dotnet'; import { tryParseFuncVersion } from '../../utils/funcCoreTools/funcVersion'; -import { getWorkspaceSetting, updateGlobalSetting } from '../../utils/vsCodeConfig/settings'; import { InitProjectStepBase } from './initProjectStepBase'; -import { DialogResponses, nonNullProp, openUrl, parseError } from '@microsoft/vscode-azext-utils'; -import { FuncVersion, ProjectLanguage } from '@microsoft/vscode-extension-logic-apps'; +import { nonNullProp } from '@microsoft/vscode-azext-utils'; +import { ProjectLanguage } from '@microsoft/vscode-extension-logic-apps'; import type { IProjectWizardContext } from '@microsoft/vscode-extension-logic-apps'; import * as path from 'path'; -import type { MessageItem, TaskDefinition } from 'vscode'; +import type { TaskDefinition } from 'vscode'; export class InitDotnetProjectStep extends InitProjectStepBase { protected preDeployTask: string = dotnetPublishTaskLabel; @@ -62,35 +61,6 @@ export class InitDotnetProjectStep extends InitProjectStepBase { // The version from the proj file takes precedence over whatever was set in `context` before this context.version = tryParseFuncVersion(versionInProjFile) || context.version; - - if (context.version === FuncVersion.v1) { - if (getWorkspaceSetting(show64BitWarningSetting)) { - const message: string = localize( - '64BitWarning', - 'In order to debug .NET Framework functions in VS Code, you must install a 64-bit version of the Azure Functions Core Tools.' - ); - - try { - const result: MessageItem = await context.ui.showWarningMessage( - message, - DialogResponses.learnMore, - DialogResponses.dontWarnAgain - ); - - if (result === DialogResponses.learnMore) { - await openUrl('https://aka.ms/azFunc64bit'); - } else if (result === DialogResponses.dontWarnAgain) { - await updateGlobalSetting(show64BitWarningSetting, false); - } - } catch (err) { - // swallow cancellations (aka if they clicked the 'x' button to dismiss the warning) and proceed to create project - if (!parseError(err).isUserCancelledError) { - throw err; - } - } - } - } - const targetFramework: string = await getTargetFramework(projFile); await this.setDeploySubpath(context, path.posix.join('bin', 'Release', targetFramework, 'publish')); this.debugSubpath = getDotnetDebugSubpath(targetFramework); diff --git a/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initScriptProjectStep.ts b/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initScriptProjectStep.ts index 927043d97cb..53975143f77 100644 --- a/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initScriptProjectStep.ts +++ b/apps/vs-code-designer/src/app/commands/initProjectForVSCode/initScriptProjectStep.ts @@ -3,13 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { extInstallTaskName, funcWatchProblemMatcher } from '../../../constants'; -import { getLocalFuncCoreToolsVersion } from '../../utils/funcCoreTools/funcVersion'; import { InitProjectStepBase } from './initProjectStepBase'; import type { IProjectWizardContext } from '@microsoft/vscode-extension-logic-apps'; -import { FuncVersion } from '@microsoft/vscode-extension-logic-apps'; import * as fse from 'fs-extra'; import * as path from 'path'; -import * as semver from 'semver'; import type { TaskDefinition } from 'vscode'; /** @@ -25,11 +22,6 @@ export class InitScriptProjectStep extends InitProjectStepBase { if (await fse.pathExists(extensionsCsprojPath)) { this.useFuncExtensionsInstall = true; context.telemetry.properties.hasExtensionsCsproj = 'true'; - } else if (context.version === FuncVersion.v2) { - // no need to check v1 or v3+ - const currentVersion: string | null = await getLocalFuncCoreToolsVersion(); - // Starting after this version, projects can use extension bundle instead of running "func extensions install" - this.useFuncExtensionsInstall = !!currentVersion && semver.lte(currentVersion, '2.5.553'); } } catch { // use default of false diff --git a/apps/vs-code-designer/src/app/funcConfig/host.ts b/apps/vs-code-designer/src/app/funcConfig/host.ts index 974da5b2fa4..5310c14202f 100644 --- a/apps/vs-code-designer/src/app/funcConfig/host.ts +++ b/apps/vs-code-designer/src/app/funcConfig/host.ts @@ -4,8 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { defaultRoutePrefix } from '../../constants'; import { isObject, isNullOrUndefined } from '@microsoft/logic-apps-shared'; -import type { IBundleMetadata, IHostJsonV1, IHostJsonV2, IParsedHostJson } from '@microsoft/vscode-extension-logic-apps'; -import { FuncVersion } from '@microsoft/vscode-extension-logic-apps'; +import type { IBundleMetadata, IHostJsonV2, IParsedHostJson } from '@microsoft/vscode-extension-logic-apps'; class ParsedHostJsonV2 implements IParsedHostJson { public data: IHostJsonV2; @@ -30,25 +29,6 @@ class ParsedHostJsonV2 implements IParsedHostJson { } } -class ParsedHostJsonV1 implements IParsedHostJson { - public data: IHostJsonV1; - - public constructor(data: unknown) { - if (!isNullOrUndefined(data) && isObject(data)) { - this.data = data as IHostJsonV1; - } else { - this.data = {}; - } - } - - public get routePrefix(): string { - if (this.data.http && this.data.http.routePrefix !== undefined) { - return this.data.http.routePrefix; - } - return defaultRoutePrefix; - } -} - -export function parseHostJson(data: unknown, version: FuncVersion | undefined): IParsedHostJson { - return version === FuncVersion.v1 ? new ParsedHostJsonV1(data) : new ParsedHostJsonV2(data); +export function parseHostJson(data: unknown): IParsedHostJson { + return new ParsedHostJsonV2(data); } diff --git a/apps/vs-code-designer/src/app/templates/TemplateProviderBase.ts b/apps/vs-code-designer/src/app/templates/TemplateProviderBase.ts index 8ee9e4fe445..b4a70e6b349 100644 --- a/apps/vs-code-designer/src/app/templates/TemplateProviderBase.ts +++ b/apps/vs-code-designer/src/app/templates/TemplateProviderBase.ts @@ -3,19 +3,14 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { ext } from '../../extensionVariables'; -import { localize } from '../../localize'; import { NotImplementedError } from '../utils/errors'; import type { IActionContext } from '@microsoft/vscode-azext-utils'; -import type { ITemplates } from '@microsoft/vscode-extension-logic-apps'; -import { FuncVersion, TemplateType } from '@microsoft/vscode-extension-logic-apps'; +import type { ITemplates, FuncVersion } from '@microsoft/vscode-extension-logic-apps'; +import { TemplateType } from '@microsoft/vscode-extension-logic-apps'; import * as path from 'path'; import * as vscode from 'vscode'; import { Disposable } from 'vscode'; -const v3BackupTemplatesVersion = '3.4.1'; -const v2BackupTemplatesVersion = '2.47.1'; -const v1BackupTemplatesVersion = '1.11.0'; - export abstract class TemplateProviderBase implements Disposable { protected static templateVersionCacheKey = 'templateVersion'; protected static projTemplateKeyCacheKey = 'projectTemplateKey'; @@ -102,19 +97,6 @@ export abstract class TemplateProviderBase implements Disposable { await this.updateCachedValue(TemplateProviderBase.projTemplateKeyCacheKey, this._sessionProjKey); } - public getBackupTemplateVersion(): string { - switch (this.version) { - case FuncVersion.v1: - return v1BackupTemplatesVersion; - case FuncVersion.v2: - return v2BackupTemplatesVersion; - case FuncVersion.v3: - return v3BackupTemplatesVersion; - default: - throw new RangeError(localize('invalidVersion', 'Invalid version "{0}".', this.version)); - } - } - protected async getCacheKeySuffix(): Promise { return ''; } @@ -126,10 +108,6 @@ export abstract class TemplateProviderBase implements Disposable { private async getCacheKey(key: string): Promise { key = key + (await this.getCacheKeySuffix()); - if (this.version !== FuncVersion.v1) { - key = `${key}.${this.version}`; - } - if (this.templateType !== TemplateType.Script) { key = `${key}.${this.templateType}`; } diff --git a/apps/vs-code-designer/src/app/tree/LogicAppResourceTree.ts b/apps/vs-code-designer/src/app/tree/LogicAppResourceTree.ts index 3dc3a68c755..dd4ef78009b 100644 --- a/apps/vs-code-designer/src/app/tree/LogicAppResourceTree.ts +++ b/apps/vs-code-designer/src/app/tree/LogicAppResourceTree.ts @@ -204,8 +204,7 @@ export class LogicAppResourceTree implements ResolvedAppResourceBase { } catch { // ignore and use default } - const version: FuncVersion = await this.getVersion(context); - result = parseHostJson(data, version); + result = parseHostJson(data); this._cachedHostJson = result; } diff --git a/apps/vs-code-designer/src/app/tree/subscriptionTree/subscriptionTreeItem.ts b/apps/vs-code-designer/src/app/tree/subscriptionTree/subscriptionTreeItem.ts index 5bbbc2c6dd0..9aa45c8d600 100644 --- a/apps/vs-code-designer/src/app/tree/subscriptionTree/subscriptionTreeItem.ts +++ b/apps/vs-code-designer/src/app/tree/subscriptionTree/subscriptionTreeItem.ts @@ -61,8 +61,12 @@ import { } from '@microsoft/vscode-azext-azureutils'; import type { AzExtTreeItem, AzureWizardExecuteStep, AzureWizardPromptStep, IActionContext } from '@microsoft/vscode-azext-utils'; import { nonNullProp, parseError, AzureWizard } from '@microsoft/vscode-azext-utils'; -import type { ILogicAppWizardContext, ICreateLogicAppContext, IIdentityWizardContext } from '@microsoft/vscode-extension-logic-apps'; -import { FuncVersion } from '@microsoft/vscode-extension-logic-apps'; +import type { + ILogicAppWizardContext, + ICreateLogicAppContext, + IIdentityWizardContext, + FuncVersion, +} from '@microsoft/vscode-extension-logic-apps'; export class SubscriptionTreeItem extends SubscriptionTreeItemBase { public readonly childTypeLabel: string = localize('LogicApp', 'Logic App (Standard) in Azure'); @@ -124,11 +128,6 @@ export class SubscriptionTreeItem extends SubscriptionTreeItemBase { ...(await createActivityContext()), }); - if (version === FuncVersion.v1) { - // v1 doesn't support linux - wizardContext.newSiteOS = WebsiteOS.windows; - } - await setRegionsTask(wizardContext); const promptSteps: AzureWizardPromptStep[] = []; diff --git a/apps/vs-code-designer/src/app/utils/__test__/debug.test.ts b/apps/vs-code-designer/src/app/utils/__test__/debug.test.ts index 4f4cef0d31f..28b4ba34301 100644 --- a/apps/vs-code-designer/src/app/utils/__test__/debug.test.ts +++ b/apps/vs-code-designer/src/app/utils/__test__/debug.test.ts @@ -21,81 +21,9 @@ describe('debug', () => { isCodeless: true, }); }); - - it('should return launch configuration for .NET Framework custom code with v1 function runtime', () => { - const result = getDebugConfiguration(FuncVersion.v1, 'TestLogicApp', TargetFramework.NetFx); - - expect(result).toEqual({ - name: 'Run/Debug logic app with local function TestLogicApp', - type: 'logicapp', - request: 'launch', - funcRuntime: 'clr', - customCodeRuntime: 'clr', - isCodeless: true, - }); - }); - - it('should return launch configuration for .NET Framework custom code with v3 function runtime', () => { - const result = getDebugConfiguration(FuncVersion.v3, 'TestLogicApp', TargetFramework.NetFx); - - expect(result).toEqual({ - name: 'Run/Debug logic app with local function TestLogicApp', - type: 'logicapp', - request: 'launch', - funcRuntime: 'coreclr', - customCodeRuntime: 'clr', - isCodeless: true, - }); - }); - - it('should return launch configuration for .NET 8 custom code with v2 function runtime', () => { - const result = getDebugConfiguration(FuncVersion.v2, 'MyApp', TargetFramework.Net8); - - expect(result).toEqual({ - name: 'Run/Debug logic app with local function MyApp', - type: 'logicapp', - request: 'launch', - funcRuntime: 'coreclr', - customCodeRuntime: 'coreclr', - isCodeless: true, - }); - }); }); describe('without custom code target framework', () => { - it('should return attach configuration for v1 function runtime', () => { - const result = getDebugConfiguration(FuncVersion.v1, 'TestLogicApp'); - - expect(result).toEqual({ - name: 'Run/Debug logic app TestLogicApp', - type: 'clr', - request: 'attach', - processId: `\${command:${extensionCommand.pickProcess}}`, - }); - }); - - it('should return attach configuration for v2 function runtime', () => { - const result = getDebugConfiguration(FuncVersion.v2, 'TestLogicApp'); - - expect(result).toEqual({ - name: 'Run/Debug logic app TestLogicApp', - type: 'coreclr', - request: 'attach', - processId: `\${command:${extensionCommand.pickProcess}}`, - }); - }); - - it('should return attach configuration for v3 function runtime', () => { - const result = getDebugConfiguration(FuncVersion.v3, 'TestLogicApp'); - - expect(result).toEqual({ - name: 'Run/Debug logic app TestLogicApp', - type: 'coreclr', - request: 'attach', - processId: `\${command:${extensionCommand.pickProcess}}`, - }); - }); - it('should return attach configuration for v4 function runtime', () => { const result = getDebugConfiguration(FuncVersion.v4, 'MyLogicApp'); @@ -122,17 +50,6 @@ describe('debug', () => { }); }); - it('should handle empty logic app name without custom code', () => { - const result = getDebugConfiguration(FuncVersion.v3, ''); - - expect(result).toEqual({ - name: 'Run/Debug logic app ', - type: 'coreclr', - request: 'attach', - processId: `\${command:${extensionCommand.pickProcess}}`, - }); - }); - it('should handle special characters in logic app name', () => { const logicAppName = 'Test-App_With.Special@Characters'; const result = getDebugConfiguration(FuncVersion.v4, logicAppName); diff --git a/apps/vs-code-designer/src/app/utils/dotnet/dotnet.ts b/apps/vs-code-designer/src/app/utils/dotnet/dotnet.ts index 5b2bd240a98..fe30ad654a7 100644 --- a/apps/vs-code-designer/src/app/utils/dotnet/dotnet.ts +++ b/apps/vs-code-designer/src/app/utils/dotnet/dotnet.ts @@ -118,18 +118,6 @@ export async function getTemplateKeyFromProjFile( targetFramework = DotnetVersion.net8; break; } - case FuncVersion.v3: { - targetFramework = DotnetVersion.net3; - break; - } - case FuncVersion.v2: { - targetFramework = DotnetVersion.net2; - break; - } - case FuncVersion.v1: { - targetFramework = DotnetVersion.net48; - break; - } } if (projectPath && (await AzExtFsExtra.pathExists(projectPath))) { diff --git a/apps/vs-code-designer/src/app/utils/funcCoreTools/funcVersion.ts b/apps/vs-code-designer/src/app/utils/funcCoreTools/funcVersion.ts index d1aff34e984..0481987bfac 100644 --- a/apps/vs-code-designer/src/app/utils/funcCoreTools/funcVersion.ts +++ b/apps/vs-code-designer/src/app/utils/funcCoreTools/funcVersion.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { funcVersionSetting } from '../../../constants'; -import { localize } from '../../../localize'; import { getWorkspaceSettingFromAnyFolder } from '../vsCodeConfig/settings'; import { executeCommand } from './cpUtils'; import { isNullOrUndefined } from '@microsoft/logic-apps-shared'; @@ -119,20 +118,3 @@ export function addLocalFuncTelemetry(context: IActionContext): void { context.telemetry.properties.funcCliVersion = 'none'; }); } - -/** - * Checks installed functions core tools version is supported. - * @param {string} version - Placeholder for input. - */ -export function checkSupportedFuncVersion(version: FuncVersion) { - if (version !== FuncVersion.v2 && version !== FuncVersion.v3 && version !== FuncVersion.v4) { - throw new Error( - localize( - 'versionNotSupported', - 'Functions core tools version "{0}" not supported. Only version "{1}" is currently supported for Codeless.', - version, - FuncVersion.v2 - ) - ); - } -} diff --git a/apps/vs-code-designer/src/app/utils/vsCodeConfig/settings.ts b/apps/vs-code-designer/src/app/utils/vsCodeConfig/settings.ts index b859fb37f6b..2ac9619d36b 100644 --- a/apps/vs-code-designer/src/app/utils/vsCodeConfig/settings.ts +++ b/apps/vs-code-designer/src/app/utils/vsCodeConfig/settings.ts @@ -99,8 +99,8 @@ function getScope(fsPath: WorkspaceFolder | string | undefined): Uri | Workspace return isString(fsPath) ? Uri.file(fsPath) : fsPath; } -function osSupportsVersion(version: FuncVersion | undefined): boolean { - return version !== FuncVersion.v1 || process.platform === Platform.windows; +function osSupportsVersion(): boolean { + return process.platform === Platform.windows; } /** @@ -113,12 +113,9 @@ export async function promptForFuncVersion(context: IActionContext, message?: st const recommended: string = localize('recommended', '(Recommended)'); let picks: IAzureQuickPickItem[] = [ { label: 'Azure Functions v4', description: recommended, data: FuncVersion.v4 }, - { label: 'Azure Functions v3', data: FuncVersion.v3 }, - { label: 'Azure Functions v2', data: FuncVersion.v2 }, - { label: 'Azure Functions v1', data: FuncVersion.v1 }, ]; - picks = picks.filter((p) => osSupportsVersion(p.data)); + picks = picks.filter(() => osSupportsVersion()); picks.push({ label: localize('learnMore', '$(link-external) Learn more...'), description: '', data: undefined }); diff --git a/apps/vs-code-designer/src/constants.ts b/apps/vs-code-designer/src/constants.ts index f44fd9381a2..9161fb9ace9 100644 --- a/apps/vs-code-designer/src/constants.ts +++ b/apps/vs-code-designer/src/constants.ts @@ -228,7 +228,6 @@ export const showDeployConfirmationSetting = 'showDeployConfirmation'; export const deploySubpathSetting = 'deploySubpath'; export const preDeployTaskSetting = 'preDeployTask'; export const pickProcessTimeoutSetting = 'pickProcessTimeout'; -export const show64BitWarningSetting = 'show64BitWarning'; export const showProjectWarningSetting = 'showProjectWarning'; export const showTargetFrameworkWarningSetting = 'showTargetFrameworkWarning'; export const showStartDesignTimeMessageSetting = 'showStartDesignTimeMessage'; diff --git a/apps/vs-code-designer/src/package.json b/apps/vs-code-designer/src/package.json index 16b9a7be444..3b7c481768c 100644 --- a/apps/vs-code-designer/src/package.json +++ b/apps/vs-code-designer/src/package.json @@ -785,9 +785,9 @@ "azureLogicAppsStandard.projectRuntime": { "scope": "resource", "type": "string", - "enum": ["~4", "~3"], + "enum": ["~4"], "description": "The default version of the Azure Functions runtime to use when performing operations like \"Create new logic app\".", - "enumDescriptions": ["Azure Functions v4", "Azure Functions v3 (.NET Core)"] + "enumDescriptions": ["Azure Functions v4"] }, "azureLogicAppsStandard.projectLanguage": { "scope": "resource", @@ -859,16 +859,6 @@ "enum": ["AddToWorkspace", "OpenInNewWindow", "OpenInCurrentWindow"], "description": "The behavior to use after creating a new project. The options are \"AddToWorkspace\", \"OpenInNewWindow\", or \"OpenInCurrentWindow\"." }, - "azureLogicAppsStandard.show64BitWarning": { - "type": "boolean", - "description": "Show a warning to install a 64-bit version of the Azure Functions Core Tools when you create a .NET Framework project.", - "default": true - }, - "azureLogicAppsStandard.showDeploySubpathWarning": { - "type": "boolean", - "description": "Show a warning when the \"deploySubpath\" setting does not match the selected folder for deploying.", - "default": true - }, "azureLogicAppsStandard.showProjectWarning": { "type": "boolean", "description": "Show a warning when an Azure Logic App project was detected that has not been initialized for use in VS Code.", diff --git a/libs/vscode-extension/src/lib/models/functions.ts b/libs/vscode-extension/src/lib/models/functions.ts index 312e8fb8e31..11bf8128556 100644 --- a/libs/vscode-extension/src/lib/models/functions.ts +++ b/libs/vscode-extension/src/lib/models/functions.ts @@ -4,23 +4,12 @@ import type { IWorkflowTemplate } from './templates'; import type { ISubscriptionContext } from '@microsoft/vscode-azext-utils'; export const FuncVersion = { - v1: '~1', - v2: '~2', - v3: '~3', v4: '~4', } as const; export type FuncVersion = (typeof FuncVersion)[keyof typeof FuncVersion]; export const latestGAVersion: FuncVersion = FuncVersion.v4; -export const azureFunctionsVersion = { - v1: 'Azure Functions v1', - v2: 'Azure Functions v2', - v3: 'Azure Functions v3', - v4: 'Azure Functions v4', -} as const; -export type azureFunctionsVersion = (typeof azureFunctionsVersion)[keyof typeof azureFunctionsVersion]; - export interface ICommandResult { code: number; cmdOutput: string; diff --git a/libs/vscode-extension/src/lib/models/host.ts b/libs/vscode-extension/src/lib/models/host.ts index 2ef59bb33b0..1047b297c62 100644 --- a/libs/vscode-extension/src/lib/models/host.ts +++ b/libs/vscode-extension/src/lib/models/host.ts @@ -34,12 +34,6 @@ export interface IBundleMetadata { version?: string; } -export interface IHostJsonV1 { - http?: { - routePrefix?: string; - }; -} - export interface IParsedHostJson { readonly routePrefix: string; readonly bundle?: IBundleMetadata; From 4b687f6a69cb4f8e3dfcd1d5216ab936809e4dcb Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Thu, 18 Sep 2025 16:29:24 -0400 Subject: [PATCH 16/46] Remove unused for contianers --- .../codefulWorkflowCreateStep.ts | 2 -- .../codelessWorkflowCreateStep.ts | 6 ++---- .../createCodelessWorkflowSteps/workflowKindStep.ts | 2 +- .../src/app/utils/dotnet/executeDotnetTemplateCommand.ts | 9 --------- apps/vs-code-designer/src/main.ts | 4 ++-- 5 files changed, 5 insertions(+), 18 deletions(-) diff --git a/apps/vs-code-designer/src/app/commands/createWorkflow/createCodefulWorkflow/createCodefulWorkflowSteps/codefulWorkflowCreateStep.ts b/apps/vs-code-designer/src/app/commands/createWorkflow/createCodefulWorkflow/createCodefulWorkflowSteps/codefulWorkflowCreateStep.ts index e1cb5c184e6..0c7e27e63df 100644 --- a/apps/vs-code-designer/src/app/commands/createWorkflow/createCodefulWorkflow/createCodefulWorkflowSteps/codefulWorkflowCreateStep.ts +++ b/apps/vs-code-designer/src/app/commands/createWorkflow/createCodefulWorkflow/createCodefulWorkflowSteps/codefulWorkflowCreateStep.ts @@ -28,7 +28,6 @@ import { vscodeFolderName, } from '../../../../../constants'; import { removeAppKindFromLocalSettings, setLocalAppSetting } from '../../../../utils/appSettings/localSettings'; -import { validateDotnetInstalled } from '../../../../utils/dotnet/executeDotnetTemplateCommand'; import { switchToDotnetProject } from '../../../workflows/switchToDotnetProject'; import * as vscode from 'vscode'; import { createConnectionsJson } from '../../../../utils/codeless/connection'; @@ -39,7 +38,6 @@ import { getDebugConfiguration } from '../../../../utils/debug'; export class CodefulWorkflowCreateStep extends WorkflowCreateStepBase { public async executeCore(context: IFunctionWizardContext): Promise { - await validateDotnetInstalled(context); const logicAppName = context.logicAppName || 'LogicApp'; const workflowFolderPath = path.join(context.projectPath, nonNullProp(context, 'functionName')); const workflowFilePath = path.join(workflowFolderPath, codefulWorkflowFileName); diff --git a/apps/vs-code-designer/src/app/commands/createWorkflow/createCodelessWorkflow/createCodelessWorkflowSteps/codelessWorkflowCreateStep.ts b/apps/vs-code-designer/src/app/commands/createWorkflow/createCodelessWorkflow/createCodelessWorkflowSteps/codelessWorkflowCreateStep.ts index 2857d9a66ce..7d4a4363ef7 100644 --- a/apps/vs-code-designer/src/app/commands/createWorkflow/createCodelessWorkflow/createCodelessWorkflowSteps/codelessWorkflowCreateStep.ts +++ b/apps/vs-code-designer/src/app/commands/createWorkflow/createCodelessWorkflow/createCodelessWorkflowSteps/codelessWorkflowCreateStep.ts @@ -23,10 +23,9 @@ import { updateFunctionsSDKVersion, writeBuildFileToDisk, } from '../../../../utils/codeless/updateBuildFile'; -import { getFramework, validateDotnetInstalled } from '../../../../utils/dotnet/executeDotnetTemplateCommand'; +import { getFramework } from '../../../../utils/dotnet/executeDotnetTemplateCommand'; import { writeFormattedJson } from '../../../../utils/fs'; import { WorkflowCreateStepBase } from '../../createWorkflowSteps/workflowCreateStepBase'; -import type { IActionContext } from '@microsoft/vscode-azext-utils'; import { nonNullProp } from '@microsoft/vscode-azext-utils'; import { WorkflowProjectType, MismatchBehavior } from '@microsoft/vscode-extension-logic-apps'; import type { IFunctionWizardContext, IWorkflowTemplate, IHostJsonV2, StandardApp } from '@microsoft/vscode-extension-logic-apps'; @@ -38,8 +37,7 @@ export class CodelessWorkflowCreateStep extends WorkflowCreateStepBase { - await validateDotnetInstalled(context); + public static async createStep(): Promise { return new CodelessWorkflowCreateStep(); } diff --git a/apps/vs-code-designer/src/app/commands/createWorkflow/createCodelessWorkflow/createCodelessWorkflowSteps/workflowKindStep.ts b/apps/vs-code-designer/src/app/commands/createWorkflow/createCodelessWorkflow/createCodelessWorkflowSteps/workflowKindStep.ts index a66710eff7e..d68c143bcd5 100644 --- a/apps/vs-code-designer/src/app/commands/createWorkflow/createCodelessWorkflow/createCodelessWorkflowSteps/workflowKindStep.ts +++ b/apps/vs-code-designer/src/app/commands/createWorkflow/createCodelessWorkflow/createCodelessWorkflowSteps/workflowKindStep.ts @@ -64,7 +64,7 @@ export class WorkflowKindStep extends AzureWizardPromptStep { - // NOTE: Doesn't feel obvious that `getFramework` would validate dotnet is installed, hence creating a separate function named `validateDotnetInstalled` to export from this file - await getFramework(context, undefined); -} - /** * Gets .NET framework version. * @param {IActionContext} context - Command context. diff --git a/apps/vs-code-designer/src/main.ts b/apps/vs-code-designer/src/main.ts index 61fc3ef49be..1dc6e6d88f8 100644 --- a/apps/vs-code-designer/src/main.ts +++ b/apps/vs-code-designer/src/main.ts @@ -34,7 +34,6 @@ import { createVSCodeAzureSubscriptionProvider } from './app/utils/services/VSCo import { logExtensionSettings, logSubscriptions, runWithDurationTelemetry } from './app/utils/telemetry'; import { registerAzureUtilsExtensionVariables } from '@microsoft/vscode-azext-azureutils'; import { getAzExtResourceType, getAzureResourcesExtensionApi } from '@microsoft/vscode-azureresources-api'; -import { validateTasksJson } from './app/utils/vsCodeConfig/tasks'; const perfStats = { loadStartTime: Date.now(), @@ -114,7 +113,8 @@ export async function activate(context: vscode.ExtensionContext) { // TODO (ccastrotrjeo): Move to somewhere else await callWithTelemetryAndErrorHandling(autoStartDesignTimeSetting, async (actionContext: IActionContext) => { await runWithDurationTelemetry(actionContext, showStartDesignTimeMessageSetting, async () => { - await validateTasksJson(actionContext, vscode.workspace.workspaceFolders); + // TODO (ccastrotrejo): Need to revert validate to support container + // await validateTasksJson(actionContext, vscode.workspace.workspaceFolders); await promptStartDesignTimeOption(activateContext); }); }); From b5d3652c0bef2afbd6d402d14c06a6fb41a439da Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Thu, 18 Sep 2025 17:51:41 -0400 Subject: [PATCH 17/46] Update container path files --- .../app/commands/cloudToLocal/cloudToLocal.ts | 2 + .../src/app/commands/convertToWorkspace.ts | 3 +- .../createWorkspace/createWorkspace.ts | 2 + .../createWorkspaceSteps/devcontainerStep.ts | 64 +++++++++++++++++++ .../src/{ => assets}/container/Dockerfile | 0 .../{ => assets}/container/devcontainer.json | 0 .../{ => assets}/container/docker-compose.yml | 0 7 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/devcontainerStep.ts rename apps/vs-code-designer/src/{ => assets}/container/Dockerfile (100%) rename apps/vs-code-designer/src/{ => assets}/container/devcontainer.json (100%) rename apps/vs-code-designer/src/{ => assets}/container/docker-compose.yml (100%) diff --git a/apps/vs-code-designer/src/app/commands/cloudToLocal/cloudToLocal.ts b/apps/vs-code-designer/src/app/commands/cloudToLocal/cloudToLocal.ts index f2bceffc183..f9291c92875 100644 --- a/apps/vs-code-designer/src/app/commands/cloudToLocal/cloudToLocal.ts +++ b/apps/vs-code-designer/src/app/commands/cloudToLocal/cloudToLocal.ts @@ -16,6 +16,7 @@ import { ProcessPackageStep } from './cloudToLocalSteps/processPackageStep'; import { SelectFolderForNewWorkspaceStep } from './cloudToLocalSteps/selectFolderForNewWorkspaceStep'; import { ExtractPackageStep } from './cloudToLocalSteps/extractPackageStep'; import { WorkspaceSettingsStep } from '../createWorkspace/createWorkspaceSteps/workspaceSettingsStep'; +import { DevcontainerStep } from '../createWorkspace/createWorkspaceSteps/devcontainerStep'; const openFolder = true; @@ -57,6 +58,7 @@ export async function cloudToLocal( // TODO(aeldridge): Can we just use WorkspaceFolderStep instead? new SelectFolderForNewWorkspaceStep(), new WorkspaceNameStep(), + new DevcontainerStep(), new LogicAppNameStep(), await ProjectTypeStep.create(context, options.templateId, options.functionSettings, true), new WorkspaceSettingsStep(), diff --git a/apps/vs-code-designer/src/app/commands/convertToWorkspace.ts b/apps/vs-code-designer/src/app/commands/convertToWorkspace.ts index 96594b8723e..d4afd9ee0f6 100644 --- a/apps/vs-code-designer/src/app/commands/convertToWorkspace.ts +++ b/apps/vs-code-designer/src/app/commands/convertToWorkspace.ts @@ -12,6 +12,7 @@ import { getWorkspaceFile, getWorkspaceFileInParentDirectory, getWorkspaceFolder import { WorkspaceNameStep } from './createWorkspace/createWorkspaceSteps/workspaceNameStep'; import { WorkspaceFileStep } from './createWorkspace/createWorkspaceSteps/workspaceFileStep'; import { isLogicAppProjectInRoot } from '../utils/verifyIsProject'; +import { DevcontainerStep } from './createWorkspace/createWorkspaceSteps/devcontainerStep'; export async function convertToWorkspace(context: IActionContext): Promise { const convertToWorkspaceStartTime = Date.now(); @@ -60,7 +61,7 @@ export async function convertToWorkspace(context: IActionContext): Promise = new AzureWizard(wizardContext, { title: localize('convertToWorkspace', 'Convert to workspace'), - promptSteps: [new WorkspaceFolderStep(), new WorkspaceNameStep(), new WorkspaceFileStep()], + promptSteps: [new WorkspaceFolderStep(), new WorkspaceNameStep(), new DevcontainerStep(), new WorkspaceFileStep()], executeSteps: [new OpenFolderStep()], }); diff --git a/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspace.ts b/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspace.ts index 5b461065400..ebbe37b7dc5 100644 --- a/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspace.ts +++ b/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspace.ts @@ -14,6 +14,7 @@ import type { IActionContext } from '@microsoft/vscode-azext-utils'; import type { ProjectLanguage, ProjectVersion } from '@microsoft/vscode-extension-logic-apps'; import { TargetFrameworkStep } from '../createProject/createCustomCodeProjectSteps/targetFrameworkStep'; import { LogicAppTemplateStep } from '../createProject/createProjectSteps/logicAppTemplateStep'; +import { DevcontainerStep } from './createWorkspaceSteps/devcontainerStep'; // TODO(aeldridge): TargetFrameworkStep should be in a subwizard on LogicAppTemplateStep export async function createWorkspace( @@ -42,6 +43,7 @@ export async function createWorkspace( [ new WorkspaceFolderStep(), new WorkspaceNameStep(), + new DevcontainerStep(), new LogicAppTemplateStep(), new TargetFrameworkStep(), new LogicAppNameStep(), diff --git a/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/devcontainerStep.ts b/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/devcontainerStep.ts new file mode 100644 index 00000000000..e713536df02 --- /dev/null +++ b/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/devcontainerStep.ts @@ -0,0 +1,64 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import { AzureWizardPromptStep } from '@microsoft/vscode-azext-utils'; +import * as fs from 'fs-extra'; +import type { IProjectWizardContext } from '@microsoft/vscode-extension-logic-apps'; +import * as path from 'path'; + +export class DevcontainerStep extends AzureWizardPromptStep { + public hideStepCount = true; + + public shouldPrompt(): boolean { + return true; + } + + public async prompt(context: IProjectWizardContext): Promise { + await this.createDevcontainerFiles(context); + } + + private async createDevcontainerFiles(context: IProjectWizardContext): Promise { + // Resolve source directory with canonical container config. When running from compiled dist the + // source 'container' folder may live beside 'src' or only within 'src/container'. Try a set of candidates. + const candidateDirs: string[] = [path.join(__dirname, 'assets', 'container')]; + + let sourceContainerDir: string | undefined; + for (const dir of candidateDirs) { + if (await fs.pathExists(dir)) { + sourceContainerDir = dir; + break; + } + } + + // Create .devcontainer folder at the same level as .code-workspace file + const devcontainerPath = path.join(context.workspacePath, '.devcontainer'); + await fs.ensureDir(devcontainerPath); + + // Files we expect in the source directory + const filesToCopy = ['devcontainer.json', 'docker-compose.yml', 'Dockerfile']; + + if (!sourceContainerDir) { + // Could not locate source directory; create marker file and return gracefully. + await fs.writeFile( + path.join(devcontainerPath, 'README.missing-devcontainer.txt'), + `Devcontainer source templates not found. Looked in:\n${candidateDirs.join('\n')}\n` + ); + return; + } + + for (const fileName of filesToCopy) { + const src = path.join(sourceContainerDir, fileName); + const dest = path.join(devcontainerPath, fileName); + try { + if (await fs.pathExists(src)) { + await fs.copyFile(src, dest); + } else { + await fs.writeFile(`${dest}.missing`, `Expected source file not found: ${src}`); + } + } catch (err) { + await fs.writeFile(`${dest}.error`, `Error copying ${fileName}: ${(err as Error).message}`); + } + } + } +} diff --git a/apps/vs-code-designer/src/container/Dockerfile b/apps/vs-code-designer/src/assets/container/Dockerfile similarity index 100% rename from apps/vs-code-designer/src/container/Dockerfile rename to apps/vs-code-designer/src/assets/container/Dockerfile diff --git a/apps/vs-code-designer/src/container/devcontainer.json b/apps/vs-code-designer/src/assets/container/devcontainer.json similarity index 100% rename from apps/vs-code-designer/src/container/devcontainer.json rename to apps/vs-code-designer/src/assets/container/devcontainer.json diff --git a/apps/vs-code-designer/src/container/docker-compose.yml b/apps/vs-code-designer/src/assets/container/docker-compose.yml similarity index 100% rename from apps/vs-code-designer/src/container/docker-compose.yml rename to apps/vs-code-designer/src/assets/container/docker-compose.yml From 79ce6ff8841acb02e55c33f87cf76fe7a168d904 Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Tue, 23 Sep 2025 09:55:48 -0400 Subject: [PATCH 18/46] Add dev dependency --- apps/vs-code-designer/src/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/vs-code-designer/src/package.json b/apps/vs-code-designer/src/package.json index 3b7c481768c..99a3556985a 100644 --- a/apps/vs-code-designer/src/package.json +++ b/apps/vs-code-designer/src/package.json @@ -951,7 +951,8 @@ "azurite.azurite", "ms-azuretools.vscode-azureresourcegroups", "ms-dotnettools.csharp", - "ms-dotnettools.csdevkit" + "ms-dotnettools.csdevkit", + "ms-vscode-remote.remote-containers" ], "enabledApiProposals": ["authenticationChallenges"], "activationEvents": [ From c94c8504ed05b9ef7bb636b17e905755a28f67ec Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Tue, 23 Sep 2025 10:53:15 -0400 Subject: [PATCH 19/46] Update readibility on pickCUstomCodeHost --- .../commands/pickCustomCodeNetHostProcess.ts | 143 ++++++++++-------- .../workflows/unitTest/runUnitTest.ts | 10 +- .../dotnet/executeDotnetTemplateCommand.ts | 2 +- apps/vs-code-designer/src/main.ts | 1 - 4 files changed, 86 insertions(+), 70 deletions(-) diff --git a/apps/vs-code-designer/src/app/commands/pickCustomCodeNetHostProcess.ts b/apps/vs-code-designer/src/app/commands/pickCustomCodeNetHostProcess.ts index 0f28da7df7b..68d8201f3bd 100644 --- a/apps/vs-code-designer/src/app/commands/pickCustomCodeNetHostProcess.ts +++ b/apps/vs-code-designer/src/app/commands/pickCustomCodeNetHostProcess.ts @@ -10,11 +10,64 @@ import { parseError, type IActionContext } from '@microsoft/vscode-azext-utils'; import type * as vscode from 'vscode'; import * as path from 'path'; import { getUnixChildren, getWindowsChildren, pickChildProcess } from './pickFuncProcess'; -import { localize } from '../../localize'; import { tryGetLogicAppProjectRoot } from '../utils/verifyIsProject'; type OSAgnosticProcess = { command: string | undefined; pid: number | string }; +const POLL_ATTEMPTS = 10; +const POLL_INTERVAL_MS = 5000; + +function failWithTelemetry(context: IActionContext, message: string): never { + context.telemetry.properties.result = 'Failed'; + context.telemetry.properties.error = message; + throw new Error(message); +} + +async function pollForResult(operation: () => Promise, maxAttempts: number, delayMs: number): Promise { + for (let attempt = 0; attempt < maxAttempts; attempt++) { + const result = await operation(); + if (result !== undefined) { + return result; + } + + if (attempt < maxAttempts - 1) { + await delay(delayMs); + } + } + + return undefined; +} + +function delay(ms: number): Promise { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +async function getNetHostChildProcessOrThrow( + context: IActionContext, + taskInfo: IRunningFuncTask, + logicAppName: string, + isCodeless: boolean, + attempts: number, + delayMs: number +): Promise { + context.telemetry.properties.lastStep = 'pickNetHostChildProcess'; + + let processId: string | undefined; + try { + processId = await pollForResult(() => pickNetHostChildProcess(taskInfo, isCodeless), attempts, delayMs); + } catch (error) { + context.telemetry.properties.result = 'Failed'; + context.telemetry.properties.error = parseError(error).message; + throw error; + } + + if (!processId) { + failWithTelemetry(context, `Failed to find the .NET host child process for the functions project for logic app "${logicAppName}".`); + } + + return processId; +} + /** * Picks the .NET host child process for the custom code project by polling the running function tasks for the workspace folder. * @param context The action context. @@ -28,62 +81,37 @@ export async function pickCustomCodeNetHostProcess( context.telemetry.properties.lastStep = 'getMatchingWorkspaceFolder'; const workspaceFolder: vscode.WorkspaceFolder = getMatchingWorkspaceFolder(debugConfig); if (!workspaceFolder) { - const errorMessage = 'Failed to find a workspace folder matching the debug configuration.'; - context.telemetry.properties.result = 'Failed'; - context.telemetry.properties.error = errorMessage; - throw new Error(localize('noMatchingWorkspaceFolder', errorMessage)); + failWithTelemetry(context, 'Failed to find a workspace folder matching the debug configuration.'); } context.telemetry.properties.lastStep = 'tryGetLogicAppProjectRoot'; const projectPath: string | undefined = await tryGetLogicAppProjectRoot(context, workspaceFolder); if (!projectPath) { - const errorMessage = 'Failed to find a logic app project in the workspace folder "{0}".'; - context.telemetry.properties.result = 'Failed'; - context.telemetry.properties.error = errorMessage.replace('{0}', workspaceFolder?.uri?.fsPath); - throw new Error(localize('noLogicAppProject', errorMessage, workspaceFolder?.uri?.fsPath)); + failWithTelemetry(context, `Failed to find a logic app project in the workspace folder "${workspaceFolder?.uri?.fsPath}".`); } const logicAppName = path.basename(projectPath); context.telemetry.properties.lastStep = 'getRunningFuncTask'; - let taskInfo: IRunningFuncTask | undefined; - const maxRetries = 10; - const delayMs = 5000; - for (let i = 0; i < maxRetries; i++) { - taskInfo = runningFuncTaskMap.get(workspaceFolder); - if (taskInfo) { - break; - } - await new Promise((resolve) => setTimeout(resolve, delayMs)); - } + const taskInfo: IRunningFuncTask | undefined = await pollForResult( + async () => runningFuncTaskMap.get(workspaceFolder), + POLL_ATTEMPTS, + POLL_INTERVAL_MS + ); if (!taskInfo) { - const errorMessage = - 'Failed to find a running func task for the logic app "{0}". The logic app must be running to attach the function debugger.'; - context.telemetry.properties.result = 'Failed'; - context.telemetry.properties.error = errorMessage.replace('{0}', logicAppName); - throw new Error(localize('noFuncTask', errorMessage, logicAppName)); + failWithTelemetry( + context, + `Failed to find a running func task for the logic app "${logicAppName}". The logic app must be running to attach the function debugger.` + ); } - context.telemetry.properties.lastStep = 'pickNetHostChildProcess'; - let customCodeNetHostProcess: string | undefined; - for (let i = 0; i < maxRetries; i++) { - try { - customCodeNetHostProcess = await pickNetHostChildProcess(taskInfo, debugConfig.isCodeless); - } catch (error) { - context.telemetry.properties.result = 'Failed'; - context.telemetry.properties.error = parseError(error).message; - throw error; - } - if (customCodeNetHostProcess) { - break; - } - await new Promise((resolve) => setTimeout(resolve, delayMs)); - } - if (!customCodeNetHostProcess) { - const errorMessage = 'Failed to find the .NET host child process for the functions project for logic app "{0}".'; - context.telemetry.properties.result = 'Failed'; - context.telemetry.properties.error = errorMessage.replace('{0}', logicAppName); - throw new Error(localize('netHostProcessNotFound', errorMessage, logicAppName)); - } + const customCodeNetHostProcess = await getNetHostChildProcessOrThrow( + context, + taskInfo, + logicAppName, + debugConfig.isCodeless, + POLL_ATTEMPTS, + POLL_INTERVAL_MS + ); context.telemetry.properties.result = 'Succeeded'; return customCodeNetHostProcess; @@ -107,28 +135,13 @@ export async function pickCustomCodeNetHostProcessInternal( context.telemetry.properties.lastStep = 'getRunningFuncTask'; const taskInfo = runningFuncTaskMap.get(workspaceFolder); if (!taskInfo) { - const errorMessage = - 'Failed to find a running func task for the logic app "{0}". The logic app must be running to attach the function debugger.'; - context.telemetry.properties.result = 'Failed'; - context.telemetry.properties.error = errorMessage.replace('{0}', logicAppName); - throw new Error(localize('noFuncTask', errorMessage, logicAppName)); + failWithTelemetry( + context, + `Failed to find a running func task for the logic app "${logicAppName}". The logic app must be running to attach the function debugger.` + ); } - context.telemetry.properties.lastStep = 'pickNetHostChildProcess'; - let customCodeNetHostProcess: string | undefined; - try { - customCodeNetHostProcess = await pickNetHostChildProcess(taskInfo, isCodeless); - } catch (error) { - context.telemetry.properties.result = 'Failed'; - context.telemetry.properties.error = parseError(error).message; - throw error; - } - if (!customCodeNetHostProcess) { - const errorMessage = 'Failed to find the .NET host child process for the functions project for logic app "{0}".'; - context.telemetry.properties.result = 'Failed'; - context.telemetry.properties.error = errorMessage.replace('{0}', logicAppName); - throw new Error(localize('netHostProcessNotFound', errorMessage, logicAppName)); - } + const customCodeNetHostProcess = await getNetHostChildProcessOrThrow(context, taskInfo, logicAppName, isCodeless, 1, 0); context.telemetry.properties.result = 'Succeeded'; return customCodeNetHostProcess; diff --git a/apps/vs-code-designer/src/app/commands/workflows/unitTest/runUnitTest.ts b/apps/vs-code-designer/src/app/commands/workflows/unitTest/runUnitTest.ts index f6d33b8b192..45285068a63 100644 --- a/apps/vs-code-designer/src/app/commands/workflows/unitTest/runUnitTest.ts +++ b/apps/vs-code-designer/src/app/commands/workflows/unitTest/runUnitTest.ts @@ -2,7 +2,12 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { defaultExtensionBundlePathValue, runUnitTestEvent, testResultsDirectoryName } from '../../../../constants'; +import { + defaultExtensionBundlePathValue, + EXTENSION_BUNDLE_VERSION, + runUnitTestEvent, + testResultsDirectoryName, +} from '../../../../constants'; import { ext } from '../../../../extensionVariables'; import { localize } from '../../../../localize'; import { getLatestUnitTest, getTestsDirectory, getUnitTestName, pickUnitTest } from '../../../utils/unitTests'; @@ -103,10 +108,9 @@ export async function runUnitTestFromPath(context: IActionContext, unitTestPath: const logicAppName = path.relative(testDirectory, unitTestPath).split(path.sep)[0]; const workflowName = path.basename(path.dirname(unitTestPath)); const unitTestName = getUnitTestName(path.basename(unitTestPath)); - const bundleVersionNumber = '1.138.54'; // TODO (ccastrotrejo): Need to get the value from the docker container const pathToExe = path.join( defaultExtensionBundlePathValue, - bundleVersionNumber, + EXTENSION_BUNDLE_VERSION, 'UnitTestExecutor', 'Microsoft.Azure.Workflows.UnitTestExecutor.exe' ); diff --git a/apps/vs-code-designer/src/app/utils/dotnet/executeDotnetTemplateCommand.ts b/apps/vs-code-designer/src/app/utils/dotnet/executeDotnetTemplateCommand.ts index 923ea7ae3cf..c87b8d2367d 100644 --- a/apps/vs-code-designer/src/app/utils/dotnet/executeDotnetTemplateCommand.ts +++ b/apps/vs-code-designer/src/app/utils/dotnet/executeDotnetTemplateCommand.ts @@ -78,7 +78,7 @@ export async function getFramework(context: IActionContext, workingDirectory: st const versions = '8'; // Prioritize "LTS", then "Current", then "Preview" - const netVersions: string[] = ['8', '6', '3', '2', '9', '10']; + const netVersions: string[] = ['8', '6']; const semVersions: SemVer[] = netVersions.map((v) => semVerCoerce(v) as SemVer); diff --git a/apps/vs-code-designer/src/main.ts b/apps/vs-code-designer/src/main.ts index 1dc6e6d88f8..69ccff5a5d4 100644 --- a/apps/vs-code-designer/src/main.ts +++ b/apps/vs-code-designer/src/main.ts @@ -110,7 +110,6 @@ export async function activate(context: vscode.ExtensionContext) { promptParameterizeConnections(activateContext, false); verifyLocalConnectionKeys(activateContext); - // TODO (ccastrotrjeo): Move to somewhere else await callWithTelemetryAndErrorHandling(autoStartDesignTimeSetting, async (actionContext: IActionContext) => { await runWithDurationTelemetry(actionContext, showStartDesignTimeMessageSetting, async () => { // TODO (ccastrotrejo): Need to revert validate to support container From 46ec0d5669cfd724dbb804ac282f75360426c129 Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Tue, 23 Sep 2025 10:54:40 -0400 Subject: [PATCH 20/46] Update swithc to dotnet --- .../codefulWorkflowCreateStep.ts | 2 +- .../src/app/commands/workflows/switchToDotnetProject.ts | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/apps/vs-code-designer/src/app/commands/createWorkflow/createCodefulWorkflow/createCodefulWorkflowSteps/codefulWorkflowCreateStep.ts b/apps/vs-code-designer/src/app/commands/createWorkflow/createCodefulWorkflow/createCodefulWorkflowSteps/codefulWorkflowCreateStep.ts index 0c7e27e63df..27344c2ce26 100644 --- a/apps/vs-code-designer/src/app/commands/createWorkflow/createCodefulWorkflow/createCodefulWorkflowSteps/codefulWorkflowCreateStep.ts +++ b/apps/vs-code-designer/src/app/commands/createWorkflow/createCodefulWorkflow/createCodefulWorkflowSteps/codefulWorkflowCreateStep.ts @@ -167,7 +167,7 @@ export class CodefulWorkflowCreateStep extends WorkflowCreateStepBase { const target = vscode.Uri.file(context.projectPath); - await switchToDotnetProject(context, target, '8', true); + await switchToDotnetProject(context, target, true); await this.updateHostJson(context, hostFileName); diff --git a/apps/vs-code-designer/src/app/commands/workflows/switchToDotnetProject.ts b/apps/vs-code-designer/src/app/commands/workflows/switchToDotnetProject.ts index 0f7a6cb2705..617c7284b8a 100644 --- a/apps/vs-code-designer/src/app/commands/workflows/switchToDotnetProject.ts +++ b/apps/vs-code-designer/src/app/commands/workflows/switchToDotnetProject.ts @@ -49,12 +49,7 @@ export async function switchToDotnetProjectCommand(context: IProjectWizardContex switchToDotnetProject(context, target); } -export async function switchToDotnetProject( - context: IProjectWizardContext, - target: vscode.Uri, - localDotNetMajorVersion = '8', - isCodeful = false -) { +export async function switchToDotnetProject(context: IProjectWizardContext, target: vscode.Uri, isCodeful = false) { if (target === undefined || Object.keys(target).length === 0) { const workspaceFolder = await getWorkspaceFolder(context); const projectPath = await tryGetLogicAppProjectRoot(context, workspaceFolder); @@ -147,7 +142,7 @@ export async function switchToDotnetProject( await copyBundleProjectFiles(target); await updateBuildFile(context, target, dotnetVersion, isCodeful); - await createGlobalJsonFile(localDotNetMajorVersion, target.fsPath); + await createGlobalJsonFile(dotnetVersion, target.fsPath); const workspaceFolder: vscode.WorkspaceFolder | undefined = getContainingWorkspace(target.fsPath); From 0a188d7e9cf3b1e2dce3ad4e2e7cfb23824ca408 Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Tue, 23 Sep 2025 12:28:33 -0400 Subject: [PATCH 21/46] Update open behavior to container --- .../app/commands/cloudToLocal/cloudToLocal.ts | 6 +- .../createProject/createProjectInternal.ts | 6 +- .../createWorkspaceSteps/openBehaviorStep.ts | 6 +- .../createWorkspaceSteps/openFolderStep.ts | 41 +++++------- .../createWorkspaceSteps/workspaceFileStep.ts | 2 +- .../workspaceSettingsStep.ts | 2 +- .../src/app/utils/devContainer.ts | 67 +++++++++++++++++++ apps/vs-code-designer/src/main.ts | 4 ++ .../src/lib/models/project.ts | 5 +- 9 files changed, 95 insertions(+), 44 deletions(-) create mode 100644 apps/vs-code-designer/src/app/utils/devContainer.ts diff --git a/apps/vs-code-designer/src/app/commands/cloudToLocal/cloudToLocal.ts b/apps/vs-code-designer/src/app/commands/cloudToLocal/cloudToLocal.ts index f9291c92875..6cf92afc038 100644 --- a/apps/vs-code-designer/src/app/commands/cloudToLocal/cloudToLocal.ts +++ b/apps/vs-code-designer/src/app/commands/cloudToLocal/cloudToLocal.ts @@ -10,7 +10,7 @@ import { LogicAppNameStep } from '../createProject/createProjectSteps/logicAppNa import { WorkspaceNameStep } from '../createWorkspace/createWorkspaceSteps/workspaceNameStep'; import { AzureWizard } from '@microsoft/vscode-azext-utils'; import type { IActionContext } from '@microsoft/vscode-azext-utils'; -import { latestGAVersion, OpenBehavior } from '@microsoft/vscode-extension-logic-apps'; +import { latestGAVersion } from '@microsoft/vscode-extension-logic-apps'; import type { ICreateFunctionOptions, IFunctionWizardContext, ProjectLanguage } from '@microsoft/vscode-extension-logic-apps'; import { ProcessPackageStep } from './cloudToLocalSteps/processPackageStep'; import { SelectFolderForNewWorkspaceStep } from './cloudToLocalSteps/selectFolderForNewWorkspaceStep'; @@ -44,9 +44,7 @@ export async function cloudToLocal( projectPath: options.folderPath, }); - if (options.suppressOpenFolder) { - wizardContext.openBehavior = OpenBehavior.dontOpen; - } else if (!wizardContext.openBehavior) { + if (!wizardContext.openBehavior) { wizardContext.openBehavior = getWorkspaceSetting(projectOpenBehaviorSetting); context.telemetry.properties.openBehaviorFromSetting = String(!!wizardContext.openBehavior); } diff --git a/apps/vs-code-designer/src/app/commands/createProject/createProjectInternal.ts b/apps/vs-code-designer/src/app/commands/createProject/createProjectInternal.ts index 1f2c7538e9f..1f88f3ba837 100644 --- a/apps/vs-code-designer/src/app/commands/createProject/createProjectInternal.ts +++ b/apps/vs-code-designer/src/app/commands/createProject/createProjectInternal.ts @@ -18,7 +18,7 @@ import { WorkspaceFolderStep } from '../createWorkspace/createWorkspaceSteps/wor import { OpenFolderStep } from '../createWorkspace/createWorkspaceSteps/openFolderStep'; import { AzureWizard } from '@microsoft/vscode-azext-utils'; import type { IActionContext } from '@microsoft/vscode-azext-utils'; -import { latestGAVersion, OpenBehavior, ProjectType } from '@microsoft/vscode-extension-logic-apps'; +import { latestGAVersion, ProjectType } from '@microsoft/vscode-extension-logic-apps'; import type { ICreateFunctionOptions, IFunctionWizardContext, ProjectLanguage } from '@microsoft/vscode-extension-logic-apps'; import * as fse from 'fs-extra'; import * as path from 'path'; @@ -46,9 +46,7 @@ export async function createProjectInternal( WorkspaceFolderStep.setProjectPath(wizardContext, options.folderPath); } - if (options.suppressOpenFolder) { - wizardContext.openBehavior = OpenBehavior.dontOpen; - } else if (!wizardContext.openBehavior) { + if (!wizardContext.openBehavior) { wizardContext.openBehavior = getWorkspaceSetting(projectOpenBehaviorSetting); context.telemetry.properties.openBehaviorFromSetting = String(!!wizardContext.openBehavior); } diff --git a/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/openBehaviorStep.ts b/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/openBehaviorStep.ts index 8570d201b3d..cf700409a47 100644 --- a/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/openBehaviorStep.ts +++ b/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/openBehaviorStep.ts @@ -10,14 +10,12 @@ import { OpenBehavior } from '@microsoft/vscode-extension-logic-apps'; export class OpenBehaviorStep extends AzureWizardPromptStep { public shouldPrompt(context: IProjectWizardContext): boolean { - return !context.openBehavior && context.openBehavior !== OpenBehavior.alreadyOpen && context.openBehavior !== OpenBehavior.dontOpen; + return !context.openBehavior && context.openBehavior !== OpenBehavior.alreadyOpen; } public async prompt(context: IProjectWizardContext): Promise { const picks: IAzureQuickPickItem[] = [ - { label: localize('OpenInCurrentWindow', 'Open in current window'), data: OpenBehavior.openInCurrentWindow }, - { label: localize('OpenInNewWindow', 'Open in new window'), data: OpenBehavior.openInNewWindow }, - { label: localize('AddToWorkspace', 'Add to workspace'), data: OpenBehavior.addToWorkspace }, + { label: localize('OpenInCurrentWindow', 'Open in current window'), data: OpenBehavior.openInContainer }, ]; const placeHolder: string = localize('selectOpenBehavior', 'Select how you would like to open your project'); diff --git a/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/openFolderStep.ts b/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/openFolderStep.ts index 472b12e303e..4de70327c35 100644 --- a/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/openFolderStep.ts +++ b/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/openFolderStep.ts @@ -7,7 +7,8 @@ import { AzureWizardExecuteStep } from '@microsoft/vscode-azext-utils'; import type { IProjectWizardContext } from '@microsoft/vscode-extension-logic-apps'; import { OpenBehavior } from '@microsoft/vscode-extension-logic-apps'; import * as fs from 'fs'; -import { commands, Uri, workspace } from 'vscode'; +import { commands, Uri } from 'vscode'; +import { tryReopenInDevContainer } from '../../../utils/devContainer'; import { extensionCommand } from '../../../../constants'; export class OpenFolderStep extends AzureWizardExecuteStep { @@ -19,7 +20,7 @@ export class OpenFolderStep extends AzureWizardExecuteStep { - const openFolders = workspace.workspaceFolders || []; - let workspaceUri: Uri; - - // Check if .code-workspace file exists in project path + // Resolve the workspace URI (.code-workspace file if present, else the folder path) const workspaceFilePath = context.workspaceFilePath; context.workspaceFolder = getContainingWorkspace(workspaceFilePath); - if (fs.existsSync(workspaceFilePath)) { - workspaceUri = Uri.file(workspaceFilePath); - } else { - workspaceUri = Uri.file(context.workspacePath); - } - - // Check if user has selected to add folder to workspace and update workspace accordingly - if (context.openBehavior === OpenBehavior.addToWorkspace && openFolders.length === 0) { - context.openBehavior = OpenBehavior.openInCurrentWindow; - } + const workspaceUri: Uri = fs.existsSync(workspaceFilePath) ? Uri.file(workspaceFilePath) : Uri.file(context.workspacePath); - if (context.openBehavior === OpenBehavior.addToWorkspace) { - if (!workspaceUri.path.endsWith('.code-workspace')) { - workspace.updateWorkspaceFolders(openFolders.length, 0, { uri: workspaceUri }); + // Attempt to open directly in a dev container. Prefer devcontainers.openFolder if available. + // Fallback: open locally, then trigger reopen. + try { + const succeeded = await commands.executeCommand('remote-containers.openFolder', workspaceUri); + if (!succeeded) { + throw new Error('devcontainers.openFolder returned falsy result'); } - } else { - // Open folder using executeCommand method of commands object with vscode.openFolder command - await commands.executeCommand( - extensionCommand.vscodeOpenFolder, - workspaceUri, - context.openBehavior === OpenBehavior.openInNewWindow /* forceNewWindow */ - ); + } catch (_err) { + // Fallback path: open locally then request a reopen. + await commands.executeCommand(extensionCommand.vscodeOpenFolder, workspaceUri, false); + await tryReopenInDevContainer(context as any); } } } diff --git a/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/workspaceFileStep.ts b/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/workspaceFileStep.ts index 991c572264f..9ce4dda6fdb 100644 --- a/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/workspaceFileStep.ts +++ b/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/workspaceFileStep.ts @@ -65,6 +65,6 @@ export class WorkspaceFileStep extends AzureWizardPromptStep 0) { + return workspaceFolders[0].uri.fsPath; + } + if (vscode.workspace.workspaceFile) { + return path.dirname(vscode.workspace.workspaceFile.fsPath); + } + return undefined; +} + +/** Checks if a .devcontainer folder exists at the given base path. */ +export function hasDevContainerFolder(basePath?: string): boolean { + if (!basePath) { + return false; + } + try { + const devcontainerDir = path.join(basePath, '.devcontainer'); + return fs.existsSync(devcontainerDir) && fs.statSync(devcontainerDir).isDirectory(); + } catch { + return false; + } +} + +/** + * Attempts to execute the Dev Containers extension reopen command if we have a .devcontainer folder & are not already inside one. + * Adds a telemetry property when provided a context. + */ +export async function tryReopenInDevContainer(context?: IActionContext): Promise { + if (isInDevContainer()) { + return false; + } + const basePath = getDevContainerBasePath(); + const hasFolder = hasDevContainerFolder(basePath); + if (context) { + context.telemetry.properties.attemptedDevContainerReopen = hasFolder ? 'true' : 'false'; + } + if (!hasFolder) { + return false; + } + try { + await vscode.commands.executeCommand('devcontainers.reopenInContainer'); + return true; + } catch (err) { + if (context) { + context.telemetry.properties.devContainerReopenError = err instanceof Error ? err.message : String(err); + } + return false; + } +} diff --git a/apps/vs-code-designer/src/main.ts b/apps/vs-code-designer/src/main.ts index 69ccff5a5d4..105e9d08e45 100644 --- a/apps/vs-code-designer/src/main.ts +++ b/apps/vs-code-designer/src/main.ts @@ -34,6 +34,7 @@ import { createVSCodeAzureSubscriptionProvider } from './app/utils/services/VSCo import { logExtensionSettings, logSubscriptions, runWithDurationTelemetry } from './app/utils/telemetry'; import { registerAzureUtilsExtensionVariables } from '@microsoft/vscode-azext-azureutils'; import { getAzExtResourceType, getAzureResourcesExtensionApi } from '@microsoft/vscode-azureresources-api'; +import { tryReopenInDevContainer } from './app/utils/devContainer'; const perfStats = { loadStartTime: Date.now(), @@ -157,6 +158,9 @@ export async function activate(context: vscode.ExtensionContext) { logSubscriptions(activateContext); logExtensionSettings(activateContext); + + // Attempt to auto-reopen in dev container (centralized utility). Adds telemetry property attemptedDevContainerReopen. + await tryReopenInDevContainer(activateContext); }); } diff --git a/libs/vscode-extension/src/lib/models/project.ts b/libs/vscode-extension/src/lib/models/project.ts index 7c5f9310bec..cdfe4ba088e 100644 --- a/libs/vscode-extension/src/lib/models/project.ts +++ b/libs/vscode-extension/src/lib/models/project.ts @@ -87,11 +87,8 @@ export interface IProjectWizardContext extends IActionContext { } export const OpenBehavior = { - addToWorkspace: 'AddToWorkspace', - openInNewWindow: 'OpenInNewWindow', - openInCurrentWindow: 'OpenInCurrentWindow', + openInContainer: 'OpenInContainer', alreadyOpen: 'AlreadyOpen', - dontOpen: 'DontOpen', } as const; export type OpenBehavior = (typeof OpenBehavior)[keyof typeof OpenBehavior]; From 1ded6379c01f55121e39878fc7051f7d7a7aa16c Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Tue, 23 Sep 2025 15:04:11 -0400 Subject: [PATCH 22/46] Add workspace and dev container --- .../createWorkspaceSteps/openFolderStep.ts | 2 +- .../src/app/utils/devContainer.ts | 93 ++++++++++++++++++- 2 files changed, 91 insertions(+), 4 deletions(-) diff --git a/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/openFolderStep.ts b/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/openFolderStep.ts index 4de70327c35..06dd0593a63 100644 --- a/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/openFolderStep.ts +++ b/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/openFolderStep.ts @@ -39,7 +39,7 @@ export class OpenFolderStep extends AzureWizardExecuteStep e.endsWith('.code-workspace') && fs.statSync(path.join(dir, e)).isFile()); + } catch { + return false; + } +} + /** * Attempts to execute the Dev Containers extension reopen command if we have a .devcontainer folder & are not already inside one. * Adds a telemetry property when provided a context. @@ -56,7 +89,18 @@ export async function tryReopenInDevContainer(context?: IActionContext): Promise return false; } try { - await vscode.commands.executeCommand('devcontainers.reopenInContainer'); + const workspaceFilePath = findWorkspaceFilePath(basePath); + if (workspaceFilePath) { + if (context) { + context.telemetry.properties.devContainerWorkspaceArg = 'true'; + } + await vscode.commands.executeCommand('remote-containers.reopenInContainer', vscode.Uri.file(workspaceFilePath)); + } else { + if (context) { + context.telemetry.properties.devContainerWorkspaceArg = 'false'; + } + await vscode.commands.executeCommand('remote-containers.reopenInContainer'); + } return true; } catch (err) { if (context) { @@ -65,3 +109,46 @@ export async function tryReopenInDevContainer(context?: IActionContext): Promise return false; } } + +/** Attempt to locate a .code-workspace file starting from basePath or using VS Code's current workspace reference. */ +function findWorkspaceFilePath(basePath?: string): string | undefined { + // If VS Code already knows the workspace file, use it first. + if (vscode.workspace.workspaceFile) { + return vscode.workspace.workspaceFile.fsPath; + } + if (!basePath) { + return undefined; + } + // Check current directory then walk up to 3 levels similar to detection logic. + const maxLevels = 3; + let current = basePath; + for (let i = 0; i <= maxLevels; i++) { + const wsFile = firstWorkspaceFileInDir(current); + if (wsFile) { + return wsFile; + } + const parent = path.dirname(current); + if (parent === current) { + break; + } + current = parent; + } + return undefined; +} + +function firstWorkspaceFileInDir(dir: string): string | undefined { + try { + const entries = fs.readdirSync(dir); + for (const e of entries) { + if (e.endsWith('.code-workspace')) { + const full = path.join(dir, e); + if (fs.statSync(full).isFile()) { + return full; + } + } + } + } catch { + // ignore + } + return undefined; +} From 6c5ec9f93c52367be75f87ac604a3e24dcc892a5 Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Wed, 24 Sep 2025 14:25:17 -0400 Subject: [PATCH 23/46] Open workspace automatically --- .../createWorkspaceSteps/openFolderStep.ts | 18 ++++++++---- .../src/app/utils/devContainer.ts | 28 +++++++++++-------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/openFolderStep.ts b/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/openFolderStep.ts index 06dd0593a63..82b2e5a4b1a 100644 --- a/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/openFolderStep.ts +++ b/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/openFolderStep.ts @@ -34,12 +34,20 @@ export class OpenFolderStep extends AzureWizardExecuteStep Date: Wed, 24 Sep 2025 16:08:21 -0400 Subject: [PATCH 24/46] Update openbehavior --- .../createWorkspace/createWorkspaceSteps/openBehaviorStep.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/openBehaviorStep.ts b/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/openBehaviorStep.ts index cf700409a47..860e4231aac 100644 --- a/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/openBehaviorStep.ts +++ b/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/openBehaviorStep.ts @@ -15,7 +15,7 @@ export class OpenBehaviorStep extends AzureWizardPromptStep { const picks: IAzureQuickPickItem[] = [ - { label: localize('OpenInCurrentWindow', 'Open in current window'), data: OpenBehavior.openInContainer }, + { label: localize('OpenInCurrentWindow', 'Open in container'), data: OpenBehavior.openInContainer }, ]; const placeHolder: string = localize('selectOpenBehavior', 'Select how you would like to open your project'); From 577f067f9a69c3d54c6d6e5d379364e6716081c6 Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Wed, 1 Oct 2025 15:55:06 -0400 Subject: [PATCH 25/46] Remove java --- .../src/assets/container/devcontainer.json | 7 ------- 1 file changed, 7 deletions(-) diff --git a/apps/vs-code-designer/src/assets/container/devcontainer.json b/apps/vs-code-designer/src/assets/container/devcontainer.json index fa20747822b..eb37c3bcea5 100644 --- a/apps/vs-code-designer/src/assets/container/devcontainer.json +++ b/apps/vs-code-designer/src/assets/container/devcontainer.json @@ -19,13 +19,6 @@ "ghcr.io/devcontainers/features/powershell:1": { "version": "latest", "modules": "Az" - }, - "ghcr.io/devcontainers/features/java:1": { - "version": "17", - "jdkDistro": "ms", - "gradleVersion": "latest", - "mavenVersion": "latest", - "installAnt": false } }, "customizations": { From eeb1b12b547d04872bc34ec71af9a60a5fe65cb9 Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Thu, 2 Oct 2025 14:55:20 -0400 Subject: [PATCH 26/46] Commit open container and fix func issues --- .../app/commands/cloudToLocal/cloudToLocal.ts | 3 +- .../src/app/commands/convertToWorkspace.ts | 3 +- .../createWorkspace/createWorkspace.ts | 3 +- .../createWorkspaceSteps/openBehaviorStep.ts | 2 +- .../createWorkspaceSteps/openFolderStep.ts | 37 +++++++------------ .../createWorkspaceSteps/workspaceFileStep.ts | 2 +- .../workspaceSettingsStep.ts | 2 +- .../src/app/debug/validatePreDebug.ts | 14 +++---- apps/vs-code-designer/src/main.ts | 4 +- .../src/lib/models/project.ts | 2 +- 10 files changed, 29 insertions(+), 43 deletions(-) diff --git a/apps/vs-code-designer/src/app/commands/cloudToLocal/cloudToLocal.ts b/apps/vs-code-designer/src/app/commands/cloudToLocal/cloudToLocal.ts index 6cf92afc038..f1461fef4cd 100644 --- a/apps/vs-code-designer/src/app/commands/cloudToLocal/cloudToLocal.ts +++ b/apps/vs-code-designer/src/app/commands/cloudToLocal/cloudToLocal.ts @@ -16,7 +16,6 @@ import { ProcessPackageStep } from './cloudToLocalSteps/processPackageStep'; import { SelectFolderForNewWorkspaceStep } from './cloudToLocalSteps/selectFolderForNewWorkspaceStep'; import { ExtractPackageStep } from './cloudToLocalSteps/extractPackageStep'; import { WorkspaceSettingsStep } from '../createWorkspace/createWorkspaceSteps/workspaceSettingsStep'; -import { DevcontainerStep } from '../createWorkspace/createWorkspaceSteps/devcontainerStep'; const openFolder = true; @@ -56,7 +55,7 @@ export async function cloudToLocal( // TODO(aeldridge): Can we just use WorkspaceFolderStep instead? new SelectFolderForNewWorkspaceStep(), new WorkspaceNameStep(), - new DevcontainerStep(), + // new DevcontainerStep(), new LogicAppNameStep(), await ProjectTypeStep.create(context, options.templateId, options.functionSettings, true), new WorkspaceSettingsStep(), diff --git a/apps/vs-code-designer/src/app/commands/convertToWorkspace.ts b/apps/vs-code-designer/src/app/commands/convertToWorkspace.ts index d4afd9ee0f6..26e7114a2d6 100644 --- a/apps/vs-code-designer/src/app/commands/convertToWorkspace.ts +++ b/apps/vs-code-designer/src/app/commands/convertToWorkspace.ts @@ -12,7 +12,6 @@ import { getWorkspaceFile, getWorkspaceFileInParentDirectory, getWorkspaceFolder import { WorkspaceNameStep } from './createWorkspace/createWorkspaceSteps/workspaceNameStep'; import { WorkspaceFileStep } from './createWorkspace/createWorkspaceSteps/workspaceFileStep'; import { isLogicAppProjectInRoot } from '../utils/verifyIsProject'; -import { DevcontainerStep } from './createWorkspace/createWorkspaceSteps/devcontainerStep'; export async function convertToWorkspace(context: IActionContext): Promise { const convertToWorkspaceStartTime = Date.now(); @@ -61,7 +60,7 @@ export async function convertToWorkspace(context: IActionContext): Promise = new AzureWizard(wizardContext, { title: localize('convertToWorkspace', 'Convert to workspace'), - promptSteps: [new WorkspaceFolderStep(), new WorkspaceNameStep(), new DevcontainerStep(), new WorkspaceFileStep()], + promptSteps: [new WorkspaceFolderStep(), new WorkspaceNameStep(), /*new DevcontainerStep(), */ new WorkspaceFileStep()], executeSteps: [new OpenFolderStep()], }); diff --git a/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspace.ts b/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspace.ts index ebbe37b7dc5..a9886db6df7 100644 --- a/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspace.ts +++ b/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspace.ts @@ -14,7 +14,6 @@ import type { IActionContext } from '@microsoft/vscode-azext-utils'; import type { ProjectLanguage, ProjectVersion } from '@microsoft/vscode-extension-logic-apps'; import { TargetFrameworkStep } from '../createProject/createCustomCodeProjectSteps/targetFrameworkStep'; import { LogicAppTemplateStep } from '../createProject/createProjectSteps/logicAppTemplateStep'; -import { DevcontainerStep } from './createWorkspaceSteps/devcontainerStep'; // TODO(aeldridge): TargetFrameworkStep should be in a subwizard on LogicAppTemplateStep export async function createWorkspace( @@ -43,7 +42,7 @@ export async function createWorkspace( [ new WorkspaceFolderStep(), new WorkspaceNameStep(), - new DevcontainerStep(), + // new DevcontainerStep(), new LogicAppTemplateStep(), new TargetFrameworkStep(), new LogicAppNameStep(), diff --git a/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/openBehaviorStep.ts b/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/openBehaviorStep.ts index 860e4231aac..2d3df3a05a7 100644 --- a/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/openBehaviorStep.ts +++ b/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/openBehaviorStep.ts @@ -15,7 +15,7 @@ export class OpenBehaviorStep extends AzureWizardPromptStep { const picks: IAzureQuickPickItem[] = [ - { label: localize('OpenInCurrentWindow', 'Open in container'), data: OpenBehavior.openInContainer }, + { label: localize('OpenInNewWindow', 'Open in new window'), data: OpenBehavior.openInNewWindow }, ]; const placeHolder: string = localize('selectOpenBehavior', 'Select how you would like to open your project'); diff --git a/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/openFolderStep.ts b/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/openFolderStep.ts index 82b2e5a4b1a..9f92e39f7e2 100644 --- a/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/openFolderStep.ts +++ b/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/openFolderStep.ts @@ -8,7 +8,6 @@ import type { IProjectWizardContext } from '@microsoft/vscode-extension-logic-ap import { OpenBehavior } from '@microsoft/vscode-extension-logic-apps'; import * as fs from 'fs'; import { commands, Uri } from 'vscode'; -import { tryReopenInDevContainer } from '../../../utils/devContainer'; import { extensionCommand } from '../../../../constants'; export class OpenFolderStep extends AzureWizardExecuteStep { @@ -29,30 +28,22 @@ export class OpenFolderStep extends AzureWizardExecuteStep { - // Resolve the workspace URI (.code-workspace file if present, else the folder path) + let workspaceUri: Uri; + + // Check if .code-workspace file exists in project path const workspaceFilePath = context.workspaceFilePath; context.workspaceFolder = getContainingWorkspace(workspaceFilePath); - const workspaceUri: Uri = fs.existsSync(workspaceFilePath) ? Uri.file(workspaceFilePath) : Uri.file(context.workspacePath); - - // Attempt to open directly in a dev container. Prefer 'remote-containers.openWorkspace' when a .code-workspace file exists. - // Fallback: open folder then trigger reopen. - try { - let succeeded: unknown; - if (workspaceUri.fsPath.endsWith('.code-workspace')) { - succeeded = await commands.executeCommand('remote-containers.openWorkspace', workspaceUri); - if (!succeeded) { - throw new Error('remote-containers.openWorkspace returned falsy result'); - } - } else { - succeeded = await commands.executeCommand('remote-containers.openFolder', workspaceUri); - if (!succeeded) { - throw new Error('remote-containers.openFolder returned falsy result'); - } - } - } catch (_err) { - // Fallback path: open locally then request a reopen. - await commands.executeCommand(extensionCommand.vscodeOpenFolder, workspaceUri, false); - await tryReopenInDevContainer(context as any); + if (fs.existsSync(workspaceFilePath)) { + workspaceUri = Uri.file(workspaceFilePath); + } else { + workspaceUri = Uri.file(context.workspacePath); } + + // Open folder using executeCommand method of commands object with vscode.openFolder command + await commands.executeCommand( + extensionCommand.vscodeOpenFolder, + workspaceUri, + context.openBehavior === OpenBehavior.openInNewWindow /* forceNewWindow */ + ); } } diff --git a/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/workspaceFileStep.ts b/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/workspaceFileStep.ts index 9ce4dda6fdb..c266a8cfc25 100644 --- a/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/workspaceFileStep.ts +++ b/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/workspaceFileStep.ts @@ -65,6 +65,6 @@ export class WorkspaceFileStep extends AzureWizardPromptStep Date: Fri, 3 Oct 2025 10:04:52 -0400 Subject: [PATCH 27/46] Update func core tools --- .../src/assets/container/Dockerfile | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/apps/vs-code-designer/src/assets/container/Dockerfile b/apps/vs-code-designer/src/assets/container/Dockerfile index 35e4380a77b..663991c1734 100644 --- a/apps/vs-code-designer/src/assets/container/Dockerfile +++ b/apps/vs-code-designer/src/assets/container/Dockerfile @@ -44,22 +44,21 @@ RUN set -eux; \ # Download & install Core Tools (func) # ----------------------------- RUN set -eux; \ - echo "Downloading Azure Functions Core Tools version: ${FUNCTIONS_CORE_TOOLS_VERSION}"; \ - FILENAME="Azure.Functions.Cli.${FUNCTIONS_CORE_TOOLS_OS_PLATFORM}-${FUNCTIONS_CORE_TOOLS_ARCH}.${FUNCTIONS_CORE_TOOLS_VERSION}.zip"; \ + echo "Downloading Azure Functions Core Tools version: ${FUNCTIONS_CORE_TOOLS_VERSION} for ${TARGETOS}/${TARGETARCH}"; \ + case "${TARGETARCH}" in \ + amd64) FUNC_ARCH="x64" ;; \ + arm64) FUNC_ARCH="arm64" ;; \ + *) echo "Unsupported architecture: ${TARGETARCH}" >&2; exit 1 ;; \ + esac; \ + FILENAME="Azure.Functions.Cli.${TARGETOS}-${FUNC_ARCH}.${FUNCTIONS_CORE_TOOLS_VERSION}.zip"; \ wget "https://github.com/Azure/azure-functions-core-tools/releases/download/${FUNCTIONS_CORE_TOOLS_VERSION}/${FILENAME}" -O "/tmp/${FILENAME}"; \ mkdir -p "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}"; \ unzip -q "/tmp/${FILENAME}" -d "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}"; \ rm -f "/tmp/${FILENAME}"; \ chmod -R a+rX "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}"; \ - for executable in \ - "func" \ - "gozip" \ - "in-proc8/func" \ - "in-proc6/func"; do \ - if [ -f "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/${executable}" ]; then \ - chmod 755 "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/${executable}"; \ - fi; \ - done; \ + for executable in func gozip in-proc8/func in-proc6/func; do \ + if [ -f "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/${executable}" ]; then chmod 755 "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/${executable}"; fi; \ + done; \ ln -sf "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/func" /usr/local/bin/func; \ ln -sf "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/func" /usr/bin/func From 7d8673b8657b714c13bb672e43e076cfd5c01913 Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Fri, 3 Oct 2025 10:23:46 -0400 Subject: [PATCH 28/46] Revert func --- .../src/assets/container/Dockerfile | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/apps/vs-code-designer/src/assets/container/Dockerfile b/apps/vs-code-designer/src/assets/container/Dockerfile index 663991c1734..35e4380a77b 100644 --- a/apps/vs-code-designer/src/assets/container/Dockerfile +++ b/apps/vs-code-designer/src/assets/container/Dockerfile @@ -44,21 +44,22 @@ RUN set -eux; \ # Download & install Core Tools (func) # ----------------------------- RUN set -eux; \ - echo "Downloading Azure Functions Core Tools version: ${FUNCTIONS_CORE_TOOLS_VERSION} for ${TARGETOS}/${TARGETARCH}"; \ - case "${TARGETARCH}" in \ - amd64) FUNC_ARCH="x64" ;; \ - arm64) FUNC_ARCH="arm64" ;; \ - *) echo "Unsupported architecture: ${TARGETARCH}" >&2; exit 1 ;; \ - esac; \ - FILENAME="Azure.Functions.Cli.${TARGETOS}-${FUNC_ARCH}.${FUNCTIONS_CORE_TOOLS_VERSION}.zip"; \ + echo "Downloading Azure Functions Core Tools version: ${FUNCTIONS_CORE_TOOLS_VERSION}"; \ + FILENAME="Azure.Functions.Cli.${FUNCTIONS_CORE_TOOLS_OS_PLATFORM}-${FUNCTIONS_CORE_TOOLS_ARCH}.${FUNCTIONS_CORE_TOOLS_VERSION}.zip"; \ wget "https://github.com/Azure/azure-functions-core-tools/releases/download/${FUNCTIONS_CORE_TOOLS_VERSION}/${FILENAME}" -O "/tmp/${FILENAME}"; \ mkdir -p "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}"; \ unzip -q "/tmp/${FILENAME}" -d "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}"; \ rm -f "/tmp/${FILENAME}"; \ chmod -R a+rX "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}"; \ - for executable in func gozip in-proc8/func in-proc6/func; do \ - if [ -f "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/${executable}" ]; then chmod 755 "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/${executable}"; fi; \ - done; \ + for executable in \ + "func" \ + "gozip" \ + "in-proc8/func" \ + "in-proc6/func"; do \ + if [ -f "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/${executable}" ]; then \ + chmod 755 "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/${executable}"; \ + fi; \ + done; \ ln -sf "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/func" /usr/local/bin/func; \ ln -sf "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/func" /usr/bin/func From b6b2165059bf37e27031b3d25bb0227b76823c2e Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Fri, 3 Oct 2025 11:46:21 -0400 Subject: [PATCH 29/46] Update docker file and add readme and shell command to build and publish --- .../src/assets/container/Dockerfile | 16 +- .../src/assets/container/README.md | 233 ++++++++++++++++++ .../src/assets/container/build-and-push.sh | 108 ++++++++ 3 files changed, 353 insertions(+), 4 deletions(-) create mode 100644 apps/vs-code-designer/src/assets/container/README.md create mode 100755 apps/vs-code-designer/src/assets/container/build-and-push.sh diff --git a/apps/vs-code-designer/src/assets/container/Dockerfile b/apps/vs-code-designer/src/assets/container/Dockerfile index 35e4380a77b..1354ace32a8 100644 --- a/apps/vs-code-designer/src/assets/container/Dockerfile +++ b/apps/vs-code-designer/src/assets/container/Dockerfile @@ -64,11 +64,19 @@ RUN set -eux; \ ln -sf "/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}/func" /usr/bin/func # ----------------------------- -# Verify CLI is on PATH +# Verify CLI is on PATH (skipped during build due to Rosetta issues on ARM) +# The func command will work when container runs, just not during build verification # ----------------------------- -RUN set -eux; \ - which func; \ - func --version +# RUN set -eux; \ +# which func; \ +# func --version # Ensure Core Tools are discoverable for all users ENV PATH=/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}:$PATH + +# ----------------------------- +# Keep container running +# ----------------------------- +# This prevents the container from exiting immediately +# When used with devcontainers or docker-compose, this will be overridden +CMD ["sleep", "infinity"] diff --git a/apps/vs-code-designer/src/assets/container/README.md b/apps/vs-code-designer/src/assets/container/README.md new file mode 100644 index 00000000000..778fffead46 --- /dev/null +++ b/apps/vs-code-designer/src/assets/container/README.md @@ -0,0 +1,233 @@ +# Docker Container Build & Push Guide + +This directory contains the Docker configuration for the Logic Apps Standard Development container. + +## 📦 Repository Information + +- **Docker Hub Repository**: `carloscastrotrejo/logicapps-dev` +- **Public URL**: https://hub.docker.com/r/carloscastrotrejo/logicapps-dev + +## 🚀 Quick Start - Build & Push + +### Prerequisites + +1. Docker Desktop installed and running +2. Docker Hub account (carloscastrotrejo) +3. Logged into Docker Hub: + ```bash + docker login + ``` + +### Build and Push with Script + +Use the provided script to build and push in one command: + +```bash +# Push as latest +./build-and-push.sh + +# Push with a specific version tag +./build-and-push.sh v1.0.0 + +# Push with semantic version +./build-and-push.sh 1.131.9 +``` + +The script will: +1. ✅ Verify Docker is running +2. ✅ Check Docker Hub authentication +3. 🔨 Build the Docker image +4. 🏷️ Tag the image (both version + latest) +5. 🚀 Push to Docker Hub + +## 📝 Manual Build & Push (Alternative) + +If you prefer to run commands manually: + +```bash +# Navigate to the container directory +cd apps/vs-code-designer/src/assets/container/ + +# Build the image +docker build -t carloscastrotrejo/logicapps-dev:v1.0.0 . + +# Tag as latest +docker tag carloscastrotrejo/logicapps-dev:v1.0.0 carloscastrotrejo/logicapps-dev:latest + +# Push both tags +docker push carloscastrotrejo/logicapps-dev:v1.0.0 +docker push carloscastrotrejo/logicapps-dev:latest +``` + +## 🔢 Version Management + +### Recommended Versioning Strategy + +Use semantic versioning aligned with the Extension Bundle version: + +```bash +# Format: MAJOR.MINOR.PATCH +./build-and-push.sh 1.131.9 # Matches EXTENSION_BUNDLE_VERSION + +# Alternative formats: +./build-and-push.sh v1.131.9 # With 'v' prefix +./build-and-push.sh 1.0.0 # Simple semantic version +./build-and-push.sh latest # Latest tag only +``` + +### Version Tracking + +Current image configuration: +- **Extension Bundle Version**: 1.131.9 +- **Functions Core Tools Version**: 4.2.2 +- **Node Version**: 22 (bookworm) +- **Base Image**: `mcr.microsoft.com/devcontainers/javascript-node:1-22-bookworm` + +When you update versions in the Dockerfile, update the image tag accordingly. + +## 👥 For Team Members - Pulling the Image + +Team members can pull and use the image in several ways: + +### Option 1: Pull Directly + +```bash +# Pull latest version +docker pull carloscastrotrejo/logicapps-dev:latest + +# Pull specific version +docker pull carloscastrotrejo/logicapps-dev:v1.0.0 +``` + +### Option 2: Use in devcontainer.json + +Update your `devcontainer.json` to use the pre-built image instead of building locally: + +**Before (building locally):** +```json +{ + "name": "Logic Apps Standard Development", + "dockerComposeFile": "docker-compose.yml", + "service": "app", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}" +} +``` + +**After (using pre-built image):** +```json +{ + "name": "Logic Apps Standard Development", + "image": "carloscastrotrejo/logicapps-dev:latest", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + "features": { + // ... same features as before + } +} +``` + +### Option 3: Update docker-compose.yml + +Modify `docker-compose.yml` to use the pre-built image: + +**Before:** +```yaml +services: + app: + build: + context: . + dockerfile: Dockerfile +``` + +**After:** +```yaml +services: + app: + image: carloscastrotrejo/logicapps-dev:latest + # or use a specific version: + # image: carloscastrotrejo/logicapps-dev:v1.0.0 +``` + +## 🔍 Verify Published Image + +Check your image on Docker Hub: + +```bash +# View local images +docker images carloscastrotrejo/logicapps-dev + +# Inspect image details +docker inspect carloscastrotrejo/logicapps-dev:latest + +# View image history +docker history carloscastrotrejo/logicapps-dev:latest +``` + +Or visit: https://hub.docker.com/r/carloscastrotrejo/logicapps-dev/tags + +## 🛠️ Troubleshooting + +### Not Logged In +```bash +docker login +# Enter your Docker Hub credentials +``` + +### Build Fails +```bash +# Check Docker is running +docker info + +# Clean up old images +docker system prune -a + +# Rebuild without cache +docker build --no-cache -t carloscastrotrejo/logicapps-dev:v1.0.0 . +``` + +### Push Fails +```bash +# Verify authentication +docker login + +# Check image exists locally +docker images carloscastrotrejo/logicapps-dev + +# Try pushing again +docker push carloscastrotrejo/logicapps-dev:latest +``` + +## 📋 What's Included in the Image + +- ✅ **Node.js 22** (Bookworm base) +- ✅ **Azure Functions Core Tools v4.2.2** +- ✅ **Extension Bundle for Workflows v1.131.9** +- ✅ **System dependencies**: ca-certificates, curl, jq, gnupg, wget, unzip +- ✅ **Runtime libraries**: libc6, libicu72, libgssapi-krb5-2, libkrb5-3, zlib1g +- ✅ **Configured paths** for `func` CLI + +## 🔄 Updating the Image + +When you need to update the image: + +1. **Update the Dockerfile** with new versions (Extension Bundle, Core Tools, etc.) +2. **Increment the version** number +3. **Build and push**: + ```bash + ./build-and-push.sh 1.132.0 # New version + ``` +4. **Update documentation** (this README) with new version numbers +5. **Notify team** to pull the latest image + +## 📊 Image Size Optimization Tips + +- Current build uses multi-stage patterns where possible +- Cleans up apt cache to reduce size +- Combines RUN commands to minimize layers +- Consider using `.dockerignore` if building from a larger context + +## 🔐 Security Notes + +- Image is based on official Microsoft DevContainer images +- Uses official Azure Functions Core Tools releases +- Extension bundles are downloaded from official Azure CDN +- Keep versions updated for security patches diff --git a/apps/vs-code-designer/src/assets/container/build-and-push.sh b/apps/vs-code-designer/src/assets/container/build-and-push.sh new file mode 100755 index 00000000000..ced5684dab5 --- /dev/null +++ b/apps/vs-code-designer/src/assets/container/build-and-push.sh @@ -0,0 +1,108 @@ +#!/bin/bash + +# Build and Push Docker Image to Docker Hub +# This script builds the Logic Apps Standard Development container and pushes it to Docker Hub + +set -e + +# Configuration +DOCKER_USERNAME="carloscastrotrejo" +DOCKER_REPO="logicapps-dev" +DOCKER_IMAGE="${DOCKER_USERNAME}/${DOCKER_REPO}" + +# Get script directory +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# Default version (can be overridden with command line argument) +VERSION="${1:-latest}" + +echo "==================================" +echo "Docker Image Build & Push Script" +echo "==================================" +echo "Repository: ${DOCKER_IMAGE}" +echo "Version: ${VERSION}" +echo "Build Context: ${SCRIPT_DIR}" +echo "==================================" +echo "" + +# Check if Docker is running +if ! docker info > /dev/null 2>&1; then + echo "❌ Error: Docker is not running. Please start Docker and try again." + exit 1 +fi + +# Check if logged into Docker Hub +echo "Checking Docker Hub authentication..." +if ! docker info | grep -q "Username: ${DOCKER_USERNAME}"; then + echo "⚠️ Not logged into Docker Hub. Attempting login..." + docker login + if [ $? -ne 0 ]; then + echo "❌ Docker Hub login failed. Please run 'docker login' manually." + exit 1 + fi +fi + +echo "✅ Docker Hub authentication verified" +echo "" + +# Build the Docker image +echo "🔨 Building Docker image for linux/amd64 platform..." +echo "Command: docker build --platform linux/amd64 -t ${DOCKER_IMAGE}:${VERSION} ${SCRIPT_DIR}" +docker build --platform linux/amd64 -t "${DOCKER_IMAGE}:${VERSION}" "${SCRIPT_DIR}" + +if [ $? -ne 0 ]; then + echo "❌ Docker build failed!" + exit 1 +fi + +echo "✅ Docker image built successfully" +echo "" + +# Tag as latest if version is not "latest" +if [ "${VERSION}" != "latest" ]; then + echo "🏷️ Tagging as latest..." + docker tag "${DOCKER_IMAGE}:${VERSION}" "${DOCKER_IMAGE}:latest" + echo "✅ Tagged as latest" + echo "" +fi + +# Show image info +echo "📦 Image information:" +docker images "${DOCKER_IMAGE}" --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}\t{{.CreatedAt}}" +echo "" + +# Push to Docker Hub +echo "🚀 Pushing to Docker Hub..." +echo "Pushing ${DOCKER_IMAGE}:${VERSION}..." +docker push "${DOCKER_IMAGE}:${VERSION}" + +if [ "${VERSION}" != "latest" ]; then + echo "Pushing ${DOCKER_IMAGE}:latest..." + docker push "${DOCKER_IMAGE}:latest" +fi + +if [ $? -ne 0 ]; then + echo "❌ Docker push failed!" + exit 1 +fi + +echo "" +echo "==================================" +echo "✅ Successfully pushed to Docker Hub!" +echo "==================================" +echo "" +echo "Your image is now available at:" +echo " - ${DOCKER_IMAGE}:${VERSION}" +if [ "${VERSION}" != "latest" ]; then + echo " - ${DOCKER_IMAGE}:latest" +fi +echo "" +echo "Others can pull it with:" +echo " docker pull ${DOCKER_IMAGE}:${VERSION}" +if [ "${VERSION}" != "latest" ]; then + echo " docker pull ${DOCKER_IMAGE}:latest" +fi +echo "" +echo "To use in devcontainer.json, update the 'image' field:" +echo " \"image\": \"${DOCKER_IMAGE}:${VERSION}\"" +echo "==================================" From 0cf4c1757dc170d404414d0a5690656e558e7a57 Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Fri, 3 Oct 2025 12:23:39 -0400 Subject: [PATCH 30/46] Update docker build command to adjust to multi platform --- .../assets/container/MULTI_PLATFORM_GUIDE.md | 222 ++++++++++++++++++ .../src/assets/container/README.md | 111 +++++++-- .../src/assets/container/build-and-push.sh | 73 ++++-- 3 files changed, 359 insertions(+), 47 deletions(-) create mode 100644 apps/vs-code-designer/src/assets/container/MULTI_PLATFORM_GUIDE.md diff --git a/apps/vs-code-designer/src/assets/container/MULTI_PLATFORM_GUIDE.md b/apps/vs-code-designer/src/assets/container/MULTI_PLATFORM_GUIDE.md new file mode 100644 index 00000000000..1c774fefec0 --- /dev/null +++ b/apps/vs-code-designer/src/assets/container/MULTI_PLATFORM_GUIDE.md @@ -0,0 +1,222 @@ +# Multi-Platform Docker Build Guide + +## Overview + +This container now uses **Docker buildx** to create multi-platform images that work seamlessly on both Intel/AMD and ARM architectures. + +## What Changed? + +### Before (Single Platform) +- Built only for `linux/amd64` +- ARM users got platform mismatch warnings +- Slower performance on Apple Silicon due to emulation + +### After (Multi-Platform) +- Builds for **both** `linux/amd64` and `linux/arm64` +- Single image tag works everywhere +- Native performance on all platforms +- No platform warnings + +## Technical Details + +### Docker Buildx + +Docker buildx is a CLI plugin that extends Docker's build capabilities with: +- Multi-platform image builds +- BuildKit backend for improved performance +- Manifest lists to support multiple architectures + +### Image Manifest + +When you build with multiple platforms, Docker creates a **manifest list** containing: +``` +carloscastrotrejo/logicapps-dev:v2.0.0 +├── linux/amd64 +│ └── [image layers for Intel/AMD] +└── linux/arm64 + └── [image layers for ARM] +``` + +### How Users Pull Images + +When someone runs: +```bash +docker pull carloscastrotrejo/logicapps-dev:v2.0.0 +``` + +Docker: +1. Fetches the manifest list +2. Identifies the user's platform (e.g., `linux/arm64` on Apple Silicon) +3. Downloads only the matching architecture +4. Stores it locally + +**The user never needs to specify `--platform`!** + +## Build Script Changes + +### Old Approach +```bash +docker build --platform linux/amd64 -t image:tag . +docker push image:tag +``` + +### New Approach +```bash +# Setup buildx builder (one-time) +docker buildx create --name multiplatform-builder --use +docker buildx inspect --bootstrap + +# Build and push for multiple platforms +docker buildx build \ + --platform linux/amd64,linux/arm64 \ + -t image:tag \ + --push \ + . +``` + +## Key Differences + +| Aspect | Single Platform | Multi-Platform | +|--------|----------------|----------------| +| Build time | ~2-3 minutes | ~5-8 minutes | +| Push method | `docker push` | Built into `buildx build --push` | +| Local testing | Image stored locally | Must pull from registry | +| Platforms | One architecture | Both amd64 + arm64 | +| Tag management | Manual tagging | Can specify multiple tags in one build | + +## Why `--push` is Required + +With multi-platform builds: +- Images are built in the buildx cache, not loaded locally +- You can't use `docker images` to see them +- Must push directly to registry with `--push` flag +- To test locally, pull the image back: `docker pull carloscastrotrejo/logicapps-dev:test` + +## Verification Commands + +### Check what platforms are available +```bash +docker buildx imagetools inspect carloscastrotrejo/logicapps-dev:v2.0.0 +``` + +Output shows: +``` +MediaType: application/vnd.docker.distribution.manifest.list.v2+json +Digest: sha256:abc123... + +Manifests: + Name: carloscastrotrejo/logicapps-dev:v2.0.0@sha256:xyz789... + MediaType: application/vnd.docker.distribution.manifest.v2+json + Platform: linux/amd64 + + Name: carloscastrotrejo/logicapps-dev:v2.0.0@sha256:def456... + MediaType: application/vnd.docker.distribution.manifest.v2+json + Platform: linux/arm64 +``` + +### Check what platform you pulled locally +```bash +docker image inspect carloscastrotrejo/logicapps-dev:v2.0.0 | grep -A 3 "Architecture" +``` + +Output on Apple Silicon: +```json +"Architecture": "arm64", +"Os": "linux", +``` + +## Best Practices + +### 1. **Always Use Versioned Tags** +```bash +./build-and-push.sh v2.0.0 # Good +./build-and-push.sh latest # OK but less traceable +``` + +### 2. **Test Both Platforms** +After pushing, test on different architectures: +```bash +# On Intel Mac/PC +docker pull --platform linux/amd64 carloscastrotrejo/logicapps-dev:v2.0.0 +docker run --rm -it carloscastrotrejo/logicapps-dev:v2.0.0 func --version + +# On Apple Silicon +docker pull --platform linux/arm64 carloscastrotrejo/logicapps-dev:v2.0.0 +docker run --rm -it carloscastrotrejo/logicapps-dev:v2.0.0 func --version +``` + +### 3. **Monitor Build Times** +Multi-platform builds take longer: +- First build: ~8-10 minutes (downloading base layers) +- Subsequent builds: ~3-5 minutes (with cache) + +### 4. **Keep Buildx Builder Updated** +Periodically recreate the builder for latest features: +```bash +docker buildx rm multiplatform-builder +docker buildx create --name multiplatform-builder --use +docker buildx inspect --bootstrap +``` + +## Troubleshooting + +### "no builder selected" error +```bash +docker buildx create --name multiplatform-builder --use +docker buildx inspect --bootstrap +``` + +### Build is very slow +- First build downloads base images for both platforms +- Enable Docker BuildKit caching +- Check internet connection speed + +### Can't find image locally after build +- Multi-platform builds don't load locally by default +- Pull the image: `docker pull carloscastrotrejo/logicapps-dev:v2.0.0` +- Or build single-platform for testing: `docker build -t test .` + +### Platform mismatch after multi-platform build +- Shouldn't happen! The manifest list handles this +- Verify manifest: `docker buildx imagetools inspect image:tag` +- Re-pull the image: `docker pull --rm image:tag && docker pull image:tag` + +## Cost Considerations + +### Build Time +- ~2x longer due to building twice (once per platform) +- Can be parallelized in CI/CD with separate jobs + +### Storage +- Docker Hub storage roughly doubles (two platform images) +- Free tier: 1 private repo + unlimited public repos +- Public repos have unlimited storage + +### Bandwidth +- Users only download their platform (same as before) +- Total registry bandwidth: ~2x (but spread across platforms) + +## Advanced: Adding More Platforms + +To support additional platforms: + +```bash +docker buildx build \ + --platform linux/amd64,linux/arm64,linux/arm/v7 \ + -t image:tag \ + --push \ + . +``` + +Common platforms: +- `linux/amd64` - Intel/AMD 64-bit (most servers, PCs) +- `linux/arm64` - ARM 64-bit (Apple Silicon, ARM servers) +- `linux/arm/v7` - ARM 32-bit (Raspberry Pi, IoT) +- `linux/386` - Intel 32-bit (legacy) + +## References + +- [Docker Buildx Documentation](https://docs.docker.com/buildx/working-with-buildx/) +- [Multi-platform Images](https://docs.docker.com/build/building/multi-platform/) +- [Docker Manifest Lists](https://docs.docker.com/registry/spec/manifest-v2-2/) +- [BuildKit](https://github.com/moby/buildkit) diff --git a/apps/vs-code-designer/src/assets/container/README.md b/apps/vs-code-designer/src/assets/container/README.md index 778fffead46..47f423f0cb4 100644 --- a/apps/vs-code-designer/src/assets/container/README.md +++ b/apps/vs-code-designer/src/assets/container/README.md @@ -6,6 +6,33 @@ This directory contains the Docker configuration for the Logic Apps Standard Dev - **Docker Hub Repository**: `carloscastrotrejo/logicapps-dev` - **Public URL**: https://hub.docker.com/r/carloscastrotrejo/logicapps-dev +- **Supported Platforms**: + - `linux/amd64` (Intel/AMD processors) + - `linux/arm64` (Apple Silicon M1/M2/M3, ARM servers) + +## 🌐 Multi-Platform Support + +The image is built using **Docker buildx** to support multiple architectures in a single image manifest. When users pull the image, Docker automatically downloads the correct architecture for their platform - no manual selection needed! + +### Benefits + +✅ **Single Image Tag**: One tag (e.g., `v1.0.0`) works for all platforms +✅ **Automatic Detection**: Docker automatically pulls the right architecture +✅ **Better Performance**: Native execution on both Intel and ARM processors +✅ **No Platform Warnings**: Eliminates "platform mismatch" warnings +✅ **Future-Proof**: Ready for ARM-based cloud infrastructure + +### How It Works + +When you run: +```bash +docker pull carloscastrotrejo/logicapps-dev:latest +``` + +Docker: +1. Checks your system architecture +2. Downloads the matching image (amd64 or arm64) +3. No `--platform` flag needed! ## 🚀 Quick Start - Build & Push @@ -36,27 +63,43 @@ Use the provided script to build and push in one command: The script will: 1. ✅ Verify Docker is running 2. ✅ Check Docker Hub authentication -3. 🔨 Build the Docker image -4. 🏷️ Tag the image (both version + latest) -5. 🚀 Push to Docker Hub +3. � Setup Docker buildx for multi-platform builds +4. 🔨 Build the image for **both amd64 and arm64** architectures +5. 🚀 Push to Docker Hub with manifest supporting both platforms + +**Note**: Multi-platform builds take longer (several minutes) because they build for multiple architectures. ## 📝 Manual Build & Push (Alternative) -If you prefer to run commands manually: +If you prefer to run commands manually with multi-platform support: ```bash # Navigate to the container directory cd apps/vs-code-designer/src/assets/container/ -# Build the image -docker build -t carloscastrotrejo/logicapps-dev:v1.0.0 . +# Create and use buildx builder (first time only) +docker buildx create --name multiplatform-builder --use +docker buildx inspect --bootstrap + +# Build for multiple platforms and push +docker buildx build \ + --platform linux/amd64,linux/arm64 \ + -t carloscastrotrejo/logicapps-dev:v1.0.0 \ + -t carloscastrotrejo/logicapps-dev:latest \ + --push \ + . +``` -# Tag as latest -docker tag carloscastrotrejo/logicapps-dev:v1.0.0 carloscastrotrejo/logicapps-dev:latest +### Single Platform Build (Faster for Testing) -# Push both tags -docker push carloscastrotrejo/logicapps-dev:v1.0.0 -docker push carloscastrotrejo/logicapps-dev:latest +For faster local testing, you can build for just your platform: + +```bash +# Build only for your current platform +docker build -t carloscastrotrejo/logicapps-dev:test . + +# Or specify a platform +docker build --platform linux/amd64 -t carloscastrotrejo/logicapps-dev:test . ``` ## 🔢 Version Management @@ -87,18 +130,29 @@ When you update versions in the Dockerfile, update the image tag accordingly. ## 👥 For Team Members - Pulling the Image -Team members can pull and use the image in several ways: +Team members can pull and use the image in several ways. **Docker automatically detects and pulls the correct architecture** for their platform! ### Option 1: Pull Directly ```bash -# Pull latest version +# Pull latest version (auto-detects your platform) docker pull carloscastrotrejo/logicapps-dev:latest # Pull specific version docker pull carloscastrotrejo/logicapps-dev:v1.0.0 + +# Verify the platform +docker image inspect carloscastrotrejo/logicapps-dev:latest | grep Architecture ``` +### Platform Detection + +- **Intel/AMD Macs & PCs**: Automatically pulls `linux/amd64` +- **Apple Silicon (M1/M2/M3)**: Automatically pulls `linux/arm64` +- **ARM Servers**: Automatically pulls `linux/arm64` + +No need to specify `--platform` - Docker handles it automatically! + ### Option 2: Use in devcontainer.json Update your `devcontainer.json` to use the pre-built image instead of building locally: @@ -149,21 +203,27 @@ services: ## 🔍 Verify Published Image -Check your image on Docker Hub: +Check your multi-platform image on Docker Hub: ```bash # View local images docker images carloscastrotrejo/logicapps-dev -# Inspect image details -docker inspect carloscastrotrejo/logicapps-dev:latest +# Inspect image details (shows supported platforms) +docker buildx imagetools inspect carloscastrotrejo/logicapps-dev:latest + +# This will show both platforms: +# - linux/amd64 +# - linux/arm64 -# View image history -docker history carloscastrotrejo/logicapps-dev:latest +# Check what platform you pulled locally +docker image inspect carloscastrotrejo/logicapps-dev:latest | grep -A 3 "Architecture" ``` Or visit: https://hub.docker.com/r/carloscastrotrejo/logicapps-dev/tags +On Docker Hub, you'll see both architectures listed for each tag. + ## 🛠️ Troubleshooting ### Not Logged In @@ -177,11 +237,20 @@ docker login # Check Docker is running docker info -# Clean up old images -docker system prune -a +# Ensure buildx is available +docker buildx version + +# Clean up and recreate builder +docker buildx rm multiplatform-builder +docker buildx create --name multiplatform-builder --use +docker buildx inspect --bootstrap # Rebuild without cache -docker build --no-cache -t carloscastrotrejo/logicapps-dev:v1.0.0 . +docker buildx build --no-cache \ + --platform linux/amd64,linux/arm64 \ + -t carloscastrotrejo/logicapps-dev:v1.0.0 \ + --push \ + . ``` ### Push Fails diff --git a/apps/vs-code-designer/src/assets/container/build-and-push.sh b/apps/vs-code-designer/src/assets/container/build-and-push.sh index ced5684dab5..dfbe64c35e8 100755 --- a/apps/vs-code-designer/src/assets/container/build-and-push.sh +++ b/apps/vs-code-designer/src/assets/container/build-and-push.sh @@ -45,44 +45,59 @@ fi echo "✅ Docker Hub authentication verified" echo "" -# Build the Docker image -echo "🔨 Building Docker image for linux/amd64 platform..." -echo "Command: docker build --platform linux/amd64 -t ${DOCKER_IMAGE}:${VERSION} ${SCRIPT_DIR}" -docker build --platform linux/amd64 -t "${DOCKER_IMAGE}:${VERSION}" "${SCRIPT_DIR}" +# Setup buildx for multi-platform builds +echo "🔧 Setting up Docker buildx for multi-platform build..." +# Create a new builder instance if it doesn't exist +if ! docker buildx inspect multiplatform-builder > /dev/null 2>&1; then + echo "Creating new buildx builder 'multiplatform-builder'..." + docker buildx create --name multiplatform-builder --use +else + echo "Using existing buildx builder 'multiplatform-builder'..." + docker buildx use multiplatform-builder +fi + +# Bootstrap the builder (downloads necessary components) +docker buildx inspect --bootstrap + +echo "✅ Buildx ready for multi-platform build" +echo "" + +# Build and push multi-platform image +echo "🔨 Building multi-platform Docker image (linux/amd64, linux/arm64)..." +echo "Command: docker buildx build --platform linux/amd64,linux/arm64 -t ${DOCKER_IMAGE}:${VERSION} --push ${SCRIPT_DIR}" +echo "" +echo "⏳ This may take several minutes as it builds for multiple architectures..." +echo "" + +docker buildx build \ + --platform linux/amd64,linux/arm64 \ + -t "${DOCKER_IMAGE}:${VERSION}" \ + --push \ + "${SCRIPT_DIR}" if [ $? -ne 0 ]; then - echo "❌ Docker build failed!" + echo "❌ Docker buildx build failed!" exit 1 fi -echo "✅ Docker image built successfully" +echo "" +echo "✅ Multi-platform image built and pushed successfully" echo "" # Tag as latest if version is not "latest" if [ "${VERSION}" != "latest" ]; then - echo "🏷️ Tagging as latest..." - docker tag "${DOCKER_IMAGE}:${VERSION}" "${DOCKER_IMAGE}:latest" - echo "✅ Tagged as latest" + echo "🏷️ Building and pushing 'latest' tag..." + docker buildx build \ + --platform linux/amd64,linux/arm64 \ + -t "${DOCKER_IMAGE}:latest" \ + --push \ + "${SCRIPT_DIR}" + echo "✅ Tagged and pushed as latest" echo "" fi -# Show image info -echo "📦 Image information:" -docker images "${DOCKER_IMAGE}" --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}\t{{.CreatedAt}}" -echo "" - -# Push to Docker Hub -echo "🚀 Pushing to Docker Hub..." -echo "Pushing ${DOCKER_IMAGE}:${VERSION}..." -docker push "${DOCKER_IMAGE}:${VERSION}" - -if [ "${VERSION}" != "latest" ]; then - echo "Pushing ${DOCKER_IMAGE}:latest..." - docker push "${DOCKER_IMAGE}:latest" -fi - if [ $? -ne 0 ]; then - echo "❌ Docker push failed!" + echo "❌ Multi-platform build/push failed!" exit 1 fi @@ -91,18 +106,24 @@ echo "==================================" echo "✅ Successfully pushed to Docker Hub!" echo "==================================" echo "" -echo "Your image is now available at:" +echo "Your multi-platform image is now available at:" echo " - ${DOCKER_IMAGE}:${VERSION}" if [ "${VERSION}" != "latest" ]; then echo " - ${DOCKER_IMAGE}:latest" fi echo "" +echo "Supported platforms:" +echo " - linux/amd64 (Intel/AMD processors)" +echo " - linux/arm64 (Apple Silicon, ARM servers)" +echo "" echo "Others can pull it with:" echo " docker pull ${DOCKER_IMAGE}:${VERSION}" if [ "${VERSION}" != "latest" ]; then echo " docker pull ${DOCKER_IMAGE}:latest" fi echo "" +echo "Docker will automatically pull the correct architecture for their platform!" +echo "" echo "To use in devcontainer.json, update the 'image' field:" echo " \"image\": \"${DOCKER_IMAGE}:${VERSION}\"" echo "==================================" From 7980dfc8a27a5ab14af9b0ff79c3ebbf48203351 Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Fri, 3 Oct 2025 12:28:51 -0400 Subject: [PATCH 31/46] Update package.json to remove dev container --- apps/vs-code-designer/src/package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/vs-code-designer/src/package.json b/apps/vs-code-designer/src/package.json index 99a3556985a..3b7c481768c 100644 --- a/apps/vs-code-designer/src/package.json +++ b/apps/vs-code-designer/src/package.json @@ -951,8 +951,7 @@ "azurite.azurite", "ms-azuretools.vscode-azureresourcegroups", "ms-dotnettools.csharp", - "ms-dotnettools.csdevkit", - "ms-vscode-remote.remote-containers" + "ms-dotnettools.csdevkit" ], "enabledApiProposals": ["authenticationChallenges"], "activationEvents": [ From 397389dacd20f577480159b326f4ae2ade5d714c Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Tue, 7 Oct 2025 21:07:41 -0400 Subject: [PATCH 32/46] Keep just one README file --- .../assets/container/MULTI_PLATFORM_GUIDE.md | 222 ------------------ .../src/assets/container/README.md | 213 ++++++++++++++++- 2 files changed, 200 insertions(+), 235 deletions(-) delete mode 100644 apps/vs-code-designer/src/assets/container/MULTI_PLATFORM_GUIDE.md diff --git a/apps/vs-code-designer/src/assets/container/MULTI_PLATFORM_GUIDE.md b/apps/vs-code-designer/src/assets/container/MULTI_PLATFORM_GUIDE.md deleted file mode 100644 index 1c774fefec0..00000000000 --- a/apps/vs-code-designer/src/assets/container/MULTI_PLATFORM_GUIDE.md +++ /dev/null @@ -1,222 +0,0 @@ -# Multi-Platform Docker Build Guide - -## Overview - -This container now uses **Docker buildx** to create multi-platform images that work seamlessly on both Intel/AMD and ARM architectures. - -## What Changed? - -### Before (Single Platform) -- Built only for `linux/amd64` -- ARM users got platform mismatch warnings -- Slower performance on Apple Silicon due to emulation - -### After (Multi-Platform) -- Builds for **both** `linux/amd64` and `linux/arm64` -- Single image tag works everywhere -- Native performance on all platforms -- No platform warnings - -## Technical Details - -### Docker Buildx - -Docker buildx is a CLI plugin that extends Docker's build capabilities with: -- Multi-platform image builds -- BuildKit backend for improved performance -- Manifest lists to support multiple architectures - -### Image Manifest - -When you build with multiple platforms, Docker creates a **manifest list** containing: -``` -carloscastrotrejo/logicapps-dev:v2.0.0 -├── linux/amd64 -│ └── [image layers for Intel/AMD] -└── linux/arm64 - └── [image layers for ARM] -``` - -### How Users Pull Images - -When someone runs: -```bash -docker pull carloscastrotrejo/logicapps-dev:v2.0.0 -``` - -Docker: -1. Fetches the manifest list -2. Identifies the user's platform (e.g., `linux/arm64` on Apple Silicon) -3. Downloads only the matching architecture -4. Stores it locally - -**The user never needs to specify `--platform`!** - -## Build Script Changes - -### Old Approach -```bash -docker build --platform linux/amd64 -t image:tag . -docker push image:tag -``` - -### New Approach -```bash -# Setup buildx builder (one-time) -docker buildx create --name multiplatform-builder --use -docker buildx inspect --bootstrap - -# Build and push for multiple platforms -docker buildx build \ - --platform linux/amd64,linux/arm64 \ - -t image:tag \ - --push \ - . -``` - -## Key Differences - -| Aspect | Single Platform | Multi-Platform | -|--------|----------------|----------------| -| Build time | ~2-3 minutes | ~5-8 minutes | -| Push method | `docker push` | Built into `buildx build --push` | -| Local testing | Image stored locally | Must pull from registry | -| Platforms | One architecture | Both amd64 + arm64 | -| Tag management | Manual tagging | Can specify multiple tags in one build | - -## Why `--push` is Required - -With multi-platform builds: -- Images are built in the buildx cache, not loaded locally -- You can't use `docker images` to see them -- Must push directly to registry with `--push` flag -- To test locally, pull the image back: `docker pull carloscastrotrejo/logicapps-dev:test` - -## Verification Commands - -### Check what platforms are available -```bash -docker buildx imagetools inspect carloscastrotrejo/logicapps-dev:v2.0.0 -``` - -Output shows: -``` -MediaType: application/vnd.docker.distribution.manifest.list.v2+json -Digest: sha256:abc123... - -Manifests: - Name: carloscastrotrejo/logicapps-dev:v2.0.0@sha256:xyz789... - MediaType: application/vnd.docker.distribution.manifest.v2+json - Platform: linux/amd64 - - Name: carloscastrotrejo/logicapps-dev:v2.0.0@sha256:def456... - MediaType: application/vnd.docker.distribution.manifest.v2+json - Platform: linux/arm64 -``` - -### Check what platform you pulled locally -```bash -docker image inspect carloscastrotrejo/logicapps-dev:v2.0.0 | grep -A 3 "Architecture" -``` - -Output on Apple Silicon: -```json -"Architecture": "arm64", -"Os": "linux", -``` - -## Best Practices - -### 1. **Always Use Versioned Tags** -```bash -./build-and-push.sh v2.0.0 # Good -./build-and-push.sh latest # OK but less traceable -``` - -### 2. **Test Both Platforms** -After pushing, test on different architectures: -```bash -# On Intel Mac/PC -docker pull --platform linux/amd64 carloscastrotrejo/logicapps-dev:v2.0.0 -docker run --rm -it carloscastrotrejo/logicapps-dev:v2.0.0 func --version - -# On Apple Silicon -docker pull --platform linux/arm64 carloscastrotrejo/logicapps-dev:v2.0.0 -docker run --rm -it carloscastrotrejo/logicapps-dev:v2.0.0 func --version -``` - -### 3. **Monitor Build Times** -Multi-platform builds take longer: -- First build: ~8-10 minutes (downloading base layers) -- Subsequent builds: ~3-5 minutes (with cache) - -### 4. **Keep Buildx Builder Updated** -Periodically recreate the builder for latest features: -```bash -docker buildx rm multiplatform-builder -docker buildx create --name multiplatform-builder --use -docker buildx inspect --bootstrap -``` - -## Troubleshooting - -### "no builder selected" error -```bash -docker buildx create --name multiplatform-builder --use -docker buildx inspect --bootstrap -``` - -### Build is very slow -- First build downloads base images for both platforms -- Enable Docker BuildKit caching -- Check internet connection speed - -### Can't find image locally after build -- Multi-platform builds don't load locally by default -- Pull the image: `docker pull carloscastrotrejo/logicapps-dev:v2.0.0` -- Or build single-platform for testing: `docker build -t test .` - -### Platform mismatch after multi-platform build -- Shouldn't happen! The manifest list handles this -- Verify manifest: `docker buildx imagetools inspect image:tag` -- Re-pull the image: `docker pull --rm image:tag && docker pull image:tag` - -## Cost Considerations - -### Build Time -- ~2x longer due to building twice (once per platform) -- Can be parallelized in CI/CD with separate jobs - -### Storage -- Docker Hub storage roughly doubles (two platform images) -- Free tier: 1 private repo + unlimited public repos -- Public repos have unlimited storage - -### Bandwidth -- Users only download their platform (same as before) -- Total registry bandwidth: ~2x (but spread across platforms) - -## Advanced: Adding More Platforms - -To support additional platforms: - -```bash -docker buildx build \ - --platform linux/amd64,linux/arm64,linux/arm/v7 \ - -t image:tag \ - --push \ - . -``` - -Common platforms: -- `linux/amd64` - Intel/AMD 64-bit (most servers, PCs) -- `linux/arm64` - ARM 64-bit (Apple Silicon, ARM servers) -- `linux/arm/v7` - ARM 32-bit (Raspberry Pi, IoT) -- `linux/386` - Intel 32-bit (legacy) - -## References - -- [Docker Buildx Documentation](https://docs.docker.com/buildx/working-with-buildx/) -- [Multi-platform Images](https://docs.docker.com/build/building/multi-platform/) -- [Docker Manifest Lists](https://docs.docker.com/registry/spec/manifest-v2-2/) -- [BuildKit](https://github.com/moby/buildkit) diff --git a/apps/vs-code-designer/src/assets/container/README.md b/apps/vs-code-designer/src/assets/container/README.md index 47f423f0cb4..70f06a497d4 100644 --- a/apps/vs-code-designer/src/assets/container/README.md +++ b/apps/vs-code-designer/src/assets/container/README.md @@ -12,7 +12,7 @@ This directory contains the Docker configuration for the Logic Apps Standard Dev ## 🌐 Multi-Platform Support -The image is built using **Docker buildx** to support multiple architectures in a single image manifest. When users pull the image, Docker automatically downloads the correct architecture for their platform - no manual selection needed! +The image is built using **Docker buildx** to create multi-platform images that work seamlessly on both Intel/AMD and ARM architectures. When users pull the image, Docker automatically downloads the correct architecture for their platform - no manual selection needed! ### Benefits @@ -24,15 +24,39 @@ The image is built using **Docker buildx** to support multiple architectures in ### How It Works +Docker buildx creates a **manifest list** containing images for multiple architectures: + +``` +carloscastrotrejo/logicapps-dev:v2.0.0 +├── linux/amd64 +│ └── [image layers for Intel/AMD] +└── linux/arm64 + └── [image layers for ARM] +``` + When you run: ```bash docker pull carloscastrotrejo/logicapps-dev:latest ``` Docker: -1. Checks your system architecture -2. Downloads the matching image (amd64 or arm64) -3. No `--platform` flag needed! +1. Fetches the manifest list +2. Identifies your system architecture (e.g., `linux/arm64` on Apple Silicon) +3. Downloads only the matching architecture +4. Stores it locally + +**The user never needs to specify `--platform`!** + +### What Changed from Single Platform? + +| Aspect | Before (Single Platform) | After (Multi-Platform) | +|--------|--------------------------|------------------------| +| Platforms | Only `linux/amd64` | Both `amd64` + `arm64` | +| ARM Performance | Emulation (slow) | Native (fast) | +| Warnings | Platform mismatch warnings | No warnings | +| Build time | ~2-3 minutes | ~5-8 minutes | +| Push method | `docker push` | Built into `buildx build --push` | +| Local testing | Image stored locally | Must pull from registry | ## 🚀 Quick Start - Build & Push @@ -63,11 +87,26 @@ Use the provided script to build and push in one command: The script will: 1. ✅ Verify Docker is running 2. ✅ Check Docker Hub authentication -3. � Setup Docker buildx for multi-platform builds +3. 🔧 Setup Docker buildx for multi-platform builds 4. 🔨 Build the image for **both amd64 and arm64** architectures 5. 🚀 Push to Docker Hub with manifest supporting both platforms -**Note**: Multi-platform builds take longer (several minutes) because they build for multiple architectures. +**Note**: Multi-platform builds take longer (5-8 minutes) because they build for multiple architectures. First build may take 8-10 minutes while downloading base layers. + +### Understanding Docker Buildx + +Docker buildx is a CLI plugin that extends Docker's build capabilities with: +- **Multi-platform image builds** - Build for multiple architectures simultaneously +- **BuildKit backend** - Improved performance and caching +- **Manifest lists** - Single tag supports multiple architectures + +### Why `--push` is Required + +With multi-platform builds: +- Images are built in the buildx cache, not loaded locally +- You can't use `docker images` to see them immediately +- Must push directly to registry with `--push` flag +- To test locally, pull the image back: `docker pull carloscastrotrejo/logicapps-dev:test` ## 📝 Manual Build & Push (Alternative) @@ -90,6 +129,28 @@ docker buildx build \ . ``` +### Build Script Changes Explained + +**Old single-platform approach:** +```bash +docker build --platform linux/amd64 -t image:tag . +docker push image:tag +``` + +**New multi-platform approach:** +```bash +# Setup buildx builder (one-time) +docker buildx create --name multiplatform-builder --use +docker buildx inspect --bootstrap + +# Build and push for multiple platforms +docker buildx build \ + --platform linux/amd64,linux/arm64 \ + -t image:tag \ + --push \ + . +``` + ### Single Platform Build (Faster for Testing) For faster local testing, you can build for just your platform: @@ -211,15 +272,34 @@ docker images carloscastrotrejo/logicapps-dev # Inspect image details (shows supported platforms) docker buildx imagetools inspect carloscastrotrejo/logicapps-dev:latest +``` -# This will show both platforms: -# - linux/amd64 -# - linux/arm64 +**Example output showing both platforms:** +``` +MediaType: application/vnd.docker.distribution.manifest.list.v2+json +Digest: sha256:abc123... + +Manifests: + Name: carloscastrotrejo/logicapps-dev:latest@sha256:xyz789... + MediaType: application/vnd.docker.distribution.manifest.v2+json + Platform: linux/amd64 + + Name: carloscastrotrejo/logicapps-dev:latest@sha256:def456... + MediaType: application/vnd.docker.distribution.manifest.v2+json + Platform: linux/arm64 +``` +```bash # Check what platform you pulled locally docker image inspect carloscastrotrejo/logicapps-dev:latest | grep -A 3 "Architecture" ``` +**Output on Apple Silicon:** +```json +"Architecture": "arm64", +"Os": "linux", +``` + Or visit: https://hub.docker.com/r/carloscastrotrejo/logicapps-dev/tags On Docker Hub, you'll see both architectures listed for each tag. @@ -232,6 +312,12 @@ docker login # Enter your Docker Hub credentials ``` +### "no builder selected" error +```bash +docker buildx create --name multiplatform-builder --use +docker buildx inspect --bootstrap +``` + ### Build Fails ```bash # Check Docker is running @@ -253,6 +339,17 @@ docker buildx build --no-cache \ . ``` +### Build is Very Slow +- First build downloads base images for both platforms (8-10 minutes) +- Subsequent builds use cache (3-5 minutes) +- Enable Docker BuildKit caching +- Check internet connection speed + +### Can't Find Image Locally After Build +- Multi-platform builds don't load locally by default +- Pull the image: `docker pull carloscastrotrejo/logicapps-dev:v2.0.0` +- Or build single-platform for testing: `docker build -t test .` + ### Push Fails ```bash # Verify authentication @@ -265,6 +362,11 @@ docker images carloscastrotrejo/logicapps-dev docker push carloscastrotrejo/logicapps-dev:latest ``` +### Platform Mismatch After Multi-Platform Build +- Shouldn't happen! The manifest list handles this automatically +- Verify manifest: `docker buildx imagetools inspect image:tag` +- Re-pull the image: `docker pull --rm image:tag && docker pull image:tag` + ## 📋 What's Included in the Image - ✅ **Node.js 22** (Bookworm base) @@ -287,16 +389,101 @@ When you need to update the image: 4. **Update documentation** (this README) with new version numbers 5. **Notify team** to pull the latest image -## 📊 Image Size Optimization Tips +## 📊 Image Size & Performance Optimization -- Current build uses multi-stage patterns where possible -- Cleans up apt cache to reduce size -- Combines RUN commands to minimize layers +### Current Optimization +- Multi-stage build patterns where possible +- Combined RUN commands to minimize layers +- Cleaned up apt cache to reduce size - Consider using `.dockerignore` if building from a larger context +### Cost Considerations + +#### Build Time +- ~2x longer due to building twice (once per platform) +- First build: ~8-10 minutes (downloading base layers) +- Subsequent builds: ~3-5 minutes (with cache) +- Can be parallelized in CI/CD with separate jobs + +#### Storage +- Docker Hub storage roughly doubles (two platform images) +- Free tier: 1 private repo + unlimited public repos +- Public repos have unlimited storage + +#### Bandwidth +- Users only download their platform (same as before) +- Total registry bandwidth: ~2x (but spread across platforms) + +## 🎯 Best Practices + +### 1. Always Use Versioned Tags +```bash +./build-and-push.sh v2.0.0 # Good - traceable +./build-and-push.sh 1.131.9 # Good - matches Extension Bundle version +./build-and-push.sh latest # OK but less traceable +``` + +### 2. Test Both Platforms +After pushing, test on different architectures: +```bash +# On Intel Mac/PC +docker pull --platform linux/amd64 carloscastrotrejo/logicapps-dev:v2.0.0 +docker run --rm -it carloscastrotrejo/logicapps-dev:v2.0.0 func --version + +# On Apple Silicon +docker pull --platform linux/arm64 carloscastrotrejo/logicapps-dev:v2.0.0 +docker run --rm -it carloscastrotrejo/logicapps-dev:v2.0.0 func --version +``` + +### 3. Monitor Build Times +- Multi-platform builds take longer than single-platform +- Use BuildKit caching for faster subsequent builds +- Consider separating test builds from production builds + +### 4. Keep Buildx Builder Updated +Periodically recreate the builder for latest features: +```bash +docker buildx rm multiplatform-builder +docker buildx create --name multiplatform-builder --use +docker buildx inspect --bootstrap +``` + ## 🔐 Security Notes - Image is based on official Microsoft DevContainer images - Uses official Azure Functions Core Tools releases - Extension bundles are downloaded from official Azure CDN - Keep versions updated for security patches + +## 🚀 Advanced: Adding More Platforms + +To support additional platforms beyond amd64 and arm64: + +```bash +docker buildx build \ + --platform linux/amd64,linux/arm64,linux/arm/v7 \ + -t carloscastrotrejo/logicapps-dev:v2.0.0 \ + --push \ + . +``` + +### Common Platforms + +- `linux/amd64` - Intel/AMD 64-bit (most servers, PCs) +- `linux/arm64` - ARM 64-bit (Apple Silicon, ARM servers) +- `linux/arm/v7` - ARM 32-bit (Raspberry Pi, IoT devices) +- `linux/386` - Intel 32-bit (legacy systems) + +## 📚 References + +- [Docker Buildx Documentation](https://docs.docker.com/buildx/working-with-buildx/) +- [Multi-platform Images Guide](https://docs.docker.com/build/building/multi-platform/) +- [Docker Manifest Lists Specification](https://docs.docker.com/registry/spec/manifest-v2-2/) +- [BuildKit Documentation](https://github.com/moby/buildkit) +- [Azure Functions Core Tools](https://github.com/Azure/azure-functions-core-tools) + +--- + +## 📖 Additional Documentation + +For more detailed information about the multi-platform implementation, see the original migration notes in git history. From eafdb45872944132a00d44e0503f2056ad59f9ff Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Tue, 7 Oct 2025 21:33:32 -0400 Subject: [PATCH 33/46] Update readme and docker file --- .../src/assets/container/Dockerfile | 40 +++++- .../src/assets/container/README.md | 114 +++++++++++------- .../src/assets/container/devcontainer.json | 11 +- 3 files changed, 109 insertions(+), 56 deletions(-) diff --git a/apps/vs-code-designer/src/assets/container/Dockerfile b/apps/vs-code-designer/src/assets/container/Dockerfile index 1354ace32a8..920d77c9699 100644 --- a/apps/vs-code-designer/src/assets/container/Dockerfile +++ b/apps/vs-code-designer/src/assets/container/Dockerfile @@ -16,6 +16,12 @@ ARG FUNCTIONS_CORE_TOOLS_OS_PLATFORM=linux ARG FUNCTIONS_CORE_TOOLS_ARCH=x64 ARG FUNCTIONS_CORE_TOOLS_FOLDER_PATH=.azurelogicapps/dependencies/FuncCoreTools +# ----------------------------- +# .NET SDK versions +# ----------------------------- +ARG DOTNET_VERSION_8=8.0 +ARG DOTNET_VERSION_6=6.0 + # ----------------------------- # OS deps + install everything # ----------------------------- @@ -26,6 +32,24 @@ RUN set -eux; \ libc6 libicu72 libgssapi-krb5-2 libkrb5-3 zlib1g; \ rm -rf /var/lib/apt/lists/* +# ----------------------------- +# Install .NET SDK 8.0 and 6.0 +# ----------------------------- +RUN set -eux; \ + # Add Microsoft package repository + wget https://packages.microsoft.com/config/debian/12/packages-microsoft-prod.deb -O /tmp/packages-microsoft-prod.deb; \ + dpkg -i /tmp/packages-microsoft-prod.deb; \ + rm /tmp/packages-microsoft-prod.deb; \ + # Update and install .NET SDKs + apt-get update; \ + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + dotnet-sdk-8.0 \ + dotnet-sdk-6.0; \ + rm -rf /var/lib/apt/lists/*; \ + # Verify installations + dotnet --version; \ + dotnet --list-sdks + # ----------------------------- # Download & unpack extension bundle # ----------------------------- @@ -67,12 +91,18 @@ RUN set -eux; \ # Verify CLI is on PATH (skipped during build due to Rosetta issues on ARM) # The func command will work when container runs, just not during build verification # ----------------------------- -# RUN set -eux; \ -# which func; \ -# func --version -# Ensure Core Tools are discoverable for all users -ENV PATH=/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}:$PATH +# ----------------------------- +# Environment variables +# ----------------------------- +# Ensure Core Tools and .NET are discoverable for all users +ENV PATH=/${FUNCTIONS_CORE_TOOLS_FOLDER_PATH}:/usr/share/dotnet:$PATH + +# Set DOTNET environment variables +ENV DOTNET_CLI_TELEMETRY_OPTOUT=1 \ + DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 \ + DOTNET_NOLOGO=1 \ + DOTNET_ROOT=/usr/share/dotnet # ----------------------------- # Keep container running diff --git a/apps/vs-code-designer/src/assets/container/README.md b/apps/vs-code-designer/src/assets/container/README.md index 70f06a497d4..fcefb5d8b32 100644 --- a/apps/vs-code-designer/src/assets/container/README.md +++ b/apps/vs-code-designer/src/assets/container/README.md @@ -1,7 +1,79 @@ -# Docker Container Build & Push Guide +# Docker Container This directory contains the Docker configuration for the Logic Apps Standard Development container. + +## 🔄 Complete Execution Flow + +Understanding how Dockerfile, docker-compose.yml, and devcontainer.json work together: + +``` +┌─────────────────────────────────────────────────────────────┐ +│ 1. BUILD PHASE (One-time or when Dockerfile changes) │ +└─────────────────────────────────────────────────────────────┘ + │ + ├─> Dockerfile executes line by line + │ ├─> FROM: Pull base image (Node.js 22 Debian) + │ ├─> RUN: Install OS packages + │ ├─> RUN: Install .NET SDK 8.0 & 6.0 + │ ├─> RUN: Download Extension Bundle + │ ├─> RUN: Download & install Functions Core Tools + │ └─> ENV: Set environment variables (PATH, DOTNET_ROOT) + │ + └─> Output: Docker image ready to use + ✅ Node.js 22 + ✅ .NET SDK 8.0 & 6.0 + ✅ Functions Core Tools 4.2.2 + ✅ Extension Bundle 1.131.9 + +┌─────────────────────────────────────────────────────────────┐ +│ 2. START PHASE (Every time you start the container) │ +└─────────────────────────────────────────────────────────────┘ + │ + ├─> docker-compose.yml executes + │ ├─> Create container from image + │ ├─> Mount volumes (your code) + │ ├─> Setup network with azurite + │ └─> Run: sleep infinity (keeps container alive) + │ + └─> Container is running with your workspace mounted + +┌─────────────────────────────────────────────────────────────┐ +│ 3. DEVCONTAINER PHASE (When VS Code connects) │ +└─────────────────────────────────────────────────────────────┘ + │ + ├─> devcontainer.json applies + │ ├─> Install features (Azure CLI, PowerShell) + │ ├─> Install VS Code extensions + │ ├─> Apply VS Code settings + │ └─> Run postStartCommand (start Azurite) + │ + └─> Development environment ready! 🎉 + ✅ All tools from Dockerfile (Node, .NET, func) + ✅ Azure CLI & PowerShell installed + ✅ VS Code extensions loaded + ✅ Azurite running +``` + +### ⚡ Key Points + +- **Dockerfile** = Heavy, slow installations (cached in image) +- **docker-compose.yml** = Runtime configuration (mounts, networking) +- **devcontainer.json** = Quick dev tools & VS Code customization + +### 📊 What Gets Installed Where + +| Component | Where | Why | +|-----------|-------|-----| +| **.NET SDK 8.0 & 6.0** | Dockerfile | Slow to install, rarely changes | +| **Functions Core Tools** | Dockerfile | Core dependency, specific version | +| **Extension Bundle** | Dockerfile | Large download, rarely changes | +| **Azure CLI** | devcontainer.json | Quick install, dev-only tool | +| **PowerShell + Az** | devcontainer.json | Quick install, dev-only tool | +| **VS Code Extensions** | devcontainer.json | User-specific preferences | + +--- + ## 📦 Repository Information - **Docker Hub Repository**: `carloscastrotrejo/logicapps-dev` @@ -447,43 +519,3 @@ docker buildx rm multiplatform-builder docker buildx create --name multiplatform-builder --use docker buildx inspect --bootstrap ``` - -## 🔐 Security Notes - -- Image is based on official Microsoft DevContainer images -- Uses official Azure Functions Core Tools releases -- Extension bundles are downloaded from official Azure CDN -- Keep versions updated for security patches - -## 🚀 Advanced: Adding More Platforms - -To support additional platforms beyond amd64 and arm64: - -```bash -docker buildx build \ - --platform linux/amd64,linux/arm64,linux/arm/v7 \ - -t carloscastrotrejo/logicapps-dev:v2.0.0 \ - --push \ - . -``` - -### Common Platforms - -- `linux/amd64` - Intel/AMD 64-bit (most servers, PCs) -- `linux/arm64` - ARM 64-bit (Apple Silicon, ARM servers) -- `linux/arm/v7` - ARM 32-bit (Raspberry Pi, IoT devices) -- `linux/386` - Intel 32-bit (legacy systems) - -## 📚 References - -- [Docker Buildx Documentation](https://docs.docker.com/buildx/working-with-buildx/) -- [Multi-platform Images Guide](https://docs.docker.com/build/building/multi-platform/) -- [Docker Manifest Lists Specification](https://docs.docker.com/registry/spec/manifest-v2-2/) -- [BuildKit Documentation](https://github.com/moby/buildkit) -- [Azure Functions Core Tools](https://github.com/Azure/azure-functions-core-tools) - ---- - -## 📖 Additional Documentation - -For more detailed information about the multi-platform implementation, see the original migration notes in git history. diff --git a/apps/vs-code-designer/src/assets/container/devcontainer.json b/apps/vs-code-designer/src/assets/container/devcontainer.json index eb37c3bcea5..9661c2e1096 100644 --- a/apps/vs-code-designer/src/assets/container/devcontainer.json +++ b/apps/vs-code-designer/src/assets/container/devcontainer.json @@ -7,15 +7,6 @@ "ghcr.io/devcontainers/features/azure-cli:1": { "version": "latest" }, - "ghcr.io/devcontainers/features/dotnet:2": { - "version": "8.0", - "additionalVersions": "6.0", - "installUsingApt": true, - "globalTools": "" - }, - "ghcr.io/jlaundry/devcontainer-features/azure-functions-core-tools:1": { - "version": "4" - }, "ghcr.io/devcontainers/features/powershell:1": { "version": "latest", "modules": "Az" @@ -45,4 +36,4 @@ "otherPortsAttributes": { "onAutoForward": "silent" } -} +} \ No newline at end of file From 2e189db636a814b53e0c568e672b4cac4477913e Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Tue, 7 Oct 2025 21:36:45 -0400 Subject: [PATCH 34/46] Update read me --- .../src/assets/container/README.md | 450 ++++++------------ 1 file changed, 140 insertions(+), 310 deletions(-) diff --git a/apps/vs-code-designer/src/assets/container/README.md b/apps/vs-code-designer/src/assets/container/README.md index fcefb5d8b32..b84b7c6c040 100644 --- a/apps/vs-code-designer/src/assets/container/README.md +++ b/apps/vs-code-designer/src/assets/container/README.md @@ -1,9 +1,24 @@ -# Docker Container +# Logic Apps Development Container This directory contains the Docker configuration for the Logic Apps Standard Development container. +## 📦 What's Inside -## 🔄 Complete Execution Flow +**Current Image Configuration:** +- **Base Image**: `mcr.microsoft.com/devcontainers/javascript-node:1-22-bookworm` +- **Node.js**: 22 (Debian Bookworm) +- **.NET SDK**: 8.0 & 6.0 +- **Functions Core Tools**: 4.2.2 +- **Extension Bundle**: 1.131.9 +- **Platforms**: `linux/amd64`, `linux/arm64` + +**Docker Hub:** +- **Repository**: `carloscastrotrejo/logicapps-dev` +- **URL**: https://hub.docker.com/r/carloscastrotrejo/logicapps-dev + +--- + +## 🔄 How It Works: Complete Execution Flow Understanding how Dockerfile, docker-compose.yml, and devcontainer.json work together: @@ -74,118 +89,119 @@ Understanding how Dockerfile, docker-compose.yml, and devcontainer.json work tog --- -## 📦 Repository Information - -- **Docker Hub Repository**: `carloscastrotrejo/logicapps-dev` -- **Public URL**: https://hub.docker.com/r/carloscastrotrejo/logicapps-dev -- **Supported Platforms**: - - `linux/amd64` (Intel/AMD processors) - - `linux/arm64` (Apple Silicon M1/M2/M3, ARM servers) - ## 🌐 Multi-Platform Support -The image is built using **Docker buildx** to create multi-platform images that work seamlessly on both Intel/AMD and ARM architectures. When users pull the image, Docker automatically downloads the correct architecture for their platform - no manual selection needed! +The image is built using **Docker buildx** to create multi-platform images that work seamlessly on both Intel/AMD and ARM architectures. ### Benefits -✅ **Single Image Tag**: One tag (e.g., `v1.0.0`) works for all platforms -✅ **Automatic Detection**: Docker automatically pulls the right architecture -✅ **Better Performance**: Native execution on both Intel and ARM processors -✅ **No Platform Warnings**: Eliminates "platform mismatch" warnings -✅ **Future-Proof**: Ready for ARM-based cloud infrastructure +✅ **Automatic Detection** - Docker pulls the correct architecture for your platform +✅ **Better Performance** - Native execution on both Intel and ARM processors +✅ **No Platform Warnings** - Eliminates "platform mismatch" warnings +✅ **Single Image Tag** - One tag works for all platforms -### How It Works +### Platform Detection -Docker buildx creates a **manifest list** containing images for multiple architectures: +- **Intel/AMD Macs & PCs**: Automatically pulls `linux/amd64` +- **Apple Silicon (M1/M2/M3)**: Automatically pulls `linux/arm64` +- **ARM Servers**: Automatically pulls `linux/arm64` -``` -carloscastrotrejo/logicapps-dev:v2.0.0 -├── linux/amd64 -│ └── [image layers for Intel/AMD] -└── linux/arm64 - └── [image layers for ARM] -``` +**No need to specify `--platform` - Docker handles it automatically!** + +--- + +## 🚀 For Developers: Using the Image + +### Pull the Pre-Built Image -When you run: ```bash +# Pull latest version (auto-detects your platform) docker pull carloscastrotrejo/logicapps-dev:latest + +# Pull specific version +docker pull carloscastrotrejo/logicapps-dev:v1.0.0 + +# Verify the platform +docker image inspect carloscastrotrejo/logicapps-dev:latest | grep Architecture ``` -Docker: -1. Fetches the manifest list -2. Identifies your system architecture (e.g., `linux/arm64` on Apple Silicon) -3. Downloads only the matching architecture -4. Stores it locally +### Use with Dev Containers -**The user never needs to specify `--platform`!** +Your `devcontainer.json` is already configured to build locally. To use the pre-built image instead: -### What Changed from Single Platform? +```json +{ + "name": "Logic Apps Standard Development", + "image": "carloscastrotrejo/logicapps-dev:latest", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + "features": { + "ghcr.io/devcontainers/features/azure-cli:1": { + "version": "latest" + }, + "ghcr.io/devcontainers/features/powershell:1": { + "version": "latest", + "modules": "Az" + } + } + // ... rest of your config +} +``` -| Aspect | Before (Single Platform) | After (Multi-Platform) | -|--------|--------------------------|------------------------| -| Platforms | Only `linux/amd64` | Both `amd64` + `arm64` | -| ARM Performance | Emulation (slow) | Native (fast) | -| Warnings | Platform mismatch warnings | No warnings | -| Build time | ~2-3 minutes | ~5-8 minutes | -| Push method | `docker push` | Built into `buildx build --push` | -| Local testing | Image stored locally | Must pull from registry | +Or update `docker-compose.yml`: -## 🚀 Quick Start - Build & Push +```yaml +services: + app: + image: carloscastrotrejo/logicapps-dev:latest + platform: linux/amd64 + volumes: + - ../..:/workspaces:cached + command: sleep infinity + network_mode: service:azurite +``` + +--- + +## 🛠️ For Maintainers: Building & Publishing ### Prerequisites 1. Docker Desktop installed and running -2. Docker Hub account (carloscastrotrejo) -3. Logged into Docker Hub: +2. Docker Hub account +3. Logged in: ```bash docker login ``` -### Build and Push with Script +### Quick Build & Push -Use the provided script to build and push in one command: +Use the provided script: ```bash # Push as latest ./build-and-push.sh -# Push with a specific version tag +# Push with specific version ./build-and-push.sh v1.0.0 -# Push with semantic version +# Push matching Extension Bundle version ./build-and-push.sh 1.131.9 ``` -The script will: -1. ✅ Verify Docker is running -2. ✅ Check Docker Hub authentication -3. 🔧 Setup Docker buildx for multi-platform builds -4. 🔨 Build the image for **both amd64 and arm64** architectures -5. 🚀 Push to Docker Hub with manifest supporting both platforms - -**Note**: Multi-platform builds take longer (5-8 minutes) because they build for multiple architectures. First build may take 8-10 minutes while downloading base layers. - -### Understanding Docker Buildx - -Docker buildx is a CLI plugin that extends Docker's build capabilities with: -- **Multi-platform image builds** - Build for multiple architectures simultaneously -- **BuildKit backend** - Improved performance and caching -- **Manifest lists** - Single tag supports multiple architectures - -### Why `--push` is Required - -With multi-platform builds: -- Images are built in the buildx cache, not loaded locally -- You can't use `docker images` to see them immediately -- Must push directly to registry with `--push` flag -- To test locally, pull the image back: `docker pull carloscastrotrejo/logicapps-dev:test` +The script automatically: +1. Verifies Docker is running +2. Checks Docker Hub authentication +3. Sets up Docker buildx for multi-platform builds +4. Builds for **both amd64 and arm64** architectures +5. Pushes to Docker Hub -## 📝 Manual Build & Push (Alternative) +**Build Time:** +- First build: ~8-10 minutes (downloading base layers) +- Subsequent builds: ~3-5 minutes (with cache) -If you prefer to run commands manually with multi-platform support: +### Manual Build (Advanced) ```bash -# Navigate to the container directory cd apps/vs-code-designer/src/assets/container/ # Create and use buildx builder (first time only) @@ -201,31 +217,9 @@ docker buildx build \ . ``` -### Build Script Changes Explained +### Single Platform Build (Testing) -**Old single-platform approach:** -```bash -docker build --platform linux/amd64 -t image:tag . -docker push image:tag -``` - -**New multi-platform approach:** -```bash -# Setup buildx builder (one-time) -docker buildx create --name multiplatform-builder --use -docker buildx inspect --bootstrap - -# Build and push for multiple platforms -docker buildx build \ - --platform linux/amd64,linux/arm64 \ - -t image:tag \ - --push \ - . -``` - -### Single Platform Build (Faster for Testing) - -For faster local testing, you can build for just your platform: +For faster local testing: ```bash # Build only for your current platform @@ -235,156 +229,52 @@ docker build -t carloscastrotrejo/logicapps-dev:test . docker build --platform linux/amd64 -t carloscastrotrejo/logicapps-dev:test . ``` -## 🔢 Version Management - -### Recommended Versioning Strategy - -Use semantic versioning aligned with the Extension Bundle version: +### Verify Published Image ```bash -# Format: MAJOR.MINOR.PATCH -./build-and-push.sh 1.131.9 # Matches EXTENSION_BUNDLE_VERSION - -# Alternative formats: -./build-and-push.sh v1.131.9 # With 'v' prefix -./build-and-push.sh 1.0.0 # Simple semantic version -./build-and-push.sh latest # Latest tag only -``` - -### Version Tracking - -Current image configuration: -- **Extension Bundle Version**: 1.131.9 -- **Functions Core Tools Version**: 4.2.2 -- **Node Version**: 22 (bookworm) -- **Base Image**: `mcr.microsoft.com/devcontainers/javascript-node:1-22-bookworm` - -When you update versions in the Dockerfile, update the image tag accordingly. - -## 👥 For Team Members - Pulling the Image - -Team members can pull and use the image in several ways. **Docker automatically detects and pulls the correct architecture** for their platform! - -### Option 1: Pull Directly - -```bash -# Pull latest version (auto-detects your platform) -docker pull carloscastrotrejo/logicapps-dev:latest - -# Pull specific version -docker pull carloscastrotrejo/logicapps-dev:v1.0.0 - -# Verify the platform -docker image inspect carloscastrotrejo/logicapps-dev:latest | grep Architecture -``` - -### Platform Detection - -- **Intel/AMD Macs & PCs**: Automatically pulls `linux/amd64` -- **Apple Silicon (M1/M2/M3)**: Automatically pulls `linux/arm64` -- **ARM Servers**: Automatically pulls `linux/arm64` - -No need to specify `--platform` - Docker handles it automatically! - -### Option 2: Use in devcontainer.json - -Update your `devcontainer.json` to use the pre-built image instead of building locally: - -**Before (building locally):** -```json -{ - "name": "Logic Apps Standard Development", - "dockerComposeFile": "docker-compose.yml", - "service": "app", - "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}" -} -``` +# Inspect image details (shows supported platforms) +docker buildx imagetools inspect carloscastrotrejo/logicapps-dev:latest -**After (using pre-built image):** -```json -{ - "name": "Logic Apps Standard Development", - "image": "carloscastrotrejo/logicapps-dev:latest", - "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", - "features": { - // ... same features as before - } -} +# Check locally pulled platform +docker image inspect carloscastrotrejo/logicapps-dev:latest | grep -A 3 "Architecture" ``` -### Option 3: Update docker-compose.yml - -Modify `docker-compose.yml` to use the pre-built image: - -**Before:** -```yaml -services: - app: - build: - context: . - dockerfile: Dockerfile -``` +--- -**After:** -```yaml -services: - app: - image: carloscastrotrejo/logicapps-dev:latest - # or use a specific version: - # image: carloscastrotrejo/logicapps-dev:v1.0.0 -``` +## 🔢 Version Management -## 🔍 Verify Published Image +### Versioning Strategy -Check your multi-platform image on Docker Hub: +Use semantic versioning aligned with the Extension Bundle version: ```bash -# View local images -docker images carloscastrotrejo/logicapps-dev - -# Inspect image details (shows supported platforms) -docker buildx imagetools inspect carloscastrotrejo/logicapps-dev:latest -``` - -**Example output showing both platforms:** -``` -MediaType: application/vnd.docker.distribution.manifest.list.v2+json -Digest: sha256:abc123... - -Manifests: - Name: carloscastrotrejo/logicapps-dev:latest@sha256:xyz789... - MediaType: application/vnd.docker.distribution.manifest.v2+json - Platform: linux/amd64 - - Name: carloscastrotrejo/logicapps-dev:latest@sha256:def456... - MediaType: application/vnd.docker.distribution.manifest.v2+json - Platform: linux/arm64 +./build-and-push.sh 1.131.9 # Matches EXTENSION_BUNDLE_VERSION +./build-and-push.sh v1.131.9 # With 'v' prefix +./build-and-push.sh latest # Latest tag only ``` -```bash -# Check what platform you pulled locally -docker image inspect carloscastrotrejo/logicapps-dev:latest | grep -A 3 "Architecture" -``` +### Updating the Image -**Output on Apple Silicon:** -```json -"Architecture": "arm64", -"Os": "linux", -``` +When updating versions: -Or visit: https://hub.docker.com/r/carloscastrotrejo/logicapps-dev/tags +1. **Update `Dockerfile`** with new versions (Extension Bundle, Core Tools, .NET) +2. **Update this README** with new version numbers +3. **Build and push**: + ```bash + ./build-and-push.sh 1.132.0 + ``` +4. **Notify team** to pull the latest image -On Docker Hub, you'll see both architectures listed for each tag. +--- ## 🛠️ Troubleshooting ### Not Logged In ```bash docker login -# Enter your Docker Hub credentials ``` -### "no builder selected" error +### "no builder selected" Error ```bash docker buildx create --name multiplatform-builder --use docker buildx inspect --bootstrap @@ -395,9 +285,6 @@ docker buildx inspect --bootstrap # Check Docker is running docker info -# Ensure buildx is available -docker buildx version - # Clean up and recreate builder docker buildx rm multiplatform-builder docker buildx create --name multiplatform-builder --use @@ -411,111 +298,54 @@ docker buildx build --no-cache \ . ``` -### Build is Very Slow -- First build downloads base images for both platforms (8-10 minutes) -- Subsequent builds use cache (3-5 minutes) -- Enable Docker BuildKit caching -- Check internet connection speed - ### Can't Find Image Locally After Build -- Multi-platform builds don't load locally by default -- Pull the image: `docker pull carloscastrotrejo/logicapps-dev:v2.0.0` -- Or build single-platform for testing: `docker build -t test .` - -### Push Fails +Multi-platform builds don't load locally by default. Pull the image: ```bash -# Verify authentication -docker login - -# Check image exists locally -docker images carloscastrotrejo/logicapps-dev - -# Try pushing again -docker push carloscastrotrejo/logicapps-dev:latest +docker pull carloscastrotrejo/logicapps-dev:v1.0.0 ``` -### Platform Mismatch After Multi-Platform Build -- Shouldn't happen! The manifest list handles this automatically -- Verify manifest: `docker buildx imagetools inspect image:tag` -- Re-pull the image: `docker pull --rm image:tag && docker pull image:tag` - -## 📋 What's Included in the Image - -- ✅ **Node.js 22** (Bookworm base) -- ✅ **Azure Functions Core Tools v4.2.2** -- ✅ **Extension Bundle for Workflows v1.131.9** -- ✅ **System dependencies**: ca-certificates, curl, jq, gnupg, wget, unzip -- ✅ **Runtime libraries**: libc6, libicu72, libgssapi-krb5-2, libkrb5-3, zlib1g -- ✅ **Configured paths** for `func` CLI - -## 🔄 Updating the Image - -When you need to update the image: - -1. **Update the Dockerfile** with new versions (Extension Bundle, Core Tools, etc.) -2. **Increment the version** number -3. **Build and push**: - ```bash - ./build-and-push.sh 1.132.0 # New version - ``` -4. **Update documentation** (this README) with new version numbers -5. **Notify team** to pull the latest image - -## 📊 Image Size & Performance Optimization - -### Current Optimization -- Multi-stage build patterns where possible -- Combined RUN commands to minimize layers -- Cleaned up apt cache to reduce size -- Consider using `.dockerignore` if building from a larger context - -### Cost Considerations - -#### Build Time -- ~2x longer due to building twice (once per platform) -- First build: ~8-10 minutes (downloading base layers) -- Subsequent builds: ~3-5 minutes (with cache) -- Can be parallelized in CI/CD with separate jobs - -#### Storage -- Docker Hub storage roughly doubles (two platform images) -- Free tier: 1 private repo + unlimited public repos -- Public repos have unlimited storage +### Build is Slow +- First build downloads base images for both platforms (8-10 minutes) +- Subsequent builds use cache (3-5 minutes) +- Check internet connection speed -#### Bandwidth -- Users only download their platform (same as before) -- Total registry bandwidth: ~2x (but spread across platforms) +--- ## 🎯 Best Practices -### 1. Always Use Versioned Tags +### 1. Use Versioned Tags ```bash ./build-and-push.sh v2.0.0 # Good - traceable -./build-and-push.sh 1.131.9 # Good - matches Extension Bundle version -./build-and-push.sh latest # OK but less traceable +./build-and-push.sh 1.131.9 # Good - matches Extension Bundle +./build-and-push.sh latest # Less traceable ``` ### 2. Test Both Platforms -After pushing, test on different architectures: ```bash -# On Intel Mac/PC +# Test amd64 docker pull --platform linux/amd64 carloscastrotrejo/logicapps-dev:v2.0.0 docker run --rm -it carloscastrotrejo/logicapps-dev:v2.0.0 func --version +docker run --rm -it carloscastrotrejo/logicapps-dev:v2.0.0 dotnet --version -# On Apple Silicon +# Test arm64 docker pull --platform linux/arm64 carloscastrotrejo/logicapps-dev:v2.0.0 docker run --rm -it carloscastrotrejo/logicapps-dev:v2.0.0 func --version +docker run --rm -it carloscastrotrejo/logicapps-dev:v2.0.0 dotnet --version ``` -### 3. Monitor Build Times -- Multi-platform builds take longer than single-platform -- Use BuildKit caching for faster subsequent builds -- Consider separating test builds from production builds - -### 4. Keep Buildx Builder Updated -Periodically recreate the builder for latest features: +### 3. Keep Builder Updated +Periodically recreate the builder: ```bash docker buildx rm multiplatform-builder docker buildx create --name multiplatform-builder --use docker buildx inspect --bootstrap ``` + +--- + +## 📚 References + +- [Docker Buildx Documentation](https://docs.docker.com/buildx/working-with-buildx/) +- [Multi-platform Images Guide](https://docs.docker.com/build/building/multi-platform/) +- [Azure Functions Core Tools](https://github.com/Azure/azure-functions-core-tools) +- [Docker Hub Repository](https://hub.docker.com/r/carloscastrotrejo/logicapps-dev) \ No newline at end of file From ca708f8f22409502fda72c3e6ffeda2ed383c9c1 Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Tue, 7 Oct 2025 21:46:11 -0400 Subject: [PATCH 35/46] update docker file --- .../src/assets/container/Dockerfile | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/apps/vs-code-designer/src/assets/container/Dockerfile b/apps/vs-code-designer/src/assets/container/Dockerfile index 920d77c9699..76bebd099b4 100644 --- a/apps/vs-code-designer/src/assets/container/Dockerfile +++ b/apps/vs-code-designer/src/assets/container/Dockerfile @@ -36,16 +36,23 @@ RUN set -eux; \ # Install .NET SDK 8.0 and 6.0 # ----------------------------- RUN set -eux; \ - # Add Microsoft package repository - wget https://packages.microsoft.com/config/debian/12/packages-microsoft-prod.deb -O /tmp/packages-microsoft-prod.deb; \ - dpkg -i /tmp/packages-microsoft-prod.deb; \ - rm /tmp/packages-microsoft-prod.deb; \ - # Update and install .NET SDKs - apt-get update; \ - DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ - dotnet-sdk-8.0 \ - dotnet-sdk-6.0; \ - rm -rf /var/lib/apt/lists/*; \ + ARCH="$(dpkg --print-architecture)"; \ + if [ "$ARCH" = "amd64" ]; then \ + # AMD64: Use APT packages + wget https://packages.microsoft.com/config/debian/12/packages-microsoft-prod.deb -O /tmp/packages-microsoft-prod.deb; \ + dpkg -i /tmp/packages-microsoft-prod.deb; \ + rm /tmp/packages-microsoft-prod.deb; \ + apt-get update; \ + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + dotnet-sdk-8.0 \ + dotnet-sdk-6.0; \ + rm -rf /var/lib/apt/lists/*; \ + elif [ "$ARCH" = "arm64" ]; then \ + # ARM64: Use manual installation script + curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --channel 8.0 --install-dir /usr/share/dotnet; \ + curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --channel 6.0 --install-dir /usr/share/dotnet; \ + ln -s /usr/share/dotnet/dotnet /usr/bin/dotnet; \ + fi; \ # Verify installations dotnet --version; \ dotnet --list-sdks From ad0e994b3771e4ccaa72b4ea3fb521ec87ad3d79 Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Wed, 8 Oct 2025 11:55:39 -0400 Subject: [PATCH 36/46] Revert back md file changes --- LESS_FILES_MIGRATION_ANALYSIS.md | 2 +- LESS_TO_MAKESTYLES_DETAILED_MIGRATION_PLAN.md | 4 ++-- LESS_TO_MAKESTYLES_MIGRATION_PLAN.md | 6 +++--- MIGRATION_DEPENDENCY_GRAPH.md | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/LESS_FILES_MIGRATION_ANALYSIS.md b/LESS_FILES_MIGRATION_ANALYSIS.md index 5020167f9ee..f3c06063231 100644 --- a/LESS_FILES_MIGRATION_ANALYSIS.md +++ b/LESS_FILES_MIGRATION_ANALYSIS.md @@ -15,7 +15,7 @@ This document provides a detailed analysis of all 124 LESS files in the LogicApp - ✅ **reviewList styles.less (32 lines) - REMOVED ENTIRELY** - apps/vs-code-react → reviewListStyles.ts (PR #7907) - ✅ **VS Code styles.less (5 lines) - REMOVED ENTIRELY** - apps/vs-code-react → inline HTML styles - ✅ SVG icon migration (3 files removed) - apps/vs-code-react -- ✅ **nodeSearchPanel** - NEW makeStyles implementation with Tabster focus management +- ✅ **nodeSearchPanel** - NEW makeStyles implementation with Tabster focus management (branch: ccastrotrejo/panelSearchMigration) - ✅ **Fluent UI v8 to v9 Component Migrations**: - SearchableDropdown: Complete migration with proper key handling and Fluent UI v9 patterns - ShimmeredDetailsList → Table: Native Fluent UI v9 table with column resizing diff --git a/LESS_TO_MAKESTYLES_DETAILED_MIGRATION_PLAN.md b/LESS_TO_MAKESTYLES_DETAILED_MIGRATION_PLAN.md index 8f0e20f3a0e..9200369da61 100644 --- a/LESS_TO_MAKESTYLES_DETAILED_MIGRATION_PLAN.md +++ b/LESS_TO_MAKESTYLES_DETAILED_MIGRATION_PLAN.md @@ -426,7 +426,7 @@ This document provides a detailed, granular breakdown of the LESS to makeStyles - In Progress: 5 - Blocked: 0 -### Recently Completed (PRs #7588, #7797, #7820, #7907) +### Recently Completed (PRs #7588, #7797, #7820, #7907, Branch: ccastrotrejo/panelSearchMigration) - ✅ VS Code React export.less → exportStyles.ts (PR #7588, #7797) - ✅ VS Code React overview.less → overviewStyles.ts (PR #7588) - ✅ VS Code React reviewList component styles → reviewListStyles.ts (PR #7907) - **COMPLEX MIGRATION** @@ -437,7 +437,7 @@ This document provides a detailed, granular breakdown of the LESS to makeStyles - Updated all consuming components (validation.tsx, review/index.tsx) - Enhanced accessibility with proper ARIA labels and tree navigation - ✅ SVG icon migration to Fluent UI icons (PR #7820) -- ✅ **nodeSearchPanel component**: New makeStyles implementation with Tabster focus management +- ✅ **nodeSearchPanel component**: New makeStyles implementation with Tabster focus management (Branch: ccastrotrejo/panelSearchMigration) - Migrated from Fluent UI v8 `FocusTrapZone` to Tabster for better accessibility - Added new dependency: `tabster: 8.5.6` - Created `nodeSearchPanelStyles.ts` with makeStyles for SearchBox styling diff --git a/LESS_TO_MAKESTYLES_MIGRATION_PLAN.md b/LESS_TO_MAKESTYLES_MIGRATION_PLAN.md index 5b61b7eb8ab..6679a2167b8 100644 --- a/LESS_TO_MAKESTYLES_MIGRATION_PLAN.md +++ b/LESS_TO_MAKESTYLES_MIGRATION_PLAN.md @@ -33,11 +33,11 @@ This document outlines a comprehensive plan to migrate 124 .less files in the Lo - ✅ flyout component (flyout.less - 50 lines) - already had makeStyles, verified - ✅ pager component (pager.less - 84 lines) - ✅ staticResult component (staticResult.less - 146 lines) - styles created -- ✅ **nodeSearchPanel** - NEW makeStyles implementation with Tabster focus management +- ✅ **nodeSearchPanel** - NEW makeStyles implementation with Tabster focus management (branch: ccastrotrejo/panelSearchMigration) - ✅ **VS CODE**: export component (export.less - 120 lines) → exportStyles.ts (PR #7588/#7797) - ✅ **VS CODE**: overview app (overview.less - 4 lines) → overviewStyles.ts (PR #7588) - ✅ **VS CODE**: reviewList component (styles.less - 32 lines) → reviewListStyles.ts (PR #7907) - **COMPLEX MIGRATION** -- ✅ **VS CODE**: root styles.less (5 lines) → **REMOVED ENTIRELY** - inline HTML styles +- ✅ **VS CODE**: root styles.less (5 lines) → **REMOVED ENTIRELY** - inline HTML styles (ccastrotrejo/FinalMigration) - ✅ **SVG MIGRATION**: 3 SVG files removed, replaced with Fluent UI icons (PR #7820) - ✅ **FLUENT UI v8 TO v9 MIGRATIONS** : - ✅ SearchableDropdown: Complete v8→v9 migration with enhanced key handling and Fluent UI v9 patterns @@ -638,7 +638,7 @@ Alongside the LESS to makeStyles migration, we're also migrating from Fluent UI - Removed validationItems parameter, simplified component API - Complete removal of styles.less file (not just migration) -7. **NodeSearchPanel Component** (✅ COMPLETED) +7. **NodeSearchPanel Component** (✅ COMPLETED - Branch: ccastrotrejo/panelSearchMigration) - v8: `FocusTrapZone` → Tabster focus management system - v8: `SearchBox` → v9: `SearchBox` with updated event handlers - Location: `/libs/designer/src/lib/ui/panel/nodeSearchPanel/` diff --git a/MIGRATION_DEPENDENCY_GRAPH.md b/MIGRATION_DEPENDENCY_GRAPH.md index 65afe2719cc..3345b46e00f 100644 --- a/MIGRATION_DEPENDENCY_GRAPH.md +++ b/MIGRATION_DEPENDENCY_GRAPH.md @@ -227,7 +227,7 @@ These patterns can accelerate the remaining designer-ui and designer library mig - ✓ **MAJOR**: ReviewList complete architecture migration (GroupedList → Tree) with file removal - ✓ Fluent UI v8 → v9 migration patterns established and refined - ✓ SVG → Fluent UI icon migration completed for VS Code -- ✓ **NEW**: NodeSearchPanel migration with Tabster focus management +- ✓ **NEW**: NodeSearchPanel migration with Tabster focus management (Branch: ccastrotrejo/panelSearchMigration) - ✓ Added `tabster: 8.5.6` dependency for advanced accessibility features - ✓ Complex component migration patterns validated (Tree, Skeleton components) - ⚠️ Performance validation in progress From d0630596291e7315eb074cb2705a4b42af5cee50 Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Fri, 10 Oct 2025 11:06:44 -0400 Subject: [PATCH 37/46] Add get public url function --- Localize/lang/strings.json | 4 ---- .../src/app/commands/dataMapper/FxWorkflowRuntime.ts | 4 +++- .../GenerateADODeploymentScriptsStep.ts | 4 +++- apps/vs-code-designer/src/app/commands/pickFuncProcess.ts | 4 +++- .../workflows/openDesigner/openDesignerForLocalProject.ts | 8 +++++--- .../openMonitoringView/openMonitoringViewForLocal.ts | 4 +++- .../src/app/commands/workflows/openOverview.ts | 4 +++- .../src/app/commands/workflows/unitTest/createUnitTest.ts | 3 ++- .../tree/remoteWorkflowsTree/RemoteWorkflowTreeItem.ts | 2 +- apps/vs-code-designer/src/app/utils/codeless/apiUtils.ts | 2 +- apps/vs-code-designer/src/app/utils/codeless/common.ts | 2 +- .../src/app/utils/codeless/startDesignTimeApi.ts | 4 +++- apps/vs-code-designer/src/app/utils/extension.ts | 6 ++++++ apps/vs-code-designer/src/app/utils/startRuntimeApi.ts | 7 ++++--- apps/vs-code-designer/src/app/utils/unitTests.ts | 5 +++-- apps/vs-code-designer/src/constants.ts | 4 ++-- 16 files changed, 43 insertions(+), 24 deletions(-) diff --git a/Localize/lang/strings.json b/Localize/lang/strings.json index ce77c0b4e70..3238a096839 100644 --- a/Localize/lang/strings.json +++ b/Localize/lang/strings.json @@ -1399,7 +1399,6 @@ "Xrd4VK": "Select variable type", "XsgpXt": "Allow both input and output channels", "XsktQ/": "Limit Logic Apps to not include workflow metadata headers in the response.", - "XtVOMn": "Something went wrong", "XtVXqm": "Save changes", "XtuP5e": "Math functions", "XulI0a": "Describe the goal or purpose for this workflow. To edit this description later, open the trigger details pane.", @@ -2892,7 +2891,6 @@ "_Xrd4VK.comment": "Placeholder for variable type", "_XsgpXt.comment": "Channel input/output.", "_XsktQ/.comment": "description of workflow headers on response setting", - "_XtVOMn.comment": "Something went wrong text", "_XtVXqm.comment": "Button text for saving operation changes", "_XtuP5e.comment": "Label for math functions", "_XulI0a.comment": "Description for the trigger description dialog.", @@ -3204,7 +3202,6 @@ "_fRrZKS.comment": "Light mode image label", "_fSMyDJ.comment": "title for request options setting", "_fVG5aD.comment": "Time zone value ", - "_fZJWBR.comment": "Loading designer text", "_fa8xG1.comment": "The information for the error message", "_faPcYk.comment": "Answer no to combine button label", "_faUrud.comment": "Message to show under the loading icon when loading connection parameters", @@ -4288,7 +4285,6 @@ "fRrZKS": "Light-mode SAS URL", "fSMyDJ": "Request options - Timeout", "fVG5aD": "(UTC-05:00) Haiti", - "fZJWBR": "Loading designer", "fa8xG1": "Template validation failed. Please check the tabs for more details to fix the errors", "faPcYk": "No", "faUrud": "Loading connection data...", diff --git a/apps/vs-code-designer/src/app/commands/dataMapper/FxWorkflowRuntime.ts b/apps/vs-code-designer/src/app/commands/dataMapper/FxWorkflowRuntime.ts index 01d9ad4a13e..5ec331f13ec 100644 --- a/apps/vs-code-designer/src/app/commands/dataMapper/FxWorkflowRuntime.ts +++ b/apps/vs-code-designer/src/app/commands/dataMapper/FxWorkflowRuntime.ts @@ -28,6 +28,7 @@ import { backendRuntimeBaseUrl } from './extensionConfig'; import type { IActionContext } from '@microsoft/vscode-azext-utils'; import * as portfinder from 'portfinder'; import { ProgressLocation, type Uri, window } from 'vscode'; +import { getPublicUrl } from '../../utils/extension'; // NOTE: LA Standard ext does this in workflowFolder/workflow-designtime // For now at least, DM is just going to do everything in workflowFolder @@ -46,7 +47,8 @@ export async function startBackendRuntime(context: IActionContext, projectPath: } // Note: Must append operationGroups as it's a valid endpoint to ping - const url = `${backendRuntimeBaseUrl}${designTimeInst.port}${designerStartApi}`; + const publicUrl = getPublicUrl(`${backendRuntimeBaseUrl}${designTimeInst.port}`); + const url = `${publicUrl}${designerStartApi}`; await window.withProgress({ location: ProgressLocation.Notification }, async (progress) => { progress.report({ message: 'Starting backend runtime, this may take a few seconds...' }); diff --git a/apps/vs-code-designer/src/app/commands/generateDeploymentScripts/generateDeploymentScriptsSteps/adoDeploymentScriptsSteps/GenerateADODeploymentScriptsStep.ts b/apps/vs-code-designer/src/app/commands/generateDeploymentScripts/generateDeploymentScriptsSteps/adoDeploymentScriptsSteps/GenerateADODeploymentScriptsStep.ts index 310a29f0ee1..5ec613cd61d 100644 --- a/apps/vs-code-designer/src/app/commands/generateDeploymentScripts/generateDeploymentScriptsSteps/adoDeploymentScriptsSteps/GenerateADODeploymentScriptsStep.ts +++ b/apps/vs-code-designer/src/app/commands/generateDeploymentScripts/generateDeploymentScriptsSteps/adoDeploymentScriptsSteps/GenerateADODeploymentScriptsStep.ts @@ -22,6 +22,7 @@ import { unzipLogicAppArtifacts } from '../../../../utils/taskUtils'; import { startDesignTimeApi } from '../../../../utils/codeless/startDesignTimeApi'; import { getAuthorizationToken, getCloudHost } from '../../../../utils/codeless/getAuthorizationToken'; import type { IAzureDeploymentScriptsContext } from '../../generateDeploymentScripts'; +import { getPublicUrl } from '../../../../utils/extension'; export class GenerateADODeploymentScriptsStep extends AzureWizardExecuteStep { public priority = 250; @@ -300,7 +301,8 @@ export class GenerateADODeploymentScriptsStep extends AzureWizardExecuteStep { let workflowFilePath: string; @@ -56,7 +57,8 @@ export async function openOverview(context: IAzureConnectorsContext, node: vscod workflowName = basename(dirname(workflowFilePath)); panelName = `${vscode.workspace.name}-${workflowName}-overview`; workflowContent = JSON.parse(readFileSync(workflowFilePath, 'utf8')); - baseUrl = `http://localhost:${ext.workflowRuntimePort}${managementApiPrefix}`; + const publicUrl = await getPublicUrl(`http://localhost:${ext.workflowRuntimePort}`); + baseUrl = `${publicUrl}${managementApiPrefix}`; apiVersion = '2019-10-01-edge-preview'; isLocal = true; triggerName = getTriggerName(workflowContent.definition); diff --git a/apps/vs-code-designer/src/app/commands/workflows/unitTest/createUnitTest.ts b/apps/vs-code-designer/src/app/commands/workflows/unitTest/createUnitTest.ts index 0e99fb90e82..e415f2b2b6d 100644 --- a/apps/vs-code-designer/src/app/commands/workflows/unitTest/createUnitTest.ts +++ b/apps/vs-code-designer/src/app/commands/workflows/unitTest/createUnitTest.ts @@ -33,6 +33,7 @@ import axios from 'axios'; import { ext } from '../../../../extensionVariables'; import { unzipLogicAppArtifacts } from '../../../utils/taskUtils'; import { syncCloudSettings } from '../../syncCloudSettings'; +import { getPublicUrl } from '../../../utils/extension'; /** * Handles the creation of a unit test for a Logic App workflow. @@ -168,7 +169,7 @@ async function generateUnitTestFromRun( } logTelemetry(context, { runtimePort: ext.workflowRuntimePort.toString() }); - const baseUrl = `http://localhost:${ext.workflowRuntimePort}`; + const baseUrl = await getPublicUrl(`http://localhost:${ext.workflowRuntimePort}`); const apiUrl = `${baseUrl}/runtime/webhooks/workflow/api/management/workflows/${encodeURIComponent(workflowName)}/runs/${encodeURIComponent(runId)}/generateUnitTest`; ext.outputChannel.appendLog(localize('apiUrl', `Calling API URL: ${apiUrl}`)); diff --git a/apps/vs-code-designer/src/app/tree/remoteWorkflowsTree/RemoteWorkflowTreeItem.ts b/apps/vs-code-designer/src/app/tree/remoteWorkflowsTree/RemoteWorkflowTreeItem.ts index 8982352a4cc..e7763589963 100644 --- a/apps/vs-code-designer/src/app/tree/remoteWorkflowsTree/RemoteWorkflowTreeItem.ts +++ b/apps/vs-code-designer/src/app/tree/remoteWorkflowsTree/RemoteWorkflowTreeItem.ts @@ -105,7 +105,7 @@ export class RemoteWorkflowTreeItem extends AzExtTreeItem { const requestTriggerName = getRequestTriggerName(node.workflowFileContent.definition); if (requestTriggerName) { try { - const url = `${this.parent.parent.id}/hostruntime${managementApiPrefix}/workflows/${this.name}/triggers/${triggerName}/listCallbackUrl?api-version=${workflowAppApiVersion}`; + const url = `${this.parent.parent.id}/hostruntime/${managementApiPrefix}/workflows/${this.name}/triggers/${triggerName}/listCallbackUrl?api-version=${workflowAppApiVersion}`; const response = await sendAzureRequest(url, this.parent._context, HTTP_METHODS.POST, node.subscription); return response.parsedBody; } catch { diff --git a/apps/vs-code-designer/src/app/utils/codeless/apiUtils.ts b/apps/vs-code-designer/src/app/utils/codeless/apiUtils.ts index 318bb3782d9..76dd1bf38e6 100644 --- a/apps/vs-code-designer/src/app/utils/codeless/apiUtils.ts +++ b/apps/vs-code-designer/src/app/utils/codeless/apiUtils.ts @@ -64,7 +64,7 @@ export async function getWorkflow( } export async function listWorkflows(node: SlotTreeItem, context: IActionContext): Promise[]> { - const url = `${node.id}/hostruntime${managementApiPrefix}/workflows?api-version=${workflowAppApiVersion}`; + const url = `${node.id}/hostruntime/${managementApiPrefix}/workflows?api-version=${workflowAppApiVersion}`; try { const response = await sendAzureRequest(url, context, 'GET', node.site.subscription); return response.parsedBody; diff --git a/apps/vs-code-designer/src/app/utils/codeless/common.ts b/apps/vs-code-designer/src/app/utils/codeless/common.ts index 976fc5b84d1..617a5e930b9 100644 --- a/apps/vs-code-designer/src/app/utils/codeless/common.ts +++ b/apps/vs-code-designer/src/app/utils/codeless/common.ts @@ -349,7 +349,7 @@ export function getWorkflowManagementBaseURI(node: RemoteWorkflowTreeItem): stri if (resourceManagerUri.endsWith('/')) { resourceManagerUri = resourceManagerUri.slice(0, -1); } - return `${resourceManagerUri}${node.parent.parent.id}/hostruntime${managementApiPrefix}`; + return `${resourceManagerUri}${node.parent.parent.id}/hostruntime/${managementApiPrefix}`; } /** diff --git a/apps/vs-code-designer/src/app/utils/codeless/startDesignTimeApi.ts b/apps/vs-code-designer/src/app/utils/codeless/startDesignTimeApi.ts index f78d54dda2d..e2a2af37478 100644 --- a/apps/vs-code-designer/src/app/utils/codeless/startDesignTimeApi.ts +++ b/apps/vs-code-designer/src/app/utils/codeless/startDesignTimeApi.ts @@ -47,6 +47,7 @@ import { Uri, window, workspace, type MessageItem } from 'vscode'; import { findChildProcess } from '../../commands/pickFuncProcess'; import pstree from 'ps-tree'; import find_process from 'find-process'; +import { getPublicUrl } from '../extension'; export async function startDesignTimeApi(projectPath: string): Promise { await callWithTelemetryAndErrorHandling('azureLogicAppsStandard.startDesignTimeApi', async (actionContext: IActionContext) => { @@ -63,7 +64,8 @@ export async function startDesignTimeApi(projectPath: string): Promise { } const designTimeInst = ext.designTimeInstances.get(projectPath); - const url = `http://localhost:${designTimeInst.port}${designerStartApi}`; + const publicUrl = await getPublicUrl(`http://localhost:${designTimeInst.port}`); + const url = `${publicUrl}${designerStartApi}`; if (designTimeInst.isStarting && !isNewDesignTime) { await waitForDesignTimeStartUp(actionContext, projectPath, url); actionContext.telemetry.properties.isDesignTimeUp = 'true'; diff --git a/apps/vs-code-designer/src/app/utils/extension.ts b/apps/vs-code-designer/src/app/utils/extension.ts index d3c01a25eb3..8686ae81c6b 100644 --- a/apps/vs-code-designer/src/app/utils/extension.ts +++ b/apps/vs-code-designer/src/app/utils/extension.ts @@ -23,3 +23,9 @@ export const getExtensionVersion = (): string => { return ''; }; + +export async function getPublicUrl(url: string) { + const local = vscode.Uri.parse(url); + const external = await vscode.env.asExternalUri(local); + return external.toString(); // use this in webviews, auth callbacks, logs, etc. +} diff --git a/apps/vs-code-designer/src/app/utils/startRuntimeApi.ts b/apps/vs-code-designer/src/app/utils/startRuntimeApi.ts index 47b48c14b35..f7e1ba8d8cb 100644 --- a/apps/vs-code-designer/src/app/utils/startRuntimeApi.ts +++ b/apps/vs-code-designer/src/app/utils/startRuntimeApi.ts @@ -20,7 +20,7 @@ import axios from 'axios'; import { localize } from '../../localize'; import { delay } from './delay'; import { findChildProcess } from '../commands/pickFuncProcess'; -import { getFunctionsCommand } from './funcCoreTools/funcVersion'; +import { getPublicUrl } from './extension'; export async function startRuntimeApi(projectPath: string): Promise { await callWithTelemetryAndErrorHandling('azureLogicAppsStandard.startRuntimeProcess', async (context: IActionContext) => { @@ -71,7 +71,7 @@ export async function startRuntimeApi(projectPath: string): Promise { try { ext.outputChannel.appendLog(localize('startingRuntime', 'Starting Runtime API for project: {0}', projectPath)); - startRuntimeProcess(projectPath, getFunctionsCommand(), 'host', 'start', `--port ${runtimeInst.port}`); + startRuntimeProcess(projectPath, 'func', 'host', 'start', `--port ${runtimeInst.port}`); await waitForRuntimeStartUp(context, projectPath, runtimeInst.port, true); context.telemetry.properties.isRuntimeUp = 'true'; } catch (error) { @@ -117,7 +117,8 @@ async function waitForRuntimeStartUp(context: IActionContext, projectPath: strin async function isRuntimeUp(port: number): Promise { try { - const url = `http://localhost:${port}${designerStartApi}`; + const baseUrl = await getPublicUrl(`http://localhost:${port}`); + const url = `${baseUrl}${designerStartApi}`; await axios.get(url); return Promise.resolve(true); } catch { diff --git a/apps/vs-code-designer/src/app/utils/unitTests.ts b/apps/vs-code-designer/src/app/utils/unitTests.ts index 391727e5b94..9321e55afd0 100644 --- a/apps/vs-code-designer/src/app/utils/unitTests.ts +++ b/apps/vs-code-designer/src/app/utils/unitTests.ts @@ -22,6 +22,7 @@ import { ext } from '../../extensionVariables'; import { localize } from '../../localize'; import { getWorkflowsInLocalProject } from './codeless/common'; import { executeCommand } from './funcCoreTools/cpUtils'; +import { getPublicUrl } from './extension'; /** * Saves a unit test definition for a workflow to the file system. @@ -1183,7 +1184,7 @@ export async function getMockableOperationTypes(): Promise { localize('errorStandardResourcesApi', 'Design time port is undefined. Please retry once Azure Functions Core Tools has started.') ); } - const baseUrl = `http://localhost:${designTimePort}`; + const baseUrl = await getPublicUrl(`http://localhost:${designTimePort}`); const listMockableOperationsUrl = `${baseUrl}/runtime/webhooks/workflow/api/management/listMockableOperations`; ext.outputChannel.appendLog(localize('listMockableOperations', `Fetching unit test mockable operations at ${listMockableOperationsUrl}`)); try { @@ -1218,7 +1219,7 @@ export async function getMockableHttpOperationTypes(): Promise { localize('errorStandardResourcesApi', 'Design time port is undefined. Please retry once Azure Functions Core Tools has started.') ); } - const baseUrl = `http://localhost:${designTimePort}`; + const baseUrl = await getPublicUrl(`http://localhost:${designTimePort}`); const listMockableHttpOperationsUrl = `${baseUrl}/runtime/webhooks/workflow/api/management/listMockableHttpOperations`; ext.outputChannel.appendLog( localize('listMockableHttpOperations', `Fetching unit test mockable http operations at ${listMockableHttpOperationsUrl}`) diff --git a/apps/vs-code-designer/src/constants.ts b/apps/vs-code-designer/src/constants.ts index 9161fb9ace9..4eda7ca8efd 100644 --- a/apps/vs-code-designer/src/constants.ts +++ b/apps/vs-code-designer/src/constants.ts @@ -113,8 +113,8 @@ export const WorkflowKind = { export type WorkflowKind = (typeof WorkflowKind)[keyof typeof WorkflowKind]; // Designer -export const managementApiPrefix = '/runtime/webhooks/workflow/api/management'; -export const designerStartApi = '/runtime/webhooks/workflow/api/management/operationGroups'; +export const managementApiPrefix = 'runtime/webhooks/workflow/api/management'; +export const designerStartApi = 'runtime/webhooks/workflow/api/management/operationGroups'; export const designerApiLoadTimeout = 300000; // Commands From ee33af5c107df883b460a1933b50c7f09fca1647 Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Fri, 10 Oct 2025 11:36:07 -0400 Subject: [PATCH 38/46] Update unit tests --- .../src/app/utils/__test__/extension.test.ts | 253 ++++++++++++++++++ .../app/utils/__test__/unitTestUtils.test.ts | 5 + apps/vs-code-designer/test-setup.ts | 5 + 3 files changed, 263 insertions(+) create mode 100644 apps/vs-code-designer/src/app/utils/__test__/extension.test.ts diff --git a/apps/vs-code-designer/src/app/utils/__test__/extension.test.ts b/apps/vs-code-designer/src/app/utils/__test__/extension.test.ts new file mode 100644 index 00000000000..dc150e538a6 --- /dev/null +++ b/apps/vs-code-designer/src/app/utils/__test__/extension.test.ts @@ -0,0 +1,253 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import { getPublicUrl, getExtensionVersion } from '../extension'; +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import * as vscode from 'vscode'; + +describe('extension utils', () => { + describe('getPublicUrl', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('should convert a local URL to a public external URL', async () => { + const localUrl = 'http://localhost:3000'; + const expectedExternalUrl = 'https://external-url.example.com:3000'; + + const mockParsedUri = { + scheme: 'http', + authority: 'localhost:3000', + toString: () => localUrl, + } as vscode.Uri; + + const mockExternalUri = { + scheme: 'https', + authority: 'external-url.example.com:3000', + toString: () => expectedExternalUrl, + } as vscode.Uri; + + const parseSpy = vi.spyOn(vscode.Uri, 'parse').mockReturnValue(mockParsedUri); + const asExternalUriSpy = vi.spyOn(vscode.env, 'asExternalUri').mockResolvedValue(mockExternalUri); + + const result = await getPublicUrl(localUrl); + + expect(parseSpy).toHaveBeenCalledWith(localUrl); + expect(asExternalUriSpy).toHaveBeenCalledWith(mockParsedUri); + expect(result).toBe(expectedExternalUrl); + }); + + it('should handle URLs with different ports', async () => { + const localUrl = 'http://localhost:8080'; + const expectedExternalUrl = 'https://external-url.example.com:8080'; + + const mockParsedUri = { + scheme: 'http', + authority: 'localhost:8080', + toString: () => localUrl, + } as vscode.Uri; + + const mockExternalUri = { + toString: () => expectedExternalUrl, + } as vscode.Uri; + + vi.spyOn(vscode.Uri, 'parse').mockReturnValue(mockParsedUri); + vi.spyOn(vscode.env, 'asExternalUri').mockResolvedValue(mockExternalUri); + + const result = await getPublicUrl(localUrl); + + expect(result).toBe(expectedExternalUrl); + }); + + it('should handle HTTPS URLs', async () => { + const localUrl = 'https://localhost:5001'; + const expectedExternalUrl = 'https://external-url.example.com:5001'; + + const mockParsedUri = { + scheme: 'https', + authority: 'localhost:5001', + toString: () => localUrl, + } as vscode.Uri; + + const mockExternalUri = { + toString: () => expectedExternalUrl, + } as vscode.Uri; + + vi.spyOn(vscode.Uri, 'parse').mockReturnValue(mockParsedUri); + vi.spyOn(vscode.env, 'asExternalUri').mockResolvedValue(mockExternalUri); + + const result = await getPublicUrl(localUrl); + + expect(result).toBe(expectedExternalUrl); + }); + + it('should handle URLs with paths', async () => { + const localUrl = 'http://localhost:3000/api/callback'; + const expectedExternalUrl = 'https://external-url.example.com:3000/api/callback'; + + const mockParsedUri = { + scheme: 'http', + authority: 'localhost:3000', + path: '/api/callback', + toString: () => localUrl, + } as vscode.Uri; + + const mockExternalUri = { + toString: () => expectedExternalUrl, + } as vscode.Uri; + + vi.spyOn(vscode.Uri, 'parse').mockReturnValue(mockParsedUri); + vi.spyOn(vscode.env, 'asExternalUri').mockResolvedValue(mockExternalUri); + + const result = await getPublicUrl(localUrl); + + expect(result).toBe(expectedExternalUrl); + }); + + it('should handle URLs with query parameters', async () => { + const localUrl = 'http://localhost:3000/callback?code=123&state=abc'; + const expectedExternalUrl = 'https://external-url.example.com:3000/callback?code=123&state=abc'; + + const mockParsedUri = { + scheme: 'http', + authority: 'localhost:3000', + path: '/callback', + query: 'code=123&state=abc', + toString: () => localUrl, + } as vscode.Uri; + + const mockExternalUri = { + toString: () => expectedExternalUrl, + } as vscode.Uri; + + vi.spyOn(vscode.Uri, 'parse').mockReturnValue(mockParsedUri); + vi.spyOn(vscode.env, 'asExternalUri').mockResolvedValue(mockExternalUri); + + const result = await getPublicUrl(localUrl); + + expect(result).toBe(expectedExternalUrl); + }); + + it('should handle non-localhost URLs', async () => { + const localUrl = 'http://127.0.0.1:3000'; + const expectedExternalUrl = 'https://external-url.example.com:3000'; + + const mockParsedUri = { + scheme: 'http', + authority: '127.0.0.1:3000', + toString: () => localUrl, + } as vscode.Uri; + + const mockExternalUri = { + toString: () => expectedExternalUrl, + } as vscode.Uri; + + vi.spyOn(vscode.Uri, 'parse').mockReturnValue(mockParsedUri); + vi.spyOn(vscode.env, 'asExternalUri').mockResolvedValue(mockExternalUri); + + const result = await getPublicUrl(localUrl); + + expect(result).toBe(expectedExternalUrl); + }); + + it('should return the same URL if no external mapping is needed', async () => { + const publicUrl = 'https://example.com:3000'; + + const mockParsedUri = { + scheme: 'https', + authority: 'example.com:3000', + toString: () => publicUrl, + } as vscode.Uri; + + const mockExternalUri = { + toString: () => publicUrl, + } as vscode.Uri; + + vi.spyOn(vscode.Uri, 'parse').mockReturnValue(mockParsedUri); + vi.spyOn(vscode.env, 'asExternalUri').mockResolvedValue(mockExternalUri); + + const result = await getPublicUrl(publicUrl); + + expect(result).toBe(publicUrl); + }); + + it('should handle vscode-webview:// scheme URLs', async () => { + const webviewUrl = 'vscode-webview://some-webview-id'; + const expectedExternalUrl = 'vscode-webview://some-webview-id'; + + const mockParsedUri = { + scheme: 'vscode-webview', + authority: 'some-webview-id', + toString: () => webviewUrl, + } as vscode.Uri; + + const mockExternalUri = { + toString: () => expectedExternalUrl, + } as vscode.Uri; + + vi.spyOn(vscode.Uri, 'parse').mockReturnValue(mockParsedUri); + vi.spyOn(vscode.env, 'asExternalUri').mockResolvedValue(mockExternalUri); + + const result = await getPublicUrl(webviewUrl); + + expect(result).toBe(expectedExternalUrl); + }); + }); + + describe('getExtensionVersion', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('should return the version from the extension package.json', () => { + const mockExtension = { + packageJSON: { + version: '1.2.3', + }, + } as vscode.Extension; + + vi.spyOn(vscode.extensions, 'getExtension').mockReturnValue(mockExtension); + + const result = getExtensionVersion(); + + expect(result).toBe('1.2.3'); + }); + + it('should return empty string if extension is not found', () => { + vi.spyOn(vscode.extensions, 'getExtension').mockReturnValue(undefined); + + const result = getExtensionVersion(); + + expect(result).toBe(''); + }); + + it('should return empty string if packageJSON is not available', () => { + const mockExtension = { + packageJSON: undefined, + } as unknown as vscode.Extension; + + vi.spyOn(vscode.extensions, 'getExtension').mockReturnValue(mockExtension); + + const result = getExtensionVersion(); + + expect(result).toBe(''); + }); + + it('should return empty string if version is not in packageJSON', () => { + const mockExtension = { + packageJSON: { + version: undefined, + }, + } as vscode.Extension; + + vi.spyOn(vscode.extensions, 'getExtension').mockReturnValue(mockExtension); + + const result = getExtensionVersion(); + + // Note: The function returns undefined when version is not present, + // which technically violates the return type signature + expect(result).toBeUndefined(); + }); + }); +}); diff --git a/apps/vs-code-designer/src/app/utils/__test__/unitTestUtils.test.ts b/apps/vs-code-designer/src/app/utils/__test__/unitTestUtils.test.ts index fbf16c2c284..910713940b1 100644 --- a/apps/vs-code-designer/src/app/utils/__test__/unitTestUtils.test.ts +++ b/apps/vs-code-designer/src/app/utils/__test__/unitTestUtils.test.ts @@ -18,6 +18,11 @@ vi.mock('axios', async () => { isAxiosError: vi.fn(), }; }); +// Mock getPublicUrl from extension utilities to avoid requiring a real VS Code environment +// Must be declared before importing the module that uses it (`../unitTests`). +vi.mock('../extension', () => ({ + getPublicUrl: vi.fn(async (url: string) => url), // no-op passthrough for tests +})); import { extractAndValidateRunId, validateRunId, diff --git a/apps/vs-code-designer/test-setup.ts b/apps/vs-code-designer/test-setup.ts index 8b7371e4fac..ad8ef85e1ec 100644 --- a/apps/vs-code-designer/test-setup.ts +++ b/apps/vs-code-designer/test-setup.ts @@ -100,6 +100,7 @@ vi.mock('vscode', () => ({ }, Uri: { file: (p: string) => ({ fsPath: p, toString: () => p }), + parse: vi.fn(), }, commands: { executeCommand: vi.fn(), @@ -117,8 +118,12 @@ vi.mock('vscode', () => ({ }, sessionId: 'test-session-id', appName: 'Visual Studio Code', + asExternalUri: vi.fn(), }, version: '1.85.0', + extensions: { + getExtension: vi.fn(), + }, })); vi.mock('./src/extensionVariables', () => ({ From f5387ad06470c483c17b40de745a4abde30e9caa Mon Sep 17 00:00:00 2001 From: Carlos Emiliano Castro Trejo Date: Fri, 10 Oct 2025 11:45:19 -0400 Subject: [PATCH 39/46] Update path --- .../createWorkspace/createWorkspaceSteps/devcontainerStep.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/devcontainerStep.ts b/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/devcontainerStep.ts index e713536df02..3e9f3b0bb79 100644 --- a/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/devcontainerStep.ts +++ b/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/devcontainerStep.ts @@ -6,6 +6,7 @@ import { AzureWizardPromptStep } from '@microsoft/vscode-azext-utils'; import * as fs from 'fs-extra'; import type { IProjectWizardContext } from '@microsoft/vscode-extension-logic-apps'; import * as path from 'path'; +import { ext } from '../../../../extensionVariables'; export class DevcontainerStep extends AzureWizardPromptStep { public hideStepCount = true; @@ -21,7 +22,7 @@ export class DevcontainerStep extends AzureWizardPromptStep { // Resolve source directory with canonical container config. When running from compiled dist the // source 'container' folder may live beside 'src' or only within 'src/container'. Try a set of candidates. - const candidateDirs: string[] = [path.join(__dirname, 'assets', 'container')]; + const candidateDirs: string[] = [path.join(ext.context.extensionPath, 'assets', 'container')]; let sourceContainerDir: string | undefined; for (const dir of candidateDirs) { From 54ab7d04b13c19b31a23b1f2203325b9bda8bdd1 Mon Sep 17 00:00:00 2001 From: Carlos Castro Trejo <102700317+ccastrotrejo@users.noreply.github.com> Date: Mon, 13 Oct 2025 15:44:20 +0000 Subject: [PATCH 40/46] Updare local url --- .../src/app/commands/pickFuncProcess.ts | 4 +- .../openDesigner/openDesignerBase.ts | 1 + .../openDesignerForLocalProject.ts | 12 +--- .../app/commands/workflows/openOverview.ts | 60 +++++++++++++++++-- .../app/utils/codeless/startDesignTimeApi.ts | 4 +- 5 files changed, 58 insertions(+), 23 deletions(-) diff --git a/apps/vs-code-designer/src/app/commands/pickFuncProcess.ts b/apps/vs-code-designer/src/app/commands/pickFuncProcess.ts index a267bd75286..6a5e5b72452 100644 --- a/apps/vs-code-designer/src/app/commands/pickFuncProcess.ts +++ b/apps/vs-code-designer/src/app/commands/pickFuncProcess.ts @@ -35,7 +35,6 @@ import parser from 'yargs-parser'; import { buildCustomCodeFunctionsProject } from './buildCustomCodeFunctionsProject'; import { getProjFiles } from '../utils/dotnet/dotnet'; import { delay } from '../utils/delay'; -import { getPublicUrl } from '../utils/extension'; type OSAgnosticProcess = { command: string | undefined; pid: number | string }; type ActualUnixPS = unixPsTree.PS & { COMM?: string }; @@ -253,9 +252,8 @@ async function startFuncTask( const taskInfo: IRunningFuncTask | undefined = runningFuncTaskMap.get(workspaceFolder); if (taskInfo) { for (const scheme of ['http', 'https']) { - const publicUrl = await getPublicUrl(`${scheme}://localhost:${funcPort}`); const statusRequest: AzExtRequestPrepareOptions = { - url: `${publicUrl}/admin/host/status`, + url: `${scheme}://localhost:${funcPort}/admin/host/status`, method: HTTP_METHODS.GET, }; if (scheme === 'https') { diff --git a/apps/vs-code-designer/src/app/commands/workflows/openDesigner/openDesignerBase.ts b/apps/vs-code-designer/src/app/commands/workflows/openDesigner/openDesignerBase.ts index 71861ddd8fb..15a4b319601 100644 --- a/apps/vs-code-designer/src/app/commands/workflows/openDesigner/openDesignerBase.ts +++ b/apps/vs-code-designer/src/app/commands/workflows/openDesigner/openDesignerBase.ts @@ -27,6 +27,7 @@ export abstract class OpenDesignerBase { protected apiVersion: string; protected panelGroupKey: string; protected baseUrl: string; + protected webviewBaseUrl: string; protected workflowRuntimeBaseUrl: string; protected connectionData: ConnectionsData; protected panel: WebviewPanel; diff --git a/apps/vs-code-designer/src/app/commands/workflows/openDesigner/openDesignerForLocalProject.ts b/apps/vs-code-designer/src/app/commands/workflows/openDesigner/openDesignerForLocalProject.ts index 7a17eca83fc..dc91745fd38 100644 --- a/apps/vs-code-designer/src/app/commands/workflows/openDesigner/openDesignerForLocalProject.ts +++ b/apps/vs-code-designer/src/app/commands/workflows/openDesigner/openDesignerForLocalProject.ts @@ -118,17 +118,7 @@ export default class OpenDesignerForLocalProject extends OpenDesignerBase { throw new Error(localize('designTimePortNotFound', 'Design time port not found.')); } - // if (!ext.runtimeInstances.has(this.projectPath)) { - // throw new Error(localize('runtimeNotRunning', `Runtime is not running for project ${this.projectPath}.`)); - // } - // const runtimePort = ext.runtimeInstances.get(this.projectPath).port; - // if (!runtimePort) { - // throw new Error(localize('runtimePortNotFound', 'Runtime port not found.')); - // } - - const publicUrl = await getPublicUrl(`http://localhost:${designTimePort}`); - this.baseUrl = `${publicUrl}${managementApiPrefix}`; - + this.baseUrl = `http://localhost:${designTimePort}/${managementApiPrefix}`; this.panel = window.createWebviewPanel( this.panelGroupKey, // Key used to reference the panel this.panelName, // Title display in the tab diff --git a/apps/vs-code-designer/src/app/commands/workflows/openOverview.ts b/apps/vs-code-designer/src/app/commands/workflows/openOverview.ts index 0dd06ca9680..a44c9487370 100644 --- a/apps/vs-code-designer/src/app/commands/workflows/openOverview.ts +++ b/apps/vs-code-designer/src/app/commands/workflows/openOverview.ts @@ -59,10 +59,20 @@ export async function openOverview(context: IAzureConnectorsContext, node: vscod workflowContent = JSON.parse(readFileSync(workflowFilePath, 'utf8')); const publicUrl = await getPublicUrl(`http://localhost:${ext.workflowRuntimePort}`); baseUrl = `${publicUrl}${managementApiPrefix}`; + apiVersion = '2019-10-01-edge-preview'; isLocal = true; triggerName = getTriggerName(workflowContent.definition); - callbackInfo = await getLocalWorkflowCallbackInfo(context, workflowContent.definition, baseUrl, workflowName, triggerName, apiVersion); + // Get callback info. Function will internalize rebasing to public origin. + callbackInfo = await getLocalWorkflowCallbackInfo( + context, + workflowContent.definition, + `http://localhost:${ext.workflowRuntimePort}/${managementApiPrefix}`, + workflowName, + triggerName, + apiVersion, + publicUrl + ); const projectPath = await getLogicAppProjectRoot(context, workflowFilePath); localSettings = projectPath ? (await getLocalSettingsJson(context, join(projectPath, localSettingsFileName))).Values || {} : {}; @@ -195,7 +205,8 @@ async function getLocalWorkflowCallbackInfo( baseUrl: string, workflowName: string, triggerName: string, - apiVersion: string + apiVersion: string, + publicOrigin?: string ): Promise { const requestTriggerName = getRequestTriggerName(definition); if (requestTriggerName) { @@ -205,17 +216,54 @@ async function getLocalWorkflowCallbackInfo( url, method: HTTP_METHODS.POST, }); - return JSON.parse(response); - // eslint-disable-next-line @typescript-eslint/no-unused-vars - } catch (error) { + const callbackInfo: ICallbackUrlResponse = JSON.parse(response); + return rebaseCallbackInfoOrigins(callbackInfo, baseUrl, publicOrigin); + } catch { return undefined; } } else { - return { + const fallback: ICallbackUrlResponse = { value: `${baseUrl}/workflows/${workflowName}/triggers/${triggerName}/run?api-version=${apiVersion}`, method: HTTP_METHODS.POST, }; + return rebaseCallbackInfoOrigins(fallback, baseUrl, publicOrigin); + } +} + +function rebaseCallbackInfoOrigins(callbackInfo: ICallbackUrlResponse, localBaseUrl: string, publicOrigin?: string): ICallbackUrlResponse { + if (!publicOrigin) { + return callbackInfo; + } + try { + const localUrlObj = new URL(localBaseUrl); + const localOrigin = `${localUrlObj.protocol}//${localUrlObj.host}`; + // Normalize public origin to avoid trailing slash duplication (e.g. http://127.0.0.1:PORT/) + const normalizedPublicOrigin = publicOrigin.replace(/\/+$/, ''); + const swap = (raw?: string) => { + if (!raw) { + return raw; + } + if (!raw.startsWith(localOrigin)) { + return raw; + } + const rest = raw.slice(localOrigin.length); // begins with '/' + return `${normalizedPublicOrigin}${rest}`; // normalizedPublicOrigin has no trailing '/' + }; + callbackInfo.value = swap(callbackInfo.value)!; + if (callbackInfo.basePath) { + callbackInfo.basePath = swap(callbackInfo.basePath); + } else if (callbackInfo.value) { + try { + const vUrl = new URL(callbackInfo.value); + callbackInfo.basePath = `${vUrl.origin}${vUrl.pathname}`; + } catch { + // ignore + } + } + } catch { + // ignore } + return callbackInfo; } function getWorkflowStateType(workflowName: string, kind: string, settings: Record): string { diff --git a/apps/vs-code-designer/src/app/utils/codeless/startDesignTimeApi.ts b/apps/vs-code-designer/src/app/utils/codeless/startDesignTimeApi.ts index e2a2af37478..08af2dd080e 100644 --- a/apps/vs-code-designer/src/app/utils/codeless/startDesignTimeApi.ts +++ b/apps/vs-code-designer/src/app/utils/codeless/startDesignTimeApi.ts @@ -47,7 +47,6 @@ import { Uri, window, workspace, type MessageItem } from 'vscode'; import { findChildProcess } from '../../commands/pickFuncProcess'; import pstree from 'ps-tree'; import find_process from 'find-process'; -import { getPublicUrl } from '../extension'; export async function startDesignTimeApi(projectPath: string): Promise { await callWithTelemetryAndErrorHandling('azureLogicAppsStandard.startDesignTimeApi', async (actionContext: IActionContext) => { @@ -64,8 +63,7 @@ export async function startDesignTimeApi(projectPath: string): Promise { } const designTimeInst = ext.designTimeInstances.get(projectPath); - const publicUrl = await getPublicUrl(`http://localhost:${designTimeInst.port}`); - const url = `${publicUrl}${designerStartApi}`; + const url = `http://localhost:${designTimeInst.port}/${designerStartApi}`; if (designTimeInst.isStarting && !isNewDesignTime) { await waitForDesignTimeStartUp(actionContext, projectPath, url); actionContext.telemetry.properties.isDesignTimeUp = 'true'; From 41a75958859eff07603bc9a951a55cbd8cfa9ee0 Mon Sep 17 00:00:00 2001 From: Carlos Castro Trejo <102700317+ccastrotrejo@users.noreply.github.com> Date: Mon, 13 Oct 2025 16:55:07 +0000 Subject: [PATCH 41/46] Add github token for codespaces --- Localize/lang/strings.json | 2 ++ .../src/app/commands/workflows/openOverview.ts | 2 ++ apps/vs-code-designer/src/app/utils/extension.ts | 2 +- apps/vs-code-react/src/app/overview/app.tsx | 2 ++ apps/vs-code-react/src/state/WorkflowSlice.ts | 4 ++++ libs/vscode-extension/src/lib/services/httpClient.ts | 6 ++++-- 6 files changed, 15 insertions(+), 3 deletions(-) diff --git a/Localize/lang/strings.json b/Localize/lang/strings.json index 3238a096839..f6a15a644e7 100644 --- a/Localize/lang/strings.json +++ b/Localize/lang/strings.json @@ -3145,6 +3145,7 @@ "_e+GuGo.comment": "Placeholder title for a newly inserted Text parameter", "_e00zot.comment": "Recurrence parameter group title", "_e1+Gqi.comment": "Description for resource location section.", + "_e1gQAz.comment": "Debug logic app project error text", "_e4JZEY.comment": "Time zone value ", "_e8JCcn.comment": "Tooltip label for the button that allows user to group search results by connector.", "_e9OvzW.comment": "Clear", @@ -4228,6 +4229,7 @@ "e+GuGo": "Input", "e00zot": "How often do you want to check for items?", "e1+Gqi": "Select the resource location for your workflow", + "e1gQAz": "Please start the project by pressing F5 or run it through the Run and Debug view", "e4JZEY": "(UTC+07:00) Tomsk", "e8JCcn": "Group actions by connector", "e9OvzW": "Clear", diff --git a/apps/vs-code-designer/src/app/commands/workflows/openOverview.ts b/apps/vs-code-designer/src/app/commands/workflows/openOverview.ts index a44c9487370..6ba01759211 100644 --- a/apps/vs-code-designer/src/app/commands/workflows/openOverview.ts +++ b/apps/vs-code-designer/src/app/commands/workflows/openOverview.ts @@ -51,6 +51,7 @@ export async function openOverview(context: IAzureConnectorsContext, node: vscod let triggerName: string; const workflowNode = getWorkflowNode(node); const panelGroupKey = ext.webViewKey.overview; + console.log('charlie', process.env.GITHUB_TOKEN); if (workflowNode instanceof vscode.Uri) { workflowFilePath = workflowNode.fsPath; @@ -155,6 +156,7 @@ export async function openOverview(context: IAzureConnectorsContext, node: vscod hostVersion: ext.extensionVersion, isLocal: isLocal, isWorkflowRuntimeRunning: isWorkflowRuntimeRunning, + githubToken: process?.env?.CODESPACES ? process?.env?.GITHUB_TOKEN : undefined, }, }); // Just shipping the access Token every 5 seconds is easier and more diff --git a/apps/vs-code-designer/src/app/utils/extension.ts b/apps/vs-code-designer/src/app/utils/extension.ts index 8686ae81c6b..055a2f634f7 100644 --- a/apps/vs-code-designer/src/app/utils/extension.ts +++ b/apps/vs-code-designer/src/app/utils/extension.ts @@ -27,5 +27,5 @@ export const getExtensionVersion = (): string => { export async function getPublicUrl(url: string) { const local = vscode.Uri.parse(url); const external = await vscode.env.asExternalUri(local); - return external.toString(); // use this in webviews, auth callbacks, logs, etc. + return external.toString(); } diff --git a/apps/vs-code-react/src/app/overview/app.tsx b/apps/vs-code-react/src/app/overview/app.tsx index 478a61d15e6..f5182cdcdd3 100644 --- a/apps/vs-code-react/src/app/overview/app.tsx +++ b/apps/vs-code-react/src/app/overview/app.tsx @@ -38,6 +38,7 @@ export const OverviewApp = () => { baseUrl: workflowState.baseUrl, apiHubBaseUrl: '', hostVersion: workflowState.hostVersion, + githubToken: workflowState.githubToken, }); return new StandardRunService({ @@ -52,6 +53,7 @@ export const OverviewApp = () => { workflowState.accessToken, workflowState.workflowProperties.name, workflowState.hostVersion, + workflowState.githubToken, ]); const loadRuns = ({ pageParam }: { pageParam?: string }) => { diff --git a/apps/vs-code-react/src/state/WorkflowSlice.ts b/apps/vs-code-react/src/state/WorkflowSlice.ts index 2d5bce3140f..06b9eb53fe9 100644 --- a/apps/vs-code-react/src/state/WorkflowSlice.ts +++ b/apps/vs-code-react/src/state/WorkflowSlice.ts @@ -15,6 +15,7 @@ export interface InitializePayload { hostVersion?: string; isLocal?: boolean; isWorkflowRuntimeRunning?: boolean; + githubToken?: string; } export const Status = { @@ -38,6 +39,7 @@ export interface WorkflowState { hostVersion?: string; isLocal?: boolean; isWorkflowRuntimeRunning?: boolean; + githubToken?: string; } const initialState: WorkflowState = { @@ -82,6 +84,7 @@ export const workflowSlice = createSlice({ hostVersion, isLocal, isWorkflowRuntimeRunning, + githubToken, } = action.payload; const initializedState = state; initializedState.accessToken = accessToken; @@ -112,6 +115,7 @@ export const workflowSlice = createSlice({ initializedState.hostVersion = hostVersion; initializedState.isLocal = isLocal; initializedState.isWorkflowRuntimeRunning = isWorkflowRuntimeRunning; + initialState.githubToken = githubToken; }, updateAccessToken: (state: WorkflowState, action: PayloadAction) => { state.accessToken = action.payload; diff --git a/libs/vscode-extension/src/lib/services/httpClient.ts b/libs/vscode-extension/src/lib/services/httpClient.ts index ed59f91d026..8a9ce58d20b 100644 --- a/libs/vscode-extension/src/lib/services/httpClient.ts +++ b/libs/vscode-extension/src/lib/services/httpClient.ts @@ -7,6 +7,7 @@ export interface HttpOptions { apiHubBaseUrl?: string; accessToken?: string; hostVersion?: string; + githubToken?: string; } export class HttpClient implements IHttpClient { @@ -19,7 +20,7 @@ export class HttpClient implements IHttpClient { this._baseUrl = options.baseUrl; this._accessToken = options.accessToken; this._apihubBaseUrl = options.apiHubBaseUrl; - this._extraHeaders = getExtraHeaders(options.hostVersion ?? ''); + this._extraHeaders = getExtraHeaders(options.hostVersion ?? '', options.githubToken); } dispose(): void {} @@ -185,9 +186,10 @@ export function isArmResourceId(resourceId: string): boolean { return resourceId ? resourceId.indexOf('/subscriptions/') !== -1 : false; } -function getExtraHeaders(hostVersion: string): Record { +function getExtraHeaders(hostVersion: string, githubToken: string | undefined): Record { return { 'x-ms-user-agent': `LogicAppsDesigner/(host vscode ${hostVersion})`, + ...(githubToken ? { 'X-GitHub-Token': githubToken } : {}), }; } From 4c58fd12a3f796b9d9546ff9e13b9cadb7e191ef Mon Sep 17 00:00:00 2001 From: Carlos Castro Trejo <102700317+ccastrotrejo@users.noreply.github.com> Date: Mon, 13 Oct 2025 17:01:20 +0000 Subject: [PATCH 42/46] Remove docker compose and just rely on the image --- Localize/lang/strings.json | 2 -- .../createWorkspaceSteps/devcontainerStep.ts | 2 +- .../src/assets/container/Dockerfile | 2 +- .../src/assets/container/README.md | 31 ++----------------- .../src/assets/container/devcontainer.json | 14 +-------- .../src/assets/container/docker-compose.yml | 14 --------- 6 files changed, 5 insertions(+), 60 deletions(-) delete mode 100644 apps/vs-code-designer/src/assets/container/docker-compose.yml diff --git a/Localize/lang/strings.json b/Localize/lang/strings.json index f6a15a644e7..3238a096839 100644 --- a/Localize/lang/strings.json +++ b/Localize/lang/strings.json @@ -3145,7 +3145,6 @@ "_e+GuGo.comment": "Placeholder title for a newly inserted Text parameter", "_e00zot.comment": "Recurrence parameter group title", "_e1+Gqi.comment": "Description for resource location section.", - "_e1gQAz.comment": "Debug logic app project error text", "_e4JZEY.comment": "Time zone value ", "_e8JCcn.comment": "Tooltip label for the button that allows user to group search results by connector.", "_e9OvzW.comment": "Clear", @@ -4229,7 +4228,6 @@ "e+GuGo": "Input", "e00zot": "How often do you want to check for items?", "e1+Gqi": "Select the resource location for your workflow", - "e1gQAz": "Please start the project by pressing F5 or run it through the Run and Debug view", "e4JZEY": "(UTC+07:00) Tomsk", "e8JCcn": "Group actions by connector", "e9OvzW": "Clear", diff --git a/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/devcontainerStep.ts b/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/devcontainerStep.ts index 3e9f3b0bb79..4b94be66f13 100644 --- a/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/devcontainerStep.ts +++ b/apps/vs-code-designer/src/app/commands/createWorkspace/createWorkspaceSteps/devcontainerStep.ts @@ -37,7 +37,7 @@ export class DevcontainerStep extends AzureWizardPromptStep docker-compose.yml executes - │ ├─> Create container from image - │ ├─> Mount volumes (your code) - │ ├─> Setup network with azurite - │ └─> Run: sleep infinity (keeps container alive) - │ - └─> Container is running with your workspace mounted - -┌─────────────────────────────────────────────────────────────┐ -│ 3. DEVCONTAINER PHASE (When VS Code connects) │ +│ 2. DEVCONTAINER PHASE (When VS Code connects) │ └─────────────────────────────────────────────────────────────┘ │ ├─> devcontainer.json applies @@ -73,7 +61,6 @@ Understanding how Dockerfile, docker-compose.yml, and devcontainer.json work tog ### ⚡ Key Points - **Dockerfile** = Heavy, slow installations (cached in image) -- **docker-compose.yml** = Runtime configuration (mounts, networking) - **devcontainer.json** = Quick dev tools & VS Code customization ### 📊 What Gets Installed Where @@ -146,20 +133,6 @@ Your `devcontainer.json` is already configured to build locally. To use the pre- // ... rest of your config } ``` - -Or update `docker-compose.yml`: - -```yaml -services: - app: - image: carloscastrotrejo/logicapps-dev:latest - platform: linux/amd64 - volumes: - - ../..:/workspaces:cached - command: sleep infinity - network_mode: service:azurite -``` - --- ## 🛠️ For Maintainers: Building & Publishing diff --git a/apps/vs-code-designer/src/assets/container/devcontainer.json b/apps/vs-code-designer/src/assets/container/devcontainer.json index 9661c2e1096..a7379de1b84 100644 --- a/apps/vs-code-designer/src/assets/container/devcontainer.json +++ b/apps/vs-code-designer/src/assets/container/devcontainer.json @@ -1,17 +1,5 @@ { - "name": "Logic Apps Standard Development", - "dockerComposeFile": "docker-compose.yml", - "service": "app", - "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", - "features": { - "ghcr.io/devcontainers/features/azure-cli:1": { - "version": "latest" - }, - "ghcr.io/devcontainers/features/powershell:1": { - "version": "latest", - "modules": "Az" - } - }, + "image": "carloscastrotrejo/logicapps-dev", "customizations": { "vscode": { "extensions": [ diff --git a/apps/vs-code-designer/src/assets/container/docker-compose.yml b/apps/vs-code-designer/src/assets/container/docker-compose.yml deleted file mode 100644 index 2c23cdcc078..00000000000 --- a/apps/vs-code-designer/src/assets/container/docker-compose.yml +++ /dev/null @@ -1,14 +0,0 @@ -services: - app: - build: - context: . - dockerfile: Dockerfile - platform: linux/amd64 - volumes: - - ../..:/workspaces:cached - command: sleep infinity - network_mode: service:azurite - - azurite: - image: mcr.microsoft.com/azure-storage/azurite - restart: unless-stopped From 83a3fb9dc82af17e74259faab59601240bc8dccd Mon Sep 17 00:00:00 2001 From: Carlos Castro Trejo <102700317+ccastrotrejo@users.noreply.github.com> Date: Mon, 13 Oct 2025 18:01:23 +0000 Subject: [PATCH 43/46] Fix typo --- .../vs-code-designer/src/app/commands/workflows/openOverview.ts | 1 - apps/vs-code-react/src/state/WorkflowSlice.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/vs-code-designer/src/app/commands/workflows/openOverview.ts b/apps/vs-code-designer/src/app/commands/workflows/openOverview.ts index 6ba01759211..60243b8d06d 100644 --- a/apps/vs-code-designer/src/app/commands/workflows/openOverview.ts +++ b/apps/vs-code-designer/src/app/commands/workflows/openOverview.ts @@ -51,7 +51,6 @@ export async function openOverview(context: IAzureConnectorsContext, node: vscod let triggerName: string; const workflowNode = getWorkflowNode(node); const panelGroupKey = ext.webViewKey.overview; - console.log('charlie', process.env.GITHUB_TOKEN); if (workflowNode instanceof vscode.Uri) { workflowFilePath = workflowNode.fsPath; diff --git a/apps/vs-code-react/src/state/WorkflowSlice.ts b/apps/vs-code-react/src/state/WorkflowSlice.ts index 06b9eb53fe9..5a2f4f0a993 100644 --- a/apps/vs-code-react/src/state/WorkflowSlice.ts +++ b/apps/vs-code-react/src/state/WorkflowSlice.ts @@ -115,7 +115,7 @@ export const workflowSlice = createSlice({ initializedState.hostVersion = hostVersion; initializedState.isLocal = isLocal; initializedState.isWorkflowRuntimeRunning = isWorkflowRuntimeRunning; - initialState.githubToken = githubToken; + initializedState.githubToken = githubToken; }, updateAccessToken: (state: WorkflowState, action: PayloadAction) => { state.accessToken = action.payload; From 22ceaa91db7466af0a458d53fdbb384e1d52ed7c Mon Sep 17 00:00:00 2001 From: Carlos Castro Trejo <102700317+ccastrotrejo@users.noreply.github.com> Date: Mon, 13 Oct 2025 18:17:51 +0000 Subject: [PATCH 44/46] Revert back github token --- Localize/lang/strings.json | 2 ++ .../src/app/commands/workflows/openOverview.ts | 1 - apps/vs-code-react/src/app/overview/app.tsx | 2 -- apps/vs-code-react/src/state/WorkflowSlice.ts | 4 ---- libs/vscode-extension/src/lib/services/httpClient.ts | 12 +++++------- 5 files changed, 7 insertions(+), 14 deletions(-) diff --git a/Localize/lang/strings.json b/Localize/lang/strings.json index 3238a096839..f6a15a644e7 100644 --- a/Localize/lang/strings.json +++ b/Localize/lang/strings.json @@ -3145,6 +3145,7 @@ "_e+GuGo.comment": "Placeholder title for a newly inserted Text parameter", "_e00zot.comment": "Recurrence parameter group title", "_e1+Gqi.comment": "Description for resource location section.", + "_e1gQAz.comment": "Debug logic app project error text", "_e4JZEY.comment": "Time zone value ", "_e8JCcn.comment": "Tooltip label for the button that allows user to group search results by connector.", "_e9OvzW.comment": "Clear", @@ -4228,6 +4229,7 @@ "e+GuGo": "Input", "e00zot": "How often do you want to check for items?", "e1+Gqi": "Select the resource location for your workflow", + "e1gQAz": "Please start the project by pressing F5 or run it through the Run and Debug view", "e4JZEY": "(UTC+07:00) Tomsk", "e8JCcn": "Group actions by connector", "e9OvzW": "Clear", diff --git a/apps/vs-code-designer/src/app/commands/workflows/openOverview.ts b/apps/vs-code-designer/src/app/commands/workflows/openOverview.ts index 60243b8d06d..a44c9487370 100644 --- a/apps/vs-code-designer/src/app/commands/workflows/openOverview.ts +++ b/apps/vs-code-designer/src/app/commands/workflows/openOverview.ts @@ -155,7 +155,6 @@ export async function openOverview(context: IAzureConnectorsContext, node: vscod hostVersion: ext.extensionVersion, isLocal: isLocal, isWorkflowRuntimeRunning: isWorkflowRuntimeRunning, - githubToken: process?.env?.CODESPACES ? process?.env?.GITHUB_TOKEN : undefined, }, }); // Just shipping the access Token every 5 seconds is easier and more diff --git a/apps/vs-code-react/src/app/overview/app.tsx b/apps/vs-code-react/src/app/overview/app.tsx index f5182cdcdd3..478a61d15e6 100644 --- a/apps/vs-code-react/src/app/overview/app.tsx +++ b/apps/vs-code-react/src/app/overview/app.tsx @@ -38,7 +38,6 @@ export const OverviewApp = () => { baseUrl: workflowState.baseUrl, apiHubBaseUrl: '', hostVersion: workflowState.hostVersion, - githubToken: workflowState.githubToken, }); return new StandardRunService({ @@ -53,7 +52,6 @@ export const OverviewApp = () => { workflowState.accessToken, workflowState.workflowProperties.name, workflowState.hostVersion, - workflowState.githubToken, ]); const loadRuns = ({ pageParam }: { pageParam?: string }) => { diff --git a/apps/vs-code-react/src/state/WorkflowSlice.ts b/apps/vs-code-react/src/state/WorkflowSlice.ts index 5a2f4f0a993..2d5bce3140f 100644 --- a/apps/vs-code-react/src/state/WorkflowSlice.ts +++ b/apps/vs-code-react/src/state/WorkflowSlice.ts @@ -15,7 +15,6 @@ export interface InitializePayload { hostVersion?: string; isLocal?: boolean; isWorkflowRuntimeRunning?: boolean; - githubToken?: string; } export const Status = { @@ -39,7 +38,6 @@ export interface WorkflowState { hostVersion?: string; isLocal?: boolean; isWorkflowRuntimeRunning?: boolean; - githubToken?: string; } const initialState: WorkflowState = { @@ -84,7 +82,6 @@ export const workflowSlice = createSlice({ hostVersion, isLocal, isWorkflowRuntimeRunning, - githubToken, } = action.payload; const initializedState = state; initializedState.accessToken = accessToken; @@ -115,7 +112,6 @@ export const workflowSlice = createSlice({ initializedState.hostVersion = hostVersion; initializedState.isLocal = isLocal; initializedState.isWorkflowRuntimeRunning = isWorkflowRuntimeRunning; - initializedState.githubToken = githubToken; }, updateAccessToken: (state: WorkflowState, action: PayloadAction) => { state.accessToken = action.payload; diff --git a/libs/vscode-extension/src/lib/services/httpClient.ts b/libs/vscode-extension/src/lib/services/httpClient.ts index 8a9ce58d20b..d9f7374140a 100644 --- a/libs/vscode-extension/src/lib/services/httpClient.ts +++ b/libs/vscode-extension/src/lib/services/httpClient.ts @@ -7,7 +7,6 @@ export interface HttpOptions { apiHubBaseUrl?: string; accessToken?: string; hostVersion?: string; - githubToken?: string; } export class HttpClient implements IHttpClient { @@ -20,7 +19,7 @@ export class HttpClient implements IHttpClient { this._baseUrl = options.baseUrl; this._accessToken = options.accessToken; this._apihubBaseUrl = options.apiHubBaseUrl; - this._extraHeaders = getExtraHeaders(options.hostVersion ?? '', options.githubToken); + this._extraHeaders = getExtraHeaders(options.hostVersion ?? ''); } dispose(): void {} @@ -33,7 +32,7 @@ export class HttpClient implements IHttpClient { headers: { ...this._extraHeaders, ...options.headers, - Authorization: `${isArmId ? this._accessToken : ''}`, + ...(isArmId ? { Authorization: `${this._accessToken}` } : {}), }, }; const response = await axios({ @@ -59,7 +58,7 @@ export class HttpClient implements IHttpClient { headers: { ...this._extraHeaders, ...options.headers, - Authorization: `${isArmId ? this._accessToken : ''}`, + ...(isArmId ? { Authorization: `${this._accessToken}` } : {}), 'Content-Type': 'application/json', }, data: options.content, @@ -116,7 +115,7 @@ export class HttpClient implements IHttpClient { headers: { ...this._extraHeaders, ...options.headers, - Authorization: `${isArmId ? this._accessToken : ''}`, + ...(isArmId ? { Authorization: `${this._accessToken}` } : {}), 'Content-Type': 'application/json', }, data: options.content, @@ -186,10 +185,9 @@ export function isArmResourceId(resourceId: string): boolean { return resourceId ? resourceId.indexOf('/subscriptions/') !== -1 : false; } -function getExtraHeaders(hostVersion: string, githubToken: string | undefined): Record { +function getExtraHeaders(hostVersion: string): Record { return { 'x-ms-user-agent': `LogicAppsDesigner/(host vscode ${hostVersion})`, - ...(githubToken ? { 'X-GitHub-Token': githubToken } : {}), }; } From 65805236b38ac2abbb199ddcdccadae798eeb117 Mon Sep 17 00:00:00 2001 From: Carlos Castro Trejo <102700317+ccastrotrejo@users.noreply.github.com> Date: Mon, 13 Oct 2025 18:24:18 +0000 Subject: [PATCH 45/46] Add ports visibility --- .../vs-code-designer/src/assets/container/devcontainer.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/vs-code-designer/src/assets/container/devcontainer.json b/apps/vs-code-designer/src/assets/container/devcontainer.json index a7379de1b84..ffadbd3858f 100644 --- a/apps/vs-code-designer/src/assets/container/devcontainer.json +++ b/apps/vs-code-designer/src/assets/container/devcontainer.json @@ -20,8 +20,12 @@ } } }, - "postStartCommand": "azurite --silent --location /home/vscode/.azurite --debug /home/vscode/.azurite/debug.log &", "otherPortsAttributes": { "onAutoForward": "silent" + }, + "portsAttributes": { + "*": { + "visibility": "public" + } } } \ No newline at end of file From 1bd2f25d104845e0df6dc36002f509824b7f8d84 Mon Sep 17 00:00:00 2001 From: Carlos Castro Trejo <102700317+ccastrotrejo@users.noreply.github.com> Date: Mon, 13 Oct 2025 18:40:44 +0000 Subject: [PATCH 46/46] Update test --- Localize/lang/strings.json | 2 -- .../src/lib/services/__test__/httpClient.spec.ts | 2 -- 2 files changed, 4 deletions(-) diff --git a/Localize/lang/strings.json b/Localize/lang/strings.json index b0b4e32b999..8f4fb1dabe5 100644 --- a/Localize/lang/strings.json +++ b/Localize/lang/strings.json @@ -3156,7 +3156,6 @@ "_e+GuGo.comment": "Placeholder title for a newly inserted Text parameter", "_e00zot.comment": "Recurrence parameter group title", "_e1+Gqi.comment": "Description for resource location section.", - "_e1gQAz.comment": "Debug logic app project error text", "_e4JZEY.comment": "Time zone value ", "_e8JCcn.comment": "Tooltip label for the button that allows user to group search results by connector.", "_e9OvzW.comment": "Clear", @@ -4241,7 +4240,6 @@ "e+GuGo": "Input", "e00zot": "How often do you want to check for items?", "e1+Gqi": "Select the resource location for your workflow", - "e1gQAz": "Please start the project by pressing F5 or run it through the Run and Debug view", "e4JZEY": "(UTC+07:00) Tomsk", "e8JCcn": "Group actions by connector", "e9OvzW": "Clear", diff --git a/libs/vscode-extension/src/lib/services/__test__/httpClient.spec.ts b/libs/vscode-extension/src/lib/services/__test__/httpClient.spec.ts index d95e6d1535d..cd73fb6017c 100644 --- a/libs/vscode-extension/src/lib/services/__test__/httpClient.spec.ts +++ b/libs/vscode-extension/src/lib/services/__test__/httpClient.spec.ts @@ -45,7 +45,6 @@ describe('HttpClient', () => { uri: '/test-get', url: `${baseUrl}/test-get`, headers: { - Authorization: '', 'x-ms-user-agent': 'LogicAppsDesigner/(host vscode 1.0.0)', }, }); @@ -190,7 +189,6 @@ describe('HttpClient', () => { url: `${baseUrl}/test-put`, content: { key: 'value' }, headers: { - Authorization: '', 'Content-Type': 'application/json', 'x-ms-user-agent': 'LogicAppsDesigner/(host vscode 1.0.0)', },