From 7a98346f51166aa847a6eeafa446690816e007b7 Mon Sep 17 00:00:00 2001 From: Zachary Eisinger Date: Thu, 24 Sep 2020 08:26:00 -0700 Subject: [PATCH] DOTNET_ROOT and short generic versions (#131) --- .github/workflows/workflow.yml | 57 ++++++++++++++- __tests__/installer.test.ts | 129 +++++---------------------------- __tests__/setup-dotnet.test.ts | 5 +- __tests__/versionutil.test.ts | 90 +++++++++++++++++++++++ dist/index.js | 9 ++- src/installer.ts | 17 ++++- 6 files changed, 186 insertions(+), 121 deletions(-) create mode 100644 __tests__/versionutil.test.ts diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 90f7350..022b034 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -75,7 +75,62 @@ jobs: run: __tests__/verify-dotnet.sh 3.1.201 2.2.402 - name: Verify dotnet (Windows) if: runner.os == 'windows' - run: __tests__/verify-dotnet.ps1 3.1.201 + run: __tests__/verify-dotnet.ps1 3.1.201 2.2.402 + + # Set new cache before 2 digit install + - name: Set new tool cache (macOS) + if: runner.os == 'macos' + run: | + echo "::set-env name=DOTNET_INSTALL_DIR::/Users/runner/.dotnet2" + - name: Set new tool cache (Ubuntu) + if: runner.os == 'linux' + run: | + echo "::set-env name=DOTNET_INSTALL_DIR::/home/runner/.dotnet2" + - name: Set new tool cache (Windows) + if: runner.os == 'windows' + run: | + echo "::set-env name=DOTNET_INSTALL_DIR::$env:LocalAppData\Microsoft\dotnet2" + # 2.0, 3.0, 5.0 needs to be in single quotes to interpret as a string instead of as an integer + - name: Setup dotnet '2.0' + uses: ./ + with: + dotnet-version: '2.0' + + # Clear cache before .x version install + - name: Set new tool cache (macOS) + if: runner.os == 'macos' + run: | + echo "::set-env name=DOTNET_INSTALL_DIR::/Users/runner/.dotnet3" + - name: Set new tool cache (Ubuntu) + if: runner.os == 'linux' + run: | + echo "::set-env name=DOTNET_INSTALL_DIR::/home/runner/.dotnet3" + - name: Set new tool cache (Windows) + if: runner.os == 'windows' + run: | + echo "::set-env name=DOTNET_INSTALL_DIR::$env:LocalAppData\Microsoft\dotnet3" + - name: Setup dotnet 2.0.x + uses: ./ + with: + dotnet-version: 2.0.x + + # Clear cache before .* version install + - name: Set new tool cache (macOS) + if: runner.os == 'macos' + run: | + echo "::set-env name=DOTNET_INSTALL_DIR::/Users/runner/.dotnet4" + - name: Set new tool cache (Ubuntu) + if: runner.os == 'linux' + run: | + echo "::set-env name=DOTNET_INSTALL_DIR::/home/runner/.dotnet4" + - name: Set new tool cache (Windows) + if: runner.os == 'windows' + run: | + echo "::set-env name=DOTNET_INSTALL_DIR::$env:LocalAppData\Microsoft\dotnet4" + - name: Setup dotnet 2.0.* + uses: ./ + with: + dotnet-version: 2.0.* test-proxy: runs-on: ubuntu-latest diff --git a/__tests__/installer.test.ts b/__tests__/installer.test.ts index 855d7ee..a7db4ea 100644 --- a/__tests__/installer.test.ts +++ b/__tests__/installer.test.ts @@ -4,79 +4,21 @@ import os = require('os'); import path = require('path'); import hc = require('@actions/http-client'); -import each from 'jest-each'; - const toolDir = path.join(__dirname, 'runner', 'tools'); const tempDir = path.join(__dirname, 'runner', 'temp'); process.env['RUNNER_TOOL_CACHE'] = toolDir; process.env['RUNNER_TEMP'] = tempDir; -import * as setup from '../src/setup-dotnet'; import * as installer from '../src/installer'; const IS_WINDOWS = process.platform === 'win32'; -describe('version tests', () => { - each(['3.1.999', '3.1.101-preview.3']).test( - "Exact version '%s' should be the same", - vers => { - let versInfo = new installer.DotNetVersionInfo(vers); - - expect(versInfo.isExactVersion()).toBe(true); - expect(versInfo.version()).toBe(vers); - } - ); - - each([ - ['3.1.x', '3.1'], - ['1.1.*', '1.1'], - ['2.0', '2.0'] - ]).test("Generic version '%s' should be '%s'", (vers, resVers) => { - let versInfo = new installer.DotNetVersionInfo(vers); - - expect(versInfo.isExactVersion()).toBe(false); - expect(versInfo.version()).toBe(resVers); - }); - - each([ - '', - '.', - '..', - ' . ', - '. ', - ' .', - ' . . ', - ' .. ', - ' . ', - '-1.-1', - '-1', - '-1.-1.-1', - '..3', - '1..3', - '1..', - '.2.3', - '.2.x', - '1', - '2.x', - '*.*.1', - '*.1', - '*.', - '1.2.', - '1.2.-abc', - 'a.b', - 'a.b.c', - 'a.b.c-preview', - ' 0 . 1 . 2 ' - ]).test("Malformed version '%s' should throw", vers => { - expect(() => new installer.DotNetVersionInfo(vers)).toThrow(); - }); -}); - describe('installer tests', () => { beforeAll(async () => { process.env.RUNNER_TOOL_CACHE = toolDir; process.env.DOTNET_INSTALL_DIR = toolDir; process.env.RUNNER_TEMP = tempDir; + process.env.DOTNET_ROOT = ''; await io.rmRF(toolDir); await io.rmRF(tempDir); }); @@ -90,47 +32,6 @@ describe('installer tests', () => { } }, 30000); - it('Resolving a normal generic version works', async () => { - const dotnetInstaller = new installer.DotnetCoreInstaller('3.1.x'); - let versInfo = await dotnetInstaller.resolveVersion( - new installer.DotNetVersionInfo('3.1.x') - ); - - expect(versInfo.startsWith('3.1.')); - }, 100000); - - it('Resolving a nonexistent generic version fails', async () => { - const dotnetInstaller = new installer.DotnetCoreInstaller('999.1.x'); - try { - await dotnetInstaller.resolveVersion( - new installer.DotNetVersionInfo('999.1.x') - ); - fail(); - } catch { - expect(true); - } - }, 100000); - - it('Resolving a exact stable version works', async () => { - const dotnetInstaller = new installer.DotnetCoreInstaller('3.1.201'); - let versInfo = await dotnetInstaller.resolveVersion( - new installer.DotNetVersionInfo('3.1.201') - ); - - expect(versInfo).toBe('3.1.201'); - }, 100000); - - it('Resolving a exact preview version works', async () => { - const dotnetInstaller = new installer.DotnetCoreInstaller( - '5.0.0-preview.6' - ); - let versInfo = await dotnetInstaller.resolveVersion( - new installer.DotNetVersionInfo('5.0.0-preview.6') - ); - - expect(versInfo).toBe('5.0.0-preview.6'); - }, 100000); - it('Acquires version of dotnet if no matching version is installed', async () => { await getDotnet('3.1.201'); expect(fs.existsSync(path.join(toolDir, 'sdk', '3.1.201'))).toBe(true); @@ -139,24 +40,30 @@ describe('installer tests', () => { } else { expect(fs.existsSync(path.join(toolDir, 'dotnet'))).toBe(true); } - }, 400000); //This needs some time to download on "slower" internet connections - it('Acquires version of dotnet from global.json if no matching version is installed', async () => { - const globalJsonPath = path.join(process.cwd(), 'global.json'); - const jsonContents = `{${os.EOL}"sdk": {${os.EOL}"version": "3.1.201"${os.EOL}}${os.EOL}}`; - if (!fs.existsSync(globalJsonPath)) { - fs.writeFileSync(globalJsonPath, jsonContents); - } - await setup.run(); + expect(process.env.DOTNET_ROOT).toBeDefined; + expect(process.env.PATH).toBeDefined; + expect(process.env.DOTNET_ROOT).toBe(toolDir); + expect(process.env.PATH?.startsWith(toolDir)).toBe(true); + }, 600000); //This needs some time to download on "slower" internet connections - expect(fs.existsSync(path.join(toolDir, 'sdk', '3.1.201'))).toBe(true); + it('Acquires generic version of dotnet if no matching version is installed', async () => { + await getDotnet('3.1'); + var directory = fs + .readdirSync(path.join(toolDir, 'sdk')) + .filter(fn => fn.startsWith('3.1.')); + expect(directory.length > 0).toBe(true); if (IS_WINDOWS) { expect(fs.existsSync(path.join(toolDir, 'dotnet.exe'))).toBe(true); } else { expect(fs.existsSync(path.join(toolDir, 'dotnet'))).toBe(true); } - fs.unlinkSync(globalJsonPath); - }, 100000); + + expect(process.env.DOTNET_ROOT).toBeDefined; + expect(process.env.PATH).toBeDefined; + expect(process.env.DOTNET_ROOT).toBe(toolDir); + expect(process.env.PATH?.startsWith(toolDir)).toBe(true); + }, 600000); //This needs some time to download on "slower" internet connections it('Throws if no location contains correct dotnet version', async () => { let thrown = false; diff --git a/__tests__/setup-dotnet.test.ts b/__tests__/setup-dotnet.test.ts index d7be6e4..c492f56 100644 --- a/__tests__/setup-dotnet.test.ts +++ b/__tests__/setup-dotnet.test.ts @@ -29,7 +29,7 @@ describe('setup-dotnet tests', () => { } }, 30000); - it('Acquires version of dotnet if no matching version is installed', async () => { + it('Acquires version of dotnet from global.json if no matching version is installed', async () => { const globalJsonPath = path.join(process.cwd(), 'global.json'); const jsonContents = `{${os.EOL}"sdk": {${os.EOL}"version": "3.1.201"${os.EOL}}${os.EOL}}`; if (!fs.existsSync(globalJsonPath)) { @@ -43,6 +43,5 @@ describe('setup-dotnet tests', () => { } else { expect(fs.existsSync(path.join(toolDir, 'dotnet'))).toBe(true); } - fs.unlinkSync(globalJsonPath); - }, 100000); + }, 400000); }); diff --git a/__tests__/versionutil.test.ts b/__tests__/versionutil.test.ts new file mode 100644 index 0000000..a238688 --- /dev/null +++ b/__tests__/versionutil.test.ts @@ -0,0 +1,90 @@ +import each from 'jest-each'; +import * as installer from '../src/installer'; + +describe('version tests', () => { + each(['3.1.999', '3.1.101-preview.3']).test( + "Exact version '%s' should be the same", + vers => { + let versInfo = new installer.DotNetVersionInfo(vers); + + expect(versInfo.isExactVersion()).toBe(true); + expect(versInfo.version()).toBe(vers); + } + ); + + each([ + ['3.1.x', '3.1'], + ['1.1.*', '1.1'], + ['2.0', '2.0'] + ]).test("Generic version '%s' should be '%s'", (vers, resVers) => { + let versInfo = new installer.DotNetVersionInfo(vers); + + expect(versInfo.isExactVersion()).toBe(false); + expect(versInfo.version()).toBe(resVers); + }); + + each([ + '', + '.', + '..', + ' . ', + '. ', + ' .', + ' . . ', + ' .. ', + ' . ', + '-1.-1', + '-1', + '-1.-1.-1', + '..3', + '1..3', + '1..', + '.2.3', + '.2.x', + '1', + '2.x', + '*.*.1', + '*.1', + '*.', + '1.2.', + '1.2.-abc', + 'a.b', + 'a.b.c', + 'a.b.c-preview', + ' 0 . 1 . 2 ' + ]).test("Malformed version '%s' should throw", vers => { + expect(() => new installer.DotNetVersionInfo(vers)).toThrow(); + }); + + each([ + ['3.1.x', '3.1.'], + ['3.1.*', '3.1.'], + ['3.1', '3.1.'], + ['5.0.0-preview.6', '5.0.0-preview.6'], + ['3.1.201', '3.1.201'] + ]).test( + "Resolving version '%s' as '%s'", + async (input, expectedVersion) => { + const dotnetInstaller = new installer.DotnetCoreInstaller(input); + let versInfo = await dotnetInstaller.resolveVersion( + new installer.DotNetVersionInfo(input) + ); + console.log(versInfo); + + expect(versInfo.startsWith(expectedVersion)); + }, + 100000 + ); + + it('Resolving a nonexistent generic version fails', async () => { + const dotnetInstaller = new installer.DotnetCoreInstaller('999.1.x'); + try { + await dotnetInstaller.resolveVersion( + new installer.DotNetVersionInfo('999.1.x') + ); + fail(); + } catch { + expect(true); + } + }, 100000); +}); diff --git a/dist/index.js b/dist/index.js index bc18a95..98a81e6 100644 --- a/dist/index.js +++ b/dist/index.js @@ -16901,8 +16901,8 @@ class DotnetCoreInstaller { fs_1.chmodSync(escapedScript, '777'); const scriptPath = yield io.which(escapedScript, true); let scriptArguments = []; - if (this.version) { - scriptArguments.push('--version', this.version); + if (calculatedVersion) { + scriptArguments.push('--version', calculatedVersion); } // process.env must be explicitly passed in for DOTNET_INSTALL_DIR to be used resultCode = yield exec.exec(`"${scriptPath}"`, scriptArguments, { @@ -16916,6 +16916,7 @@ class DotnetCoreInstaller { } if (process.env['DOTNET_INSTALL_DIR']) { core.addPath(process.env['DOTNET_INSTALL_DIR']); + core.exportVariable('DOTNET_ROOT', process.env['DOTNET_INSTALL_DIR']); } else { if (IS_WINDOWS) { @@ -16926,6 +16927,7 @@ class DotnetCoreInstaller { else { // This is the default set in install-dotnet.sh core.addPath(path.join(process.env['HOME'] + '', '.dotnet')); + core.exportVariable('DOTNET_ROOT', path.join(process.env['HOME'] + '', '.dotnet')); } } console.log(process.env['PATH']); @@ -16972,7 +16974,8 @@ class DotnetCoreInstaller { releasesInfo = releasesInfo.filter((info) => { // channel-version is the first 2 elements of the version (e.g. 2.1), filter out versions that don't match 2.1.x. const sdkParts = info['channel-version'].split('.'); - if (versionParts.length >= 2 && versionParts[1] != 'x') { + if (versionParts.length >= 2 && + !(versionParts[1] == 'x' || versionParts[1] == '*')) { return versionParts[0] == sdkParts[0] && versionParts[1] == sdkParts[1]; } return versionParts[0] == sdkParts[0]; diff --git a/src/installer.ts b/src/installer.ts index 66032fc..f0b48a2 100644 --- a/src/installer.ts +++ b/src/installer.ts @@ -146,8 +146,8 @@ export class DotnetCoreInstaller { const scriptPath = await io.which(escapedScript, true); let scriptArguments: string[] = []; - if (this.version) { - scriptArguments.push('--version', this.version); + if (calculatedVersion) { + scriptArguments.push('--version', calculatedVersion); } // process.env must be explicitly passed in for DOTNET_INSTALL_DIR to be used @@ -163,6 +163,7 @@ export class DotnetCoreInstaller { if (process.env['DOTNET_INSTALL_DIR']) { core.addPath(process.env['DOTNET_INSTALL_DIR']); + core.exportVariable('DOTNET_ROOT', process.env['DOTNET_INSTALL_DIR']); } else { if (IS_WINDOWS) { // This is the default set in install-dotnet.ps1 @@ -176,6 +177,10 @@ export class DotnetCoreInstaller { } else { // This is the default set in install-dotnet.sh core.addPath(path.join(process.env['HOME'] + '', '.dotnet')); + core.exportVariable( + 'DOTNET_ROOT', + path.join(process.env['HOME'] + '', '.dotnet') + ); } } @@ -245,19 +250,25 @@ export class DotnetCoreInstaller { const response = await httpClient.getJson(DotNetCoreIndexUrl); const result = response.result || {}; let releasesInfo: any[] = result['releases-index']; + releasesInfo = releasesInfo.filter((info: any) => { // channel-version is the first 2 elements of the version (e.g. 2.1), filter out versions that don't match 2.1.x. const sdkParts: string[] = info['channel-version'].split('.'); - if (versionParts.length >= 2 && versionParts[1] != 'x') { + if ( + versionParts.length >= 2 && + !(versionParts[1] == 'x' || versionParts[1] == '*') + ) { return versionParts[0] == sdkParts[0] && versionParts[1] == sdkParts[1]; } return versionParts[0] == sdkParts[0]; }); + if (releasesInfo.length === 0) { throw `Could not find info for version ${versionParts.join( '.' )} at ${DotNetCoreIndexUrl}`; } + return releasesInfo[0]['releases.json']; }