src/goToolsInformation: fix go-outline version

There is no v1.0.0 version.

The tagging of go-outline project doesn't follow go modules
versioning convention, so the release tag version is not
recognized.

Since we pinned the 3rd party tools versions after
https://go-review.googlesource.com/c/vscode-go/+/435375
we also need to adjust the code path that pick the version
of tools whose latest versions require go 1.18+ to build.
Use Tool.defaultVersion only if we are handling these special
cases. (gofumpt, golangci-lint, staticcheck)

Also, set GOMODCACHE explicitly when interacting with the
fake local proxy. When the test runs in an environment with
GOMODCACHE is set, the test ends up polluting the specified
GOMODCACHE with fake data from the local test proxy. Our
intention was to use GOPATH[0]/pkg/mod as module cache
during the test.

Fixes golang/vscode-go#2485
Updates golang/vscode-go#1850

Change-Id: Iad6cb662f637d444b9a8047db2aa166965144db8
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/442786
Reviewed-by: Jamal Carvalho <jamal@golang.org>
Run-TryBot: Hyang-Ah Hana Kim <hyangah@gmail.com>
TryBot-Result: kokoro <noreply+kokoro@google.com>
diff --git a/src/goInstallTools.ts b/src/goInstallTools.ts
index 51ccbad..d607d57 100644
--- a/src/goInstallTools.ts
+++ b/src/goInstallTools.ts
@@ -255,12 +255,8 @@
 		importPath = getImportPath(tool, goVersion);
 	} else {
 		let version: semver.SemVer | string | undefined | null = tool.version;
-		if (!version) {
-			if (tool.usePrereleaseInPreviewMode && extensionInfo.isPreview) {
-				version = await latestToolVersion(tool, true);
-			} else if (tool.defaultVersion) {
-				version = tool.defaultVersion;
-			}
+		if (!version && tool.usePrereleaseInPreviewMode && extensionInfo.isPreview) {
+			version = await latestToolVersion(tool, true);
 		}
 		importPath = getImportPathWithVersion(tool, version, goVersion);
 	}
@@ -421,7 +417,7 @@
 	}
 	const cmd = goVersion.lt('1.16')
 		? `go get -v ${getImportPath(tool, goVersion)}`
-		: `go install -v ${getImportPathWithVersion(tool, tool.defaultVersion, goVersion)}`;
+		: `go install -v ${getImportPathWithVersion(tool, undefined, goVersion)}`;
 	const selected = await vscode.window.showErrorMessage(
 		`The "${tool.name}" command is not available. Run "${cmd}" to install.`,
 		...installOptions
diff --git a/src/goTools.ts b/src/goTools.ts
index 392633f..8db1dc8 100644
--- a/src/goTools.ts
+++ b/src/goTools.ts
@@ -95,6 +95,9 @@
 	if (tool.name === 'golangci-lint') {
 		if (goVersion.lt('1.18')) return importPath + '@v1.47.3';
 	}
+	if (tool.defaultVersion) {
+		return importPath + '@' + tool.defaultVersion;
+	}
 	return importPath + '@latest';
 }
 
diff --git a/src/goToolsInformation.ts b/src/goToolsInformation.ts
index 5f3ccfc..70da072 100644
--- a/src/goToolsInformation.ts
+++ b/src/goToolsInformation.ts
@@ -32,7 +32,7 @@
 		replacedByGopls: true,
 		isImportant: true,
 		description: 'Go to symbol in file', // GoDocumentSymbolProvider, used by 'run test' codelens
