Skip to content

Commit ebe4bed

Browse files
committed
Properly compare semver
1 parent 7e11969 commit ebe4bed

File tree

4 files changed

+91
-18
lines changed

4 files changed

+91
-18
lines changed

src/main/kotlin/com/coder/gateway/sdk/CoderCLIManager.kt

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -285,16 +285,33 @@ class CoderCLIManager @JvmOverloads constructor(
285285
)
286286

287287
/**
288-
* Return the binary version or null if it could not be determined.
288+
* Return the binary version.
289+
*
290+
* Throws if it could not be determined.
289291
*/
290-
fun version(): String? {
292+
fun version(): CoderSemVer {
293+
val raw = exec("version", "--output", "json")
294+
val json = Gson().fromJson(raw, Version::class.java)
295+
if (json?.version == null) {
296+
throw InvalidVersionException("No version found in output")
297+
}
298+
return CoderSemVer.parse(json.version)
299+
}
300+
301+
/**
302+
* Returns true if the CLI has the same major/minor/patch version as the
303+
* provided version and false if it does not match or the CLI version could
304+
* not be determined or the provided version is invalid.
305+
*/
306+
fun matchesVersion(buildVersion: String): Boolean {
291307
return try {
292-
val raw = exec("version", "--output", "json")
293-
val json = Gson().fromJson(raw, Version::class.java)
294-
json.version
308+
val cliVersion = version()
309+
val matches = cliVersion == CoderSemVer.parse(buildVersion)
310+
logger.info("$localBinaryPath version $cliVersion matches $buildVersion: $matches")
311+
matches
295312
} catch (e: Exception) {
296-
logger.warn("Unable to determine CLI version: ${e.message}")
297-
null
313+
logger.info("Unable to determine $localBinaryPath version: ${e.message}")
314+
false
298315
}
299316
}
300317

src/main/kotlin/com/coder/gateway/sdk/CoderSemVer.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class CoderSemVer(private val major: Long = 0, private val minor: Long = 0, priv
1414

1515

1616
override fun toString(): String {
17-
return "CoderSemVer(major=$major, minor=$minor)"
17+
return "CoderSemVer(major=$major, minor=$minor, patch=$patch)"
1818
}
1919

2020
override fun equals(other: Any?): Boolean {

src/main/kotlin/com/coder/gateway/views/steps/CoderWorkspacesStepView.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -472,11 +472,9 @@ class CoderWorkspacesStepView(val setNextButtonEnabled: (Boolean) -> Unit) : Cod
472472
// supported if the binary is downloaded from alternate sources.
473473
// For CLIs without the JSON output flag we will fall back to
474474
// the 304 method.
475-
if (cliManager.version() != clientService.buildVersion) {
475+
if (!cliManager.matchesVersion(clientService.buildVersion)) {
476476
this.indicator.text = "Downloading Coder CLI..."
477477
cliManager.downloadCLI()
478-
} else {
479-
logger.info("Found existing binary at ${cliManager.localBinaryPath} with the expected version ${clientService.buildVersion}")
480478
}
481479

482480
this.indicator.text = "Authenticating Coder CLI..."

src/test/groovy/CoderCLIManagerTest.groovy

Lines changed: 65 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.coder.gateway.sdk
22

3+
import com.google.gson.JsonSyntaxException
34
import com.sun.net.httpserver.HttpExchange
45
import com.sun.net.httpserver.HttpHandler
56
import com.sun.net.httpserver.HttpServer
@@ -131,10 +132,11 @@ class CoderCLIManagerTest extends Specification {
131132

132133
when:
133134
def downloaded = ccm.downloadCLI()
135+
ccm.version()
134136

135137
then:
136138
downloaded
137-
CoderSemVer.isValidVersion(ccm.version())
139+
noExceptionThrown()
138140

139141
// Make sure login failures propagate correctly.
140142
when:
@@ -443,11 +445,67 @@ class CoderCLIManagerTest extends Specification {
443445

444446
where:
445447
contents | expected
446-
"""echo '{"version": "1.0.0"}'""" | "1.0.0"
447-
"""echo '{"version": "1.0.0", "foo": true, "baz": 1}'""" | "1.0.0"
448-
"""echo '{"foo": true, "baz": 1}'""" | null
449-
"""echo '{"version: """ | null
450-
"exit 0" | null
451-
"exit 1" | null
448+
"""echo '{"version": "1.0.0"}'""" | CoderSemVer.parse("1.0.0")
449+
"""echo '{"version": "1.0.0", "foo": true, "baz": 1}'""" | CoderSemVer.parse("1.0.0")
450+
}
451+
452+
@IgnoreIf({ os.windows })
453+
def "fails to parse version"() {
454+
given:
455+
def ccm = new CoderCLIManager(new URL("https://test.coder.parse-fail.invalid"), tmpdir)
456+
Files.createDirectories(ccm.localBinaryPath.parent)
457+
458+
when:
459+
if (contents != null) {
460+
ccm.localBinaryPath.toFile().text = "#!/bin/sh\n$contents"
461+
ccm.localBinaryPath.toFile().setExecutable(true)
462+
}
463+
ccm.version()
464+
465+
then:
466+
thrown(expected)
467+
468+
where:
469+
contents | expected
470+
null | ProcessInitException
471+
"""echo '{"foo": true, "baz": 1}'""" | InvalidVersionException
472+
"""echo '{"version: '""" | JsonSyntaxException
473+
"exit 0" | InvalidVersionException
474+
"exit 1" | InvalidExitValueException
475+
}
476+
477+
@IgnoreIf({ os.windows })
478+
def "checks if version matches"() {
479+
given:
480+
def ccm = new CoderCLIManager(new URL("https://test.coder.version-matches.invalid"), tmpdir)
481+
Files.createDirectories(ccm.localBinaryPath.parent)
482+
483+
when:
484+
if (contents != null) {
485+
ccm.localBinaryPath.toFile().text = "#!/bin/sh\n$contents"
486+
ccm.localBinaryPath.toFile().setExecutable(true)
487+
}
488+
489+
then:
490+
ccm.matchesVersion(build) == matches
491+
492+
where:
493+
contents | build | matches
494+
null | "v1.0.0" | false
495+
"""echo '{"version": "v1.0.0"}'""" | "v1.0.0" | true
496+
"""echo '{"version": "v1.0.0"}'""" | "v1.0.0-devel+b5b5b5b5" | true
497+
"""echo '{"version": "v1.0.0-devel+b5b5b5b5"}'""" | "v1.0.0-devel+b5b5b5b5" | true
498+
"""echo '{"version": "v1.0.0-devel+b5b5b5b5"}'""" | "v1.0.0" | true
499+
"""echo '{"version": "v1.0.0-devel+b5b5b5b5"}'""" | "v1.0.0-devel+c6c6c6c6" | true
500+
"""echo '{"version": "v1.0.0-prod+b5b5b5b5"}'""" | "v1.0.0-devel+b5b5b5b5" | true
501+
"""echo '{"version": "v1.0.0"}'""" | "v1.0.1" | false
502+
"""echo '{"version": "v1.0.0"}'""" | "v1.1.0" | false
503+
"""echo '{"version": "v1.0.0"}'""" | "v2.0.0" | false
504+
"""echo '{"version": "v1.0.0"}'""" | "v0.0.0" | false
505+
"""echo '{"version": ""}'""" | "v1.0.0" | false
506+
"""echo '{"version": "v1.0.0"}'""" | "" | false
507+
"""echo '{"version'""" | "v1.0.0" | false
508+
"""exit 0""" | "v1.0.0" | false
509+
"""exit 1""" | "v1.0.0" | false
452510
}
453511
}

0 commit comments

Comments
 (0)