From a5cce9bf9f2a76b36773dfd29cd36d265c042429 Mon Sep 17 00:00:00 2001 From: litetex Date: Sat, 4 Apr 2020 19:23:59 +0200 Subject: [PATCH] Refactoring * Added more tests * Allowed also exact versions again --- __tests__/installer.test.ts | 89 +++++++++++++++++++++++++++++++++++- src/installer.ts | 91 +++++++++++++++++++++++-------------- 2 files changed, 143 insertions(+), 37 deletions(-) diff --git a/__tests__/installer.test.ts b/__tests__/installer.test.ts index 9e8ad3f..7c2a82d 100644 --- a/__tests__/installer.test.ts +++ b/__tests__/installer.test.ts @@ -13,6 +13,92 @@ import * as installer from '../src/installer'; const IS_WINDOWS = process.platform === 'win32'; +describe('version tests', () => { + + it('Exact normal version', async() => { + let versInfo = new installer.DotNetVersionInfo('3.1.201'); + + expect(versInfo.isExactVersion()).toBe(true); + expect(versInfo.version()).toBe('3.1.201'); + }); + + it('Exact preview version', async() => { + let versInfo = new installer.DotNetVersionInfo('3.1.201-preview1'); + + expect(versInfo.isExactVersion()).toBe(true); + expect(versInfo.version()).toBe('3.1.201-preview1'); + }); + + it('Generic x version', async() => { + let versInfo = new installer.DotNetVersionInfo('3.1.x'); + + expect(versInfo.isExactVersion()).toBe(false); + expect(versInfo.version()).toBe('3.1'); + }); + + it('Generic * version', async() => { + let versInfo = new installer.DotNetVersionInfo('1.1.*'); + + expect(versInfo.isExactVersion()).toBe(false); + expect(versInfo.version()).toBe('1.1'); + }); + + it('Generic -no patch- version', async() => { + let versInfo = new installer.DotNetVersionInfo('2.0'); + + expect(versInfo.isExactVersion()).toBe(false); + expect(versInfo.version()).toBe('2.0'); + }); + + it('Generic -no minor- version', async() => { + expect(() => { + new installer.DotNetVersionInfo('2'); + }).toThrow(); + }); + + it('empty version', async() => { + expect(() => { + new installer.DotNetVersionInfo(''); + }).toThrow(); + }); + + it('malformed no patch but dot version', async() => { + expect(() => { + new installer.DotNetVersionInfo('1.2.'); + }).toThrow(); + }); + + it('malformed generic minor version', async() => { + expect(() => { + new installer.DotNetVersionInfo('1.*.2'); + }).toThrow(); + }); + + it('malformed generic major version', async() => { + expect(() => { + new installer.DotNetVersionInfo('*.2.2'); + }).toThrow(); + }); + + it('malformed letter version', async() => { + expect(() => { + new installer.DotNetVersionInfo('a.b.c'); + }).toThrow(); + }); + + it('malformed letter preview version', async() => { + expect(() => { + new installer.DotNetVersionInfo('a.b.c-preview'); + }).toThrow(); + }); + + it('malformed letter -no minor- version', async() => { + expect(() => { + new installer.DotNetVersionInfo('a.b'); + }).toThrow(); + }); +}) + describe('installer tests', () => { beforeAll(async () => { await io.rmRF(toolDir); @@ -28,7 +114,6 @@ describe('installer tests', () => { } }, 100000); - /* it('Check if get version works', async () => { @@ -48,7 +133,7 @@ describe('installer tests', () => { expect(true).toBe(true); - }, 400000);*/ + }, 400000); it('Acquires version of dotnet if no matching version is installed', async () => { await getDotnet('2.2.205'); diff --git a/src/installer.ts b/src/installer.ts index 1807a9b..a4f5e3c 100644 --- a/src/installer.ts +++ b/src/installer.ts @@ -10,6 +10,7 @@ import * as os from 'os'; import * as path from 'path'; import * as semver from 'semver'; import { stringWriter } from 'xmlbuilder'; +import { timingSafeEqual } from 'crypto'; const IS_WINDOWS = process.platform === 'win32'; @@ -28,16 +29,34 @@ if (!tempDirectory) { tempDirectory = path.join(baseLocation, 'actions', 'temp'); } -class DotNetVersionInfo { - major: number; - minor: number; - patch?: number; +export class DotNetVersionInfo { + + private fullversion : string; + private isExactVersionSet: boolean = false; + + private major: number; + private minor: number; + private patch?: number; constructor(version: string) { - //todo: add support for previews! - let regexResult = version.match(/^(\d+\.)(\d+\.)(\*|x|\d+)$/); + + // Check for exact match + if(semver.valid(semver.clean(version) || '') != null) { + + this.fullversion = semver.clean(version) as string; + this.isExactVersionSet = true; + + this.major = semver.major(this.fullversion); + this.minor = semver.minor(this.fullversion); + this.patch = semver.patch(this.fullversion); + + return; + } + + //Note: No support for previews when using generic + let regexResult = version.match(/^(\d+\.)(\d+)?(\.\*|\.x|)$/); if(regexResult == null) { - throw 'Invalid version. Supported formats: 1.2.3, 1.2, 1.2.x, 1.2.*'; + throw 'Invalid version format! Supported: 1.2.3, 1.2, 1.2.x, 1.2.*'; } let parts : string[] = (regexResult as RegExpMatchArray).slice(1); @@ -45,25 +64,18 @@ class DotNetVersionInfo { this.major = +(parts[0].replace('.','')); this.minor = +(parts[1].replace('.','')); - if(parts.length > 2) { - // just set if it is a number - if(!isNaN(Number(parts[2]))) { - this.patch = +parts[2]; - } - } + this.fullversion = this.major + '.' + this.minor; } - public isGeneric() : boolean { - return this.patch ? true : false; + /** + * If true exacatly one version should be resolved + */ + public isExactVersion() : boolean { + return this.isExactVersionSet; } - public toString() : string { - let version = this.major + "." + this.minor; - - if(this.patch) - version += "." + this.patch; - - return version; + public version() : string { + return this.fullversion; } } @@ -102,12 +114,12 @@ export class DotnetCoreInstaller { } // If version is not generic -> look up cache - if(!this.versionInfo.isGeneric()) - toolPath = this.getLocalTool(this.versionInfo.toString()); + if(this.versionInfo.isExactVersion()) + toolPath = this.getLocalTool(this.versionInfo.version()); if (!toolPath) { // download, extract, cache - console.log('Getting a download url', this.versionInfo.toString()); + console.log('Getting a download url', this.versionInfo.version()); let resolvedVersionInfo = await this.resolveInfos(osSuffixes, this.versionInfo); //Check if cache exists for resolved version @@ -246,7 +258,7 @@ export class DotnetCoreInstaller { // OsSuffixes - The suffix which is a part of the file name ex- linux-x64, windows-x86 // Type - SDK / Runtime // Version - Version of the SDK/Runtime - private async resolveInfos( + async resolveInfos( osSuffixes: string[], versionInfo: DotNetVersionInfo ): Promise { @@ -255,9 +267,10 @@ export class DotnetCoreInstaller { allowRetries: true, maxRetries: 3 }); + const releasesJsonUrl: string = await this.getReleasesJsonUrl( httpClient, - [String(versionInfo.major), String(versionInfo.minor)] + versionInfo.version().split('.') ); const releasesResponse = await httpClient.getJson(releasesJsonUrl); @@ -265,12 +278,20 @@ export class DotnetCoreInstaller { let releasesInfo: any[] = releasesResult['releases']; releasesInfo = releasesInfo.filter((releaseInfo: any) => { return ( - semver.satisfies(releaseInfo['sdk']['version'], versionInfo.toString()) || - semver.satisfies(releaseInfo['sdk']['version-display'], versionInfo.toString()) + semver.satisfies(releaseInfo['sdk']['version'], versionInfo.version()) || + semver.satisfies(releaseInfo['sdk']['version-display'], versionInfo.version()) ); }); - //Sort for latest version + // Exclude versions that are newer than the latest if using not exact + if(!versionInfo.isExactVersion()) { + + let latestSdk : string = releasesResponse['latest-sdk']; + + releasesInfo = releasesInfo.filter((releaseInfo: any) => semver.lte(releaseInfo['sdk']['version'], latestSdk)); + } + + // Sort for latest version releasesInfo = releasesInfo.sort((a,b) => semver.rcompare(a['sdk']['version'],b['sdk']['version'])); let downloadedVersion : string = ''; @@ -299,21 +320,21 @@ export class DotnetCoreInstaller { } } else { console.log( - `Could not fetch download information for version ${versionInfo.toString()}` + `Could not fetch download information for version ${versionInfo.version()}` ); - if(!versionInfo.isGeneric()) { + if(versionInfo.isExactVersion()) { console.log('Using fallback'); - downloadUrls = await this.getFallbackDownloadUrls(versionInfo.toString()); - downloadedVersion = versionInfo.toString(); + downloadUrls = await this.getFallbackDownloadUrls(versionInfo.version()); + downloadedVersion = versionInfo.version(); } else { console.log('Unable to use fallback, version is generic!'); } } if (downloadUrls.length == 0) { - throw `Could not construct download URL. Please ensure that specified version ${versionInfo.toString()}/${downloadedVersion} is valid.`; + throw `Could not construct download URL. Please ensure that specified version ${versionInfo.version()}/${downloadedVersion} is valid.`; } core.debug(`Got download urls ${downloadUrls}`);