Refactor installer

This commit is contained in:
Nikolai Laevskii 2023-05-12 16:28:16 +02:00
parent 6d92b9bd53
commit aa85432603
3 changed files with 218 additions and 176 deletions

View File

@ -117,7 +117,7 @@ describe('DotnetCoreInstaller tests', () => {
it('Throws if no location contains correct dotnet version', async () => { it('Throws if no location contains correct dotnet version', async () => {
await expect(async () => { await expect(async () => {
await getDotnet('1000.0.0'); await getDotnet('1000.0.0')
}).rejects.toThrow(); }).rejects.toThrow();
}, 30000); }, 30000);
@ -177,7 +177,7 @@ describe('DotnetVersionResolver tests', () => {
const dotnetVersionResolver = new installer.DotnetVersionResolver( const dotnetVersionResolver = new installer.DotnetVersionResolver(
version version
); );
const versionObject = await dotnetVersionResolver.createDotNetVersion(); const versionObject = await dotnetVersionResolver.createDotnetVersion();
expect(!!versionObject.value).toBe(true); expect(!!versionObject.value).toBe(true);
} }
@ -216,7 +216,7 @@ describe('DotnetVersionResolver tests', () => {
); );
await expect( await expect(
async () => await dotnetVersionResolver.createDotNetVersion() async () => await dotnetVersionResolver.createDotnetVersion()
).rejects.toThrow(); ).rejects.toThrow();
} }
); );
@ -227,7 +227,7 @@ describe('DotnetVersionResolver tests', () => {
const dotnetVersionResolver = new installer.DotnetVersionResolver( const dotnetVersionResolver = new installer.DotnetVersionResolver(
version version
); );
const versionObject = await dotnetVersionResolver.createDotNetVersion(); const versionObject = await dotnetVersionResolver.createDotnetVersion();
expect(versionObject.type.toLowerCase().includes('channel')).toBe(true); expect(versionObject.type.toLowerCase().includes('channel')).toBe(true);
} }
@ -239,7 +239,7 @@ describe('DotnetVersionResolver tests', () => {
const dotnetVersionResolver = new installer.DotnetVersionResolver( const dotnetVersionResolver = new installer.DotnetVersionResolver(
version version
); );
const versionObject = await dotnetVersionResolver.createDotNetVersion(); const versionObject = await dotnetVersionResolver.createDotnetVersion();
expect(versionObject.type.toLowerCase().includes('channel')).toBe(true); expect(versionObject.type.toLowerCase().includes('channel')).toBe(true);
expect(versionObject.qualityFlag).toBe(true); expect(versionObject.qualityFlag).toBe(true);
@ -252,7 +252,7 @@ describe('DotnetVersionResolver tests', () => {
const dotnetVersionResolver = new installer.DotnetVersionResolver( const dotnetVersionResolver = new installer.DotnetVersionResolver(
version version
); );
const versionObject = await dotnetVersionResolver.createDotNetVersion(); const versionObject = await dotnetVersionResolver.createDotnetVersion();
expect(versionObject.type.toLowerCase().includes('version')).toBe(true); expect(versionObject.type.toLowerCase().includes('version')).toBe(true);
expect(versionObject.qualityFlag).toBe(false); expect(versionObject.qualityFlag).toBe(false);
@ -265,7 +265,7 @@ describe('DotnetVersionResolver tests', () => {
const dotnetVersionResolver = new installer.DotnetVersionResolver( const dotnetVersionResolver = new installer.DotnetVersionResolver(
version version
); );
const versionObject = await dotnetVersionResolver.createDotNetVersion(); const versionObject = await dotnetVersionResolver.createDotnetVersion();
const windowsRegEx = new RegExp(/^-[VC]/); const windowsRegEx = new RegExp(/^-[VC]/);
const nonWindowsRegEx = new RegExp(/^--[vc]/); const nonWindowsRegEx = new RegExp(/^--[vc]/);

172
dist/index.js vendored
View File

@ -229,9 +229,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
var __importDefault = (this && this.__importDefault) || function (mod) { var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod }; return (mod && mod.__esModule) ? mod : { "default": mod };
}; };
var _a;
Object.defineProperty(exports, "__esModule", ({ value: true })); Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.DotnetCoreInstaller = exports.DotnetVersionResolver = void 0; exports.DotnetCoreInstaller = exports.DotnetInstallDir = exports.DotnetInstallScript = exports.DotnetVersionResolver = void 0;
// Load tempDirectory before it gets wiped by tool-cache // Load tempDirectory before it gets wiped by tool-cache
const core = __importStar(__nccwpck_require__(2186)); const core = __importStar(__nccwpck_require__(2186));
const exec = __importStar(__nccwpck_require__(1514)); const exec = __importStar(__nccwpck_require__(1514));
@ -279,7 +278,7 @@ class DotnetVersionResolver {
isNumericTag(versionTag) { isNumericTag(versionTag) {
return /^\d+$/.test(versionTag); return /^\d+$/.test(versionTag);
} }
createDotNetVersion() { createDotnetVersion() {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
yield this.resolveVersionInput(); yield this.resolveVersionInput();
if (!this.resolvedArgument.type) { if (!this.resolvedArgument.type) {
@ -314,11 +313,77 @@ class DotnetVersionResolver {
} }
exports.DotnetVersionResolver = DotnetVersionResolver; exports.DotnetVersionResolver = DotnetVersionResolver;
DotnetVersionResolver.DotNetCoreIndexUrl = 'https://dotnetcli.azureedge.net/dotnet/release-metadata/releases-index.json'; DotnetVersionResolver.DotNetCoreIndexUrl = 'https://dotnetcli.azureedge.net/dotnet/release-metadata/releases-index.json';
class DotnetCoreInstaller { class DotnetInstallScript {
constructor(version, quality) { constructor() {
this.version = version; this.scriptName = utils_1.IS_WINDOWS ? 'install-dotnet.ps1' : 'install-dotnet.sh';
this.quality = quality; this.scriptArguments = [];
this.scriptPath = '';
this.escapedScript = path_1.default
.join(__dirname, '..', 'externals', this.scriptName)
.replace(/'/g, "''");
this.scriptReady = utils_1.IS_WINDOWS
? this.setupScriptPowershell()
: this.setupScriptBash();
} }
setupScriptPowershell() {
return __awaiter(this, void 0, void 0, function* () {
this.scriptArguments = [
'-NoLogo',
'-Sta',
'-NoProfile',
'-NonInteractive',
'-ExecutionPolicy',
'Unrestricted',
'-Command'
];
this.scriptArguments.push('&', `'${this.escapedScript}'`);
if (process.env['https_proxy'] != null) {
this.scriptArguments.push(`-ProxyAddress ${process.env['https_proxy']}`);
}
// This is not currently an option
if (process.env['no_proxy'] != null) {
this.scriptArguments.push(`-ProxyBypassList ${process.env['no_proxy']}`);
}
this.scriptPath = (yield io.which('pwsh', false)) || (yield io.which('powershell', true));
});
}
setupScriptBash() {
return __awaiter(this, void 0, void 0, function* () {
(0, fs_1.chmodSync)(this.escapedScript, '777');
this.scriptArguments = [];
this.scriptPath = yield io.which(this.escapedScript, true);
});
}
useArguments(...args) {
this.scriptArguments.push(...args);
return this;
}
useVersion(dotnetVersion, quality) {
if (dotnetVersion.type) {
this.useArguments(dotnetVersion.type, dotnetVersion.value);
}
if (quality && !dotnetVersion.qualityFlag) {
core.warning(`'dotnet-quality' input can be used only with .NET SDK version in A.B, A.B.x, A and A.x formats where the major tag is higher than 5. You specified: ${dotnetVersion.value}. 'dotnet-quality' input is ignored.`);
return this;
}
if (quality) {
this.useArguments(utils_1.IS_WINDOWS ? '-Quality' : '--quality', quality);
}
return this;
}
execute() {
return __awaiter(this, void 0, void 0, function* () {
const getExecOutputOptions = {
ignoreReturnCode: true,
env: process.env
};
yield this.scriptReady;
return exec.getExecOutput(`"${this.scriptPath}"`, this.scriptArguments, getExecOutputOptions);
});
}
}
exports.DotnetInstallScript = DotnetInstallScript;
class DotnetInstallDir {
static convertInstallPathToAbsolute(installDir) { static convertInstallPathToAbsolute(installDir) {
let transformedPath; let transformedPath;
if (path_1.default.isAbsolute(installDir)) { if (path_1.default.isAbsolute(installDir)) {
@ -335,70 +400,33 @@ class DotnetCoreInstaller {
core.addPath(process.env['DOTNET_INSTALL_DIR']); core.addPath(process.env['DOTNET_INSTALL_DIR']);
core.exportVariable('DOTNET_ROOT', process.env['DOTNET_INSTALL_DIR']); core.exportVariable('DOTNET_ROOT', process.env['DOTNET_INSTALL_DIR']);
} }
setQuality(dotnetVersion, scriptArguments) { static initialize() {
const option = utils_1.IS_WINDOWS ? '-Quality' : '--quality'; process.env['DOTNET_INSTALL_DIR'] = DotnetInstallDir.path;
if (dotnetVersion.qualityFlag) {
scriptArguments.push(option, this.quality);
}
else {
core.warning(`'dotnet-quality' input can be used only with .NET SDK version in A.B, A.B.x, A and A.x formats where the major tag is higher than 5. You specified: ${this.version}. 'dotnet-quality' input is ignored.`);
} }
}
exports.DotnetInstallDir = DotnetInstallDir;
DotnetInstallDir.default = {
linux: '/usr/share/dotnet',
mac: path_1.default.join(process.env['HOME'] + '', '.dotnet'),
windows: path_1.default.join(process.env['PROGRAMFILES'] + '', 'dotnet')
};
DotnetInstallDir.path = process.env['DOTNET_INSTALL_DIR']
? DotnetInstallDir.convertInstallPathToAbsolute(process.env['DOTNET_INSTALL_DIR'])
: DotnetInstallDir.default[(0, utils_1.getPlatform)()];
class DotnetCoreInstaller {
constructor(version, quality) {
this.version = version;
this.quality = quality;
} }
;
installDotnet() { installDotnet() {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const windowsDefaultOptions = [
'-NoLogo',
'-Sta',
'-NoProfile',
'-NonInteractive',
'-ExecutionPolicy',
'Unrestricted',
'-Command'
];
const scriptName = utils_1.IS_WINDOWS ? 'install-dotnet.ps1' : 'install-dotnet.sh';
const escapedScript = path_1.default
.join(__dirname, '..', 'externals', scriptName)
.replace(/'/g, "''");
let scriptArguments;
let scriptPath = '';
const versionResolver = new DotnetVersionResolver(this.version); const versionResolver = new DotnetVersionResolver(this.version);
const dotnetVersion = yield versionResolver.createDotNetVersion(); const dotnetVersion = yield versionResolver.createDotnetVersion();
if (utils_1.IS_WINDOWS) { const installScript = new DotnetInstallScript()
scriptArguments = ['&', `'${escapedScript}'`]; .useArguments(utils_1.IS_WINDOWS ? '-SkipNonVersionedFiles' : '--skip-non-versioned-files')
if (dotnetVersion.type) { .useVersion(dotnetVersion, this.quality);
scriptArguments.push(dotnetVersion.type, dotnetVersion.value); const { exitCode, stderr } = yield installScript.execute();
}
if (this.quality) {
this.setQuality(dotnetVersion, scriptArguments);
}
if (process.env['https_proxy'] != null) {
scriptArguments.push(`-ProxyAddress ${process.env['https_proxy']}`);
}
// This is not currently an option
if (process.env['no_proxy'] != null) {
scriptArguments.push(`-ProxyBypassList ${process.env['no_proxy']}`);
}
scriptPath =
(yield io.which('pwsh', false)) || (yield io.which('powershell', true));
scriptArguments = windowsDefaultOptions.concat(scriptArguments);
}
else {
(0, fs_1.chmodSync)(escapedScript, '777');
scriptPath = yield io.which(escapedScript, true);
scriptArguments = [];
if (dotnetVersion.type) {
scriptArguments.push(dotnetVersion.type, dotnetVersion.value);
}
if (this.quality) {
this.setQuality(dotnetVersion, scriptArguments);
}
}
// process.env must be explicitly passed in for DOTNET_INSTALL_DIR to be used
const getExecOutputOptions = {
ignoreReturnCode: true,
env: process.env
};
const { exitCode, stderr } = yield exec.getExecOutput(`"${scriptPath}"`, scriptArguments, getExecOutputOptions);
if (exitCode) { if (exitCode) {
throw new Error(`Failed to install dotnet, exit code: ${exitCode}. ${stderr}`); throw new Error(`Failed to install dotnet, exit code: ${exitCode}. ${stderr}`);
} }
@ -417,17 +445,9 @@ class DotnetCoreInstaller {
} }
} }
exports.DotnetCoreInstaller = DotnetCoreInstaller; exports.DotnetCoreInstaller = DotnetCoreInstaller;
_a = DotnetCoreInstaller; DotnetCoreInstaller.addToPath = DotnetInstallDir.addToPath;
(() => { (() => {
const dotnetInstallDirDefault = { DotnetInstallDir.initialize;
linux: '/usr/share/dotnet',
mac: path_1.default.join(process.env['HOME'] + '', '.dotnet'),
windows: path_1.default.join(process.env['PROGRAMFILES'] + '', 'dotnet')
}[(0, utils_1.getPlatform)()];
const dotnetInstallDir = process.env['DOTNET_INSTALL_DIR']
? _a.convertInstallPathToAbsolute(process.env['DOTNET_INSTALL_DIR'])
: dotnetInstallDirDefault;
process.env['DOTNET_INSTALL_DIR'] = dotnetInstallDir;
})(); })();

View File

@ -61,7 +61,7 @@ export class DotnetVersionResolver {
return /^\d+$/.test(versionTag); return /^\d+$/.test(versionTag);
} }
public async createDotNetVersion(): Promise<{ public async createDotnetVersion(): Promise<{
type: string; type: string;
value: string; value: string;
qualityFlag: boolean; qualityFlag: boolean;
@ -110,28 +110,105 @@ export class DotnetVersionResolver {
'https://dotnetcli.azureedge.net/dotnet/release-metadata/releases-index.json'; 'https://dotnetcli.azureedge.net/dotnet/release-metadata/releases-index.json';
} }
export class DotnetCoreInstaller { export class DotnetInstallScript {
private version: string; private scriptName = IS_WINDOWS ? 'install-dotnet.ps1' : 'install-dotnet.sh';
private quality: QualityOptions; private escapedScript: string;
private scriptArguments: string[] = [];
private scriptPath = '';
private scriptReady: Promise<void>;
static { constructor() {
const dotnetInstallDirDefault = { this.escapedScript = path
.join(__dirname, '..', 'externals', this.scriptName)
.replace(/'/g, "''");
this.scriptReady = IS_WINDOWS
? this.setupScriptPowershell()
: this.setupScriptBash();
}
private async setupScriptPowershell() {
this.scriptArguments = [
'-NoLogo',
'-Sta',
'-NoProfile',
'-NonInteractive',
'-ExecutionPolicy',
'Unrestricted',
'-Command'
];
this.scriptArguments.push('&', `'${this.escapedScript}'`);
if (process.env['https_proxy'] != null) {
this.scriptArguments.push(`-ProxyAddress ${process.env['https_proxy']}`);
}
// This is not currently an option
if (process.env['no_proxy'] != null) {
this.scriptArguments.push(`-ProxyBypassList ${process.env['no_proxy']}`);
}
this.scriptPath = (await io.which('pwsh', false)) || (await io.which('powershell', true));
}
private async setupScriptBash() {
chmodSync(this.escapedScript, '777');
this.scriptArguments = [];
this.scriptPath = await io.which(this.escapedScript, true);
}
public useArguments(...args: string[]) {
this.scriptArguments.push(...args);
return this;
}
public useVersion(dotnetVersion: DotnetVersion, quality?: QualityOptions) {
if (dotnetVersion.type) {
this.useArguments(dotnetVersion.type, dotnetVersion.value);
}
if (quality && !dotnetVersion.qualityFlag) {
core.warning(
`'dotnet-quality' input can be used only with .NET SDK version in A.B, A.B.x, A and A.x formats where the major tag is higher than 5. You specified: ${dotnetVersion.value}. 'dotnet-quality' input is ignored.`
);
return this;
}
if (quality) {
this.useArguments(IS_WINDOWS ? '-Quality' : '--quality', quality);
}
return this;
}
public async execute() {
const getExecOutputOptions = {
ignoreReturnCode: true,
env: process.env as {string: string}
};
await this.scriptReady;
return exec.getExecOutput(
`"${this.scriptPath}"`,
this.scriptArguments,
getExecOutputOptions,
)
}
}
export abstract class DotnetInstallDir {
private static readonly default = {
linux: '/usr/share/dotnet', linux: '/usr/share/dotnet',
mac: path.join(process.env['HOME'] + '', '.dotnet'), mac: path.join(process.env['HOME'] + '', '.dotnet'),
windows: path.join(process.env['PROGRAMFILES'] + '', 'dotnet') windows: path.join(process.env['PROGRAMFILES'] + '', 'dotnet')
}[getPlatform()];
const dotnetInstallDir = process.env['DOTNET_INSTALL_DIR']
? this.convertInstallPathToAbsolute(process.env['DOTNET_INSTALL_DIR'])
: dotnetInstallDirDefault;
process.env['DOTNET_INSTALL_DIR'] = dotnetInstallDir;
} }
constructor(version: string, quality: QualityOptions) { public static readonly path = process.env['DOTNET_INSTALL_DIR']
this.version = version; ? DotnetInstallDir.convertInstallPathToAbsolute(process.env['DOTNET_INSTALL_DIR'])
this.quality = quality; : DotnetInstallDir.default[getPlatform()]
}
private static convertInstallPathToAbsolute(installDir: string): string { private static convertInstallPathToAbsolute(installDir: string): string {
let transformedPath; let transformedPath;
@ -145,90 +222,35 @@ export class DotnetCoreInstaller {
return path.normalize(transformedPath); return path.normalize(transformedPath);
} }
static addToPath() { public static addToPath() {
core.addPath(process.env['DOTNET_INSTALL_DIR']!); core.addPath(process.env['DOTNET_INSTALL_DIR']!);
core.exportVariable('DOTNET_ROOT', process.env['DOTNET_INSTALL_DIR']); core.exportVariable('DOTNET_ROOT', process.env['DOTNET_INSTALL_DIR']);
} }
private setQuality( public static initialize() {
dotnetVersion: DotnetVersion, process.env['DOTNET_INSTALL_DIR'] = DotnetInstallDir.path;
scriptArguments: string[]
): void {
const option = IS_WINDOWS ? '-Quality' : '--quality';
if (dotnetVersion.qualityFlag) {
scriptArguments.push(option, this.quality);
} else {
core.warning(
`'dotnet-quality' input can be used only with .NET SDK version in A.B, A.B.x, A and A.x formats where the major tag is higher than 5. You specified: ${this.version}. 'dotnet-quality' input is ignored.`
);
} }
}
export class DotnetCoreInstaller {
static addToPath = DotnetInstallDir.addToPath;
static {
DotnetInstallDir.initialize;
} }
constructor(private version: string, private quality: QualityOptions) {};
public async installDotnet(): Promise<string> { public async installDotnet(): Promise<string> {
const windowsDefaultOptions = [
'-NoLogo',
'-Sta',
'-NoProfile',
'-NonInteractive',
'-ExecutionPolicy',
'Unrestricted',
'-Command'
];
const scriptName = IS_WINDOWS ? 'install-dotnet.ps1' : 'install-dotnet.sh';
const escapedScript = path
.join(__dirname, '..', 'externals', scriptName)
.replace(/'/g, "''");
let scriptArguments: string[];
let scriptPath = '';
const versionResolver = new DotnetVersionResolver(this.version); const versionResolver = new DotnetVersionResolver(this.version);
const dotnetVersion = await versionResolver.createDotNetVersion(); const dotnetVersion = await versionResolver.createDotnetVersion();
if (IS_WINDOWS) { const installScript = new DotnetInstallScript()
scriptArguments = ['&', `'${escapedScript}'`]; .useArguments(IS_WINDOWS ? '-SkipNonVersionedFiles' : '--skip-non-versioned-files')
.useVersion(dotnetVersion, this.quality);
if (dotnetVersion.type) { const {exitCode, stderr} = await installScript.execute();
scriptArguments.push(dotnetVersion.type, dotnetVersion.value);
}
if (this.quality) {
this.setQuality(dotnetVersion, scriptArguments);
}
if (process.env['https_proxy'] != null) {
scriptArguments.push(`-ProxyAddress ${process.env['https_proxy']}`);
}
// This is not currently an option
if (process.env['no_proxy'] != null) {
scriptArguments.push(`-ProxyBypassList ${process.env['no_proxy']}`);
}
scriptPath =
(await io.which('pwsh', false)) || (await io.which('powershell', true));
scriptArguments = windowsDefaultOptions.concat(scriptArguments);
} else {
chmodSync(escapedScript, '777');
scriptPath = await io.which(escapedScript, true);
scriptArguments = [];
if (dotnetVersion.type) {
scriptArguments.push(dotnetVersion.type, dotnetVersion.value);
}
if (this.quality) {
this.setQuality(dotnetVersion, scriptArguments);
}
}
// process.env must be explicitly passed in for DOTNET_INSTALL_DIR to be used
const getExecOutputOptions = {
ignoreReturnCode: true,
env: process.env as {string: string}
};
const {exitCode, stderr} = await exec.getExecOutput(
`"${scriptPath}"`,
scriptArguments,
getExecOutputOptions
);
if (exitCode) { if (exitCode) {
throw new Error( throw new Error(
`Failed to install dotnet, exit code: ${exitCode}. ${stderr}` `Failed to install dotnet, exit code: ${exitCode}. ${stderr}`