mirror of
https://github.com/actions/setup-dotnet.git
synced 2026-03-21 22:22:17 +08:00
Add support for optional architecture input for cross-architecture .NET installs (#700)
* fix basic validation with npm command
* Revert "fix basic validation with npm command"
This reverts commit 27a0803a2a.
* add architecture support
* updated installdir logic
* update architecture resolution
* update normalizeArch
This commit is contained in:
35
.github/workflows/e2e-tests.yml
vendored
35
.github/workflows/e2e-tests.yml
vendored
@@ -623,3 +623,38 @@ jobs:
|
|||||||
- name: Verify dotnet
|
- name: Verify dotnet
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
run: __tests__/verify-dotnet.ps1 -Patterns "^9\.0"
|
run: __tests__/verify-dotnet.ps1 -Patterns "^9\.0"
|
||||||
|
|
||||||
|
test-setup-with-architecture-input:
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os: [macos-latest, ubuntu-latest, windows-latest]
|
||||||
|
arch: [x64, arm64]
|
||||||
|
exclude:
|
||||||
|
- os: windows-latest
|
||||||
|
arch: arm64
|
||||||
|
- os: ubuntu-latest
|
||||||
|
arch: arm64
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Clear toolcache
|
||||||
|
shell: pwsh
|
||||||
|
run: __tests__/clear-toolcache.ps1 ${{ runner.os }}
|
||||||
|
|
||||||
|
- name: Setup dotnet (${{ matrix.arch }})
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
dotnet-version: |
|
||||||
|
8.0.416
|
||||||
|
8.0.x
|
||||||
|
9.0.308
|
||||||
|
10.0.101
|
||||||
|
architecture: ${{ matrix.arch }}
|
||||||
|
|
||||||
|
- name: Verify dotnet
|
||||||
|
shell: pwsh
|
||||||
|
run: __tests__/verify-dotnet.ps1 -Patterns "^8.0.416$", "^9.0.308$", "^10.0.101$", "^8.0"
|
||||||
|
|||||||
17
README.md
17
README.md
@@ -59,6 +59,23 @@ The `dotnet-version` input supports following syntax:
|
|||||||
- **A.B.Cxx** (e.g. 8.0.4xx) - available since `.NET 5.0` release. Installs the latest version of the specific SDK release, including prerelease versions (preview, rc).
|
- **A.B.Cxx** (e.g. 8.0.4xx) - available since `.NET 5.0` release. Installs the latest version of the specific SDK release, including prerelease versions (preview, rc).
|
||||||
|
|
||||||
|
|
||||||
|
## Using the `architecture` input
|
||||||
|
Using the architecture input, it is possible to specify the required .NET SDK architecture. Possible values: `x64`, `x86`, `arm64`, `amd64`, `arm`, `s390x`, `ppc64le`, `riscv64`. If the input is not specified, the architecture defaults to the host OS architecture (not all of the architectures are available on all platforms).
|
||||||
|
|
||||||
|
**Example: Install multiple SDK versions for a specific architecture**
|
||||||
|
```yml
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- name: Setup dotnet (x86)
|
||||||
|
uses: actions/setup-dotnet@v5
|
||||||
|
with:
|
||||||
|
dotnet-version: |
|
||||||
|
8.0.x
|
||||||
|
9.0.x
|
||||||
|
architecture: x86
|
||||||
|
- run: dotnet build <my project>
|
||||||
|
```
|
||||||
|
|
||||||
## Using the `dotnet-quality` input
|
## Using the `dotnet-quality` input
|
||||||
This input sets up the action to install the latest build of the specified quality in the channel. The possible values of `dotnet-quality` are: **daily**, **signed**, **validated**, **preview**, **ga**.
|
This input sets up the action to install the latest build of the specified quality in the channel. The possible values of `dotnet-quality` are: **daily**, **signed**, **validated**, **preview**, **ga**.
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import each from 'jest-each';
|
|||||||
import semver from 'semver';
|
import semver from 'semver';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import fspromises from 'fs/promises';
|
import fspromises from 'fs/promises';
|
||||||
|
import os from 'os';
|
||||||
import * as exec from '@actions/exec';
|
import * as exec from '@actions/exec';
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import * as io from '@actions/io';
|
import * as io from '@actions/io';
|
||||||
@@ -327,6 +328,143 @@ describe('installer tests', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
it(`should supply 'architecture' argument to the installation script when architecture is provided`, async () => {
|
||||||
|
const inputVersion = '10.0.101';
|
||||||
|
const inputQuality = '' as QualityOptions;
|
||||||
|
const inputArchitecture = 'x64';
|
||||||
|
const stdout = `Fictitious dotnet version ${inputVersion} is installed`;
|
||||||
|
|
||||||
|
getExecOutputSpy.mockImplementation(() => {
|
||||||
|
return Promise.resolve({
|
||||||
|
exitCode: 0,
|
||||||
|
stdout: `${stdout}`,
|
||||||
|
stderr: ''
|
||||||
|
});
|
||||||
|
});
|
||||||
|
maxSatisfyingSpy.mockImplementation(() => inputVersion);
|
||||||
|
|
||||||
|
const dotnetInstaller = new installer.DotnetCoreInstaller(
|
||||||
|
inputVersion,
|
||||||
|
inputQuality,
|
||||||
|
inputArchitecture
|
||||||
|
);
|
||||||
|
|
||||||
|
await dotnetInstaller.installDotnet();
|
||||||
|
|
||||||
|
const callIndex = 1;
|
||||||
|
const scriptArguments = (
|
||||||
|
getExecOutputSpy.mock.calls[callIndex][1] as string[]
|
||||||
|
).join(' ');
|
||||||
|
const expectedArgument = IS_WINDOWS
|
||||||
|
? `-Architecture ${inputArchitecture}`
|
||||||
|
: `--architecture ${inputArchitecture}`;
|
||||||
|
|
||||||
|
expect(scriptArguments).toContain(expectedArgument);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should NOT supply 'architecture' argument when architecture is not provided`, async () => {
|
||||||
|
const inputVersion = '10.0.101';
|
||||||
|
const inputQuality = '' as QualityOptions;
|
||||||
|
const stdout = `Fictitious dotnet version ${inputVersion} is installed`;
|
||||||
|
|
||||||
|
getExecOutputSpy.mockImplementation(() => {
|
||||||
|
return Promise.resolve({
|
||||||
|
exitCode: 0,
|
||||||
|
stdout: `${stdout}`,
|
||||||
|
stderr: ''
|
||||||
|
});
|
||||||
|
});
|
||||||
|
maxSatisfyingSpy.mockImplementation(() => inputVersion);
|
||||||
|
|
||||||
|
const dotnetInstaller = new installer.DotnetCoreInstaller(
|
||||||
|
inputVersion,
|
||||||
|
inputQuality
|
||||||
|
);
|
||||||
|
|
||||||
|
await dotnetInstaller.installDotnet();
|
||||||
|
|
||||||
|
const callIndex = 1;
|
||||||
|
const scriptArguments = (
|
||||||
|
getExecOutputSpy.mock.calls[callIndex][1] as string[]
|
||||||
|
).join(' ');
|
||||||
|
|
||||||
|
expect(scriptArguments).not.toContain('--architecture');
|
||||||
|
expect(scriptArguments).not.toContain('-Architecture');
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should supply 'install-dir' with arch subdirectory for cross-arch install`, async () => {
|
||||||
|
const inputVersion = '10.0.101';
|
||||||
|
const inputQuality = '' as QualityOptions;
|
||||||
|
const inputArchitecture = 'x64';
|
||||||
|
const stdout = `Fictitious dotnet version ${inputVersion} is installed`;
|
||||||
|
|
||||||
|
getExecOutputSpy.mockImplementation(() => {
|
||||||
|
return Promise.resolve({
|
||||||
|
exitCode: 0,
|
||||||
|
stdout: `${stdout}`,
|
||||||
|
stderr: ''
|
||||||
|
});
|
||||||
|
});
|
||||||
|
maxSatisfyingSpy.mockImplementation(() => inputVersion);
|
||||||
|
|
||||||
|
// Mock os.arch() to return a different arch to simulate cross-arch
|
||||||
|
const archSpy = jest.spyOn(os, 'arch').mockReturnValue('arm64');
|
||||||
|
|
||||||
|
const dotnetInstaller = new installer.DotnetCoreInstaller(
|
||||||
|
inputVersion,
|
||||||
|
inputQuality,
|
||||||
|
inputArchitecture
|
||||||
|
);
|
||||||
|
|
||||||
|
await dotnetInstaller.installDotnet();
|
||||||
|
|
||||||
|
const callIndex = 1;
|
||||||
|
const scriptArguments = (
|
||||||
|
getExecOutputSpy.mock.calls[callIndex][1] as string[]
|
||||||
|
).join(' ');
|
||||||
|
|
||||||
|
const expectedInstallDirFlag = IS_WINDOWS
|
||||||
|
? '-InstallDir'
|
||||||
|
: '--install-dir';
|
||||||
|
|
||||||
|
expect(scriptArguments).toContain(expectedInstallDirFlag);
|
||||||
|
expect(scriptArguments).toContain(inputArchitecture);
|
||||||
|
|
||||||
|
archSpy.mockRestore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should NOT supply 'install-dir' when architecture matches runner's native arch`, async () => {
|
||||||
|
const inputVersion = '10.0.101';
|
||||||
|
const inputQuality = '' as QualityOptions;
|
||||||
|
const nativeArch = os.arch().toLowerCase();
|
||||||
|
const stdout = `Fictitious dotnet version ${inputVersion} is installed`;
|
||||||
|
|
||||||
|
getExecOutputSpy.mockImplementation(() => {
|
||||||
|
return Promise.resolve({
|
||||||
|
exitCode: 0,
|
||||||
|
stdout: `${stdout}`,
|
||||||
|
stderr: ''
|
||||||
|
});
|
||||||
|
});
|
||||||
|
maxSatisfyingSpy.mockImplementation(() => inputVersion);
|
||||||
|
|
||||||
|
const dotnetInstaller = new installer.DotnetCoreInstaller(
|
||||||
|
inputVersion,
|
||||||
|
inputQuality,
|
||||||
|
nativeArch
|
||||||
|
);
|
||||||
|
|
||||||
|
await dotnetInstaller.installDotnet();
|
||||||
|
|
||||||
|
const callIndex = 1;
|
||||||
|
const scriptArguments = (
|
||||||
|
getExecOutputSpy.mock.calls[callIndex][1] as string[]
|
||||||
|
).join(' ');
|
||||||
|
|
||||||
|
expect(scriptArguments).not.toContain('--install-dir');
|
||||||
|
expect(scriptArguments).not.toContain('-InstallDir');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('addToPath() tests', () => {
|
describe('addToPath() tests', () => {
|
||||||
@@ -346,6 +484,32 @@ describe('installer tests', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('normalizeArch() tests', () => {
|
||||||
|
it(`should normalize 'amd64' to 'x64'`, () => {
|
||||||
|
expect(installer.normalizeArch('amd64')).toBe('x64');
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should normalize 'AMD64' to 'x64' (case-insensitive)`, () => {
|
||||||
|
expect(installer.normalizeArch('AMD64')).toBe('x64');
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should pass through 'x64' unchanged`, () => {
|
||||||
|
expect(installer.normalizeArch('x64')).toBe('x64');
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should pass through 'arm64' unchanged`, () => {
|
||||||
|
expect(installer.normalizeArch('arm64')).toBe('arm64');
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should lowercase 'ARM64'`, () => {
|
||||||
|
expect(installer.normalizeArch('ARM64')).toBe('arm64');
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should pass through 'x86' unchanged`, () => {
|
||||||
|
expect(installer.normalizeArch('x86')).toBe('x86');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('DotnetVersionResolver tests', () => {
|
describe('DotnetVersionResolver tests', () => {
|
||||||
describe('createDotnetVersion() tests', () => {
|
describe('createDotnetVersion() tests', () => {
|
||||||
each([
|
each([
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import * as core from '@actions/core';
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import semver from 'semver';
|
import semver from 'semver';
|
||||||
import * as auth from '../src/authutil';
|
import * as auth from '../src/authutil';
|
||||||
|
import os from 'os';
|
||||||
import * as setup from '../src/setup-dotnet';
|
import * as setup from '../src/setup-dotnet';
|
||||||
import {DotnetCoreInstaller, DotnetInstallDir} from '../src/installer';
|
import {DotnetCoreInstaller, DotnetInstallDir} from '../src/installer';
|
||||||
import * as cacheUtils from '../src/cache-utils';
|
import * as cacheUtils from '../src/cache-utils';
|
||||||
@@ -221,5 +221,40 @@ describe('setup-dotnet tests', () => {
|
|||||||
await setup.run();
|
await setup.run();
|
||||||
expect(restoreCacheSpy).not.toHaveBeenCalled();
|
expect(restoreCacheSpy).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should pass valid architecture input to DotnetCoreInstaller', async () => {
|
||||||
|
inputs['dotnet-version'] = ['10.0.101'];
|
||||||
|
inputs['dotnet-quality'] = '';
|
||||||
|
inputs['architecture'] = os.arch().toLowerCase();
|
||||||
|
|
||||||
|
installDotnetSpy.mockImplementation(() => Promise.resolve(''));
|
||||||
|
|
||||||
|
await setup.run();
|
||||||
|
expect(installDotnetSpy).toHaveBeenCalledTimes(1);
|
||||||
|
expect(DotnetInstallDir.addToPath).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should work with empty architecture input for auto-detection', async () => {
|
||||||
|
inputs['dotnet-version'] = ['10.0.101'];
|
||||||
|
inputs['dotnet-quality'] = '';
|
||||||
|
inputs['architecture'] = '';
|
||||||
|
|
||||||
|
installDotnetSpy.mockImplementation(() => Promise.resolve(''));
|
||||||
|
|
||||||
|
await setup.run();
|
||||||
|
expect(installDotnetSpy).toHaveBeenCalledTimes(1);
|
||||||
|
expect(DotnetInstallDir.addToPath).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail the action if unsupported architecture is provided', async () => {
|
||||||
|
inputs['dotnet-version'] = ['10.0.101'];
|
||||||
|
inputs['dotnet-quality'] = '';
|
||||||
|
inputs['architecture'] = 'x688';
|
||||||
|
|
||||||
|
const expectedErrorMessage = `Value 'x688' is not supported for the 'architecture' option. Supported values are: x64, x86, arm64, amd64, arm, s390x, ppc64le, riscv64.`;
|
||||||
|
|
||||||
|
await setup.run();
|
||||||
|
expect(setFailedSpy).toHaveBeenCalledWith(expectedErrorMessage);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -27,6 +27,9 @@ inputs:
|
|||||||
workloads:
|
workloads:
|
||||||
description: 'Optional SDK workloads to install for additional platform support. Examples: wasm-tools, maui, aspire.'
|
description: 'Optional SDK workloads to install for additional platform support. Examples: wasm-tools, maui, aspire.'
|
||||||
required: false
|
required: false
|
||||||
|
architecture:
|
||||||
|
description: 'Optional architecture for the .NET install. Supported values: x64, x86, arm64, amd64, arm, s390x, ppc64le, riscv64. If not set, the installer auto-detects the current system architecture.'
|
||||||
|
required: false
|
||||||
outputs:
|
outputs:
|
||||||
cache-hit:
|
cache-hit:
|
||||||
description: 'A boolean value to indicate if a cache was hit.'
|
description: 'A boolean value to indicate if a cache was hit.'
|
||||||
|
|||||||
65
dist/setup/index.js
vendored
65
dist/setup/index.js
vendored
@@ -54714,6 +54714,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.DotnetCoreInstaller = exports.DotnetInstallDir = exports.DotnetInstallScript = exports.DotnetVersionResolver = void 0;
|
exports.DotnetCoreInstaller = exports.DotnetInstallDir = exports.DotnetInstallScript = exports.DotnetVersionResolver = void 0;
|
||||||
|
exports.normalizeArch = normalizeArch;
|
||||||
// Load tempDirectory before it gets wiped by tool-cache
|
// Load tempDirectory before it gets wiped by tool-cache
|
||||||
const core = __importStar(__nccwpck_require__(42186));
|
const core = __importStar(__nccwpck_require__(42186));
|
||||||
const exec = __importStar(__nccwpck_require__(71514));
|
const exec = __importStar(__nccwpck_require__(71514));
|
||||||
@@ -54859,6 +54860,13 @@ class DotnetInstallScript {
|
|||||||
this.scriptArguments.push(...args);
|
this.scriptArguments.push(...args);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
// When architecture is empty/undefined, the installer auto-detects the current runner architecture.
|
||||||
|
useArchitecture(architecture) {
|
||||||
|
if (!architecture)
|
||||||
|
return this;
|
||||||
|
this.useArguments(utils_1.IS_WINDOWS ? '-Architecture' : '--architecture', architecture);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
useVersion(dotnetVersion, quality) {
|
useVersion(dotnetVersion, quality) {
|
||||||
if (dotnetVersion.type) {
|
if (dotnetVersion.type) {
|
||||||
this.useArguments(dotnetVersion.type, dotnetVersion.value);
|
this.useArguments(dotnetVersion.type, dotnetVersion.value);
|
||||||
@@ -54907,30 +54915,53 @@ class DotnetInstallDir {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.DotnetInstallDir = DotnetInstallDir;
|
exports.DotnetInstallDir = DotnetInstallDir;
|
||||||
|
function normalizeArch(arch) {
|
||||||
|
switch (arch.toLowerCase()) {
|
||||||
|
case 'amd64':
|
||||||
|
return 'x64';
|
||||||
|
case 'ia32':
|
||||||
|
return 'x86';
|
||||||
|
default:
|
||||||
|
return arch.toLowerCase();
|
||||||
|
}
|
||||||
|
}
|
||||||
class DotnetCoreInstaller {
|
class DotnetCoreInstaller {
|
||||||
version;
|
version;
|
||||||
quality;
|
quality;
|
||||||
|
architecture;
|
||||||
static {
|
static {
|
||||||
DotnetInstallDir.setEnvironmentVariable();
|
DotnetInstallDir.setEnvironmentVariable();
|
||||||
}
|
}
|
||||||
constructor(version, quality) {
|
constructor(version, quality, architecture) {
|
||||||
this.version = version;
|
this.version = version;
|
||||||
this.quality = quality;
|
this.quality = quality;
|
||||||
|
this.architecture = architecture;
|
||||||
}
|
}
|
||||||
async installDotnet() {
|
async installDotnet() {
|
||||||
const versionResolver = new DotnetVersionResolver(this.version);
|
const versionResolver = new DotnetVersionResolver(this.version);
|
||||||
const dotnetVersion = await versionResolver.createDotnetVersion();
|
const dotnetVersion = await versionResolver.createDotnetVersion();
|
||||||
|
const architectureArguments = this.architecture &&
|
||||||
|
normalizeArch(this.architecture) !== normalizeArch(os_1.default.arch())
|
||||||
|
? [
|
||||||
|
utils_1.IS_WINDOWS ? '-InstallDir' : '--install-dir',
|
||||||
|
utils_1.IS_WINDOWS
|
||||||
|
? `"${path_1.default.join(DotnetInstallDir.dirPath, this.architecture)}"`
|
||||||
|
: path_1.default.join(DotnetInstallDir.dirPath, this.architecture)
|
||||||
|
]
|
||||||
|
: [];
|
||||||
/**
|
/**
|
||||||
* Install dotnet runitme first in order to get
|
* Install dotnet runtime first in order to get
|
||||||
* the latest stable version of dotnet CLI
|
* the latest stable version of dotnet CLI
|
||||||
*/
|
*/
|
||||||
const runtimeInstallOutput = await new DotnetInstallScript()
|
const runtimeInstallOutput = await new DotnetInstallScript()
|
||||||
|
.useArchitecture(this.architecture)
|
||||||
// If dotnet CLI is already installed - avoid overwriting it
|
// If dotnet CLI is already installed - avoid overwriting it
|
||||||
.useArguments(utils_1.IS_WINDOWS ? '-SkipNonVersionedFiles' : '--skip-non-versioned-files')
|
.useArguments(utils_1.IS_WINDOWS ? '-SkipNonVersionedFiles' : '--skip-non-versioned-files')
|
||||||
// Install only runtime + CLI
|
// Install only runtime + CLI
|
||||||
.useArguments(utils_1.IS_WINDOWS ? '-Runtime' : '--runtime', 'dotnet')
|
.useArguments(utils_1.IS_WINDOWS ? '-Runtime' : '--runtime', 'dotnet')
|
||||||
// Use latest stable version
|
// Use latest stable version
|
||||||
.useArguments(utils_1.IS_WINDOWS ? '-Channel' : '--channel', 'LTS')
|
.useArguments(utils_1.IS_WINDOWS ? '-Channel' : '--channel', 'LTS')
|
||||||
|
.useArguments(...architectureArguments)
|
||||||
.execute();
|
.execute();
|
||||||
if (runtimeInstallOutput.exitCode) {
|
if (runtimeInstallOutput.exitCode) {
|
||||||
/**
|
/**
|
||||||
@@ -54944,10 +54975,12 @@ class DotnetCoreInstaller {
|
|||||||
* dotnet CLI
|
* dotnet CLI
|
||||||
*/
|
*/
|
||||||
const dotnetInstallOutput = await new DotnetInstallScript()
|
const dotnetInstallOutput = await new DotnetInstallScript()
|
||||||
|
.useArchitecture(this.architecture)
|
||||||
// Don't overwrite CLI because it should be already installed
|
// Don't overwrite CLI because it should be already installed
|
||||||
.useArguments(utils_1.IS_WINDOWS ? '-SkipNonVersionedFiles' : '--skip-non-versioned-files')
|
.useArguments(utils_1.IS_WINDOWS ? '-SkipNonVersionedFiles' : '--skip-non-versioned-files')
|
||||||
// Use version provided by user
|
// Use version provided by user
|
||||||
.useVersion(dotnetVersion, this.quality)
|
.useVersion(dotnetVersion, this.quality)
|
||||||
|
.useArguments(...architectureArguments)
|
||||||
.execute();
|
.execute();
|
||||||
if (dotnetInstallOutput.exitCode) {
|
if (dotnetInstallOutput.exitCode) {
|
||||||
throw new Error(`Failed to install dotnet, exit code: ${dotnetInstallOutput.exitCode}. ${dotnetInstallOutput.stderr}`);
|
throw new Error(`Failed to install dotnet, exit code: ${dotnetInstallOutput.exitCode}. ${dotnetInstallOutput.stderr}`);
|
||||||
@@ -55018,6 +55051,7 @@ const installer_1 = __nccwpck_require__(12574);
|
|||||||
const fs = __importStar(__nccwpck_require__(57147));
|
const fs = __importStar(__nccwpck_require__(57147));
|
||||||
const path_1 = __importDefault(__nccwpck_require__(71017));
|
const path_1 = __importDefault(__nccwpck_require__(71017));
|
||||||
const semver_1 = __importDefault(__nccwpck_require__(11383));
|
const semver_1 = __importDefault(__nccwpck_require__(11383));
|
||||||
|
const os_1 = __importDefault(__nccwpck_require__(22037));
|
||||||
const auth = __importStar(__nccwpck_require__(17573));
|
const auth = __importStar(__nccwpck_require__(17573));
|
||||||
const cache_utils_1 = __nccwpck_require__(41678);
|
const cache_utils_1 = __nccwpck_require__(41678);
|
||||||
const cache_restore_1 = __nccwpck_require__(19517);
|
const cache_restore_1 = __nccwpck_require__(19517);
|
||||||
@@ -55030,6 +55064,16 @@ const qualityOptions = [
|
|||||||
'preview',
|
'preview',
|
||||||
'ga'
|
'ga'
|
||||||
];
|
];
|
||||||
|
const supportedArchitectures = [
|
||||||
|
'x64',
|
||||||
|
'x86',
|
||||||
|
'arm64',
|
||||||
|
'amd64',
|
||||||
|
'arm',
|
||||||
|
's390x',
|
||||||
|
'ppc64le',
|
||||||
|
'riscv64'
|
||||||
|
];
|
||||||
async function run() {
|
async function run() {
|
||||||
try {
|
try {
|
||||||
//
|
//
|
||||||
@@ -55043,6 +55087,7 @@ async function run() {
|
|||||||
//
|
//
|
||||||
const versions = core.getMultilineInput('dotnet-version');
|
const versions = core.getMultilineInput('dotnet-version');
|
||||||
const installedDotnetVersions = [];
|
const installedDotnetVersions = [];
|
||||||
|
const architecture = getArchitectureInput();
|
||||||
const globalJsonFileInput = core.getInput('global-json-file');
|
const globalJsonFileInput = core.getInput('global-json-file');
|
||||||
if (globalJsonFileInput) {
|
if (globalJsonFileInput) {
|
||||||
const globalJsonPath = path_1.default.resolve(process.cwd(), globalJsonFileInput);
|
const globalJsonPath = path_1.default.resolve(process.cwd(), globalJsonFileInput);
|
||||||
@@ -55070,10 +55115,14 @@ async function run() {
|
|||||||
let dotnetInstaller;
|
let dotnetInstaller;
|
||||||
const uniqueVersions = new Set(versions);
|
const uniqueVersions = new Set(versions);
|
||||||
for (const version of uniqueVersions) {
|
for (const version of uniqueVersions) {
|
||||||
dotnetInstaller = new installer_1.DotnetCoreInstaller(version, quality);
|
dotnetInstaller = new installer_1.DotnetCoreInstaller(version, quality, architecture);
|
||||||
const installedVersion = await dotnetInstaller.installDotnet();
|
const installedVersion = await dotnetInstaller.installDotnet();
|
||||||
installedDotnetVersions.push(installedVersion);
|
installedDotnetVersions.push(installedVersion);
|
||||||
}
|
}
|
||||||
|
if (architecture &&
|
||||||
|
(0, installer_1.normalizeArch)(architecture) !== (0, installer_1.normalizeArch)(os_1.default.arch())) {
|
||||||
|
process.env['DOTNET_INSTALL_DIR'] = path_1.default.join(installer_1.DotnetInstallDir.dirPath, architecture);
|
||||||
|
}
|
||||||
installer_1.DotnetInstallDir.addToPath();
|
installer_1.DotnetInstallDir.addToPath();
|
||||||
const workloadsInput = core.getInput('workloads');
|
const workloadsInput = core.getInput('workloads');
|
||||||
if (workloadsInput) {
|
if (workloadsInput) {
|
||||||
@@ -55111,6 +55160,16 @@ async function run() {
|
|||||||
core.setFailed(error.message);
|
core.setFailed(error.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function getArchitectureInput() {
|
||||||
|
const raw = (core.getInput('architecture') || '').trim();
|
||||||
|
if (!raw)
|
||||||
|
return '';
|
||||||
|
const normalized = raw.toLowerCase();
|
||||||
|
if (supportedArchitectures.includes(normalized)) {
|
||||||
|
return (0, installer_1.normalizeArch)(normalized);
|
||||||
|
}
|
||||||
|
throw new Error(`Value '${raw}' is not supported for the 'architecture' option. Supported values are: ${supportedArchitectures.join(', ')}.`);
|
||||||
|
}
|
||||||
function getVersionFromGlobalJson(globalJsonPath) {
|
function getVersionFromGlobalJson(globalJsonPath) {
|
||||||
let version = '';
|
let version = '';
|
||||||
const globalJson = json5_1.default.parse(
|
const globalJson = json5_1.default.parse(
|
||||||
|
|||||||
@@ -184,6 +184,16 @@ export class DotnetInstallScript {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When architecture is empty/undefined, the installer auto-detects the current runner architecture.
|
||||||
|
public useArchitecture(architecture?: string) {
|
||||||
|
if (!architecture) return this;
|
||||||
|
this.useArguments(
|
||||||
|
IS_WINDOWS ? '-Architecture' : '--architecture',
|
||||||
|
architecture
|
||||||
|
);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public useVersion(dotnetVersion: DotnetVersion, quality?: QualityOptions) {
|
public useVersion(dotnetVersion: DotnetVersion, quality?: QualityOptions) {
|
||||||
if (dotnetVersion.type) {
|
if (dotnetVersion.type) {
|
||||||
this.useArguments(dotnetVersion.type, dotnetVersion.value);
|
this.useArguments(dotnetVersion.type, dotnetVersion.value);
|
||||||
@@ -250,6 +260,17 @@ export abstract class DotnetInstallDir {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function normalizeArch(arch: string): string {
|
||||||
|
switch (arch.toLowerCase()) {
|
||||||
|
case 'amd64':
|
||||||
|
return 'x64';
|
||||||
|
case 'ia32':
|
||||||
|
return 'x86';
|
||||||
|
default:
|
||||||
|
return arch.toLowerCase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class DotnetCoreInstaller {
|
export class DotnetCoreInstaller {
|
||||||
static {
|
static {
|
||||||
DotnetInstallDir.setEnvironmentVariable();
|
DotnetInstallDir.setEnvironmentVariable();
|
||||||
@@ -257,18 +278,30 @@ export class DotnetCoreInstaller {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private version: string,
|
private version: string,
|
||||||
private quality: QualityOptions
|
private quality: QualityOptions,
|
||||||
|
private architecture?: string
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public async installDotnet(): Promise<string | null> {
|
public async installDotnet(): Promise<string | null> {
|
||||||
const versionResolver = new DotnetVersionResolver(this.version);
|
const versionResolver = new DotnetVersionResolver(this.version);
|
||||||
const dotnetVersion = await versionResolver.createDotnetVersion();
|
const dotnetVersion = await versionResolver.createDotnetVersion();
|
||||||
|
|
||||||
|
const architectureArguments =
|
||||||
|
this.architecture &&
|
||||||
|
normalizeArch(this.architecture) !== normalizeArch(os.arch())
|
||||||
|
? [
|
||||||
|
IS_WINDOWS ? '-InstallDir' : '--install-dir',
|
||||||
|
IS_WINDOWS
|
||||||
|
? `"${path.join(DotnetInstallDir.dirPath, this.architecture)}"`
|
||||||
|
: path.join(DotnetInstallDir.dirPath, this.architecture)
|
||||||
|
]
|
||||||
|
: [];
|
||||||
/**
|
/**
|
||||||
* Install dotnet runitme first in order to get
|
* Install dotnet runtime first in order to get
|
||||||
* the latest stable version of dotnet CLI
|
* the latest stable version of dotnet CLI
|
||||||
*/
|
*/
|
||||||
const runtimeInstallOutput = await new DotnetInstallScript()
|
const runtimeInstallOutput = await new DotnetInstallScript()
|
||||||
|
.useArchitecture(this.architecture)
|
||||||
// If dotnet CLI is already installed - avoid overwriting it
|
// If dotnet CLI is already installed - avoid overwriting it
|
||||||
.useArguments(
|
.useArguments(
|
||||||
IS_WINDOWS ? '-SkipNonVersionedFiles' : '--skip-non-versioned-files'
|
IS_WINDOWS ? '-SkipNonVersionedFiles' : '--skip-non-versioned-files'
|
||||||
@@ -277,6 +310,7 @@ export class DotnetCoreInstaller {
|
|||||||
.useArguments(IS_WINDOWS ? '-Runtime' : '--runtime', 'dotnet')
|
.useArguments(IS_WINDOWS ? '-Runtime' : '--runtime', 'dotnet')
|
||||||
// Use latest stable version
|
// Use latest stable version
|
||||||
.useArguments(IS_WINDOWS ? '-Channel' : '--channel', 'LTS')
|
.useArguments(IS_WINDOWS ? '-Channel' : '--channel', 'LTS')
|
||||||
|
.useArguments(...architectureArguments)
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
if (runtimeInstallOutput.exitCode) {
|
if (runtimeInstallOutput.exitCode) {
|
||||||
@@ -294,12 +328,14 @@ export class DotnetCoreInstaller {
|
|||||||
* dotnet CLI
|
* dotnet CLI
|
||||||
*/
|
*/
|
||||||
const dotnetInstallOutput = await new DotnetInstallScript()
|
const dotnetInstallOutput = await new DotnetInstallScript()
|
||||||
|
.useArchitecture(this.architecture)
|
||||||
// Don't overwrite CLI because it should be already installed
|
// Don't overwrite CLI because it should be already installed
|
||||||
.useArguments(
|
.useArguments(
|
||||||
IS_WINDOWS ? '-SkipNonVersionedFiles' : '--skip-non-versioned-files'
|
IS_WINDOWS ? '-SkipNonVersionedFiles' : '--skip-non-versioned-files'
|
||||||
)
|
)
|
||||||
// Use version provided by user
|
// Use version provided by user
|
||||||
.useVersion(dotnetVersion, this.quality)
|
.useVersion(dotnetVersion, this.quality)
|
||||||
|
.useArguments(...architectureArguments)
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
if (dotnetInstallOutput.exitCode) {
|
if (dotnetInstallOutput.exitCode) {
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import * as exec from '@actions/exec';
|
import * as exec from '@actions/exec';
|
||||||
import {DotnetCoreInstaller, DotnetInstallDir} from './installer';
|
import {
|
||||||
|
DotnetCoreInstaller,
|
||||||
|
DotnetInstallDir,
|
||||||
|
normalizeArch
|
||||||
|
} from './installer';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import semver from 'semver';
|
import semver from 'semver';
|
||||||
|
import os from 'os';
|
||||||
import * as auth from './authutil';
|
import * as auth from './authutil';
|
||||||
import {isCacheFeatureAvailable} from './cache-utils';
|
import {isCacheFeatureAvailable} from './cache-utils';
|
||||||
import {restoreCache} from './cache-restore';
|
import {restoreCache} from './cache-restore';
|
||||||
@@ -17,6 +22,17 @@ const qualityOptions = [
|
|||||||
'preview',
|
'preview',
|
||||||
'ga'
|
'ga'
|
||||||
] as const;
|
] as const;
|
||||||
|
const supportedArchitectures = [
|
||||||
|
'x64',
|
||||||
|
'x86',
|
||||||
|
'arm64',
|
||||||
|
'amd64',
|
||||||
|
'arm',
|
||||||
|
's390x',
|
||||||
|
'ppc64le',
|
||||||
|
'riscv64'
|
||||||
|
] as const;
|
||||||
|
type SupportedArchitecture = (typeof supportedArchitectures)[number];
|
||||||
|
|
||||||
export type QualityOptions = (typeof qualityOptions)[number];
|
export type QualityOptions = (typeof qualityOptions)[number];
|
||||||
|
|
||||||
@@ -33,6 +49,7 @@ export async function run() {
|
|||||||
//
|
//
|
||||||
const versions = core.getMultilineInput('dotnet-version');
|
const versions = core.getMultilineInput('dotnet-version');
|
||||||
const installedDotnetVersions: (string | null)[] = [];
|
const installedDotnetVersions: (string | null)[] = [];
|
||||||
|
const architecture = getArchitectureInput();
|
||||||
|
|
||||||
const globalJsonFileInput = core.getInput('global-json-file');
|
const globalJsonFileInput = core.getInput('global-json-file');
|
||||||
if (globalJsonFileInput) {
|
if (globalJsonFileInput) {
|
||||||
@@ -70,10 +87,23 @@ export async function run() {
|
|||||||
let dotnetInstaller: DotnetCoreInstaller;
|
let dotnetInstaller: DotnetCoreInstaller;
|
||||||
const uniqueVersions = new Set<string>(versions);
|
const uniqueVersions = new Set<string>(versions);
|
||||||
for (const version of uniqueVersions) {
|
for (const version of uniqueVersions) {
|
||||||
dotnetInstaller = new DotnetCoreInstaller(version, quality);
|
dotnetInstaller = new DotnetCoreInstaller(
|
||||||
|
version,
|
||||||
|
quality,
|
||||||
|
architecture
|
||||||
|
);
|
||||||
const installedVersion = await dotnetInstaller.installDotnet();
|
const installedVersion = await dotnetInstaller.installDotnet();
|
||||||
installedDotnetVersions.push(installedVersion);
|
installedDotnetVersions.push(installedVersion);
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
architecture &&
|
||||||
|
normalizeArch(architecture) !== normalizeArch(os.arch())
|
||||||
|
) {
|
||||||
|
process.env['DOTNET_INSTALL_DIR'] = path.join(
|
||||||
|
DotnetInstallDir.dirPath,
|
||||||
|
architecture
|
||||||
|
);
|
||||||
|
}
|
||||||
DotnetInstallDir.addToPath();
|
DotnetInstallDir.addToPath();
|
||||||
|
|
||||||
const workloadsInput = core.getInput('workloads');
|
const workloadsInput = core.getInput('workloads');
|
||||||
@@ -119,6 +149,20 @@ export async function run() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getArchitectureInput(): SupportedArchitecture | '' {
|
||||||
|
const raw = (core.getInput('architecture') || '').trim();
|
||||||
|
if (!raw) return '';
|
||||||
|
const normalized = raw.toLowerCase();
|
||||||
|
if ((supportedArchitectures as readonly string[]).includes(normalized)) {
|
||||||
|
return normalizeArch(normalized) as SupportedArchitecture;
|
||||||
|
}
|
||||||
|
throw new Error(
|
||||||
|
`Value '${raw}' is not supported for the 'architecture' option. Supported values are: ${supportedArchitectures.join(
|
||||||
|
', '
|
||||||
|
)}.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function getVersionFromGlobalJson(globalJsonPath: string): string {
|
function getVersionFromGlobalJson(globalJsonPath: string): string {
|
||||||
let version = '';
|
let version = '';
|
||||||
const globalJson = JSON5.parse(
|
const globalJson = JSON5.parse(
|
||||||
|
|||||||
Reference in New Issue
Block a user