src/goEnvironmentStatus.ts: handle failed getGoVersion call

getGoVersion can return undefined. Handle the case and display
 `Go (unknown)` in the status item.

Made formatGoVersion to take GoVersion or undefined.

Also, utilize GoVersion.format(includePrerelease) to choose
the correct version string. It turned out GoVersion.format
uses sesmver.format, which reformats version strings like 1.14rc1
to 1.14.0. That's not ideal for go version display purpose.

Change-Id: I923a9efff90abaa4b6b4a4018ed402a04161169e
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/245439
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
diff --git a/src/goEnvironmentStatus.ts b/src/goEnvironmentStatus.ts
index c70757e..bbc7403 100644
--- a/src/goEnvironmentStatus.ts
+++ b/src/goEnvironmentStatus.ts
@@ -15,7 +15,7 @@
 import { toolInstallationEnvironment } from './goEnv';
 import { outputChannel } from './goStatus';
 import { getFromWorkspaceState, updateWorkspaceState } from './stateUtils';
-import { getBinPath, getGoVersion, getTempFilePath, rmdirRecursive } from './util';
+import { getBinPath, getGoVersion, getTempFilePath, rmdirRecursive, GoVersion } from './util';
 import { correctBinname, getBinPathFromEnvVar, getCurrentGoRoot, pathExists } from './utils/goPath';
 
 export class GoEnvironmentOption {
@@ -46,7 +46,7 @@
 	}
 	// set Go version and command
 	const version = await getGoVersion();
-	const goOption = new GoEnvironmentOption(version.binaryPath, formatGoVersion(version.format()));
+	const goOption = new GoEnvironmentOption(version.binaryPath, formatGoVersion(version));
 
 	hideGoStatusBar();
 	goEnvStatusbarItem.text = goOption.label;
@@ -367,16 +367,16 @@
 	return goEnvStatusbarItem;
 }
 
-export function formatGoVersion(version: string): string {
-	const versionWords = version.split(' ');
-	if (versionWords[0] === 'devel') {
+export function formatGoVersion(version?: GoVersion): string {
+	if (!version || !version.isValid()) {
+		return `Go (unknown)`;
+	}
+	const versionStr = version.format(true);
+	const versionWords = versionStr.split(' ');
+	if (versionWords.length > 1 && versionWords[0] === 'devel') {
 		// Go devel +hash
-		return `Go ${versionWords[0]} ${versionWords[4]}`;
-	} else if (versionWords.length > 0) {
-		// some other version format
-		return `Go ${version.substr(0, 8)}`;
+		return `Go ${versionWords[1]}`;
 	} else {
-		// default semantic version format
 		return `Go ${versionWords[0]}`;
 	}
 }
@@ -411,7 +411,7 @@
 	const version = await getGoVersion();
 	return new GoEnvironmentOption(
 		path.join(goroot, 'bin', correctBinname('go')),
-		formatGoVersion(version.format()),
+		formatGoVersion(version),
 	);
 }
 
diff --git a/test/integration/statusbar.test.ts b/test/integration/statusbar.test.ts
index 6f982ad..8396db6 100644
--- a/test/integration/statusbar.test.ts
+++ b/test/integration/statusbar.test.ts
@@ -43,7 +43,7 @@
 
 	it('should create a status bar item with a label matching go.goroot version', async () => {
 		const version = await ourutil.getGoVersion();
-		const versionLabel = formatGoVersion(version.format());
+		const versionLabel = formatGoVersion(version);
 		assert.equal(
 			getGoEnvironmentStatusbarItem().text,
 			versionLabel,
@@ -58,7 +58,7 @@
 	let goOption: GoEnvironmentOption;
 	let defaultMemento: vscode.Memento;
 	const version = await ourutil.getGoVersion();
-	const defaultGoOption = new GoEnvironmentOption(version.binaryPath, formatGoVersion(version.format()));
+	const defaultGoOption = new GoEnvironmentOption(version.binaryPath, formatGoVersion(version));
 
 	this.beforeAll(async () => {
 		defaultMemento = getWorkspaceState();
@@ -116,7 +116,7 @@
 	let tmpRootBin: string | undefined;
 	let sandbox: sinon.SinonSandbox | undefined;
 	const version = await ourutil.getGoVersion();
-	const defaultGoOption = new GoEnvironmentOption(version.binaryPath, formatGoVersion(version.format()));
+	const defaultGoOption = new GoEnvironmentOption(version.binaryPath, formatGoVersion(version));
 
 	this.beforeAll(async () => {
 		defaultMemento = getWorkspaceState();