From 9889b95b47a7c2d15fe3728475f802c027470a3d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Feb 2026 15:21:53 +0000 Subject: [PATCH 1/4] Initial plan From 59ec6e3dd64677b2e0833637dbc36ae03240b2e9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Feb 2026 15:26:46 +0000 Subject: [PATCH 2/4] Add automated Linux install and upgrade support using official setup scripts Co-authored-by: garrytrinder <11563347+garrytrinder@users.noreply.github.com> --- src/commands/install.ts | 58 +++++++++++++++++++++++++++++++--- src/constants.ts | 2 ++ src/test/notifications.test.ts | 2 +- src/test/shell.test.ts | 15 ++++++++- src/utils/index.ts | 1 + src/utils/shell.ts | 9 ++++++ 6 files changed, 80 insertions(+), 7 deletions(-) diff --git a/src/commands/install.ts b/src/commands/install.ts index c6bfaf7..c2185f6 100644 --- a/src/commands/install.ts +++ b/src/commands/install.ts @@ -1,8 +1,9 @@ import * as vscode from 'vscode'; -import { Commands, Urls } from '../constants'; +import { Commands } from '../constants'; import { executeCommand, getPackageIdentifier, + getInstallScriptUrl, upgradeDevProxyWithPackageManager, openUpgradeDocumentation, } from '../utils/shell'; @@ -40,8 +41,7 @@ async function installDevProxy( } else if (platform === 'darwin') { await installOnMac(versionPreference); } else if (platform === 'linux') { - // Linux requires manual installation - vscode.env.openExternal(vscode.Uri.parse(Urls.linuxInstall)); + await installOnLinux(versionPreference); } } finally { message.dispose(); @@ -93,14 +93,62 @@ async function installOnMac(versionPreference: VersionPreference): Promise } } +async function installOnLinux(versionPreference: VersionPreference): Promise { + const scriptUrl = getInstallScriptUrl(versionPreference); + + // Check if bash is available + try { + await executeCommand('bash --version'); + } catch { + vscode.window.showErrorMessage('Bash is not available. Please install bash and try again.'); + return; + } + + // Check if curl is available + try { + await executeCommand('curl --version'); + } catch { + vscode.window.showErrorMessage('curl is not installed. Please install curl and try again.'); + return; + } + + try { + await executeCommand(`bash -c "$(curl -sL ${scriptUrl})"`); + const result = await vscode.window.showInformationMessage('Dev Proxy installed.', 'Reload'); + if (result === 'Reload') { + await vscode.commands.executeCommand('workbench.action.reloadWindow'); + } + } catch (error) { + vscode.window.showErrorMessage(`Failed to install Dev Proxy.\n${error}`); + } +} + async function upgradeDevProxy(configuration: vscode.WorkspaceConfiguration): Promise { const platform = process.platform; const versionPreference = configuration.get('version') as VersionPreference; const isBeta = versionPreference === VersionPreference.Beta; - // Linux always redirects to documentation + // Linux uses install script to upgrade if (platform === 'linux') { - openUpgradeDocumentation(); + const scriptUrl = getInstallScriptUrl(versionPreference); + const versionText = isBeta ? 'Dev Proxy Beta' : 'Dev Proxy'; + const statusMessage = vscode.window.setStatusBarMessage(`Upgrading ${versionText}...`); + + try { + await executeCommand(`bash -c "$(curl -sL ${scriptUrl})"`); + statusMessage.dispose(); + + const result = await vscode.window.showInformationMessage( + `${versionText} has been successfully upgraded!`, + 'Reload Window' + ); + if (result === 'Reload Window') { + await vscode.commands.executeCommand('workbench.action.reloadWindow'); + } + } catch { + statusMessage.dispose(); + openUpgradeDocumentation(); + } return; } diff --git a/src/constants.ts b/src/constants.ts index 4ae635a..b97d9a4 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -93,6 +93,8 @@ export const DiagnosticCodes = { export const Urls = { upgradeDoc: 'https://aka.ms/devproxy/upgrade', linuxInstall: 'https://aka.ms/devproxy/start/linux', + linuxSetupScript: 'https://aka.ms/devproxy/setup.sh', + linuxSetupBetaScript: 'https://aka.ms/devproxy/setup-beta.sh', schemaBase: 'https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas', diagnosticsDoc: 'https://learn.microsoft.com/microsoft-cloud/dev/dev-proxy/technical-reference/toolkit-diagnostics', } as const; diff --git a/src/test/notifications.test.ts b/src/test/notifications.test.ts index c6300fe..51f53ad 100644 --- a/src/test/notifications.test.ts +++ b/src/test/notifications.test.ts @@ -73,7 +73,7 @@ suite('notifications', () => { assert.strictEqual(actual, expected); }); - test('should not show install notification when running in unsupported operating system', async () => { + test('should not show install notification when devproxy is installed on linux', async () => { const context = await getExtensionContext(); await context.globalState.update( 'devProxyInstall', diff --git a/src/test/shell.test.ts b/src/test/shell.test.ts index 310a757..9873b64 100644 --- a/src/test/shell.test.ts +++ b/src/test/shell.test.ts @@ -3,13 +3,14 @@ * Tests for pure utility functions in shell.ts. */ import * as assert from 'assert'; -import { getPackageIdentifier, resolveDevProxyExecutable } from '../utils/shell'; +import { getPackageIdentifier, getInstallScriptUrl, resolveDevProxyExecutable } from '../utils/shell'; import { PackageManager, VersionPreference, HomebrewPackageIdentifier, WingetPackageIdentifier, } from '../enums'; +import { Urls } from '../constants'; suite('getPackageIdentifier', () => { test('should return stable Homebrew package for stable preference', () => { @@ -41,6 +42,18 @@ suite('getPackageIdentifier', () => { }); }); +suite('getInstallScriptUrl', () => { + test('should return stable script URL for stable preference', () => { + const result = getInstallScriptUrl(VersionPreference.Stable); + assert.strictEqual(result, Urls.linuxSetupScript); + }); + + test('should return beta script URL for beta preference', () => { + const result = getInstallScriptUrl(VersionPreference.Beta); + assert.strictEqual(result, Urls.linuxSetupBetaScript); + }); +}); + suite('resolveDevProxyExecutable', () => { const NONEXISTENT_DEVPROXY_COMMAND = 'devproxy-command-that-does-not-exist-for-tests'; diff --git a/src/utils/index.ts b/src/utils/index.ts index 01d3f29..b0089c2 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -23,6 +23,7 @@ export { executeCommand, sleep, getPackageIdentifier, + getInstallScriptUrl, upgradeDevProxyWithPackageManager, openUpgradeDocumentation, resolveDevProxyExecutable, diff --git a/src/utils/shell.ts b/src/utils/shell.ts index b4fef6f..bd00e70 100644 --- a/src/utils/shell.ts +++ b/src/utils/shell.ts @@ -58,6 +58,15 @@ export function getPackageIdentifier( return undefined; } +/** + * Get the Linux install script URL based on version preference. + */ +export function getInstallScriptUrl(versionPreference: VersionPreference): string { + return versionPreference === VersionPreference.Stable + ? Urls.linuxSetupScript + : Urls.linuxSetupBetaScript; +} + /** * Upgrade Dev Proxy using a package manager. * From f9b179d5d684cd90b3d33cff03df9cfd9d263a03 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Feb 2026 15:28:19 +0000 Subject: [PATCH 3/4] Refactor: extract shared Linux prerequisite checks and build command helper Co-authored-by: garrytrinder <11563347+garrytrinder@users.noreply.github.com> --- src/commands/install.ts | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/commands/install.ts b/src/commands/install.ts index c2185f6..705fc2f 100644 --- a/src/commands/install.ts +++ b/src/commands/install.ts @@ -93,27 +93,37 @@ async function installOnMac(versionPreference: VersionPreference): Promise } } -async function installOnLinux(versionPreference: VersionPreference): Promise { - const scriptUrl = getInstallScriptUrl(versionPreference); - - // Check if bash is available +async function checkLinuxPrerequisites(): Promise { try { await executeCommand('bash --version'); } catch { - vscode.window.showErrorMessage('Bash is not available. Please install bash and try again.'); - return; + vscode.window.showErrorMessage('Bash is not available. Please install Bash and try again.'); + return false; } - // Check if curl is available try { await executeCommand('curl --version'); } catch { vscode.window.showErrorMessage('curl is not installed. Please install curl and try again.'); + return false; + } + + return true; +} + +function buildLinuxInstallCommand(scriptUrl: string): string { + return `bash -c "$(curl -sL ${scriptUrl})"`; +} + +async function installOnLinux(versionPreference: VersionPreference): Promise { + if (!(await checkLinuxPrerequisites())) { return; } + const scriptUrl = getInstallScriptUrl(versionPreference); + try { - await executeCommand(`bash -c "$(curl -sL ${scriptUrl})"`); + await executeCommand(buildLinuxInstallCommand(scriptUrl)); const result = await vscode.window.showInformationMessage('Dev Proxy installed.', 'Reload'); if (result === 'Reload') { await vscode.commands.executeCommand('workbench.action.reloadWindow'); @@ -130,12 +140,17 @@ async function upgradeDevProxy(configuration: vscode.WorkspaceConfiguration): Pr // Linux uses install script to upgrade if (platform === 'linux') { + if (!(await checkLinuxPrerequisites())) { + openUpgradeDocumentation(); + return; + } + const scriptUrl = getInstallScriptUrl(versionPreference); const versionText = isBeta ? 'Dev Proxy Beta' : 'Dev Proxy'; const statusMessage = vscode.window.setStatusBarMessage(`Upgrading ${versionText}...`); try { - await executeCommand(`bash -c "$(curl -sL ${scriptUrl})"`); + await executeCommand(buildLinuxInstallCommand(scriptUrl)); statusMessage.dispose(); const result = await vscode.window.showInformationMessage( From 2b0b2dd5496c937df97ac0a59530faa4adfdd779 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Feb 2026 21:16:20 +0000 Subject: [PATCH 4/4] Add changelog and readme updates for Linux install support Co-authored-by: garrytrinder <11563347+garrytrinder@users.noreply.github.com> --- CHANGELOG.md | 1 + README.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a9c248..a4f3930 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added: +- Install: Added automated install and upgrade support for Linux using official setup scripts - Quick Fixes: Enable local language model fix now adds or updates `languageModel.enabled: true` for supported plugins only - Workspace: Added automatic prompt to recommend extension in `.vscode/extensions.json` when Dev Proxy config files are detected - Command: Added `Add to Workspace Recommendations` to manually add extension to workspace recommendations diff --git a/README.md b/README.md index 906b79b..58d2f09 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Supercharge your [Dev Proxy](https://aka.ms/devproxy) workflow with IntelliSense ## Quick Start -1. **Install this extension** - [Install from VS Code](vscode:extension/garrytrinder.dev-proxy-toolkit). You'll be prompted to install Dev Proxy if it's not already installed. +1. **Install this extension** - [Install from VS Code](vscode:extension/garrytrinder.dev-proxy-toolkit). You'll be prompted to install Dev Proxy if it's not already installed. Automated install is supported on Windows (winget), macOS (Homebrew), and Linux (setup script). 2. **Create a config** - Run `Dev Proxy Toolkit: Create configuration file` from the Command Palette 3. **Configure your proxy** - Add URLs to watch and plugins using snippets (type `devproxy-`) or let [GitHub Copilot help](#mcp-server) 4. **Start Dev Proxy** - Run `Dev Proxy Toolkit: Start` from the Command Palette