Added option that can be used to specify the architecture.

This commit is contained in:
Dirk Lemstra 2023-11-19 15:15:07 +01:00
parent 2216f56ae1
commit 66ae3ded49
No known key found for this signature in database
GPG Key ID: 40B84DE7D6271D30
8 changed files with 395 additions and 242 deletions

View File

@ -30,6 +30,17 @@ steps:
```
> **Warning**: Unless a concrete version is specified in the [`global.json`](https://learn.microsoft.com/en-us/dotnet/core/tools/global-json) file, **_the latest .NET version installed on the runner (including preinstalled versions) will be used [by default](https://learn.microsoft.com/en-us/dotnet/core/versions/selection#the-sdk-uses-the-latest-installed-version)_**. Please refer to the [documentation](https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-software) for the currently preinstalled .NET SDK versions.
**Specific architecture:**
```yml
steps:
- uses: actions/checkout@v3
- uses: actions/setup-dotnet@v2
with:
dotnet-version: '8.0.x'
architecture: 'x86'
- run: dotnet build <my project>
```
**Multiple version installation**:
```yml
steps:
@ -51,7 +62,6 @@ The `dotnet-version` input supports following syntax:
- **A** or **A.x** (e.g. 3, 3.x) - installs the latest minor version of the specified major tag, including prerelease versions (preview, rc)
- **A.B.Cxx** (e.g. 6.0.4xx) - available since `.NET 5.0` release. Installs the latest version of the specific SDK release, including prerelease versions (preview, rc).
## 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**.

View File

