Added support for latest version syntax

This commit is contained in:
litetex 2020-04-04 18:05:12 +02:00
parent 00f2601192
commit fd402244d0
2 changed files with 134 additions and 30 deletions

View File

@ -28,6 +28,28 @@ describe('installer tests', () => {
} }
}, 100000); }, 100000);
/*
it('Check if get version works', async () => {
const dotnetInstaller = new installer.DotnetCoreInstaller('3.1.201');
let arr = await dotnetInstaller.resolveInfos(["win-x64"],new installer.DotNetVersionInfo("3.1.201"));
console.log(arr);
expect(true).toBe(true);
}, 400000);
it('Check if get latest version works', async () => {
const dotnetInstaller = new installer.DotnetCoreInstaller('3.1.x');
let arr = await dotnetInstaller.resolveInfos(["win-x64"],new installer.DotNetVersionInfo("3.1.x"));
console.log(arr);
expect(true).toBe(true);
}, 400000);*/
it('Acquires version of dotnet if no matching version is installed', async () => { it('Acquires version of dotnet if no matching version is installed', async () => {
await getDotnet('2.2.205'); await getDotnet('2.2.205');
const dotnetDir = path.join(toolDir, 'dncs', '2.2.205', os.arch()); const dotnetDir = path.join(toolDir, 'dncs', '2.2.205', os.arch());
@ -38,7 +60,7 @@ describe('installer tests', () => {
} else { } else {
expect(fs.existsSync(path.join(dotnetDir, 'dotnet'))).toBe(true); expect(fs.existsSync(path.join(dotnetDir, 'dotnet'))).toBe(true);
} }
}, 100000); }, 400000);
it('Throws if no location contains correct dotnet version', async () => { it('Throws if no location contains correct dotnet version', async () => {
let thrown = false; let thrown = false;

View File

@ -9,6 +9,7 @@ import {chmodSync} from 'fs';
import * as os from 'os'; import * as os from 'os';
import * as path from 'path'; import * as path from 'path';
import * as semver from 'semver'; import * as semver from 'semver';
import { stringWriter } from 'xmlbuilder';
const IS_WINDOWS = process.platform === 'win32'; const IS_WINDOWS = process.platform === 'win32';
@ -27,31 +28,96 @@ if (!tempDirectory) {
tempDirectory = path.join(baseLocation, 'actions', 'temp'); tempDirectory = path.join(baseLocation, 'actions', 'temp');
} }
class DotNetVersionInfo {
major: number;
minor: number;
patch?: number;
constructor(version: string) {
//todo: add support for previews!
let regexResult = version.match(/^(\d+\.)(\d+\.)(\*|x|\d+)$/);
if(regexResult == null) {
throw 'Invalid version. Supported formats: 1.2.3, 1.2, 1.2.x, 1.2.*';
}
let parts : string[] = (regexResult as RegExpMatchArray).slice(1);
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];
}
}
}
public isGeneric() : boolean {
return this.patch ? true : false;
}
public toString() : string {
let version = this.major + "." + this.minor;
if(this.patch)
version += "." + this.patch;
return version;
}
}
class ResolvedVersionInfo {
downloadUrls: string[];
resolvedVersion: string;
constructor(downloadUrls: string[], resolvedVersion: string) {
if(downloadUrls.length === 0) {
throw 'DownloadUrls can not be empty';
}
if(!resolvedVersion) {
throw 'Resolved version is invalid';
}
this.downloadUrls = downloadUrls;
this.resolvedVersion = resolvedVersion;
}
}
export class DotnetCoreInstaller { export class DotnetCoreInstaller {
constructor(version: string) { constructor(version: string) {
if (semver.valid(semver.clean(version) || '') == null) { this.versionInfo = new DotNetVersionInfo(version);
throw 'Implicit version not permitted';
}
this.version = version;
this.cachedToolName = 'dncs'; this.cachedToolName = 'dncs';
this.arch = 'x64'; this.arch = 'x64';
} }
public async installDotnet() { public async installDotnet() {
// Check cache // Check cache
let toolPath: string; let toolPath: string = "";
let osSuffixes = await this.detectMachineOS(); let osSuffixes = await this.detectMachineOS();
let parts = osSuffixes[0].split('-'); let parts = osSuffixes[0].split('-');
if (parts.length > 1) { if (parts.length > 1) {
this.arch = parts[1]; this.arch = parts[1];
} }
toolPath = this.getLocalTool();
// If version is not generic -> look up cache
if(!this.versionInfo.isGeneric())
toolPath = this.getLocalTool(this.versionInfo.toString());
if (!toolPath) { if (!toolPath) {
// download, extract, cache // download, extract, cache
console.log('Getting a download url', this.version); console.log('Getting a download url', this.versionInfo.toString());
let downloadUrls = await this.getDownloadUrls(osSuffixes, this.version); let resolvedVersionInfo = await this.resolveInfos(osSuffixes, this.versionInfo);
toolPath = await this.downloadAndInstall(downloadUrls);
//Check if cache exists for resolved version
toolPath = this.getLocalTool(resolvedVersionInfo.resolvedVersion);
if(!toolPath) {
//If not exists install it
toolPath = await this.downloadAndInstall(resolvedVersionInfo);
} else {
console.log('Using cached tool');
}
} else { } else {
console.log('Using cached tool'); console.log('Using cached tool');
} }
@ -63,9 +129,9 @@ export class DotnetCoreInstaller {
core.addPath(toolPath); core.addPath(toolPath);
} }
private getLocalTool(): string { private getLocalTool(version: string): string {
console.log('Checking tool cache'); console.log('Checking tool cache', version);
return tc.find(this.cachedToolName, this.version, this.arch); return tc.find(this.cachedToolName, version, this.arch);
} }
private async detectMachineOS(): Promise<string[]> { private async detectMachineOS(): Promise<string[]> {
@ -141,16 +207,16 @@ export class DotnetCoreInstaller {
return osSuffix; return osSuffix;
} }
private async downloadAndInstall(downloadUrls: string[]) { private async downloadAndInstall(resolvedVersionInfo: ResolvedVersionInfo) {
let downloaded = false; let downloaded = false;
let downloadPath = ''; let downloadPath = '';
for (const url of downloadUrls) { for (const url of resolvedVersionInfo.downloadUrls) {
try { try {
downloadPath = await tc.downloadTool(url); downloadPath = await tc.downloadTool(url);
downloaded = true; downloaded = true;
break; break;
} catch (error) { } catch (error) {
console.log('Could Not Download', url, JSON.stringify(error)); console.log('Could not Download', url, JSON.stringify(error));
} }
} }
@ -169,22 +235,21 @@ export class DotnetCoreInstaller {
let cachedDir = await tc.cacheDir( let cachedDir = await tc.cacheDir(
extPath, extPath,
this.cachedToolName, this.cachedToolName,
this.version, resolvedVersionInfo.resolvedVersion,
this.arch this.arch
); );
console.log('Successfully installed', this.version); console.log('Successfully installed', resolvedVersionInfo.resolvedVersion);
return cachedDir; return cachedDir;
} }
// OsSuffixes - The suffix which is a part of the file name ex- linux-x64, windows-x86 // OsSuffixes - The suffix which is a part of the file name ex- linux-x64, windows-x86
// Type - SDK / Runtime // Type - SDK / Runtime
// Version - Version of the SDK/Runtime // Version - Version of the SDK/Runtime
private async getDownloadUrls( private async resolveInfos(
osSuffixes: string[], osSuffixes: string[],
version: string versionInfo: DotNetVersionInfo
): Promise<string[]> { ): Promise<ResolvedVersionInfo> {
let downloadUrls: string[] = [];
const httpClient = new hc.HttpClient('actions/setup-dotnet', [], { const httpClient = new hc.HttpClient('actions/setup-dotnet', [], {
allowRetries: true, allowRetries: true,
@ -192,7 +257,7 @@ export class DotnetCoreInstaller {
}); });
const releasesJsonUrl: string = await this.getReleasesJsonUrl( const releasesJsonUrl: string = await this.getReleasesJsonUrl(
httpClient, httpClient,
version.split('.') [String(versionInfo.major), String(versionInfo.minor)]
); );
const releasesResponse = await httpClient.getJson<any>(releasesJsonUrl); const releasesResponse = await httpClient.getJson<any>(releasesJsonUrl);
@ -200,13 +265,22 @@ export class DotnetCoreInstaller {
let releasesInfo: any[] = releasesResult['releases']; let releasesInfo: any[] = releasesResult['releases'];
releasesInfo = releasesInfo.filter((releaseInfo: any) => { releasesInfo = releasesInfo.filter((releaseInfo: any) => {
return ( return (
releaseInfo['sdk']['version'] === version || semver.satisfies(releaseInfo['sdk']['version'], versionInfo.toString()) ||
releaseInfo['sdk']['version-display'] === version semver.satisfies(releaseInfo['sdk']['version-display'], versionInfo.toString())
); );
}); });
//Sort for latest version
releasesInfo = releasesInfo.sort((a,b) => semver.rcompare(a['sdk']['version'],b['sdk']['version']));
let downloadedVersion : string = '';
let downloadUrls: string[] = [];
if (releasesInfo.length != 0) { if (releasesInfo.length != 0) {
let release = releasesInfo[0]; let release = releasesInfo[0];
downloadedVersion = release['sdk']['version'];
let files: any[] = release['sdk']['files']; let files: any[] = release['sdk']['files'];
files = files.filter((file: any) => { files = files.filter((file: any) => {
if (file['rid'] == osSuffixes[0] || file['rid'] == osSuffixes[1]) { if (file['rid'] == osSuffixes[0] || file['rid'] == osSuffixes[1]) {
@ -225,18 +299,26 @@ export class DotnetCoreInstaller {
} }
} else { } else {
console.log( console.log(
`Could not fetch download information for version ${version}` `Could not fetch download information for version ${versionInfo.toString()}`
); );
downloadUrls = await this.getFallbackDownloadUrls(version);
if(!versionInfo.isGeneric()) {
console.log('Using fallback');
downloadUrls = await this.getFallbackDownloadUrls(versionInfo.toString());
downloadedVersion = versionInfo.toString();
} else {
console.log('Unable to use fallback, version is generic!');
}
} }
if (downloadUrls.length == 0) { if (downloadUrls.length == 0) {
throw `Could not construct download URL. Please ensure that specified version ${version} is valid.`; throw `Could not construct download URL. Please ensure that specified version ${versionInfo.toString()}/${downloadedVersion} is valid.`;
} }
core.debug(`Got download urls ${downloadUrls}`); core.debug(`Got download urls ${downloadUrls}`);
return downloadUrls; return new ResolvedVersionInfo(downloadUrls, downloadedVersion);
} }
private async getReleasesJsonUrl( private async getReleasesJsonUrl(
@ -361,7 +443,7 @@ export class DotnetCoreInstaller {
return [primaryUrl, legacyUrl]; return [primaryUrl, legacyUrl];
} }
private version: string; private versionInfo: DotNetVersionInfo;
private cachedToolName: string; private cachedToolName: string;
private arch: string; private arch: string;
} }