From 947039b4067cc09685431ca7a7b13a802647f74f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 20 Aug 2025 15:08:09 +0000 Subject: [PATCH 1/7] Initial plan From 55bf81bf87e7ecbe9a2661c6fab00b51ecb1adf5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 20 Aug 2025 15:11:48 +0000 Subject: [PATCH 2/7] Initial plan for multiple test environment files support Co-authored-by: jfoshee <480334+jfoshee@users.noreply.github.com> --- extension/package-lock.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/package-lock.json b/extension/package-lock.json index d15fff953b..648162322b 100644 --- a/extension/package-lock.json +++ b/extension/package-lock.json @@ -49,7 +49,7 @@ }, "engines": { "node": ">=16.14.2", - "vscode": "^1.75.0" + "vscode": "^1.90.0" } }, "node_modules/@babel/code-frame": { From 59454b8954e3051caac987e788134486f420af99 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 20 Aug 2025 15:18:53 +0000 Subject: [PATCH 3/7] Implement multiple test environment files support Co-authored-by: jfoshee <480334+jfoshee@users.noreply.github.com> --- extension/package.json | 12 +++- extension/src/testUtils.ts | 26 ++++++-- extension/test/unit/testEnvFiles.test.ts | 83 ++++++++++++++++++++++++ 3 files changed, 115 insertions(+), 6 deletions(-) create mode 100644 extension/test/unit/testEnvFiles.test.ts diff --git a/extension/package.json b/extension/package.json index 2d48b1fff8..f3e06d109a 100644 --- a/extension/package.json +++ b/extension/package.json @@ -1438,7 +1438,17 @@ "go.testEnvFile": { "type": "string", "default": null, - "description": "Absolute path to a file containing environment variables definitions. File contents should be of the form key=value.", + "description": "Absolute path to a file containing environment variables definitions. File contents should be of the form key=value. (Deprecated: Use go.testEnvFiles instead)", + "scope": "resource", + "deprecationMessage": "Use go.testEnvFiles instead" + }, + "go.testEnvFiles": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "Array of absolute paths to files containing environment variables definitions. File contents should be of the form key=value.", "scope": "resource" }, "go.testFlags": { diff --git a/extension/src/testUtils.ts b/extension/src/testUtils.ts index 4070f6e6d1..8a379be5c9 100644 --- a/extension/src/testUtils.ts +++ b/extension/src/testUtils.ts @@ -19,7 +19,7 @@ import { getCurrentPackage } from './goModules'; import { GoDocumentSymbolProvider } from './goDocumentSymbols'; import { getNonVendorPackages } from './goPackages'; import { getBinPath, getCurrentGoPath, getTempFilePath, LineBuffer, resolvePath } from './util'; -import { parseEnvFile } from './utils/envUtils'; +import { parseEnvFile, parseEnvFiles } from './utils/envUtils'; import { getEnvPath, expandFilePathInOutput, @@ -111,12 +111,28 @@ export function getTestEnvVars(config: vscode.WorkspaceConfiguration): any { const envVars = toolExecutionEnvironment(); const testEnvConfig = config['testEnvVars'] || {}; - let fileEnv: { [key: string]: any } = {}; - let testEnvFile = config['testEnvFile']; + // Collect environment files from both settings + const envFiles: string[] = []; + + // Add files from the new testEnvFiles setting (array) + const testEnvFiles = config['testEnvFiles'] || []; + if (Array.isArray(testEnvFiles)) { + envFiles.push(...testEnvFiles); + } + + // Add the deprecated testEnvFile setting (single file) for backward compatibility + const testEnvFile = config['testEnvFile']; if (testEnvFile) { - testEnvFile = resolvePath(testEnvFile); + envFiles.push(testEnvFile); + } + + // Parse all environment files + let fileEnv: { [key: string]: any } = {}; + if (envFiles.length > 0) { try { - fileEnv = parseEnvFile(testEnvFile, envVars); + // Resolve paths for all files + const resolvedFiles = envFiles.map((file) => resolvePath(file)); + fileEnv = parseEnvFiles(resolvedFiles, envVars); } catch (e) { console.log(e); } diff --git a/extension/test/unit/testEnvFiles.test.ts b/extension/test/unit/testEnvFiles.test.ts new file mode 100644 index 0000000000..3b75bb763c --- /dev/null +++ b/extension/test/unit/testEnvFiles.test.ts @@ -0,0 +1,83 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See LICENSE in the project root for license information. + *--------------------------------------------------------*/ + +import * as assert from 'assert'; +import * as path from 'path'; +import * as fs from 'fs'; +import * as os from 'os'; +import { parseEnvFiles } from '../../src/utils/envUtils'; + +suite('parseEnvFiles Tests', () => { + let tmpDir: string; + + setup(() => { + tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'go-test-env-')); + }); + + teardown(() => { + if (tmpDir && fs.existsSync(tmpDir)) { + // Use rmdir for compatibility with older Node.js versions + const rimraf = (dir: string) => { + if (fs.existsSync(dir)) { + fs.readdirSync(dir).forEach((file) => { + const curPath = path.join(dir, file); + if (fs.lstatSync(curPath).isDirectory()) { + rimraf(curPath); + } else { + fs.unlinkSync(curPath); + } + }); + fs.rmdirSync(dir); + } + }; + rimraf(tmpDir); + } + }); + + test('should handle empty array', () => { + const result = parseEnvFiles([]); + assert.deepStrictEqual(result, {}); + }); + + test('should handle undefined input', () => { + const result = parseEnvFiles(undefined); + assert.deepStrictEqual(result, {}); + }); + + test('should handle single string input', () => { + const envFile = path.join(tmpDir, 'single.env'); + fs.writeFileSync(envFile, 'SINGLE_VAR=single_value'); + + const result = parseEnvFiles(envFile); + assert.strictEqual(result.SINGLE_VAR, 'single_value'); + }); + + test('should handle array of files', () => { + const envFile1 = path.join(tmpDir, 'first.env'); + const envFile2 = path.join(tmpDir, 'second.env'); + + fs.writeFileSync(envFile1, 'VAR1=value1\nSHARED=from_first'); + fs.writeFileSync(envFile2, 'VAR2=value2\nSHARED=from_second'); + + const result = parseEnvFiles([envFile1, envFile2]); + + assert.strictEqual(result.VAR1, 'value1'); + assert.strictEqual(result.VAR2, 'value2'); + // Later files should override earlier ones + assert.strictEqual(result.SHARED, 'from_second'); + }); + + test('should handle mixed valid and invalid files', () => { + const validFile = path.join(tmpDir, 'valid.env'); + const invalidFile = path.join(tmpDir, 'nonexistent.env'); + + fs.writeFileSync(validFile, 'VALID_VAR=valid_value'); + + // This should throw when trying to parse invalid file + assert.throws(() => { + parseEnvFiles([validFile, invalidFile]); + }); + }); +}); From 5b1bab2f181160ccd437fe9d8f1d1856692d5572 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 20 Aug 2025 16:58:09 +0000 Subject: [PATCH 4/7] Address test file feedback: fix imports, use fs.rmSync, remove single string test Co-authored-by: jfoshee <480334+jfoshee@users.noreply.github.com> --- extension/test/unit/testEnvFiles.test.ts | 26 ++---------------------- 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/extension/test/unit/testEnvFiles.test.ts b/extension/test/unit/testEnvFiles.test.ts index 3b75bb763c..9ad3b5fa68 100644 --- a/extension/test/unit/testEnvFiles.test.ts +++ b/extension/test/unit/testEnvFiles.test.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See LICENSE in the project root for license information. *--------------------------------------------------------*/ -import * as assert from 'assert'; +import assert from 'assert'; import * as path from 'path'; import * as fs from 'fs'; import * as os from 'os'; @@ -18,21 +18,7 @@ suite('parseEnvFiles Tests', () => { teardown(() => { if (tmpDir && fs.existsSync(tmpDir)) { - // Use rmdir for compatibility with older Node.js versions - const rimraf = (dir: string) => { - if (fs.existsSync(dir)) { - fs.readdirSync(dir).forEach((file) => { - const curPath = path.join(dir, file); - if (fs.lstatSync(curPath).isDirectory()) { - rimraf(curPath); - } else { - fs.unlinkSync(curPath); - } - }); - fs.rmdirSync(dir); - } - }; - rimraf(tmpDir); + fs.rmSync(tmpDir, { recursive: true }); } }); @@ -46,14 +32,6 @@ suite('parseEnvFiles Tests', () => { assert.deepStrictEqual(result, {}); }); - test('should handle single string input', () => { - const envFile = path.join(tmpDir, 'single.env'); - fs.writeFileSync(envFile, 'SINGLE_VAR=single_value'); - - const result = parseEnvFiles(envFile); - assert.strictEqual(result.SINGLE_VAR, 'single_value'); - }); - test('should handle array of files', () => { const envFile1 = path.join(tmpDir, 'first.env'); const envFile2 = path.join(tmpDir, 'second.env'); From a692826d291f9203501105388c49ac91d1256e77 Mon Sep 17 00:00:00 2001 From: Jacob Foshee Date: Wed, 20 Aug 2025 17:00:08 -0500 Subject: [PATCH 5/7] revert extension/package-lock.json --- extension/package-lock.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/package-lock.json b/extension/package-lock.json index 648162322b..d15fff953b 100644 --- a/extension/package-lock.json +++ b/extension/package-lock.json @@ -49,7 +49,7 @@ }, "engines": { "node": ">=16.14.2", - "vscode": "^1.90.0" + "vscode": "^1.75.0" } }, "node_modules/@babel/code-frame": { From b7570808ceaf8c6914bf3e492be5c64c86431718 Mon Sep 17 00:00:00 2001 From: Jacob Foshee Date: Wed, 20 Aug 2025 17:00:31 -0500 Subject: [PATCH 6/7] Use conventional imports --- extension/test/unit/testEnvFiles.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extension/test/unit/testEnvFiles.test.ts b/extension/test/unit/testEnvFiles.test.ts index 9ad3b5fa68..44236eb1e0 100644 --- a/extension/test/unit/testEnvFiles.test.ts +++ b/extension/test/unit/testEnvFiles.test.ts @@ -4,9 +4,9 @@ *--------------------------------------------------------*/ import assert from 'assert'; -import * as path from 'path'; -import * as fs from 'fs'; -import * as os from 'os'; +import path from 'path'; +import fs from 'fs'; +import os from 'os'; import { parseEnvFiles } from '../../src/utils/envUtils'; suite('parseEnvFiles Tests', () => { From e2a344ee7ab7dd178b65f2507c7da49a422d6daf Mon Sep 17 00:00:00 2001 From: Jacob Foshee Date: Wed, 20 Aug 2025 17:15:51 -0500 Subject: [PATCH 7/7] fix: use `rmdirSync` --- extension/package-lock.json | 2 +- extension/test/unit/testEnvFiles.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/extension/package-lock.json b/extension/package-lock.json index d15fff953b..648162322b 100644 --- a/extension/package-lock.json +++ b/extension/package-lock.json @@ -49,7 +49,7 @@ }, "engines": { "node": ">=16.14.2", - "vscode": "^1.75.0" + "vscode": "^1.90.0" } }, "node_modules/@babel/code-frame": { diff --git a/extension/test/unit/testEnvFiles.test.ts b/extension/test/unit/testEnvFiles.test.ts index 44236eb1e0..c9cdcc7359 100644 --- a/extension/test/unit/testEnvFiles.test.ts +++ b/extension/test/unit/testEnvFiles.test.ts @@ -18,7 +18,7 @@ suite('parseEnvFiles Tests', () => { teardown(() => { if (tmpDir && fs.existsSync(tmpDir)) { - fs.rmSync(tmpDir, { recursive: true }); + fs.rmdirSync(tmpDir, { recursive: true }); } });