Skip to content

Commit 9232981

Browse files
authored
Add support to CODER_BINARY_DESTINATION environment variable (#597)
Fixes #256
1 parent 2c7974c commit 9232981

File tree

8 files changed

+52
-18
lines changed

8 files changed

+52
-18
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## Unreleased
44

5+
### Added
6+
7+
- Support for `CODER_BINARY_DESTINATION` environment variable to set CLI download location (overridden by extension setting `coder.binaryDestination` if configured).
8+
59
## [v1.11.0](https://github.com/coder/vscode-coder/releases/tag/v1.11.0) 2025-09-24
610

711
### Changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
"default": ""
5757
},
5858
"coder.binaryDestination": {
59-
"markdownDescription": "The full path of the directory into which the Coder CLI will be downloaded. Defaults to the extension's global storage directory.",
59+
"markdownDescription": "The full path of the directory into which the Coder CLI will be downloaded. Defaults to the value of `CODER_BINARY_DESTINATION` if not set, otherwise the extension's global storage directory.",
6060
"type": "string",
6161
"default": ""
6262
},

src/commands.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,13 @@ export class Commands {
102102
* CODER_URL or enter a new one. Undefined means the user aborted.
103103
*/
104104
private async askURL(selection?: string): Promise<string | undefined> {
105-
const defaultURL =
106-
vscode.workspace.getConfiguration().get<string>("coder.defaultUrl") ?? "";
105+
const defaultURL = vscode.workspace
106+
.getConfiguration()
107+
.get<string>("coder.defaultUrl")
108+
?.trim();
107109
const quickPick = vscode.window.createQuickPick();
108-
quickPick.value = selection || defaultURL || process.env.CODER_URL || "";
110+
quickPick.value =
111+
selection || defaultURL || process.env.CODER_URL?.trim() || "";
109112
quickPick.placeholder = "https://example.coder.com";
110113
quickPick.title = "Enter the URL of your Coder deployment.";
111114

src/core/pathResolver.test.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as path from "path";
2-
import { describe, it, expect, beforeEach } from "vitest";
2+
import { describe, it, expect, beforeEach, vi } from "vitest";
33
import { MockConfigurationProvider } from "../__mocks__/testHelpers";
44
import { PathResolver } from "./pathResolver";
55

@@ -11,6 +11,7 @@ describe("PathResolver", () => {
1111
let mockConfig: MockConfigurationProvider;
1212

1313
beforeEach(() => {
14+
vi.unstubAllEnvs();
1415
pathResolver = new PathResolver(basePath, codeLogPath);
1516
mockConfig = new MockConfigurationProvider();
1617
});
@@ -32,6 +33,7 @@ describe("PathResolver", () => {
3233
});
3334

3435
it("should use default path when custom destination is empty or whitespace", () => {
36+
vi.stubEnv("CODER_BINARY_DESTINATION", " ");
3537
mockConfig.set("coder.binaryDestination", " ");
3638
expect(pathResolver.getBinaryCachePath("deployment")).toBe(
3739
path.join(basePath, "deployment", "bin"),
@@ -41,7 +43,28 @@ describe("PathResolver", () => {
4143
it("should normalize custom paths", () => {
4244
mockConfig.set("coder.binaryDestination", "/custom/../binary/./path");
4345
expect(pathResolver.getBinaryCachePath("deployment")).toBe(
44-
path.normalize("/custom/../binary/./path"),
46+
"/binary/path",
47+
);
48+
});
49+
50+
it("should use CODER_BINARY_DESTINATION environment variable with proper precedence", () => {
51+
// Use the global storage when the environment variable and setting are unset/blank
52+
vi.stubEnv("CODER_BINARY_DESTINATION", "");
53+
mockConfig.set("coder.binaryDestination", "");
54+
expect(pathResolver.getBinaryCachePath("deployment")).toBe(
55+
path.join(basePath, "deployment", "bin"),
56+
);
57+
58+
// Test environment variable takes precedence over global storage
59+
vi.stubEnv("CODER_BINARY_DESTINATION", " /env/binary/path ");
60+
expect(pathResolver.getBinaryCachePath("deployment")).toBe(
61+
"/env/binary/path",
62+
);
63+
64+
// Test setting takes precedence over environment variable
65+
mockConfig.set("coder.binaryDestination", " /setting/path ");
66+
expect(pathResolver.getBinaryCachePath("deployment")).toBe(
67+
"/setting/path",
4568
);
4669
});
4770
});

src/core/pathResolver.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,14 @@ export class PathResolver {
2828
* The caller must ensure this directory exists before use.
2929
*/
3030
public getBinaryCachePath(label: string): string {
31-
const configPath = vscode.workspace
31+
const settingPath = vscode.workspace
3232
.getConfiguration()
33-
.get<string>("coder.binaryDestination");
34-
return configPath && configPath.trim().length > 0
35-
? path.normalize(configPath)
33+
.get<string>("coder.binaryDestination")
34+
?.trim();
35+
const binaryPath =
36+
settingPath || process.env.CODER_BINARY_DESTINATION?.trim();
37+
return binaryPath
38+
? path.normalize(binaryPath)
3639
: path.join(this.getGlobalConfigDir(label), "bin");
3740
}
3841

src/extension.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,9 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
423423
// Handle autologin, if not already logged in.
424424
const cfg = vscode.workspace.getConfiguration();
425425
if (cfg.get("coder.autologin") === true) {
426-
const defaultUrl = cfg.get("coder.defaultUrl") || process.env.CODER_URL;
426+
const defaultUrl =
427+
cfg.get<string>("coder.defaultUrl")?.trim() ||
428+
process.env.CODER_URL?.trim();
427429
if (defaultUrl) {
428430
vscode.commands.executeCommand(
429431
"coder.login",

src/headers.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,9 @@ describe("getHeaderCommand", () => {
123123
expect(getHeaderCommand(config)).toBeUndefined();
124124
});
125125

126-
it("should return undefined if coder.headerCommand is not a string", () => {
126+
it("should return undefined if coder.headerCommand is a blank string", () => {
127127
const config = {
128-
get: () => 1234,
128+
get: () => " ",
129129
} as unknown as WorkspaceConfiguration;
130130

131131
expect(getHeaderCommand(config)).toBeUndefined();

src/headers.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,10 @@ export function getHeaderCommand(
1919
config: WorkspaceConfiguration,
2020
): string | undefined {
2121
const cmd =
22-
config.get("coder.headerCommand") || process.env.CODER_HEADER_COMMAND;
23-
if (!cmd || typeof cmd !== "string") {
24-
return undefined;
25-
}
26-
return cmd;
22+
config.get<string>("coder.headerCommand")?.trim() ||
23+
process.env.CODER_HEADER_COMMAND?.trim();
24+
25+
return cmd ? cmd : undefined;
2726
}
2827

2928
export function getHeaderArgs(config: WorkspaceConfiguration): string[] {

0 commit comments

Comments
 (0)