Skip to content

Commit ced10ec

Browse files
Add automated install and upgrade support for Linux (#347)
* Initial plan * Add automated Linux install and upgrade support using official setup scripts Co-authored-by: garrytrinder <11563347+garrytrinder@users.noreply.github.com> * Refactor: extract shared Linux prerequisite checks and build command helper Co-authored-by: garrytrinder <11563347+garrytrinder@users.noreply.github.com> * Add changelog and readme updates for Linux install support Co-authored-by: garrytrinder <11563347+garrytrinder@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: garrytrinder <11563347+garrytrinder@users.noreply.github.com>
1 parent ab59bc9 commit ced10ec

File tree

8 files changed

+97
-8
lines changed

8 files changed

+97
-8
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
### Added:
1313

14+
- Install: Added automated install and upgrade support for Linux using official setup scripts
1415
- Quick Fixes: Enable local language model fix now adds or updates `languageModel.enabled: true` for supported plugins only
1516
- Workspace: Added automatic prompt to recommend extension in `.vscode/extensions.json` when Dev Proxy config files are detected
1617
- Command: Added `Add to Workspace Recommendations` to manually add extension to workspace recommendations

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Supercharge your [Dev Proxy](https://aka.ms/devproxy) workflow with IntelliSense
1111

1212
## Quick Start
1313

14-
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.
14+
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).
1515
2. **Create a config** - Run `Dev Proxy Toolkit: Create configuration file` from the Command Palette
1616
3. **Configure your proxy** - Add URLs to watch and plugins using snippets (type `devproxy-`) or let [GitHub Copilot help](#mcp-server)
1717
4. **Start Dev Proxy** - Run `Dev Proxy Toolkit: Start` from the Command Palette

src/commands/install.ts

Lines changed: 68 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import * as vscode from 'vscode';
2-
import { Commands, Urls } from '../constants';
2+
import { Commands } from '../constants';
33
import {
44
executeCommand,
55
getPackageIdentifier,
6+
getInstallScriptUrl,
67
upgradeDevProxyWithPackageManager,
78
openUpgradeDocumentation,
89
} from '../utils/shell';
@@ -40,8 +41,7 @@ async function installDevProxy(
4041
} else if (platform === 'darwin') {
4142
await installOnMac(versionPreference);
4243
} else if (platform === 'linux') {
43-
// Linux requires manual installation
44-
vscode.env.openExternal(vscode.Uri.parse(Urls.linuxInstall));
44+
await installOnLinux(versionPreference);
4545
}
4646
} finally {
4747
message.dispose();
@@ -93,14 +93,77 @@ async function installOnMac(versionPreference: VersionPreference): Promise<void>
9393
}
9494
}
9595

