Skip to content

Commit

Permalink
fix: do version check for dependencies (#755)
Browse files Browse the repository at this point in the history
Signed-off-by: Lenin Mehedy <lenin.mehedy@swirldslabs.com>
Signed-off-by: Jeromy Cannon <jeromy@swirldslabs.com>
  • Loading branch information
leninmehedy committed Feb 13, 2024
1 parent 096b5c3 commit 520cb47
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 35 deletions.
6 changes: 3 additions & 3 deletions solo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ An opinionated CLI tool to deploy and manage private Hedera Networks.

## Requirements

* Node(^18.19.0) (*lts/hydrogen*)
* Helm(^3.14.0)
* Kubectl(^1.28.2)
* Node(^v18.19.0) (*lts/hydrogen*)
* Helm(^v3.12.3)
* Kubectl(^v1.28.2)

## Setup

Expand Down
30 changes: 16 additions & 14 deletions solo/src/core/dependency_manager.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,15 @@
*
*/
import { FullstackTestingError } from './errors.mjs'
import { constants } from './index.mjs'
import * as core from './index.mjs'
import * as helpers from './helpers.mjs'
import { ShellRunner } from './shell_runner.mjs'

export class DependencyManager extends ShellRunner {
static depVersions = new Map()
.set(constants.HELM, 'v3.12.3')

constructor (logger) {
super(logger)

Expand All @@ -27,23 +32,21 @@ export class DependencyManager extends ShellRunner {
.set(core.constants.HELM, () => this.checkHelm())
}

async runCheck (cmdString) {
try {
await this.run(cmdString)
} catch (e) {
this.logger.error(e)
return false
}

return true
}

/**
* Check if 'helm' CLI program is installed or not
* @returns {Promise<boolean>}
*/
async checkHelm () {
return this.runCheck(`${core.constants.HELM} version`)
try {
const output = await this.run(`${core.constants.HELM} version --short`)
const parts = output[0].split('+')
this.logger.debug(`Found dependency ${constants.HELM}:${parts[0]}`)
return helpers.compareVersion(DependencyManager.depVersions.get(constants.HELM), parts[0]) >= 0
} catch (e) {
this.logger.error(`failed to check helm dependency:${e.message}`, e)
}

return false
}

/**
Expand All @@ -61,8 +64,7 @@ export class DependencyManager extends ShellRunner {
}

if (!status) {
this.logger.warn(`Dependency ${dep} is not found`)
throw new FullstackTestingError(`${dep} is not found`)
throw new FullstackTestingError(`${dep}:^${DependencyManager.depVersions.get(dep)} is not found`)
}

this.logger.debug(`Dependency ${dep} is found`)
Expand Down
48 changes: 39 additions & 9 deletions solo/src/core/helpers.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -67,19 +67,19 @@ export function packageVersion () {
}

/**
* Split the release version into its major, minor and patch number
* @param releaseTag platform release version
* Split semantic version into its major, minor and patch number
* @param semver release version
* @return {{patch: number, major: number, minor: number}}
*/
export function parseReleaseTag (releaseTag) {
if (!releaseTag || releaseTag[0] !== 'v') {
throw new FullstackTestingError(`invalid release tag. Expected 'v<MAJOR>.<MINOR>.<PATCH>', found '${releaseTag}'`)
export function parseSemver (semver) {
if (!semver || semver[0] !== 'v') {
throw new FullstackTestingError(`invalid version. Expected 'v<MAJOR>.<MINOR>.<PATCH>', found '${semver}'`)
}

releaseTag = releaseTag.replace('v', '') // remove first 'v'
const parts = releaseTag.split('-')[0].split('.') // just take the major.minor.patch part of the version
const version = semver.replace('v', '') // remove first 'v'
const parts = version.split('-')[0].split('.') // just take the major.minor.patch part of the version
if (parts.length < 3) {
throw new FullstackTestingError('releaseTag must have the format MAJOR.MINOR.PATCH')
throw new FullstackTestingError(`version '${semver}' must have the format MAJOR.MINOR.PATCH`)
}

return {
Expand All @@ -89,13 +89,43 @@ export function parseReleaseTag (releaseTag) {
}
}

/**
* Compare two version
*
* It returns 1, 0, -1 depending on the following three cases:
* - candidate > target: 1
* - candidate == target: 0
* - candidate < target: -1
*
* @param target target version
* @param candidate candidate version
* @return {number}
*/
export function compareVersion (target, candidate) {
const v1 = parseSemver(target)
const v2 = parseSemver(candidate)

if (v2.major === v1.major && v2.minor === v1.minor && v2.patch === v1.patch) {
return 0
}

if ((v2.major > v1.major) ||
(v2.major >= v1.major && v2.minor > v1.minor) ||
(v2.major >= v1.major && v2.minor >= v1.minor && v2.patch >= v1.patch)
) {
return 1
}

return -1
}

/**
* Return the required root image for a platform version
* @param releaseTag platform version
* @return {string}
*/
export function getRootImageRepository (releaseTag) {
const releaseVersion = parseReleaseTag(releaseTag)
const releaseVersion = parseSemver(releaseTag)
if (releaseVersion.minor < 46) {
return 'hashgraph/full-stack-testing/ubi8-init-java17'
}
Expand Down
2 changes: 1 addition & 1 deletion solo/src/core/platform_installer.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ export class PlatformInstaller {
const appName = constants.HEDERA_APP_NAME
const nodeStakeAmount = constants.HEDERA_NODE_DEFAULT_STAKE_AMOUNT

const releaseVersion = helpers.parseReleaseTag(releaseTag)
const releaseVersion = helpers.parseSemver(releaseTag)

try {
const configLines = []
Expand Down
2 changes: 1 addition & 1 deletion solo/test/unit/core/dependency_manager.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ describe('DependencyManager', () => {

describe('checkDependency', () => {
it('should fail during invalid dependency check', async () => {
await expect(depManager.checkDependency('INVALID_PROGRAM')).rejects.toThrowError(new FullstackTestingError('INVALID_PROGRAM is not found'))
await expect(depManager.checkDependency('INVALID_PROGRAM')).rejects.toThrowError(new FullstackTestingError('INVALID_PROGRAM:^undefined is not found'))
})
it('should succeed during kubectl dependency check', async () => {
await expect(depManager.checkDependency(constants.HELM)).resolves.toBe(true)
Expand Down
43 changes: 36 additions & 7 deletions solo/test/unit/core/helpers.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,51 @@ describe('Helpers', () => {
['v0.42.5', { major: 0, minor: 42, patch: 5 }],
['v0.42.5-alpha.0', { major: 0, minor: 42, patch: 5 }]
])('should parse release tag into major, minor and patch numbers', (input, expected) => {
const result = helpers.parseReleaseTag(input)
const result = helpers.parseSemver(input)
expect(result).toEqual(expected)
})

it.each([
['', new FullstackTestingError('invalid release tag. Expected \'v<MAJOR>.<MINOR>.<PATCH>\', found \'\'')],
['0.42.5', new FullstackTestingError('invalid release tag. Expected \'v<MAJOR>.<MINOR>.<PATCH>\', found \'0.42.5\'')],
['v0.42', new FullstackTestingError('releaseTag must have the format MAJOR.MINOR.PATCH')],
['v0.42', new FullstackTestingError('releaseTag must have the format MAJOR.MINOR.PATCH')],
['v0.NEW', new FullstackTestingError('releaseTag must have the format MAJOR.MINOR.PATCH')]
['', new FullstackTestingError('invalid version. Expected \'v<MAJOR>.<MINOR>.<PATCH>\', found \'\'')],
['0.42.5', new FullstackTestingError('invalid version. Expected \'v<MAJOR>.<MINOR>.<PATCH>\', found \'0.42.5\'')],
['v0.42', new FullstackTestingError("version 'v0.42' must have the format MAJOR.MINOR.PATCH")],
['v0.NEW', new FullstackTestingError("version 'v0.NEW' must have the format MAJOR.MINOR.PATCH")]
])('should throw error in parsing release tag', (input, expectedError) => {
expect.assertions(1)
try {
helpers.parseReleaseTag(input) // Error(new FullstackTestingError('releaseTag must have the format MAJOR.MINOR.PATCH'))
helpers.parseSemver(input) // Error(new FullstackTestingError('releaseTag must have the format MAJOR.MINOR.PATCH'))
} catch (e) {
expect(e).toEqual(expectedError)
}
})

describe('compareVersion', () => {
it('should succeed with same version', () => {
expect(helpers.compareVersion('v3.14.0', 'v3.14.0')).toBe(0)
})

it('should succeed with patch higher than target', () => {
expect(helpers.compareVersion('v3.14.0', 'v3.14.1')).toBe(1)
})

it('should succeed with minor version higher than target', () => {
expect(helpers.compareVersion('v3.14.0', 'v3.15.0')).toBe(1)
})

it('should succeed with major version higher than target', () => {
expect(helpers.compareVersion('v3.14.0', 'v4.14.0')).toBe(1)
})

it('should fail with major version lower than target', () => {
expect(helpers.compareVersion('v3.14.0', 'v2.14.0')).toBe(-1)
})

it('should fail with minor version lower than target', () => {
expect(helpers.compareVersion('v3.14.0', 'v3.11.0')).toBe(-1)
})

it('should succeed with a later version', () => {
expect(helpers.compareVersion('v3.12.3', 'v3.14.0')).toBe(1)
})
})
})

0 comments on commit 520cb47

Please sign in to comment.