Skip to content

Commit

Permalink
improvement: more precise error handling in binary tool version checker
Browse files Browse the repository at this point in the history
Unified error format in tools version checker.
Added a link to the documentation with requirements described.
  • Loading branch information
vvagaytsev committed Sep 20, 2022
1 parent 383f2cb commit c102eba
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 39 deletions.
2 changes: 1 addition & 1 deletion core/src/build-staging/rsync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { syncWithOptions } from "../util/sync"
import { BuildStaging, SyncParams } from "./build-staging"
import { validateInstall } from "../util/validateInstall"

const minRsyncVersion = "3.1.0"
export const minRsyncVersion = "3.1.0"
const versionRegex = /rsync\s+version\s+v?(\d+.\d+.\d+)/

/**
Expand Down
45 changes: 22 additions & 23 deletions core/src/util/validateInstall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,43 +18,48 @@ type BinaryVersionCheckParams = {
minVersion: string
}

const versionDetectFailure = (params: BinaryVersionCheckParams) =>
new RuntimeError(
function versionCheckError(params: BinaryVersionCheckParams, msg: string, detail: object): RuntimeError {
return new RuntimeError(
deline`
Could not detect ${params.name} version.
Please make sure ${params.name} version ${params.minVersion} or later is installed and on your PATH.
`,
{}
${msg}
Please make sure ${params.name} (version ${params.minVersion} or later) is installed and on your PATH.
More about garden installation and requirements can be found in our documentation at https://docs.garden.io/getting-started/1-installation#requirements
`,
detail
)
}

async function execVersionCheck(params: BinaryVersionCheckParams): Promise<string> {
try {
return (await exec(params.versionCommand.cmd, params.versionCommand.args)).stdout
} catch (error) {
throw new RuntimeError(
deline`
Could not find ${params.name} binary.
Please make sure ${params.name} (version ${params.minVersion} or later) is installed and on your PATH.
`,
{ error }
)
throw versionCheckError(params, `Could not find ${params.name} binary.`, { error })
}
}

function parseVersionOutput(versionOutput: string, params: BinaryVersionCheckParams): string {
const versionOutputFirstLine = versionOutput.split("\n")[0]
const match = versionOutputFirstLine.match(params.versionRegex)
if (!match || match.length < 2) {
throw versionDetectFailure(params)
throw versionCheckError(
params,
`Could not detect ${params.name} binary version in the version command's output: "${versionOutputFirstLine}".`,
{
versionOutput: versionOutputFirstLine,
regex: params.versionRegex,
}
)
}
return match[1]
}

function validateVersionNumber(version: string, params: BinaryVersionCheckParams): boolean {
try {
return semver.gte(version, params.minVersion)
} catch (_) {
throw versionDetectFailure(params)
} catch (error) {
throw versionCheckError(params, `Could not parse the ${params.name} version ${version} as a valid semver value.`, {
error,
})
}
}

Expand All @@ -67,12 +72,6 @@ export async function validateInstall(params: BinaryVersionCheckParams): Promise
const versionGte = validateVersionNumber(version, params)

if (!versionGte) {
throw new RuntimeError(
deline`
Found ${params.name} binary but the version is too old (${version}).
Please install version ${params.minVersion} or later.
`,
{ version }
)
throw versionCheckError(params, `Found ${params.name} binary but the version is too old (${version}).`, { version })
}
}
39 changes: 24 additions & 15 deletions core/test/unit/src/build-staging/build-staging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { BuildStaging, SyncParams } from "../../../../src/build-staging/build-st
import { LogEntry } from "../../../../src/logger/log-entry"
import Bluebird from "bluebird"
import { TestGardenOpts } from "../../../../src/util/testing"
import { BuildDirRsync } from "../../../../src/build-staging/rsync"
import { BuildDirRsync, minRsyncVersion } from "../../../../src/build-staging/rsync"

/*
Module dependency diagram for build-dir test project
Expand Down Expand Up @@ -238,6 +238,15 @@ describe("BuildStaging", () => {
describe("BuildStagingRsync", () => {
let garden: TestGarden

function expectCommonRsyncVersionErrorMsg(err) {
expect(err.message).to.include(
`Please make sure rsync (version ${minRsyncVersion} or later) is installed and on your PATH.`
)
expect(err.message).to.include(
"More about garden installation and requirements can be found in our documentation at https://docs.garden.io/getting-started/1-installation#requirements"
)
}

before(async () => {
garden = await makeGarden({ legacyBuildSync: true })
})
Expand All @@ -258,18 +267,17 @@ describe("BuildStagingRsync", () => {
process.env.PATH = ""
await expectError(
() => BuildDirRsync.factory(garden.projectRoot, garden.gardenDirPath),
(err) =>
expect(err.message).to.equal(
"Could not find rsync binary. Please make sure rsync (version 3.1.0 or later) is installed " +
"and on your PATH."
)
(err) => {
expect(err.message).to.include("Could not find rsync binary.")
expectCommonRsyncVersionErrorMsg(err)
}
)
} finally {
process.env.PATH = orgPath
}
})

it("should work with rsync v3.1.0", async () => {
it(`should work with rsync v${minRsyncVersion}`, async () => {
const orgPath = process.env.PATH

try {
Expand Down Expand Up @@ -298,10 +306,10 @@ describe("BuildStagingRsync", () => {
process.env.PATH = getDataDir("dummy-rsync", "old-version")
await expectError(
() => BuildDirRsync.factory(garden.projectRoot, garden.gardenDirPath),
(err) =>
expect(err.message).to.equal(
"Found rsync binary but the version is too old (2.1.2). Please install version 3.1.0 or later."
)
(err) => {
expect(err.message).to.include("Found rsync binary but the version is too old (2.1.2).")
expectCommonRsyncVersionErrorMsg(err)
}
)
} finally {
process.env.PATH = orgPath
Expand All @@ -315,11 +323,12 @@ describe("BuildStagingRsync", () => {
process.env.PATH = getDataDir("dummy-rsync", "invalid")
await expectError(
() => BuildDirRsync.factory(garden.projectRoot, garden.gardenDirPath),
(err) =>
expect(err.message).to.equal(
"Could not detect rsync version. Please make sure rsync version 3.1.0 or later is installed " +
"and on your PATH."
(err) => {
expect(err.message).to.include(
`Could not detect rsync binary version in the version command's output: "rsync version ABCDEF protocol version 31".`
)
expectCommonRsyncVersionErrorMsg(err)
}
)
} finally {
process.env.PATH = orgPath
Expand Down

0 comments on commit c102eba

Please sign in to comment.