-		defaultVersion: 'v1.0.0'
+		defaultVersion: 'v0.0.0-20210608161538-9736a4bde949'
 	},
 	'go-symbols': {
 		name: 'go-symbols',
diff --git a/test/integration/install.test.ts b/test/integration/install.test.ts
index 18adf18..37cd297 100644
--- a/test/integration/install.test.ts
+++ b/test/integration/install.test.ts
@@ -64,17 +64,26 @@
 		for (const p of [tmpToolsGopath, tmpToolsGopath2]) {
 			envForTest['GOPATH'] = p;
 			const execFile = util.promisify(cp.execFile);
-			await execFile(goRuntimePath, ['clean', '-modcache'], {
-				env: envForTest
-			});
-			rmdirRecursive(p);
+			try {
+				await execFile(goRuntimePath, ['clean', '-modcache'], {
+					env: envForTest
+				});
+				rmdirRecursive(p);
+			} catch (e) {
+				console.log(`failed to clean module cache directory: ${e}`);
+			}
 		}
 	});
 
 	// runTest actually executes the logic of the test.
 	// If withLocalProxy is true, the test does not require internet.
 	// If withGOBIN is true, the test will set GOBIN env var.
-	async function runTest(testCases: installationTestCase[], withLocalProxy?: boolean, withGOBIN?: boolean) {
+	async function runTest(
+		testCases: installationTestCase[],
+		withLocalProxy?: boolean,
+		withGOBIN?: boolean,
+		withGoVersion?: string
+	) {
 		const gobin = withLocalProxy && withGOBIN ? path.join(tmpToolsGopath, 'gobin') : undefined;
 
 		let proxyDir: string | undefined;
@@ -86,7 +95,10 @@
 					value: {
 						GOPROXY: url.pathToFileURL(proxyDir),
 						GOSUMDB: 'off',
-						GOBIN: gobin
+						GOBIN: gobin,
+						// Build environment may have GOMODCACHE set. Avoid writing
+						// fake data to it.
+						GOMODCACHE: path.join(tmpToolsGopath, 'pkg', 'mod')
 					}
 				},
 				gopath: { value: toolsGopath }
@@ -103,11 +115,15 @@
 		}
 
 		const missingTools = testCases.map((tc) => getToolAtVersion(tc.name));
-		const goVersion = await getGoVersion();
+		const goVersion = withGoVersion
+			? /* we want a fake go version, but need the real 'go' binary to run `go install` */
+			  new GoVersion(getBinPath('go'), `go version ${withGoVersion} amd64/linux`)
+			: await getGoVersion();
 
 		sandbox.stub(vscode.commands, 'executeCommand').withArgs('go.languageserver.restart');
 
-		await installTools(missingTools, goVersion);
+		const failures = await installTools(missingTools, goVersion);
+		assert(!failures || failures.length === 0, `installTools failed: ${JSON.stringify(failures)}`);
 
 		// Confirm that each expected tool has been installed.
 		const checks: Promise<void>[] = [];
@@ -180,6 +196,24 @@
 		);
 	});
 
+	const gofumptDefault = allToolsInformation['gofumpt'].defaultVersion!;
+	test('Install gofumpt with old go', async () => {
+		await runTest(
+			[{ name: 'gofumpt', versions: ['v0.2.1', gofumptDefault], wantVersion: 'v0.2.1' }],
+			true, // LOCAL PROXY
+			true, // GOBIN
+			'go1.17' // Go Version
+		);
+	});
+
+	test('Install gofumpt with new go', async () => {
+		await runTest(
+			[{ name: 'gofumpt', versions: ['v0.2.1', gofumptDefault], wantVersion: gofumptDefault }],
+			true, // LOCAL PROXY
+			true, // GOBIN
+			'go1.18' // Go Version
+		);
+	});
 	test('Install all tools via GOPROXY', async () => {
 		// Only run this test if we are in CI before a Nightly release.
 		if (!shouldRunSlowTests()) {
diff --git a/tools/allTools.ts.in b/tools/allTools.ts.in
index 89f4d63..af0eee3 100644
--- a/tools/allTools.ts.in
+++ b/tools/allTools.ts.in
@@ -30,7 +30,7 @@
 		replacedByGopls: true,
 		isImportant: true,
 		description: 'Go to symbol in file', // GoDocumentSymbolProvider, used by 'run test' codelens
-		defaultVersion: 'v1.0.0'
+		defaultVersion: 'v0.0.0-20210608161538-9736a4bde949'
 	},
 	'go-symbols': {
 		name: 'go-symbols',