96+
async function checkLinuxPrerequisites(): Promise<boolean> {
97+
try {
98+
await executeCommand('bash --version');
99+
} catch {
100+
vscode.window.showErrorMessage('Bash is not available. Please install Bash and try again.');
101+
return false;
102+
}
103+
104+
try {
105+
await executeCommand('curl --version');
106+
} catch {
107+
vscode.window.showErrorMessage('curl is not installed. Please install curl and try again.');
108+
return false;
109+
}
110+
111+
return true;
112+
}
113+
114+
function buildLinuxInstallCommand(scriptUrl: string): string {
115+
return `bash -c "$(curl -sL ${scriptUrl})"`;
116+
}
117+
118+
async function installOnLinux(versionPreference: VersionPreference): Promise<void> {
119+
if (!(await checkLinuxPrerequisites())) {
120+
return;
121+
}
122+
123+
const scriptUrl = getInstallScriptUrl(versionPreference);
124+
125+
try {
126+
await executeCommand(buildLinuxInstallCommand(scriptUrl));
127+
const result = await vscode.window.showInformationMessage('Dev Proxy installed.', 'Reload');
128+
if (result === 'Reload') {
129+
await vscode.commands.executeCommand('workbench.action.reloadWindow');
130+
}
131+
} catch (error) {
132+
vscode.window.showErrorMessage(`Failed to install Dev Proxy.\n${error}`);
133+
}
134+
}
135+
96136
async function upgradeDevProxy(configuration: vscode.WorkspaceConfiguration): Promise<void> {
97137
const platform = process.platform;
98138
const versionPreference = configuration.get('version') as VersionPreference;
99139
const isBeta = versionPreference === VersionPreference.Beta;
100140

101-
// Linux always redirects to documentation
141+
// Linux uses install script to upgrade
102142
if (platform === 'linux') {
103-
openUpgradeDocumentation();
143+
if (!(await checkLinuxPrerequisites())) {
144+
openUpgradeDocumentation();
145+
return;
146+
}
147+
148+
const scriptUrl = getInstallScriptUrl(versionPreference);
149+
const versionText = isBeta ? 'Dev Proxy Beta' : 'Dev Proxy';
150+
const statusMessage = vscode.window.setStatusBarMessage(`Upgrading ${versionText}...`);
151+
152+
try {
153+
await executeCommand(buildLinuxInstallCommand(scriptUrl));
154+
statusMessage.dispose();
155+
156+
const result = await vscode.window.showInformationMessage(
157+
`${versionText} has been successfully upgraded!`,
158+
'Reload Window'
159+
);
160+
if (result === 'Reload Window') {
161+
await vscode.commands.executeCommand('workbench.action.reloadWindow');
162+
}
163+
} catch {
164+
statusMessage.dispose();
165+
openUpgradeDocumentation();
166+
}
104167
return;
105168
}
106169

src/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ export const DiagnosticCodes = {
9393
export const Urls = {
9494
upgradeDoc: 'https://aka.ms/devproxy/upgrade',
9595
linuxInstall: 'https://aka.ms/devproxy/start/linux',
96+
linuxSetupScript: 'https://aka.ms/devproxy/setup.sh',
97+
linuxSetupBetaScript: 'https://aka.ms/devproxy/setup-beta.sh',
9698
schemaBase: 'https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas',
9799
diagnosticsDoc: 'https://learn.microsoft.com/microsoft-cloud/dev/dev-proxy/technical-reference/toolkit-diagnostics',
98100
} as const;

src/test/notifications.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ suite('notifications', () => {
7373
assert.strictEqual(actual, expected);
7474
});
7575

76-
test('should not show install notification when running in unsupported operating system', async () => {
76+
test('should not show install notification when devproxy is installed on linux', async () => {
7777
const context = await getExtensionContext();
7878
await context.globalState.update(
7979
'devProxyInstall',

src/test/shell.test.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33
* Tests for pure utility functions in shell.ts.
44
*/
55
import * as assert from 'assert';
6-
import { getPackageIdentifier, resolveDevProxyExecutable } from '../utils/shell';
6+
import { getPackageIdentifier, getInstallScriptUrl, resolveDevProxyExecutable } from '../utils/shell';
77
import {
88
PackageManager,
99
VersionPreference,
1010
HomebrewPackageIdentifier,
1111
WingetPackageIdentifier,
1212
} from '../enums';
13+
import { Urls } from '../constants';
1314

1415
suite('getPackageIdentifier', () => {
1516
test('should return stable Homebrew package for stable preference', () => {
@@ -41,6 +42,18 @@ suite('getPackageIdentifier', () => {
4142
});
4243
});
4344

45+
suite('getInstallScriptUrl', () => {
46+
test('should return stable script URL for stable preference', () => {
47+
const result = getInstallScriptUrl(VersionPreference.Stable);
48+
assert.strictEqual(result, Urls.linuxSetupScript);
49+
});
50+
51+
test('should return beta script URL for beta preference', () => {
52+
const result = getInstallScriptUrl(VersionPreference.Beta);
53+
assert.strictEqual(result, Urls.linuxSetupBetaScript);
54+
});
55+
});
56+
4457
suite('resolveDevProxyExecutable', () => {
4558
const NONEXISTENT_DEVPROXY_COMMAND = 'devproxy-command-that-does-not-exist-for-tests';
4659

src/utils/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export {
2323
executeCommand,
2424
sleep,
2525
getPackageIdentifier,
26+
getInstallScriptUrl,
2627
upgradeDevProxyWithPackageManager,
2728
openUpgradeDocumentation,
2829
resolveDevProxyExecutable,

src/utils/shell.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,15 @@ export function getPackageIdentifier(
5858
return undefined;
5959
}
6060

61+
/**
62+
* Get the Linux install script URL based on version preference.
63+
*/
64+
export function getInstallScriptUrl(versionPreference: VersionPreference): string {
65+
return versionPreference === VersionPreference.Stable
66+
? Urls.linuxSetupScript
67+
: Urls.linuxSetupBetaScript;
68+
}
69+
6170
/**
6271
* Upgrade Dev Proxy using a package manager.
6372
*

0 commit comments

Comments
 (0)