mirror of
https://github.com/actions/setup-dotnet.git
synced 2024-11-26 05:13:05 +07:00
Merge branch 'litetex-support-latest-version'
This commit is contained in:
commit
6efb2bd78f
@ -20,7 +20,7 @@ steps:
|
|||||||
- uses: actions/checkout@master
|
- uses: actions/checkout@master
|
||||||
- uses: actions/setup-dotnet@v1
|
- uses: actions/setup-dotnet@v1
|
||||||
with:
|
with:
|
||||||
dotnet-version: '3.1.100' # SDK Version to use.
|
dotnet-version: '3.1.x' # SDK Version to use; x will use the latest version of the 3.1 channel
|
||||||
- run: dotnet build <my project>
|
- run: dotnet build <my project>
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ jobs:
|
|||||||
runs-on: ubuntu-16.04
|
runs-on: ubuntu-16.04
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
dotnet: [ '2.2.103', '3.0.100', '3.1.100' ]
|
dotnet: [ '2.2.103', '3.0', '3.1.x' ]
|
||||||
name: Dotnet ${{ matrix.dotnet }} sample
|
name: Dotnet ${{ matrix.dotnet }} sample
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@master
|
- uses: actions/checkout@master
|
||||||
@ -49,7 +49,7 @@ steps:
|
|||||||
# Authenticates packages to push to GPR
|
# Authenticates packages to push to GPR
|
||||||
- uses: actions/setup-dotnet@v1
|
- uses: actions/setup-dotnet@v1
|
||||||
with:
|
with:
|
||||||
dotnet-version: '3.1.100' # SDK Version to use.
|
dotnet-version: '3.1.x' # SDK Version to use.
|
||||||
source-url: https://nuget.pkg.github.com/<owner>/index.json
|
source-url: https://nuget.pkg.github.com/<owner>/index.json
|
||||||
env:
|
env:
|
||||||
NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
||||||
|
@ -4,6 +4,8 @@ import os = require('os');
|
|||||||
import path = require('path');
|
import path = require('path');
|
||||||
import hc = require('@actions/http-client');
|
import hc = require('@actions/http-client');
|
||||||
|
|
||||||
|
import each from 'jest-each';
|
||||||
|
|
||||||
const toolDir = path.join(__dirname, 'runner', 'tools');
|
const toolDir = path.join(__dirname, 'runner', 'tools');
|
||||||
const tempDir = path.join(__dirname, 'runner', 'temp');
|
const tempDir = path.join(__dirname, 'runner', 'temp');
|
||||||
|
|
||||||
@ -14,6 +16,61 @@ import * as installer from '../src/installer';
|
|||||||
|
|
||||||
const IS_WINDOWS = process.platform === 'win32';
|
const IS_WINDOWS = process.platform === 'win32';
|
||||||
|
|
||||||
|
describe('version tests', () => {
|
||||||
|
each(['3.1.999', '3.1.101-preview.3']).test(
|
||||||
|
"Exact version '%s' should be the same",
|
||||||
|
vers => {
|
||||||
|
let versInfo = new installer.DotNetVersionInfo(vers);
|
||||||
|
|
||||||
|
expect(versInfo.isExactVersion()).toBe(true);
|
||||||
|
expect(versInfo.version()).toBe(vers);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
each([['3.1.x', '3.1'], ['1.1.*', '1.1'], ['2.0', '2.0']]).test(
|
||||||
|
"Generic version '%s' should be '%s'",
|
||||||
|
(vers, resVers) => {
|
||||||
|
let versInfo = new installer.DotNetVersionInfo(vers);
|
||||||
|
|
||||||
|
expect(versInfo.isExactVersion()).toBe(false);
|
||||||
|
expect(versInfo.version()).toBe(resVers);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
each([
|
||||||
|
'',
|
||||||
|
'.',
|
||||||
|
'..',
|
||||||
|
' . ',
|
||||||
|
'. ',
|
||||||
|
' .',
|
||||||
|
' . . ',
|
||||||
|
' .. ',
|
||||||
|
' . ',
|
||||||
|
'-1.-1',
|
||||||
|
'-1',
|
||||||
|
'-1.-1.-1',
|
||||||
|
'..3',
|
||||||
|
'1..3',
|
||||||
|
'1..',
|
||||||
|
'.2.3',
|
||||||
|
'.2.x',
|
||||||
|
'1',
|
||||||
|
'2.x',
|
||||||
|
'*.*.1',
|
||||||
|
'*.1',
|
||||||
|
'*.',
|
||||||
|
'1.2.',
|
||||||
|
'1.2.-abc',
|
||||||
|
'a.b',
|
||||||
|
'a.b.c',
|
||||||
|
'a.b.c-preview',
|
||||||
|
' 0 . 1 . 2 '
|
||||||
|
]).test("Malformed version '%s' should throw", vers => {
|
||||||
|
expect(() => new installer.DotNetVersionInfo(vers)).toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('installer tests', () => {
|
describe('installer tests', () => {
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await io.rmRF(toolDir);
|
await io.rmRF(toolDir);
|
||||||
@ -29,6 +86,51 @@ describe('installer tests', () => {
|
|||||||
}
|
}
|
||||||
}, 100000);
|
}, 100000);
|
||||||
|
|
||||||
|
it('Resolving a normal generic version works', async () => {
|
||||||
|
const dotnetInstaller = new installer.DotnetCoreInstaller('3.1.x');
|
||||||
|
let versInfo = await dotnetInstaller.resolveInfos(
|
||||||
|
['win-x64'],
|
||||||
|
new installer.DotNetVersionInfo('3.1.x')
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(versInfo.resolvedVersion.startsWith('3.1.'));
|
||||||
|
}, 100000);
|
||||||
|
|
||||||
|
it('Resolving a nonexistent generic version fails', async () => {
|
||||||
|
const dotnetInstaller = new installer.DotnetCoreInstaller('999.1.x');
|
||||||
|
try {
|
||||||
|
await dotnetInstaller.resolveInfos(
|
||||||
|
['win-x64'],
|
||||||
|
new installer.DotNetVersionInfo('999.1.x')
|
||||||
|
);
|
||||||
|
fail();
|
||||||
|
} catch {
|
||||||
|
expect(true);
|
||||||
|
}
|
||||||
|
}, 100000);
|
||||||
|
|
||||||
|
it('Resolving a exact stable version works', async () => {
|
||||||
|
const dotnetInstaller = new installer.DotnetCoreInstaller('3.1.201');
|
||||||
|
let versInfo = await dotnetInstaller.resolveInfos(
|
||||||
|
['win-x64'],
|
||||||
|
new installer.DotNetVersionInfo('3.1.201')
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(versInfo.resolvedVersion).toBe('3.1.201');
|
||||||
|
}, 100000);
|
||||||
|
|
||||||
|
it('Resolving a exact preview version works', async () => {
|
||||||
|
const dotnetInstaller = new installer.DotnetCoreInstaller(
|
||||||
|
'5.0.0-preview.4'
|
||||||
|
);
|
||||||
|
let versInfo = await dotnetInstaller.resolveInfos(
|
||||||
|
['win-x64'],
|
||||||
|
new installer.DotNetVersionInfo('5.0.0-preview.4')
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(versInfo.resolvedVersion).toBe('5.0.0-preview.4');
|
||||||
|
}, 100000);
|
||||||
|
|
||||||
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());
|
||||||
@ -39,7 +141,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); //This needs some time to download on "slower" internet connections
|
||||||
|
|
||||||
it('Acquires version of dotnet if no matching version is installed', async () => {
|
it('Acquires version of dotnet if no matching version is installed', async () => {
|
||||||
const dotnetDir = path.join(toolDir, 'dncs', '2.2.105', os.arch());
|
const dotnetDir = path.join(toolDir, 'dncs', '2.2.105', os.arch());
|
||||||
|
@ -6,7 +6,7 @@ branding:
|
|||||||
color: green
|
color: green
|
||||||
inputs:
|
inputs:
|
||||||
dotnet-version:
|
dotnet-version:
|
||||||
description: 'SDK version to use. Example: 2.2.104'
|
description: 'SDK version to use. Examples: 2.2.104, 3.1, 3.1.x'
|
||||||
source-url:
|
source-url:
|
||||||
description: 'Optional package source for which to set up authentication. Will consult any existing NuGet.config in the root of the repo and provide a temporary NuGet.config using the NUGET_AUTH_TOKEN environment variable as a ClearTextPassword'
|
description: 'Optional package source for which to set up authentication. Will consult any existing NuGet.config in the root of the repo and provide a temporary NuGet.config using the NUGET_AUTH_TOKEN environment variable as a ClearTextPassword'
|
||||||
owner:
|
owner:
|
||||||
|
145
dist/index.js
vendored
145
dist/index.js
vendored
@ -17392,7 +17392,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.DotnetCoreInstaller = void 0;
|
exports.DotnetCoreInstaller = exports.DotNetVersionInfo = void 0;
|
||||||
// Load tempDirectory before it gets wiped by tool-cache
|
// Load tempDirectory before it gets wiped by tool-cache
|
||||||
let tempDirectory = process.env['RUNNER_TEMPDIRECTORY'] || '';
|
let tempDirectory = process.env['RUNNER_TEMPDIRECTORY'] || '';
|
||||||
const core = __importStar(__webpack_require__(470));
|
const core = __importStar(__webpack_require__(470));
|
||||||
@ -17421,30 +17421,103 @@ if (!tempDirectory) {
|
|||||||
}
|
}
|
||||||
tempDirectory = path.join(baseLocation, 'actions', 'temp');
|
tempDirectory = path.join(baseLocation, 'actions', 'temp');
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Represents the inputted version information
|
||||||
|
*/
|
||||||
|
class DotNetVersionInfo {
|
||||||
|
constructor(version) {
|
||||||
|
this.isExactVersionSet = false;
|
||||||
|
// Check for exact match
|
||||||
|
if (semver.valid(semver.clean(version) || '') != null) {
|
||||||
|
this.fullversion = semver.clean(version);
|
||||||
|
this.isExactVersionSet = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//Note: No support for previews when using generic
|
||||||
|
let parts = version.split('.');
|
||||||
|
if (parts.length < 2 || parts.length > 3)
|
||||||
|
this.throwInvalidVersionFormat();
|
||||||
|
if (parts.length == 3 && parts[2] !== 'x' && parts[2] !== '*') {
|
||||||
|
this.throwInvalidVersionFormat();
|
||||||
|
}
|
||||||
|
let major = this.getVersionNumberOrThrow(parts[0]);
|
||||||
|
let minor = this.getVersionNumberOrThrow(parts[1]);
|
||||||
|
this.fullversion = major + '.' + minor;
|
||||||
|
}
|
||||||
|
getVersionNumberOrThrow(input) {
|
||||||
|
try {
|
||||||
|
if (!input || input.trim() === '')
|
||||||
|
this.throwInvalidVersionFormat();
|
||||||
|
let number = Number(input);
|
||||||
|
if (Number.isNaN(number) || number < 0)
|
||||||
|
this.throwInvalidVersionFormat();
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
catch (_a) {
|
||||||
|
this.throwInvalidVersionFormat();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throwInvalidVersionFormat() {
|
||||||
|
throw 'Invalid version format! Supported: 1.2.3, 1.2, 1.2.x, 1.2.*';
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* If true exacatly one version should be resolved
|
||||||
|
*/
|
||||||
|
isExactVersion() {
|
||||||
|
return this.isExactVersionSet;
|
||||||
|
}
|
||||||
|
version() {
|
||||||
|
return this.fullversion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.DotNetVersionInfo = DotNetVersionInfo;
|
||||||
|
/**
|
||||||
|
* Represents a resolved version from the Web-Api
|
||||||
|
*/
|
||||||
|
class ResolvedVersionInfo {
|
||||||
|
constructor(downloadUrls, resolvedVersion) {
|
||||||
|
if (downloadUrls.length === 0) {
|
||||||
|
throw 'DownloadUrls can not be empty';
|
||||||
|
}
|
||||||
|
if (!resolvedVersion) {
|
||||||
|
throw 'Resolved version is invalid';
|
||||||
|
}
|
||||||
|
this.downloadUrls = downloadUrls;
|
||||||
|
this.resolvedVersion = resolvedVersion;
|
||||||
|
}
|
||||||
|
}
|
||||||
class DotnetCoreInstaller {
|
class DotnetCoreInstaller {
|
||||||
constructor(version) {
|
constructor(version) {
|
||||||
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';
|
||||||
}
|
}
|
||||||
installDotnet() {
|
installDotnet() {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
// Check cache
|
// Check cache
|
||||||
let toolPath;
|
let toolPath = '';
|
||||||
let osSuffixes = yield this.detectMachineOS();
|
let osSuffixes = yield 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.isExactVersion())
|
||||||
|
toolPath = this.getLocalTool(this.versionInfo.version());
|
||||||
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.version());
|
||||||
let downloadUrls = yield this.getDownloadUrls(osSuffixes, this.version);
|
let resolvedVersionInfo = yield this.resolveInfos(osSuffixes, this.versionInfo);
|
||||||
toolPath = yield this.downloadAndInstall(downloadUrls);
|
//Check if cache exists for resolved version
|
||||||
|
toolPath = this.getLocalTool(resolvedVersionInfo.resolvedVersion);
|
||||||
|
if (!toolPath) {
|
||||||
|
//If not exists install it
|
||||||
|
toolPath = yield this.downloadAndInstall(resolvedVersionInfo);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.log('Using cached tool');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
console.log('Using cached tool');
|
console.log('Using cached tool');
|
||||||
@ -17455,9 +17528,9 @@ class DotnetCoreInstaller {
|
|||||||
core.addPath(toolPath);
|
core.addPath(toolPath);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
getLocalTool() {
|
getLocalTool(version) {
|
||||||
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);
|
||||||
}
|
}
|
||||||
detectMachineOS() {
|
detectMachineOS() {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
@ -17517,18 +17590,18 @@ class DotnetCoreInstaller {
|
|||||||
return osSuffix;
|
return osSuffix;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
downloadAndInstall(downloadUrls) {
|
downloadAndInstall(resolvedVersionInfo) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
let downloaded = false;
|
let downloaded = false;
|
||||||
let downloadPath = '';
|
let downloadPath = '';
|
||||||
for (const url of downloadUrls) {
|
for (const url of resolvedVersionInfo.downloadUrls) {
|
||||||
try {
|
try {
|
||||||
downloadPath = yield tc.downloadTool(url);
|
downloadPath = yield 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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!downloaded) {
|
if (!downloaded) {
|
||||||
@ -17541,31 +17614,40 @@ class DotnetCoreInstaller {
|
|||||||
: yield tc.extractTar(downloadPath);
|
: yield tc.extractTar(downloadPath);
|
||||||
// cache tool
|
// cache tool
|
||||||
console.log('Caching tool');
|
console.log('Caching tool');
|
||||||
let cachedDir = yield tc.cacheDir(extPath, this.cachedToolName, this.version, this.arch);
|
let cachedDir = yield tc.cacheDir(extPath, this.cachedToolName, resolvedVersionInfo.resolvedVersion, 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
|
// versionInfo - versionInfo of the SDK/Runtime
|
||||||
getDownloadUrls(osSuffixes, version) {
|
resolveInfos(osSuffixes, versionInfo) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
let downloadUrls = [];
|
|
||||||
const httpClient = new hc.HttpClient('actions/setup-dotnet', [], {
|
const httpClient = new hc.HttpClient('actions/setup-dotnet', [], {
|
||||||
allowRetries: true,
|
allowRetries: true,
|
||||||
maxRetries: 3
|
maxRetries: 3
|
||||||
});
|
});
|
||||||
const releasesJsonUrl = yield this.getReleasesJsonUrl(httpClient, version.split('.'));
|
const releasesJsonUrl = yield this.getReleasesJsonUrl(httpClient, versionInfo.version().split('.'));
|
||||||
const releasesResponse = yield httpClient.getJson(releasesJsonUrl);
|
const releasesResponse = yield httpClient.getJson(releasesJsonUrl);
|
||||||
const releasesResult = releasesResponse.result || {};
|
const releasesResult = releasesResponse.result || {};
|
||||||
let releasesInfo = releasesResult['releases'];
|
let releasesInfo = releasesResult['releases'];
|
||||||
releasesInfo = releasesInfo.filter((releaseInfo) => {
|
releasesInfo = releasesInfo.filter((releaseInfo) => {
|
||||||
return (releaseInfo['sdk']['version'] === version ||
|
return (semver.satisfies(releaseInfo['sdk']['version'], versionInfo.version()) ||
|
||||||
releaseInfo['sdk']['version-display'] === version);
|
semver.satisfies(releaseInfo['sdk']['version-display'], versionInfo.version()));
|
||||||
});
|
});
|
||||||
|
// Exclude versions that are newer than the latest if using not exact
|
||||||
|
if (!versionInfo.isExactVersion()) {
|
||||||
|
let latestSdk = releasesResult['latest-sdk'];
|
||||||
|
releasesInfo = releasesInfo.filter((releaseInfo) => 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 = '';
|
||||||
|
let downloadUrls = [];
|
||||||
if (releasesInfo.length != 0) {
|
if (releasesInfo.length != 0) {
|
||||||
let release = releasesInfo[0];
|
let release = releasesInfo[0];
|
||||||
|
downloadedVersion = release['sdk']['version'];
|
||||||
let files = release['sdk']['files'];
|
let files = release['sdk']['files'];
|
||||||
files = files.filter((file) => {
|
files = files.filter((file) => {
|
||||||
if (file['rid'] == osSuffixes[0] || file['rid'] == osSuffixes[1]) {
|
if (file['rid'] == osSuffixes[0] || file['rid'] == osSuffixes[1]) {
|
||||||
@ -17582,14 +17664,21 @@ class DotnetCoreInstaller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
console.log(`Could not fetch download information for version ${version}`);
|
console.log(`Could not fetch download information for version ${versionInfo.version()}`);
|
||||||
downloadUrls = yield this.getFallbackDownloadUrls(version);
|
if (versionInfo.isExactVersion()) {
|
||||||
|
console.log('Using fallback');
|
||||||
|
downloadUrls = yield this.getFallbackDownloadUrls(versionInfo.version());
|
||||||
|
downloadedVersion = versionInfo.version();
|
||||||
|
}
|
||||||
|
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.version()}/${downloadedVersion} is valid.`;
|
||||||
}
|
}
|
||||||
core.debug(`Got download urls ${downloadUrls}`);
|
core.debug(`Got download urls ${downloadUrls}`);
|
||||||
return downloadUrls;
|
return new ResolvedVersionInfo(downloadUrls, downloadedVersion);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
getReleasesJsonUrl(httpClient, versionParts) {
|
getReleasesJsonUrl(httpClient, versionParts) {
|
||||||
|
191
src/installer.ts
191
src/installer.ts
@ -27,31 +27,125 @@ if (!tempDirectory) {
|
|||||||
tempDirectory = path.join(baseLocation, 'actions', 'temp');
|
tempDirectory = path.join(baseLocation, 'actions', 'temp');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the inputted version information
|
||||||
|
*/
|
||||||
|
export class DotNetVersionInfo {
|
||||||
|
private fullversion: string;
|
||||||
|
private isExactVersionSet: boolean = false;
|
||||||
|
|
||||||
|
constructor(version: string) {
|
||||||
|
// Check for exact match
|
||||||
|
if (semver.valid(semver.clean(version) || '') != null) {
|
||||||
|
this.fullversion = semver.clean(version) as string;
|
||||||
|
this.isExactVersionSet = true;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Note: No support for previews when using generic
|
||||||
|
let parts: string[] = version.split('.');
|
||||||
|
|
||||||
|
if (parts.length < 2 || parts.length > 3) this.throwInvalidVersionFormat();
|
||||||
|
|
||||||
|
if (parts.length == 3 && parts[2] !== 'x' && parts[2] !== '*') {
|
||||||
|
this.throwInvalidVersionFormat();
|
||||||
|
}
|
||||||
|
|
||||||
|
let major = this.getVersionNumberOrThrow(parts[0]);
|
||||||
|
let minor = this.getVersionNumberOrThrow(parts[1]);
|
||||||
|
|
||||||
|
this.fullversion = major + '.' + minor;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getVersionNumberOrThrow(input: string): number {
|
||||||
|
try {
|
||||||
|
if (!input || input.trim() === '') this.throwInvalidVersionFormat();
|
||||||
|
|
||||||
|
let number = Number(input);
|
||||||
|
|
||||||
|
if (Number.isNaN(number) || number < 0) this.throwInvalidVersionFormat();
|
||||||
|
|
||||||
|
return number;
|
||||||
|
} catch {
|
||||||
|
this.throwInvalidVersionFormat();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private throwInvalidVersionFormat() {
|
||||||
|
throw 'Invalid version format! Supported: 1.2.3, 1.2, 1.2.x, 1.2.*';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If true exacatly one version should be resolved
|
||||||
|
*/
|
||||||
|
public isExactVersion(): boolean {
|
||||||
|
return this.isExactVersionSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public version(): string {
|
||||||
|
return this.fullversion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a resolved version from the Web-Api
|
||||||
|
*/
|
||||||
|
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.isExactVersion())
|
||||||
|
toolPath = this.getLocalTool(this.versionInfo.version());
|
||||||
|
|
||||||
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.version());
|
||||||
let downloadUrls = await this.getDownloadUrls(osSuffixes, this.version);
|
let resolvedVersionInfo = await this.resolveInfos(
|
||||||
toolPath = await this.downloadAndInstall(downloadUrls);
|
osSuffixes,
|
||||||
|
this.versionInfo
|
||||||
|
);
|
||||||
|
|
||||||
|
//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 +157,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 +235,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,30 +263,29 @@ 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
|
// versionInfo - versionInfo of the SDK/Runtime
|
||||||
private async getDownloadUrls(
|
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,
|
||||||
maxRetries: 3
|
maxRetries: 3
|
||||||
});
|
});
|
||||||
|
|
||||||
const releasesJsonUrl: string = await this.getReleasesJsonUrl(
|
const releasesJsonUrl: string = await this.getReleasesJsonUrl(
|
||||||
httpClient,
|
httpClient,
|
||||||
version.split('.')
|
versionInfo.version().split('.')
|
||||||
);
|
);
|
||||||
|
|
||||||
const releasesResponse = await httpClient.getJson<any>(releasesJsonUrl);
|
const releasesResponse = await httpClient.getJson<any>(releasesJsonUrl);
|
||||||
@ -200,13 +293,39 @@ 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-display'] === version
|
releaseInfo['sdk']['version'],
|
||||||
|
versionInfo.version()
|
||||||
|
) ||
|
||||||
|
semver.satisfies(
|
||||||
|
releaseInfo['sdk']['version-display'],
|
||||||
|
versionInfo.version()
|
||||||
|
)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Exclude versions that are newer than the latest if using not exact
|
||||||
|
if (!versionInfo.isExactVersion()) {
|
||||||
|
let latestSdk: string = releasesResult['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 = '';
|
||||||
|
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 +344,28 @@ 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.version()}`
|
||||||
);
|
);
|
||||||
downloadUrls = await this.getFallbackDownloadUrls(version);
|
|
||||||
|
if (versionInfo.isExactVersion()) {
|
||||||
|
console.log('Using fallback');
|
||||||
|
|
||||||
|
downloadUrls = await this.getFallbackDownloadUrls(
|
||||||
|
versionInfo.version()
|
||||||
|
);
|
||||||
|
downloadedVersion = versionInfo.version();
|
||||||
|
} 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.version()}/${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 +490,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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user