@ -8,7 +8,7 @@ import * as io from '@actions/io';
import * as installer from '../src/installer';
import {IS_WINDOWS} from '../src/utils';
import {QualityOptions} from '../src/setup-dotnet';
import {QualityOptions, ArchitectureOptions} from '../src/setup-dotnet';
describe('installer tests', () => {
const env = process.env;
@ -119,6 +119,86 @@ describe('installer tests', () => {
expect(scriptArguments).toContain(expectedArgument);
});
it(`should not supply 'architecture' argument to the installation script when architecture is an empty string`, async () => {
const inputVersion = '6.0.300';
const inputQuality = '' as QualityOptions;
const inputArchitecture = '' as ArchitectureOptions;
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();
/**
* First time script would be called to
* install runtime, here we checking only the
* second one that installs actual SDK. i.e. 1
*/
const callIndex = 1;
const scriptArguments = (
getExecOutputSpy.mock.calls[callIndex][1] as string[]
).join(' ');
const unexpectedArgument = IS_WINDOWS
? `-Architecture`
: `--architecture`;
expect(scriptArguments).not.toContain(unexpectedArgument);
});
it(`should supply 'architecture' argument to the installation script when arrchitecture is supplied`, async () => {
const inputVersion = '6.0.300';
const inputQuality = '' as QualityOptions;
const inputArchitecture = 'x86';
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();
/**
* First time script would be called to
* install runtime, here we checking only the
* second one that installs actual SDK. i.e. 1
*/
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 warn if the 'quality' input is set and the supplied version is in A.B.C syntax`, async () => {
const inputVersion = '6.0.300';
const inputQuality = 'ga' as QualityOptions;

View File

@ -9,7 +9,7 @@ import * as cacheUtils from '../src/cache-utils';
import * as cacheRestore from '../src/cache-restore';
describe('setup-dotnet tests', () => {
const inputs = {} as any;
let inputs = {} as any;
const getInputSpy = jest.spyOn(core, 'getInput');
const getMultilineInputSpy = jest.spyOn(core, 'getMultilineInput');
@ -49,6 +49,7 @@ describe('setup-dotnet tests', () => {
DotnetInstallDir.addToPath = addToPathOriginal;
jest.clearAllMocks();
jest.resetAllMocks();
inputs = {};
});
it('should fail the action if global-json-file input is present, but the file does not exist in the file system', async () => {
@ -62,7 +63,6 @@ describe('setup-dotnet tests', () => {
});
test(`if 'dotnet-version' and 'global-json-file' inputs aren't present, should log into debug output, try to find global.json in the repo root, fail and log message into info output`, async () => {
inputs['global-json-file'] = '';
inputs['dotnet-version'] = [];
maxSatisfyingSpy.mockImplementation(() => null);
@ -80,7 +80,6 @@ describe('setup-dotnet tests', () => {
});
it('should fail the action if quality is supplied but its value is not supported', async () => {
inputs['global-json-file'] = '';
inputs['dotnet-version'] = ['6.0'];
inputs['dotnet-quality'] = 'fictitiousQuality';
@ -90,10 +89,19 @@ describe('setup-dotnet tests', () => {
expect(setFailedSpy).toHaveBeenCalledWith(expectedErrorMessage);
});
it('should fail the action if architecture is supplied but its value is not supported', async () => {
console.log(inputs);
inputs['dotnet-version'] = ['6.0'];
inputs['dotnet-architecture'] = 'fictitiousArchitecture';
const expectedErrorMessage = `Value '${inputs['dotnet-architecture']}' is not supported for the 'dotnet-architecture' option. Supported values are: amd64, x64, x86, arm64, arm, s390x, ppc64le, loongarch64.`;
await setup.run();
expect(setFailedSpy).toHaveBeenCalledWith(expectedErrorMessage);
});
it('should call installDotnet() multiple times if dotnet-version multiline input is provided', async () => {
inputs['global-json-file'] = '';
inputs['dotnet-version'] = ['6.0', '7.0'];
inputs['dotnet-quality'] = '';
installDotnetSpy.mockImplementation(() => Promise.resolve(''));
@ -102,9 +110,7 @@ describe('setup-dotnet tests', () => {
});
it('should call addToPath() after installation complete', async () => {
inputs['global-json-file'] = '';
inputs['dotnet-version'] = ['6.0', '7.0'];
inputs['dotnet-quality'] = '';
installDotnetSpy.mockImplementation(() => Promise.resolve(''));
@ -113,9 +119,7 @@ describe('setup-dotnet tests', () => {
});
it('should call auth.configAuthentication() if source-url input is provided', async () => {
inputs['global-json-file'] = '';
inputs['dotnet-version'] = [];
inputs['dotnet-quality'] = '';
inputs['source-url'] = 'fictitious.source.url';
configAuthenticationSpy.mockImplementation(() => {});
@ -128,9 +132,7 @@ describe('setup-dotnet tests', () => {
});
it('should call auth.configAuthentication() with proper parameters if source-url and config-file inputs are provided', async () => {
inputs['global-json-file'] = '';
inputs['dotnet-version'] = [];
inputs['dotnet-quality'] = '';
inputs['source-url'] = 'fictitious.source.url';
inputs['config-file'] = 'fictitious.path';
@ -178,7 +180,6 @@ describe('setup-dotnet tests', () => {
it(`should get 'cache-dependency-path' and call restoreCache() if input cache is set to true and cache feature is available`, async () => {
inputs['dotnet-version'] = ['6.0.300'];
inputs['dotnet-quality'] = '';
inputs['cache'] = true;
inputs['cache-dependency-path'] = 'fictitious.package.lock.json';
@ -196,7 +197,6 @@ describe('setup-dotnet tests', () => {
it(`shouldn't call restoreCache() if input cache isn't set to true`, async () => {
inputs['dotnet-version'] = ['6.0.300'];
inputs['dotnet-quality'] = '';
inputs['cache'] = false;
installDotnetSpy.mockImplementation(() => Promise.resolve(''));
@ -210,7 +210,6 @@ describe('setup-dotnet tests', () => {
it(`shouldn't call restoreCache() if cache feature isn't available`, async () => {
inputs['dotnet-version'] = ['6.0.300'];
inputs['dotnet-quality'] = '';
inputs['cache'] = true;
installDotnetSpy.mockImplementation(() => Promise.resolve(''));

View File

@ -9,6 +9,8 @@ inputs:
description: 'Optional SDK version(s) to use. If not provided, will install global.json version when available. Examples: 2.2.104, 3.1, 3.1.x, 3.x, 6.0.2xx'
dotnet-quality:
description: 'Optional quality of the build. The possible values are: daily, signed, validated, preview, ga.'
dotnet-architecture:
description: 'Optional architecture of the .NET binaries to install. Possible values: amd64, x64, x86, arm64, arm, s390x, ppc64le and loongarch64. If not provided, defaults to the OS architecture.'
global-json-file:
description: 'Optional global.json location, if your global.json isn''t located in the root of the repo.'
source-url:

28
dist/setup/index.js vendored
View File

@ -72984,7 +72984,7 @@ class DotnetInstallScript {
this.scriptArguments.push(...args);
return this;
}
useVersion(dotnetVersion, quality) {
useVersion(dotnetVersion, quality, architecture) {
if (dotnetVersion.type) {
this.useArguments(dotnetVersion.type, dotnetVersion.value);
}
@ -72995,6 +72995,9 @@ class DotnetInstallScript {
if (quality) {
this.useArguments(utils_1.IS_WINDOWS ? '-Quality' : '--quality', quality);
}
if (architecture) {
this.useArguments(utils_1.IS_WINDOWS ? '-Architecture' : '--architecture', architecture);
}
return this;
}
execute() {
@ -73035,9 +73038,10 @@ DotnetInstallDir.dirPath = process.env['DOTNET_INSTALL_DIR']
? DotnetInstallDir.convertInstallPathToAbsolute(process.env['DOTNET_INSTALL_DIR'])
: DotnetInstallDir.default[utils_1.PLATFORM];
class DotnetCoreInstaller {
constructor(version, quality) {
constructor(version, quality, architecture) {
this.version = version;
this.quality = quality;
this.architecture = architecture;
}
installDotnet() {
return __awaiter(this, void 0, void 0, function* () {
@ -73070,7 +73074,7 @@ class DotnetCoreInstaller {
// Don't overwrite CLI because it should be already installed
.useArguments(utils_1.IS_WINDOWS ? '-SkipNonVersionedFiles' : '--skip-non-versioned-files')
// Use version provided by user
.useVersion(dotnetVersion, this.quality)
.useVersion(dotnetVersion, this.quality, this.architecture)
.execute();
if (dotnetInstallOutput.exitCode) {
throw new Error(`Failed to install dotnet, exit code: ${dotnetInstallOutput.exitCode}. ${dotnetInstallOutput.stderr}`);
@ -73155,6 +73159,16 @@ const qualityOptions = [
'preview',
'ga'
];
const architectureOptions = [
'amd64',
'x64',
'x86',
'arm64',
'arm',
's390x',
'ppc64le',
'loongarch64'
];
function run() {
return __awaiter(this, void 0, void 0, function* () {
try {
@ -73191,12 +73205,16 @@ function run() {
if (versions.length) {
const quality = core.getInput('dotnet-quality');
if (quality && !qualityOptions.includes(quality)) {
throw new Error(`Value '${quality}' is not supported for the 'dotnet-quality' option. Supported values are: daily, signed, validated, preview, ga.`);
throw new Error(`Value '${quality}' is not supported for the 'dotnet-quality' option. Supported values are: ${qualityOptions.join(', ')}.`);
}
const architecture = core.getInput('dotnet-architecture');
if (architecture && !architectureOptions.includes(architecture)) {
throw new Error(`Value '${architecture}' is not supported for the 'dotnet-architecture' option. Supported values are: ${architectureOptions.join(', ')}.`);
}
let dotnetInstaller;
const uniqueVersions = new Set(versions);
for (const version of uniqueVersions) {
dotnetInstaller = new installer_1.DotnetCoreInstaller(version, quality);
dotnetInstaller = new installer_1.DotnetCoreInstaller(version, quality, architecture);
const installedVersion = yield dotnetInstaller.installDotnet();
installedDotnetVersions.push(installedVersion);
}

View File

@ -8,7 +8,7 @@ import path from 'path';
import os from 'os';
import semver from 'semver';
import {IS_WINDOWS, PLATFORM} from './utils';
import {QualityOptions} from './setup-dotnet';
import {QualityOptions, ArchitectureOptions} from './setup-dotnet';
export interface DotnetVersion {
type: string;
@ -182,7 +182,11 @@ export class DotnetInstallScript {
return this;
}
public useVersion(dotnetVersion: DotnetVersion, quality?: QualityOptions) {
public useVersion(
dotnetVersion: DotnetVersion,
quality?: QualityOptions,
architecture?: ArchitectureOptions
) {
if (dotnetVersion.type) {
this.useArguments(dotnetVersion.type, dotnetVersion.value);
}
@ -198,6 +202,13 @@ export class DotnetInstallScript {
this.useArguments(IS_WINDOWS ? '-Quality' : '--quality', quality);
}
if (architecture) {
this.useArguments(
IS_WINDOWS ? '-Architecture' : '--architecture',
architecture
);
}
return this;
}
@ -253,7 +264,11 @@ export class DotnetCoreInstaller {
DotnetInstallDir.setEnvironmentVariable();
}
constructor(private version: string, private quality: QualityOptions) {}
constructor(
private version: string,
private quality: QualityOptions,
private architecture?: ArchitectureOptions
) {}
public async installDotnet(): Promise<string | null> {
const versionResolver = new DotnetVersionResolver(this.version);
@ -294,7 +309,7 @@ export class DotnetCoreInstaller {
IS_WINDOWS ? '-SkipNonVersionedFiles' : '--skip-non-versioned-files'
)
// Use version provided by user
.useVersion(dotnetVersion, this.quality)
.useVersion(dotnetVersion, this.quality, this.architecture)
.execute();
if (dotnetInstallOutput.exitCode) {

View File

@ -19,6 +19,19 @@ const qualityOptions = [
export type QualityOptions = (typeof qualityOptions)[number];
const architectureOptions = [
'amd64',
'x64',
'x86',
'arm64',
'arm',
's390x',
'ppc64le',
'loongarch64'
] as const;
export type ArchitectureOptions = (typeof architectureOptions)[number];
export async function run() {
try {
//
@ -59,17 +72,33 @@ export async function run() {
if (versions.length) {
const quality = core.getInput('dotnet-quality') as QualityOptions;
if (quality && !qualityOptions.includes(quality)) {
throw new Error(
`Value '${quality}' is not supported for the 'dotnet-quality' option. Supported values are: daily, signed, validated, preview, ga.`
`Value '${quality}' is not supported for the 'dotnet-quality' option. Supported values are: ${qualityOptions.join(
', '
)}.`
);
}
const architecture = core.getInput(
'dotnet-architecture'
) as ArchitectureOptions;
if (architecture && !architectureOptions.includes(architecture)) {
throw new Error(
`Value '${architecture}' is not supported for the 'dotnet-architecture' option. Supported values are: ${architectureOptions.join(
', '
)}.`
);
}
let dotnetInstaller: DotnetCoreInstaller;
const uniqueVersions = new Set<string>(versions);
for (const version of uniqueVersions) {
dotnetInstaller = new DotnetCoreInstaller(version, quality);
dotnetInstaller = new DotnetCoreInstaller(
version,
quality,
architecture
);
const installedVersion = await dotnetInstaller.installDotnet();
installedDotnetVersions.push(installedVersion);
}