Skip to content

Commit 0bcbca0

Browse files
committed
[release] src/util.ts: attempt to fix version parsing again
https://go-review.googlesource.com/c/vscode-go/+/245397 attempted to correct the use of regex matching result. But didn't notice that the regexp for released version does not capture the patch version part. Use of semver.coerce on the full go version output previously worked by accident because coercing recognized the version string and built the SemVer out of it. Adjust the regexp so that it captures the whole version string part including the patch and the prerelease tags. semver.coerce drops the prerelease tags from Go's version string (e.g. go1.15rc1, etc), and modifies incomplete semver string to `major.minor.patch` format (e.g. go1.14 -> go1.14.0). In certain cases, we want the exact version string as `go version` outputs. So, store the original version string and if `includePrerelease` is set, `GoVersion.format` returns the original version string instead of the result of `semver.format`. This CL adds tests for Go version parsing and formatting. Change-Id: I8986d4d5b03d1735d707c4c3b2b38895314dd497 Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/245438 Run-TryBot: Hyang-Ah Hana Kim <[email protected]> Reviewed-by: Rebecca Stambler <[email protected]> (cherry picked from commit dc9de1c) Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/245600
1 parent 1daea80 commit 0bcbca0

File tree

2 files changed

+99
-7
lines changed

2 files changed

+99
-7
lines changed

src/util.ts

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,16 +82,24 @@ export const goBuiltinTypes: Set<string> = new Set<string>([
8282

8383
export class GoVersion {
8484
public sv?: semver.SemVer;
85+
// Go version tags are not following the strict semver format
86+
// so semver drops the prerelease tags used in Go version.
87+
// If sv is valid, let's keep the original version string
88+
// including the prerelease tag parts.
89+
public svString?: string;
90+
8591
public isDevel?: boolean;
8692
private commit?: string;
87-
88-
constructor(public binaryPath: string, version: string) {
89-
const matchesRelease = /go version go(\d.\d+).*/.exec(version);
93+
94+
constructor(public binaryPath: string, public version: string) {
95+
const matchesRelease = /^go version go(\d\.\d+\S*)\s+/.exec(version);
9096
const matchesDevel = /go version devel \+(.[a-zA-Z0-9]+).*/.exec(version);
9197
if (matchesRelease) {
98+
// note: semver.parse does not work with Go version string like go1.14.
9299
const sv = semver.coerce(matchesRelease[1]);
93100
if (sv) {
94101
this.sv = sv;
102+
this.svString = matchesRelease[1];
95103
}
96104
} else if (matchesDevel) {
97105
this.isDevel = true;
@@ -103,11 +111,17 @@ export class GoVersion {
103111
return !!this.sv || !!this.isDevel;
104112
}
105113

106-
public format(): string {
114+
public format(includePrerelease?: boolean): string {
107115
if (this.sv) {
116+
if (includePrerelease && this.svString) {
117+
return this.svString;
118+
}
108119
return this.sv.format();
109120
}
110-
return `devel +${this.commit}`;
121+
if (this.isDevel) {
122+
return `devel +${this.commit}`;
123+
}
124+
return `unknown`;
111125
}
112126

113127
public lt(version: string): boolean {
@@ -300,9 +314,14 @@ export function getUserNameHash() {
300314

301315
/**
302316
* Gets version of Go based on the output of the command `go version`.
303-
* Returns null if go is being used from source/tip in which case `go version` will not return release tag like go1.6.3
317+
* Returns undefined if go version can't be determined because
318+
* go is not available or `go version` fails.
304319
*/
305320
export async function getGoVersion(): Promise<GoVersion | undefined> {
321+
// TODO(hyangah): limit the number of concurrent getGoVersion call.
322+
// When the extension starts, at least 4 concurrent calls race
323+
// and end up calling `go version`.
324+
306325
const goRuntimePath = getBinPath('go');
307326

308327
const warn = (msg: string) => {

test/integration/utils.test.ts

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*--------------------------------------------------------*/
55

66
import * as assert from 'assert';
7-
import { guessPackageNameFromFile, substituteEnv } from '../../src/util';
7+
import { GoVersion, guessPackageNameFromFile, substituteEnv } from '../../src/util';
88

99
suite('utils Tests', () => {
1010
test('substituteEnv: default', () => {
@@ -21,6 +21,79 @@ suite('utils Tests', () => {
2121
// test completed
2222
process.env = env;
2323
});
24+
25+
test('build GoVersion', () => {
26+
// [input, wantFormat, wantFormatIncludePrerelease, wantIsValid]
27+
const testCases: [string|undefined, string, string, boolean][] = [
28+
[
29+
'go version devel +a295d59d Fri Jun 26 19:00:25 2020 +0000 darwin/amd64',
30+
'devel +a295d59d',
31+
'devel +a295d59d',
32+
true,
33+
],
34+
[
35+
'go version go1.14 darwin/amd64',
36+
'1.14.0',
37+
'1.14',
38+
true,
39+
],
40+
[
41+
'go version go1.14.1 linux/amd64',
42+
'1.14.1',
43+
'1.14.1',
44+
true,
45+
],
46+
[
47+
'go version go1.15rc1 darwin/amd64',
48+
'1.15.0',
49+
'1.15rc1',
50+
true,
51+
],
52+
[
53+
'go version go1.15.1rc2 windows/amd64',
54+
'1.15.1',
55+
'1.15.1rc2',
56+
true,
57+
],
58+
[
59+
'go version go1.15.3-beta.1 darwin/amd64',
60+
'1.15.3',
61+
'1.15.3-beta.1',
62+
true,
63+
],
64+
[
65+
'go version go1.15.3-beta.1.2.3 foobar/amd64',
66+
'1.15.3',
67+
'1.15.3-beta.1.2.3',
68+
true,
69+
],
70+
[
71+
'go version go10.0.1 js/amd64',
72+
'unknown',
73+
'unknown',
74+
false,
75+
],
76+
[
77+
undefined,
78+
'unknown',
79+
'unknown',
80+
false,
81+
],
82+
[
83+
'something wrong',
84+
'unknown',
85+
'unknown',
86+
false,
87+
]
88+
];
89+
for (const [input, wantFormat, wantFormatIncludePrerelease, wantIsValid] of testCases) {
90+
const go = new GoVersion('/path/to/go', input);
91+
92+
assert.equal(go.isValid(), wantIsValid, `GoVersion(${input}) = ${JSON.stringify(go)}`);
93+
assert.equal(go.format(), wantFormat, `GoVersion(${input}) = ${JSON.stringify(go)}`);
94+
assert.equal(go.format(true), wantFormatIncludePrerelease, `GoVersion(${input}) = ${JSON.stringify(go)}`);
95+
}
96+
});
2497
});
2598

2699
suite('GuessPackageNameFromFile Tests', () => {

0 commit comments

Comments
 (0)