extension/src/utils: Support exported environment variables with go.testEnvFile

This changes adds support for exported environment variables in environment files with the go.testEnvFile configuration option

Fixes golang/vscode-go#3879

Change-Id: Idd7073fb8efaf93a15d51a2bfab4c361911efa4f
GitHub-Last-Rev: 5bfe02883fac742dfd7fd648c7f38ec51081c465
GitHub-Pull-Request: golang/vscode-go#3880
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/706135
Reviewed-by: Hongxiang Jiang <hxjiang@golang.org>
Reviewed-by: Junyang Shao <shaojunyang@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Hongxiang Jiang <hxjiang@golang.org>
diff --git a/extension/src/utils/envUtils.ts b/extension/src/utils/envUtils.ts
index 442b8e4..bd798f6 100644
--- a/extension/src/utils/envUtils.ts
+++ b/extension/src/utils/envUtils.ts
@@ -17,7 +17,11 @@
 }
 
 /**
- * returns the environment variable collection created by parsing the given .env file.
+ * Returns the environment variable collection created by parsing the given .env file.
+ * Each line in the .env file is expected to be in the format `KEY=VALUE` or `export KEY=VALUE`.
+ * Keys can contain alphanumeric characters, periods, and hyphens.
+ * Values can be optionally enclosed in single or double quotes. Double-quoted values support `\n` for newlines.
+ * Environment variable substitution using `${VAR}` syntax is also supported within values.
  */
 export function parseEnvFile(envFilePath: string, globalVars?: NodeJS.Dict<string>): { [key: string]: string } {
 	const env: { [key: string]: string } = {};
@@ -31,14 +35,14 @@
 	try {
 		const buffer = stripBOM(fs.readFileSync(envFilePath, 'utf8'));
 		buffer.split('\n').forEach((line) => {
-			const r = line.match(/^\s*([\w\.\-]+)\s*=\s*(.*)?\s*$/);
+			const r = line.match(/^\s*(export\s+)?([\w\.\-]+)\s*=\s*(.*)?\s*$/);
 			if (r !== null) {
-				let value = r[2] || '';
+				let value = r[3] || '';
 				if (value.length > 0 && value.charAt(0) === '"' && value.charAt(value.length - 1) === '"') {
 					value = value.replace(/\\n/gm, '\n');
 				}
 				const v = value.replace(/(^['"]|['"]$)/g, '');
-				env[r[1]] = substituteEnvVars(v, env, globalVars!);
+				env[r[2]] = substituteEnvVars(v, env, globalVars!);
 			}
 		});
 		return env;
diff --git a/extension/test/integration/goDebugConfiguration.test.ts b/extension/test/integration/goDebugConfiguration.test.ts
index 2b22ae3..9db9865 100644
--- a/extension/test/integration/goDebugConfiguration.test.ts
+++ b/extension/test/integration/goDebugConfiguration.test.ts
@@ -130,7 +130,7 @@
 	test('launchArgs.env overwrites launchArgs.envFile', () => {
 		const env = { SOMEVAR1: 'valueFromEnv' };
 		const envFile = path.join(tmpDir, 'env');
-		fs.writeFileSync(envFile, ['SOMEVAR1=valueFromEnvFile1', 'SOMEVAR2=valueFromEnvFile2'].join('\n'));
+		fs.writeFileSync(envFile, ['SOMEVAR1=valueFromEnvFile1', 'export SOMEVAR2=valueFromEnvFile2'].join('\n'));
 
 		runTest(
 			{ env, envFile },