Skip to content

Commit c8a18d8

Browse files
authored
Remove verbose or debug environment variables from Ruby env (#1889)
* Use stubs to setup Ruby and Debugger test * Remove verbose or debug environment variables
1 parent 9f3505a commit c8a18d8

File tree

3 files changed

+112
-48
lines changed

3 files changed

+112
-48
lines changed

vscode/src/ruby.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,6 @@ export class Ruby implements RubyInterface {
150150
}
151151

152152
this.fetchRubyVersionInfo();
153-
this.deleteGcEnvironmentVariables();
154153
await this.setupBundlePath();
155154
this._error = false;
156155
} catch (error: any) {
@@ -172,6 +171,8 @@ export class Ruby implements RubyInterface {
172171
const { env, version, yjit } = await manager.activate();
173172
const [major, minor, _patch] = version.split(".").map(Number);
174173

174+
this.sanitizeEnvironment(env);
175+
175176
// We need to set the process environment too to make other extensions such as Sorbet find the right Ruby paths
176177
process.env = env;
177178
this._env = env;
@@ -240,12 +241,20 @@ export class Ruby implements RubyInterface {
240241
}
241242
}
242243

243-
private deleteGcEnvironmentVariables() {
244-
Object.keys(this._env).forEach((key) => {
244+
// Deletes environment variables that are known to cause issues for launching the Ruby LSP. For example, GC tuning
245+
// variables or verbose settings
246+
private sanitizeEnvironment(env: NodeJS.ProcessEnv) {
247+
// Delete all GC tuning variables
248+
Object.keys(env).forEach((key) => {
245249
if (key.startsWith("RUBY_GC")) {
246-
delete this._env[key];
250+
delete env[key];
247251
}
248252
});
253+
254+
// Delete verbose or debug related settings. These often make Bundler or other dependencies print things to STDOUT,
255+
// which breaks the client/server communication
256+
delete env.VERBOSE;
257+
delete env.DEBUG;
249258
}
250259

251260
private async setupBundlePath() {

vscode/src/test/suite/debugger.test.ts

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import * as path from "path";
44
import * as os from "os";
55

66
import * as vscode from "vscode";
7+
import sinon from "sinon";
78

89
import { Debugger } from "../../debugger";
910
import { Ruby, ManagerIdentifier } from "../../ruby";
@@ -158,21 +159,25 @@ suite("Debugger", () => {
158159

159160
test("Launching the debugger", async () => {
160161
// eslint-disable-next-line no-process-env
161-
if (process.env.CI) {
162-
await vscode.workspace
163-
.getConfiguration("rubyLsp")
164-
.update("rubyVersionManager", ManagerIdentifier.None, true, true);
165-
}
166-
167-
// By default, VS Code always saves all open files when launching a debugging session. This is a problem for tests
168-
// because it attempts to save an untitled test file and then we get stuck in the save file dialog with no way of
169-
// closing it. We have to disable that before running this test
170-
const currentSaveBeforeStart = await vscode.workspace
171-
.getConfiguration("debug")
172-
.get("saveBeforeStart");
173-
await vscode.workspace
174-
.getConfiguration("debug")
175-
.update("saveBeforeStart", "none", true, true);
162+
const manager = process.env.CI
163+
? ManagerIdentifier.None
164+
: ManagerIdentifier.Chruby;
165+
166+
const configStub = sinon
167+
.stub(vscode.workspace, "getConfiguration")
168+
.returns({
169+
get: (name: string) => {
170+
if (name === "rubyVersionManager") {
171+
return manager;
172+
} else if (name === "bundleGemfile") {
173+
return "";
174+
} else if (name === "saveBeforeStart") {
175+
return "none";
176+
}
177+
178+
return undefined;
179+
},
180+
} as unknown as vscode.WorkspaceConfiguration);
176181

177182
const tmpPath = fs.mkdtempSync(
178183
path.join(os.tmpdir(), "ruby-lsp-test-debugger"),
@@ -225,14 +230,16 @@ suite("Debugger", () => {
225230
}
226231

227232
// The debugger might take a bit of time to disconnect from the editor. We need to perform cleanup when we receive
228-
// the termination callback or else we try to dispose of the debugger client too early
229-
vscode.debug.onDidTerminateDebugSession(async (_session) => {
230-
debug.dispose();
231-
context.subscriptions.forEach((subscription) => subscription.dispose());
232-
fs.rmSync(tmpPath, { recursive: true, force: true });
233-
await vscode.workspace
234-
.getConfiguration("debug")
235-
.update("saveBeforeStart", currentSaveBeforeStart, true, true);
233+
// the termination callback or else we try to dispose of the debugger client too early, but we need to wait for that
234+
// so that we can clean up stubs otherwise they leak into other tests.
235+
await new Promise<void>((resolve) => {
236+
vscode.debug.onDidTerminateDebugSession((_session) => {
237+
configStub.restore();
238+
debug.dispose();
239+
context.subscriptions.forEach((subscription) => subscription.dispose());
240+
fs.rmSync(tmpPath, { recursive: true, force: true });
241+
resolve();
242+
});
236243
});
237244
}).timeout(45000);
238245
});

vscode/src/test/suite/ruby.test.ts

Lines changed: 69 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,50 @@
1+
/* eslint-disable no-process-env */
12
import * as assert from "assert";
2-
import * as fs from "fs";
33
import * as path from "path";
4-
import * as os from "os";
54

65
import * as vscode from "vscode";
6+
import sinon from "sinon";
77

88
import { Ruby, ManagerIdentifier } from "../../ruby";
99
import { WorkspaceChannel } from "../../workspaceChannel";
1010
import { LOG_CHANNEL } from "../../common";
1111

1212
suite("Ruby environment activation", () => {
13-
let ruby: Ruby;
13+
const workspacePath = path.dirname(
14+
path.dirname(path.dirname(path.dirname(__dirname))),
15+
);
16+
const workspaceFolder: vscode.WorkspaceFolder = {
17+
uri: vscode.Uri.file(workspacePath),
18+
name: path.basename(workspacePath),
19+
index: 0,
20+
};
1421

1522
test("Activate fetches Ruby information when outside of Ruby LSP", async () => {
16-
if (os.platform() !== "win32") {
17-
// eslint-disable-next-line no-process-env
18-
process.env.SHELL = "/bin/bash";
19-
}
23+
const manager = process.env.CI
24+
? ManagerIdentifier.None
25+
: ManagerIdentifier.Chruby;
2026

21-
const tmpPath = fs.mkdtempSync(path.join(os.tmpdir(), "ruby-lsp-test-"));
22-
fs.writeFileSync(path.join(tmpPath, ".ruby-version"), "3.3.0");
27+
const configStub = sinon
28+
.stub(vscode.workspace, "getConfiguration")
29+
.returns({
30+
get: (name: string) => {
31+
if (name === "rubyVersionManager") {
32+
return manager;
33+
} else if (name === "bundleGemfile") {
34+
return "";
35+
}
36+
37+
return undefined;
38+
},
39+
} as unknown as vscode.WorkspaceConfiguration);
2340

2441
const context = {
2542
extensionMode: vscode.ExtensionMode.Test,
2643
} as vscode.ExtensionContext;
2744
const outputChannel = new WorkspaceChannel("fake", LOG_CHANNEL);
2845

29-
ruby = new Ruby(
30-
context,
31-
{
32-
uri: vscode.Uri.file(tmpPath),
33-
} as vscode.WorkspaceFolder,
34-
outputChannel,
35-
);
36-
await ruby.activateRuby(
37-
// eslint-disable-next-line no-process-env
38-
process.env.CI ? ManagerIdentifier.None : ManagerIdentifier.Chruby,
39-
);
46+
const ruby = new Ruby(context, workspaceFolder, outputChannel);
47+
await ruby.activateRuby();
4048

4149
assert.ok(ruby.rubyVersion, "Expected Ruby version to be set");
4250
assert.notStrictEqual(
@@ -45,6 +53,46 @@ suite("Ruby environment activation", () => {
4553
"Expected YJIT support to be set to true or false",
4654
);
4755

48-
fs.rmSync(tmpPath, { recursive: true, force: true });
56+
configStub.restore();
57+
}).timeout(10000);
58+
59+
test("Deletes verbose and GC settings from activated environment", async () => {
60+
const manager = process.env.CI
61+
? ManagerIdentifier.None
62+
: ManagerIdentifier.Chruby;
63+
64+
const configStub = sinon
65+
.stub(vscode.workspace, "getConfiguration")
66+
.returns({
67+
get: (name: string) => {
68+
if (name === "rubyVersionManager") {
69+
return manager;
70+
} else if (name === "bundleGemfile") {
71+
return "";
72+
}
73+
74+
return undefined;
75+
},
76+
} as unknown as vscode.WorkspaceConfiguration);
77+
78+
const context = {
79+
extensionMode: vscode.ExtensionMode.Test,
80+
} as vscode.ExtensionContext;
81+
const outputChannel = new WorkspaceChannel("fake", LOG_CHANNEL);
82+
83+
const ruby = new Ruby(context, workspaceFolder, outputChannel);
84+
85+
process.env.VERBOSE = "1";
86+
process.env.DEBUG = "WARN";
87+
process.env.RUBY_GC_HEAP_GROWTH_FACTOR = "1.7";
88+
await ruby.activateRuby();
89+
90+
assert.strictEqual(ruby.env.VERBOSE, undefined);
91+
assert.strictEqual(ruby.env.DEBUG, undefined);
92+
assert.strictEqual(ruby.env.RUBY_GC_HEAP_GROWTH_FACTOR, undefined);
93+
delete process.env.VERBOSE;
94+
delete process.env.DEBUG;
95+
delete process.env.RUBY_GC_HEAP_GROWTH_FACTOR;
96+
configStub.restore();
4997
});
5098
});

0 commit comments

Comments
 (0)