This commit is contained in:
Justin Lampe 2025-11-11 16:05:10 +01:00
parent 1e4599d6b5
commit bbe37706ae
4 changed files with 130 additions and 29 deletions

View File

@ -54,6 +54,8 @@ steps:
The `dotnet-runtime` input allows you to install .NET runtimes separately from SDKs. This is useful for multi-targeting scenarios where you need one SDK version but multiple runtime versions for testing.
When `dotnet-runtime` is specified, both the .NET Runtime (Microsoft.NETCore.App) and the ASP.NET Core Runtime (Microsoft.AspNetCore.App) are installed for each specified version.
**Example: Install SDK 10 with runtimes 8 and 9**:
```yml
steps:
@ -69,8 +71,6 @@ steps:
- run: dotnet test <my project>
```
> **Note**: The `dotnet-runtime` input supports the same version syntax as `dotnet-version`. The `dotnet-quality` input applies to both SDK and runtime installations.
## Supported version syntax
The `dotnet-version` and `dotnet-runtime` inputs support following syntax:

View File

@ -346,7 +346,17 @@ describe('installer tests', () => {
});
describe('installRuntime() tests', () => {
it('should throw the error in case of non-zero exit code of the runtime installation script. The error message should contain logs.', async () => {
beforeAll(() => {
whichSpy.mockImplementation(() => Promise.resolve('PathToShell'));
chmodSyncSpy.mockImplementation(() => {});
readdirSpy.mockImplementation(() => Promise.resolve([]));
});
afterAll(() => {
jest.resetAllMocks();
});
it('should throw the error in case of non-zero exit code of the .NET runtime installation script. The error message should contain logs.', async () => {
const inputVersion = '8.0.402';
const inputQuality = '' as QualityOptions;
const errorMessage = 'fictitious error message!';
@ -368,6 +378,36 @@ describe('installer tests', () => {
);
});
it('should throw the error in case of non-zero exit code of the ASP.NET Core runtime installation script. The error message should contain logs.', async () => {
const inputVersion = '8.0.402';
const inputQuality = '' as QualityOptions;
const errorMessage = 'fictitious aspnetcore error message!';
getExecOutputSpy
.mockImplementationOnce(() => {
return Promise.resolve({
exitCode: 0,
stdout: `Fictitious dotnet runtime version ${inputVersion} is installed`,
stderr: ''
});
})
.mockImplementationOnce(() => {
return Promise.resolve({
exitCode: 1,
stdout: '',
stderr: errorMessage
});
});
const dotnetInstaller = new installer.DotnetCoreInstaller(
inputVersion,
inputQuality
);
await expect(dotnetInstaller.installRuntime()).rejects.toThrow(
`Failed to install aspnetcore runtime, exit code: 1. ${errorMessage}`
);
});
it('should return version of .NET runtime after installation complete', async () => {
const inputVersion = '8.0.402';
const inputQuality = '' as QualityOptions;
@ -390,7 +430,7 @@ describe('installer tests', () => {
expect(installedVersion).toBe(inputVersion);
});
it(`should supply '--runtime dotnet' argument to the installation script`, async () => {
it(`should supply '--runtime dotnet' and '--runtime aspnetcore' arguments to the installation script`, async () => {
const inputVersion = '8.0.402';
const inputQuality = '' as QualityOptions;
const stdout = `Fictitious dotnet runtime version ${inputVersion} is installed`;
@ -411,17 +451,28 @@ describe('installer tests', () => {
await dotnetInstaller.installRuntime();
const scriptArguments = (
// Check first call installs .NET runtime
const dotnetScriptArguments = (
getExecOutputSpy.mock.calls[0][1] as string[]
).join(' ');
const expectedArgument = IS_WINDOWS
const expectedDotnetArgument = IS_WINDOWS
? `-Runtime dotnet`
: `--runtime dotnet`;
expect(scriptArguments).toContain(expectedArgument);
expect(dotnetScriptArguments).toContain(expectedDotnetArgument);
// Check second call installs ASP.NET Core runtime
const aspnetcoreScriptArguments = (
getExecOutputSpy.mock.calls[1][1] as string[]
).join(' ');
const expectedAspnetcoreArgument = IS_WINDOWS
? `-Runtime aspnetcore`
: `--runtime aspnetcore`;
expect(aspnetcoreScriptArguments).toContain(expectedAspnetcoreArgument);
});
it(`should supply 'version' argument to the installation script if supplied version is in A.B.C syntax`, async () => {
it(`should supply 'version' argument to both runtime installation scripts if supplied version is in A.B.C syntax`, async () => {
const inputVersion = '8.0.402';
const inputQuality = '' as QualityOptions;
const stdout = `Fictitious dotnet runtime version ${inputVersion} is installed`;
@ -442,14 +493,20 @@ describe('installer tests', () => {
await dotnetInstaller.installRuntime();
const scriptArguments = (
getExecOutputSpy.mock.calls[0][1] as string[]
).join(' ');
const expectedArgument = IS_WINDOWS
? `-Version ${inputVersion}`
: `--version ${inputVersion}`;
expect(scriptArguments).toContain(expectedArgument);
// Check both calls contain version argument
const dotnetScriptArguments = (
getExecOutputSpy.mock.calls[0][1] as string[]
).join(' ');
expect(dotnetScriptArguments).toContain(expectedArgument);
const aspnetcoreScriptArguments = (
getExecOutputSpy.mock.calls[1][1] as string[]
).join(' ');
expect(aspnetcoreScriptArguments).toContain(expectedArgument);
});
it(`should warn if the 'quality' input is set and the supplied version is in A.B.C syntax`, async () => {
@ -478,7 +535,7 @@ describe('installer tests', () => {
});
each(['8', '8.0', '8.0.x', '8.0.*', '8.0.X']).test(
`should supply 'quality' argument to the installation script if quality input is set and version (%s) is not in A.B.C syntax`,
`should supply 'quality' argument to both runtime installation scripts if quality input is set and version (%s) is not in A.B.C syntax`,
async inputVersion => {
const inputQuality = 'ga' as QualityOptions;
const exitCode = 0;
@ -499,14 +556,20 @@ describe('installer tests', () => {
await dotnetInstaller.installRuntime();
const scriptArguments = (
getExecOutputSpy.mock.calls[0][1] as string[]
).join(' ');
const expectedArgument = IS_WINDOWS
? `-Quality ${inputQuality}`
: `--quality ${inputQuality}`;
expect(scriptArguments).toContain(expectedArgument);
// Check both calls contain quality argument
const dotnetScriptArguments = (
getExecOutputSpy.mock.calls[0][1] as string[]
).join(' ');
expect(dotnetScriptArguments).toContain(expectedArgument);
const aspnetcoreScriptArguments = (
getExecOutputSpy.mock.calls[1][1] as string[]
).join(' ');
expect(aspnetcoreScriptArguments).toContain(expectedArgument);
}
);
});

28
dist/setup/index.js vendored
View File

@ -100720,21 +100720,37 @@ class DotnetCoreInstaller {
const versionResolver = new DotnetVersionResolver(this.version);
const dotnetVersion = await versionResolver.createDotnetVersion();
/**
* Install dotnet runtime only (without SDK)
* Install .NET runtime (Microsoft.NETCore.App)
* Skip non-versioned files to avoid overwriting CLI
*/
const runtimeInstallOutput = await new DotnetInstallScript()
const dotnetRuntimeOutput = await new DotnetInstallScript()
// If dotnet CLI is already installed - avoid overwriting it
.useArguments(utils_1.IS_WINDOWS ? '-SkipNonVersionedFiles' : '--skip-non-versioned-files')
// Install only runtime (Microsoft.NETCore.App)
// Install .NET runtime (Microsoft.NETCore.App)
.useArguments(utils_1.IS_WINDOWS ? '-Runtime' : '--runtime', 'dotnet')
// Use version provided by user
.useVersion(dotnetVersion, this.quality)
.execute();
if (runtimeInstallOutput.exitCode) {
throw new Error(`Failed to install dotnet runtime, exit code: ${runtimeInstallOutput.exitCode}. ${runtimeInstallOutput.stderr}`);
if (dotnetRuntimeOutput.exitCode) {
throw new Error(`Failed to install dotnet runtime, exit code: ${dotnetRuntimeOutput.exitCode}. ${dotnetRuntimeOutput.stderr}`);
}
return this.parseInstalledVersion(runtimeInstallOutput.stdout);
/**
* Install ASP.NET Core runtime (Microsoft.AspNetCore.App)
* Skip non-versioned files to avoid overwriting CLI
*/
const aspnetcoreRuntimeOutput = await new DotnetInstallScript()
// If dotnet CLI is already installed - avoid overwriting it
.useArguments(utils_1.IS_WINDOWS ? '-SkipNonVersionedFiles' : '--skip-non-versioned-files')
// Install ASP.NET Core runtime (Microsoft.AspNetCore.App)
.useArguments(utils_1.IS_WINDOWS ? '-Runtime' : '--runtime', 'aspnetcore')
// Use version provided by user
.useVersion(dotnetVersion, this.quality)
.execute();
if (aspnetcoreRuntimeOutput.exitCode) {
throw new Error(`Failed to install aspnetcore runtime, exit code: ${aspnetcoreRuntimeOutput.exitCode}. ${aspnetcoreRuntimeOutput.stderr}`);
}
// Return the .NET runtime version (both should be the same version)
return this.parseInstalledVersion(dotnetRuntimeOutput.stdout);
}
parseInstalledVersion(stdout) {
const regex = /(?<version>\d+\.\d+\.\d+[a-z0-9._-]*)/gm;

View File

@ -316,27 +316,49 @@ export class DotnetCoreInstaller {
const dotnetVersion = await versionResolver.createDotnetVersion();
/**
* Install dotnet runtime only (without SDK)
* Install .NET runtime (Microsoft.NETCore.App)
* Skip non-versioned files to avoid overwriting CLI
*/
const runtimeInstallOutput = await new DotnetInstallScript()
const dotnetRuntimeOutput = await new DotnetInstallScript()
// If dotnet CLI is already installed - avoid overwriting it
.useArguments(
IS_WINDOWS ? '-SkipNonVersionedFiles' : '--skip-non-versioned-files'
)
// Install only runtime (Microsoft.NETCore.App)
// Install .NET runtime (Microsoft.NETCore.App)
.useArguments(IS_WINDOWS ? '-Runtime' : '--runtime', 'dotnet')
// Use version provided by user
.useVersion(dotnetVersion, this.quality)
.execute();
if (runtimeInstallOutput.exitCode) {
if (dotnetRuntimeOutput.exitCode) {
throw new Error(
`Failed to install dotnet runtime, exit code: ${runtimeInstallOutput.exitCode}. ${runtimeInstallOutput.stderr}`
`Failed to install dotnet runtime, exit code: ${dotnetRuntimeOutput.exitCode}. ${dotnetRuntimeOutput.stderr}`
);
}
return this.parseInstalledVersion(runtimeInstallOutput.stdout);
/**
* Install ASP.NET Core runtime (Microsoft.AspNetCore.App)
* Skip non-versioned files to avoid overwriting CLI
*/
const aspnetcoreRuntimeOutput = await new DotnetInstallScript()
// If dotnet CLI is already installed - avoid overwriting it
.useArguments(
IS_WINDOWS ? '-SkipNonVersionedFiles' : '--skip-non-versioned-files'
)
// Install ASP.NET Core runtime (Microsoft.AspNetCore.App)
.useArguments(IS_WINDOWS ? '-Runtime' : '--runtime', 'aspnetcore')
// Use version provided by user
.useVersion(dotnetVersion, this.quality)
.execute();
if (aspnetcoreRuntimeOutput.exitCode) {
throw new Error(
`Failed to install aspnetcore runtime, exit code: ${aspnetcoreRuntimeOutput.exitCode}. ${aspnetcoreRuntimeOutput.stderr}`
);
}
// Return the .NET runtime version (both should be the same version)
return this.parseInstalledVersion(dotnetRuntimeOutput.stdout);
}
private parseInstalledVersion(stdout: string): string | null {