Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
73 changes: 68 additions & 5 deletions src/commands/install.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -93,14 +93,77 @@ async function installOnMac(versionPreference: VersionPreference): Promise<void>
}
}

async function checkLinuxPrerequisites(): Promise<boolean> {
try {
await executeCommand('bash --version');
} catch {
vscode.window.showErrorMessage('Bash is not available. Please install Bash and try again.');
return false;
}

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<void> {
if (!(await checkLinuxPrerequisites())) {
return;
}

const scriptUrl = getInstallScriptUrl(versionPreference);

try {
await executeCommand(buildLinuxInstallCommand(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<void> {
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();
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(buildLinuxInstallCommand(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;
}

Expand Down
2 changes: 2 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/test/notifications.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
15 changes: 14 additions & 1 deletion src/test/shell.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down Expand Up @@ -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';

Expand Down
1 change: 1 addition & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export {
executeCommand,
sleep,
getPackageIdentifier,
getInstallScriptUrl,
upgradeDevProxyWithPackageManager,
openUpgradeDocumentation,
resolveDevProxyExecutable,
Expand Down
9 changes: 9 additions & 0 deletions src/utils/shell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down