2019-09-10 00:27:23 +07:00
|
|
|
// Load tempDirectory before it gets wiped by tool-cache
|
|
|
|
import * as core from '@actions/core';
|
|
|
|
import * as exec from '@actions/exec';
|
|
|
|
import * as io from '@actions/io';
|
2020-01-26 13:37:54 +07:00
|
|
|
import hc = require('@actions/http-client');
|
2019-09-10 00:27:23 +07:00
|
|
|
import {chmodSync} from 'fs';
|
|
|
|
import * as path from 'path';
|
2020-09-15 23:36:09 +07:00
|
|
|
import {ExecOptions} from '@actions/exec/lib/interfaces';
|
2019-09-10 00:27:23 +07:00
|
|
|
import * as semver from 'semver';
|
|
|
|
|
|
|
|
const IS_WINDOWS = process.platform === 'win32';
|
|
|
|
|
2020-04-10 00:26:10 +07:00
|
|
|
/**
|
|
|
|
* Represents the inputted version information
|
|
|
|
*/
|
2020-04-05 00:23:59 +07:00
|
|
|
export class DotNetVersionInfo {
|
2020-09-15 23:36:09 +07:00
|
|
|
public inputVersion: string;
|
2020-04-10 00:38:39 +07:00
|
|
|
private fullversion: string;
|
2020-04-05 00:23:59 +07:00
|
|
|
private isExactVersionSet: boolean = false;
|
|
|
|
|
2019-09-10 00:27:23 +07:00
|
|
|
constructor(version: string) {
|
2020-09-15 23:36:09 +07:00
|
|
|
this.inputVersion = version;
|
|
|
|
|
2020-04-05 00:23:59 +07:00
|
|
|
// Check for exact match
|
2020-04-10 00:38:39 +07:00
|
|
|
if (semver.valid(semver.clean(version) || '') != null) {
|
2020-04-05 00:23:59 +07:00
|
|
|
this.fullversion = semver.clean(version) as string;
|
|
|
|
this.isExactVersionSet = true;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Note: No support for previews when using generic
|
2021-03-17 18:56:08 +07:00
|
|
|
const parts: string[] = version.split('.');
|
2020-04-05 20:37:29 +07:00
|
|
|
|
2020-04-10 00:38:39 +07:00
|
|
|
if (parts.length < 2 || parts.length > 3) this.throwInvalidVersionFormat();
|
2020-04-05 20:37:29 +07:00
|
|
|
|
2020-04-10 00:38:39 +07:00
|
|
|
if (parts.length == 3 && parts[2] !== 'x' && parts[2] !== '*') {
|
|
|
|
this.throwInvalidVersionFormat();
|
2020-04-05 20:37:29 +07:00
|
|
|
}
|
|
|
|
|
2021-03-17 18:56:08 +07:00
|
|
|
const major = this.getVersionNumberOrThrow(parts[0]);
|
2021-03-17 18:58:04 +07:00
|
|
|
const minor = ['x', '*'].includes(parts[1])
|
|
|
|
? parts[1]
|
|
|
|
: this.getVersionNumberOrThrow(parts[1]);
|
2020-04-04 23:05:12 +07:00
|
|
|
|
2020-04-10 00:26:10 +07:00
|
|
|
this.fullversion = major + '.' + minor;
|
2020-04-04 23:05:12 +07:00
|
|
|
}
|
|
|
|
|
2020-04-10 00:38:39 +07:00
|
|
|
private getVersionNumberOrThrow(input: string): number {
|
|
|
|
try {
|
|
|
|
if (!input || input.trim() === '') this.throwInvalidVersionFormat();
|
2020-04-05 20:37:29 +07:00
|
|
|
|
|
|
|
let number = Number(input);
|
|
|
|
|
2020-04-10 00:38:39 +07:00
|
|
|
if (Number.isNaN(number) || number < 0) this.throwInvalidVersionFormat();
|
|
|
|
|
2020-04-05 20:37:29 +07:00
|
|
|
return number;
|
|
|
|
} catch {
|
|
|
|
this.throwInvalidVersionFormat();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private throwInvalidVersionFormat() {
|
2021-03-17 16:38:57 +07:00
|
|
|
throw new Error(
|
|
|
|
'Invalid version format! Supported: 1.2.3, 1.2, 1.2.x, 1.2.*'
|
|
|
|
);
|
2020-04-05 20:37:29 +07:00
|
|
|
}
|
|
|
|
|
2020-04-05 00:23:59 +07:00
|
|
|
/**
|
|
|
|
* If true exacatly one version should be resolved
|
|
|
|
*/
|
2020-04-10 00:38:39 +07:00
|
|
|
public isExactVersion(): boolean {
|
2020-04-05 00:23:59 +07:00
|
|
|
return this.isExactVersionSet;
|
2020-04-04 23:05:12 +07:00
|
|
|
}
|
|
|
|
|
2020-04-10 00:38:39 +07:00
|
|
|
public version(): string {
|
2020-04-05 00:23:59 +07:00
|
|
|
return this.fullversion;
|
2020-04-04 23:05:12 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export class DotnetCoreInstaller {
|
|
|
|
constructor(version: string) {
|
2020-09-15 23:36:09 +07:00
|
|
|
this.version = version;
|
2019-09-10 00:27:23 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
public async installDotnet() {
|
2020-09-15 23:36:09 +07:00
|
|
|
let output = '';
|
|
|
|
let resultCode = 0;
|
2019-09-10 00:27:23 +07:00
|
|
|
|
2020-09-15 23:36:09 +07:00
|
|
|
let calculatedVersion = await this.resolveVersion(
|
|
|
|
new DotNetVersionInfo(this.version)
|
|
|
|
);
|
2020-04-04 23:05:12 +07:00
|
|
|
|
2020-09-15 23:36:09 +07:00
|
|
|
var envVariables: {[key: string]: string} = {};
|
|
|
|
for (let key in process.env) {
|
|
|
|
if (process.env[key]) {
|
|
|
|
let value: any = process.env[key];
|
|
|
|
envVariables[key] = value;
|
2020-04-04 23:05:12 +07:00
|
|
|
}
|
2019-09-10 00:27:23 +07:00
|
|
|
}
|
|
|
|
if (IS_WINDOWS) {
|
|
|
|
let escapedScript = path
|
2020-09-15 23:36:09 +07:00
|
|
|
.join(__dirname, '..', 'externals', 'install-dotnet.ps1')
|
2019-09-10 00:27:23 +07:00
|
|
|
.replace(/'/g, "''");
|
|
|
|
let command = `& '${escapedScript}'`;
|
2020-09-15 23:36:09 +07:00
|
|
|
if (calculatedVersion) {
|
|
|
|
command += ` -Version ${calculatedVersion}`;
|
|
|
|
}
|
|
|
|
if (process.env['https_proxy'] != null) {
|
|
|
|
command += ` -ProxyAddress ${process.env['https_proxy']}`;
|
|
|
|
}
|
|
|
|
// This is not currently an option
|
|
|
|
if (process.env['no_proxy'] != null) {
|
|
|
|
command += ` -ProxyBypassList ${process.env['no_proxy']}`;
|
|
|
|
}
|
2019-09-10 00:27:23 +07:00
|
|
|
|
2020-09-15 23:36:09 +07:00
|
|
|
// process.env must be explicitly passed in for DOTNET_INSTALL_DIR to be used
|
2019-09-10 00:27:23 +07:00
|
|
|
const powershellPath = await io.which('powershell', true);
|
2020-09-15 23:36:09 +07:00
|
|
|
|
|
|
|
var options: ExecOptions = {
|
|
|
|
listeners: {
|
|
|
|
stdout: (data: Buffer) => {
|
|
|
|
output += data.toString();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
env: envVariables
|
|
|
|
};
|
|
|
|
|
2019-09-10 00:27:23 +07:00
|
|
|
resultCode = await exec.exec(
|
|
|
|
`"${powershellPath}"`,
|
|
|
|
[
|
|
|
|
'-NoLogo',
|
|
|
|
'-Sta',
|
|
|
|
'-NoProfile',
|
|
|
|
'-NonInteractive',
|
|
|
|
'-ExecutionPolicy',
|
|
|
|
'Unrestricted',
|
|
|
|
'-Command',
|
|
|
|
command
|
|
|
|
],
|
2020-09-15 23:36:09 +07:00
|
|
|
options
|
2019-09-10 00:27:23 +07:00
|
|
|
);
|
|
|
|
} else {
|
2020-09-15 23:36:09 +07:00
|
|
|
let escapedScript = path
|
|
|
|
.join(__dirname, '..', 'externals', 'install-dotnet.sh')
|
|
|
|
.replace(/'/g, "''");
|
|
|
|
chmodSync(escapedScript, '777');
|
|
|
|
|
|
|
|
const scriptPath = await io.which(escapedScript, true);
|
2019-09-10 00:27:23 +07:00
|
|
|
|
2020-09-15 23:36:09 +07:00
|
|
|
let scriptArguments: string[] = [];
|
2020-09-24 22:26:00 +07:00
|
|
|
if (calculatedVersion) {
|
|
|
|
scriptArguments.push('--version', calculatedVersion);
|
2020-09-15 23:36:09 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
// process.env must be explicitly passed in for DOTNET_INSTALL_DIR to be used
|
|
|
|
resultCode = await exec.exec(`"${scriptPath}"`, scriptArguments, {
|
2019-09-10 00:27:23 +07:00
|
|
|
listeners: {
|
|
|
|
stdout: (data: Buffer) => {
|
|
|
|
output += data.toString();
|
|
|
|
}
|
2020-09-15 23:36:09 +07:00
|
|
|
},
|
|
|
|
env: envVariables
|
2019-09-10 00:27:23 +07:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-09-15 23:36:09 +07:00
|
|
|
if (process.env['DOTNET_INSTALL_DIR']) {
|
|
|
|
core.addPath(process.env['DOTNET_INSTALL_DIR']);
|
2020-09-24 22:26:00 +07:00
|
|
|
core.exportVariable('DOTNET_ROOT', process.env['DOTNET_INSTALL_DIR']);
|
2020-09-15 23:36:09 +07:00
|
|
|
} else {
|
|
|
|
if (IS_WINDOWS) {
|
|
|
|
// This is the default set in install-dotnet.ps1
|
|
|
|
core.addPath(
|
|
|
|
path.join(process.env['LocalAppData'] + '', 'Microsoft', 'dotnet')
|
|
|
|
);
|
|
|
|
core.exportVariable(
|
|
|
|
'DOTNET_ROOT',
|
|
|
|
path.join(process.env['LocalAppData'] + '', 'Microsoft', 'dotnet')
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
// This is the default set in install-dotnet.sh
|
|
|
|
core.addPath(path.join(process.env['HOME'] + '', '.dotnet'));
|
2020-09-24 22:26:00 +07:00
|
|
|
core.exportVariable(
|
|
|
|
'DOTNET_ROOT',
|
|
|
|
path.join(process.env['HOME'] + '', '.dotnet')
|
|
|
|
);
|
2020-09-15 23:36:09 +07:00
|
|
|
}
|
2019-09-10 00:27:23 +07:00
|
|
|
}
|
|
|
|
|
2020-09-15 23:36:09 +07:00
|
|
|
console.log(process.env['PATH']);
|
2019-09-10 00:27:23 +07:00
|
|
|
|
2020-09-15 23:36:09 +07:00
|
|
|
if (resultCode != 0) {
|
2021-03-17 16:38:57 +07:00
|
|
|
throw new Error(`Failed to install dotnet ${resultCode}. ${output}`);
|
2019-09-10 00:27:23 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-15 23:36:09 +07:00
|
|
|
// versionInfo - versionInfo of the SDK/Runtime
|
|
|
|
async resolveVersion(versionInfo: DotNetVersionInfo): Promise<string> {
|
|
|
|
if (versionInfo.isExactVersion()) {
|
|
|
|
return versionInfo.version();
|
2019-09-10 00:27:23 +07:00
|
|
|
}
|
|
|
|
|
2020-01-26 13:37:54 +07:00
|
|
|
const httpClient = new hc.HttpClient('actions/setup-dotnet', [], {
|
|
|
|
allowRetries: true,
|
|
|
|
maxRetries: 3
|
|
|
|
});
|
2020-04-05 00:23:59 +07:00
|
|
|
|
2019-11-08 23:15:28 +07:00
|
|
|
const releasesJsonUrl: string = await this.getReleasesJsonUrl(
|
2020-01-26 13:37:54 +07:00
|
|
|
httpClient,
|
2020-04-05 00:23:59 +07:00
|
|
|
versionInfo.version().split('.')
|
2019-11-08 23:15:28 +07:00
|
|
|
);
|
|
|
|
|
2020-01-26 13:37:54 +07:00
|
|
|
const releasesResponse = await httpClient.getJson<any>(releasesJsonUrl);
|
|
|
|
const releasesResult = releasesResponse.result || {};
|
|
|
|
let releasesInfo: any[] = releasesResult['releases'];
|
2019-09-10 00:27:23 +07:00
|
|
|
releasesInfo = releasesInfo.filter((releaseInfo: any) => {
|
|
|
|
return (
|
2020-04-10 00:38:39 +07:00
|
|
|
semver.satisfies(
|
|
|
|
releaseInfo['sdk']['version'],
|
|
|
|
versionInfo.version()
|
|
|
|
) ||
|
|
|
|
semver.satisfies(
|
|
|
|
releaseInfo['sdk']['version-display'],
|
|
|
|
versionInfo.version()
|
|
|
|
)
|
2019-09-10 00:27:23 +07:00
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2020-04-05 00:23:59 +07:00
|
|
|
// Exclude versions that are newer than the latest if using not exact
|
2020-09-15 23:36:09 +07:00
|
|
|
let latestSdk: string = releasesResult['latest-sdk'];
|
2020-04-05 00:23:59 +07:00
|
|
|
|
2020-09-15 23:36:09 +07:00
|
|
|
releasesInfo = releasesInfo.filter((releaseInfo: any) =>
|
|
|
|
semver.lte(releaseInfo['sdk']['version'], latestSdk)
|
|
|
|
);
|
2020-04-05 00:23:59 +07:00
|
|
|
|
|
|
|
// Sort for latest version
|
2020-04-10 00:38:39 +07:00
|
|
|
releasesInfo = releasesInfo.sort((a, b) =>
|
|
|
|
semver.rcompare(a['sdk']['version'], b['sdk']['version'])
|
|
|
|
);
|
2020-04-04 23:05:12 +07:00
|
|
|
|
2020-09-15 23:36:09 +07:00
|
|
|
if (releasesInfo.length == 0) {
|
2021-03-17 16:38:57 +07:00
|
|
|
throw new Error(
|
|
|
|
`Could not find dotnet core version. Please ensure that specified version ${versionInfo.inputVersion} is valid.`
|
|
|
|
);
|
2019-09-10 00:27:23 +07:00
|
|
|
}
|
|
|
|
|
2020-09-15 23:36:09 +07:00
|
|
|
let release = releasesInfo[0];
|
|
|
|
return release['sdk']['version'];
|
2019-09-10 00:27:23 +07:00
|
|
|
}
|
|
|
|
|
2019-11-08 23:15:28 +07:00
|
|
|
private async getReleasesJsonUrl(
|
2020-01-26 13:37:54 +07:00
|
|
|
httpClient: hc.HttpClient,
|
2019-11-08 23:15:28 +07:00
|
|
|
versionParts: string[]
|
|
|
|
): Promise<string> {
|
2020-01-26 13:37:54 +07:00
|
|
|
const response = await httpClient.getJson<any>(DotNetCoreIndexUrl);
|
|
|
|
const result = response.result || {};
|
|
|
|
let releasesInfo: any[] = result['releases-index'];
|
2020-09-24 22:26:00 +07:00
|
|
|
|
2019-11-08 23:15:28 +07:00
|
|
|
releasesInfo = releasesInfo.filter((info: any) => {
|
|
|
|
// channel-version is the first 2 elements of the version (e.g. 2.1), filter out versions that don't match 2.1.x.
|
|
|
|
const sdkParts: string[] = info['channel-version'].split('.');
|
2020-09-24 22:26:00 +07:00
|
|
|
if (
|
|
|
|
versionParts.length >= 2 &&
|
|
|
|
!(versionParts[1] == 'x' || versionParts[1] == '*')
|
|
|
|
) {
|
2019-11-08 23:15:28 +07:00
|
|
|
return versionParts[0] == sdkParts[0] && versionParts[1] == sdkParts[1];
|
|
|
|
}
|
|
|
|
return versionParts[0] == sdkParts[0];
|
|
|
|
});
|
2020-09-24 22:26:00 +07:00
|
|
|
|
2019-11-08 23:15:28 +07:00
|
|
|
if (releasesInfo.length === 0) {
|
2021-03-17 16:38:57 +07:00
|
|
|
throw new Error(
|
|
|
|
`Could not find info for version ${versionParts.join(
|
|
|
|
'.'
|
|
|
|
)} at ${DotNetCoreIndexUrl}`
|
|
|
|
);
|
2019-11-08 23:15:28 +07:00
|
|
|
}
|
2020-09-24 22:26:00 +07:00
|
|
|
|
2019-11-08 23:15:28 +07:00
|
|
|
return releasesInfo[0]['releases.json'];
|
2019-09-10 00:27:23 +07:00
|
|
|
}
|
|
|
|
|
2020-09-15 23:36:09 +07:00
|
|
|
private version: string;
|
2019-09-10 00:27:23 +07:00
|
|
|
}
|
|
|
|
|
2019-11-08 23:15:28 +07:00
|
|
|
const DotNetCoreIndexUrl: string =
|
|
|
|
'https://dotnetcli.blob.core.windows.net/dotnet/release-metadata/releases-index.json';
|