diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 42f055a..332eebc 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -451,3 +451,33 @@ jobs: - name: Verify dotnet shell: pwsh run: __tests__/verify-dotnet.ps1 -Patterns "^3.1.201$" -CheckNugetConfig + + test-sequential-version-installation: + runs-on: ${{ matrix.operating-system }} + strategy: + fail-fast: false + matrix: + operating-system: [ubuntu-latest, windows-latest, macOS-latest] + lower-version: ['3.1.426'] + higher-version: ['7.0.203'] + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Clear toolcache + shell: pwsh + run: __tests__/clear-toolcache.ps1 ${{ runner.os }} + # Install one version, use it for something, then switch to next version + - name: Setup dotnet (lower version) + uses: ./ + with: + dotnet-version: ${{ matrix.lower-version }} + - name: Verify dotnet (lower version) + shell: pwsh + run: __tests__/verify-dotnet.ps1 -Patterns "^${{ matrix.lower-version }}$" + - name: Setup dotnet (higher version) + uses: ./ + with: + dotnet-version: ${{ matrix.higher-version }} + - name: Verify dotnet (higher version) + shell: pwsh + run: __tests__/verify-dotnet.ps1 -Patterns "^${{ matrix.lower-version }}$", "^${{ matrix.higher-version }}$" diff --git a/__tests__/installer.test.ts b/__tests__/installer.test.ts index ceb4b37..84aea32 100644 --- a/__tests__/installer.test.ts +++ b/__tests__/installer.test.ts @@ -102,8 +102,15 @@ describe('installer tests', () => { 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[0][1] as string[] + getExecOutputSpy.mock.calls[callIndex][1] as string[] ).join(' '); const expectedArgument = IS_WINDOWS ? `-Version ${inputVersion}` @@ -185,8 +192,15 @@ describe('installer tests', () => { 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[0][1] as string[] + getExecOutputSpy.mock.calls[callIndex][1] as string[] ).join(' '); const expectedArgument = IS_WINDOWS ? `-Quality ${inputQuality}` @@ -218,8 +232,15 @@ describe('installer tests', () => { 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[0][1] as string[] + getExecOutputSpy.mock.calls[callIndex][1] as string[] ).join(' '); const expectedArgument = IS_WINDOWS ? `-Channel 6.0` @@ -252,8 +273,15 @@ describe('installer tests', () => { 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[0][1] as string[] + getExecOutputSpy.mock.calls[callIndex][1] as string[] ).join(' '); expect(scriptArguments).toContain( @@ -283,8 +311,15 @@ describe('installer tests', () => { 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[0][1] as string[] + getExecOutputSpy.mock.calls[callIndex][1] as string[] ).join(' '); expect(scriptArguments).toContain( diff --git a/dist/setup/index.js b/dist/setup/index.js index ee61d25..65067a2 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -72843,14 +72843,39 @@ class DotnetCoreInstaller { return __awaiter(this, void 0, void 0, function* () { const versionResolver = new DotnetVersionResolver(this.version); const dotnetVersion = yield versionResolver.createDotnetVersion(); - const installScript = new DotnetInstallScript() + /** + * Install dotnet runitme first in order to get + * the latest stable version of dotnet CLI + */ + const runtimeInstallOutput = yield new DotnetInstallScript() + // If dotnet CLI is already installed - avoid overwriting it .useArguments(utils_1.IS_WINDOWS ? '-SkipNonVersionedFiles' : '--skip-non-versioned-files') - .useVersion(dotnetVersion, this.quality); - const { exitCode, stderr, stdout } = yield installScript.execute(); - if (exitCode) { - throw new Error(`Failed to install dotnet, exit code: ${exitCode}. ${stderr}`); + // Install only runtime + CLI + .useArguments(utils_1.IS_WINDOWS ? '-Runtime' : '--runtime', 'dotnet') + // Use latest stable version + .useArguments(utils_1.IS_WINDOWS ? '-Channel' : '--channel', 'LTS') + .execute(); + if (runtimeInstallOutput.exitCode) { + /** + * dotnetInstallScript will install CLI and runtime even if previous script haven't succeded, + * so at this point it's too early to throw an error + */ + core.warning(`Failed to install dotnet runtime + cli, exit code: ${runtimeInstallOutput.exitCode}. ${runtimeInstallOutput.stderr}`); } - return this.parseInstalledVersion(stdout); + /** + * Install dotnet over the latest version of + * dotnet CLI + */ + const dotnetInstallOutput = yield new DotnetInstallScript() + // 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) + .execute(); + if (dotnetInstallOutput.exitCode) { + throw new Error(`Failed to install dotnet, exit code: ${dotnetInstallOutput.exitCode}. ${dotnetInstallOutput.stderr}`); + } + return this.parseInstalledVersion(dotnetInstallOutput.stdout); }); } parseInstalledVersion(stdout) { diff --git a/src/installer.ts b/src/installer.ts index 4d61e5d..4900afa 100644 --- a/src/installer.ts +++ b/src/installer.ts @@ -259,21 +259,51 @@ export class DotnetCoreInstaller { const versionResolver = new DotnetVersionResolver(this.version); const dotnetVersion = await versionResolver.createDotnetVersion(); - const installScript = new DotnetInstallScript() + /** + * Install dotnet runitme first in order to get + * the latest stable version of dotnet CLI + */ + const runtimeInstallOutput = await new DotnetInstallScript() + // If dotnet CLI is already installed - avoid overwriting it .useArguments( IS_WINDOWS ? '-SkipNonVersionedFiles' : '--skip-non-versioned-files' ) - .useVersion(dotnetVersion, this.quality); + // Install only runtime + CLI + .useArguments(IS_WINDOWS ? '-Runtime' : '--runtime', 'dotnet') + // Use latest stable version + .useArguments(IS_WINDOWS ? '-Channel' : '--channel', 'LTS') + .execute(); - const {exitCode, stderr, stdout} = await installScript.execute(); - - if (exitCode) { - throw new Error( - `Failed to install dotnet, exit code: ${exitCode}. ${stderr}` + if (runtimeInstallOutput.exitCode) { + /** + * dotnetInstallScript will install CLI and runtime even if previous script haven't succeded, + * so at this point it's too early to throw an error + */ + core.warning( + `Failed to install dotnet runtime + cli, exit code: ${runtimeInstallOutput.exitCode}. ${runtimeInstallOutput.stderr}` ); } - return this.parseInstalledVersion(stdout); + /** + * Install dotnet over the latest version of + * dotnet CLI + */ + const dotnetInstallOutput = await new DotnetInstallScript() + // Don't overwrite CLI because it should be already installed + .useArguments( + IS_WINDOWS ? '-SkipNonVersionedFiles' : '--skip-non-versioned-files' + ) + // Use version provided by user + .useVersion(dotnetVersion, this.quality) + .execute(); + + if (dotnetInstallOutput.exitCode) { + throw new Error( + `Failed to install dotnet, exit code: ${dotnetInstallOutput.exitCode}. ${dotnetInstallOutput.stderr}` + ); + } + + return this.parseInstalledVersion(dotnetInstallOutput.stdout); } private parseInstalledVersion(stdout: string): string | null {