mirror of
				https://gitea.com/actions/setup-node.git
				synced 2025-10-29 15:52:42 +08:00 
			
		
		
		
	Add support for v8-canary, nightly and rc (#655)
This commit is contained in:
		
							
								
								
									
										20
									
								
								.github/workflows/versions.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								.github/workflows/versions.yml
									
									
									
									
										vendored
									
									
								
							| @@ -51,6 +51,26 @@ jobs: | |||||||
|           __tests__/verify-node.sh "${BASH_REMATCH[1]}" |           __tests__/verify-node.sh "${BASH_REMATCH[1]}" | ||||||
|         shell: bash |         shell: bash | ||||||
|  |  | ||||||
|  |   v8-canary-syntax: | ||||||
|  |     runs-on: ${{ matrix.os }} | ||||||
|  |     strategy: | ||||||
|  |       fail-fast: false | ||||||
|  |       matrix: | ||||||
|  |         os: [ubuntu-latest, windows-latest, macos-latest] | ||||||
|  |         node-version: ['20-v8-canary', '20.0.0-v8-canary','20.0.0-v8-canary20221103f7e2421e91'] | ||||||
|  |     steps: | ||||||
|  |       - uses: actions/checkout@v3 | ||||||
|  |       - name: Setup Node | ||||||
|  |         uses: ./ | ||||||
|  |         with: | ||||||
|  |           node-version: ${{ matrix.node-version }} | ||||||
|  |       - name: Verify node and npm | ||||||
|  |         run: | | ||||||
|  |           canaryVersion="${{ matrix.node-version }}" | ||||||
|  |           majorVersion=$(echo $canaryVersion | cut -d- -f1) | ||||||
|  |           __tests__/verify-node.sh "$majorVersion" | ||||||
|  |         shell: bash | ||||||
|  |  | ||||||
|   nightly-syntax: |   nightly-syntax: | ||||||
|     runs-on: ${{ matrix.os }} |     runs-on: ${{ matrix.os }} | ||||||
|     strategy: |     strategy: | ||||||
|   | |||||||
							
								
								
									
										21
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								README.md
									
									
									
									
									
								
							| @@ -128,16 +128,17 @@ If the runner is not able to access github.com, any Nodejs versions requested du | |||||||
|  |  | ||||||
| ## Advanced usage | ## Advanced usage | ||||||
|  |  | ||||||
| 1. [Check latest version](docs/advanced-usage.md#check-latest-version) |  - [Check latest version](docs/advanced-usage.md#check-latest-version) | ||||||
| 2. [Using a node version file](docs/advanced-usage.md#node-version-file) |  - [Using a node version file](docs/advanced-usage.md#node-version-file) | ||||||
| 3. [Using different architectures](docs/advanced-usage.md#architecture) |  - [Using different architectures](docs/advanced-usage.md#architecture) | ||||||
| 4. [Using nightly versions](docs/advanced-usage.md#nightly-versions) |  - [Using v8 canary versions](docs/advanced-usage.md#v8-canary-versions) | ||||||
| 5. [Using rc versions](docs/advanced-usage.md#rc-versions) |  - [Using nigthly versions](docs/advanced-usage.md#nightly-versions) | ||||||
| 6. [Caching packages data](docs/advanced-usage.md#caching-packages-data) |  - [Using rc versions](docs/advanced-usage.md#rc-versions) | ||||||
| 7. [Using multiple operating systems and architectures](docs/advanced-usage.md#multiple-operating-systems-and-architectures) |  - [Caching packages data](docs/advanced-usage.md#caching-packages-data) | ||||||
| 8. [Publishing to npmjs and GPR with npm](docs/advanced-usage.md#publish-to-npmjs-and-gpr-with-npm) |  - [Using multiple operating systems and architectures](docs/advanced-usage.md#multiple-operating-systems-and-architectures) | ||||||
| 9. [Publishing to npmjs and GPR with yarn](docs/advanced-usage.md#publish-to-npmjs-and-gpr-with-yarn) |  - [Publishing to npmjs and GPR with npm](docs/advanced-usage.md#publish-to-npmjs-and-gpr-with-npm) | ||||||
| 10. [Using private packages](docs/advanced-usage.md#use-private-packages) |  - [Publishing to npmjs and GPR with yarn](docs/advanced-usage.md#publish-to-npmjs-and-gpr-with-yarn) | ||||||
|  |  - [Using private packages](docs/advanced-usage.md#use-private-packages) | ||||||
|  |  | ||||||
| ## License | ## License | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										531
									
								
								__tests__/canary-installer.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										531
									
								
								__tests__/canary-installer.test.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,531 @@ | |||||||
|  | import * as core from '@actions/core'; | ||||||
|  | import * as io from '@actions/io'; | ||||||
|  | import * as tc from '@actions/tool-cache'; | ||||||
|  | import * as httpm from '@actions/http-client'; | ||||||
|  | import * as exec from '@actions/exec'; | ||||||
|  | import * as cache from '@actions/cache'; | ||||||
|  | import fs from 'fs'; | ||||||
|  | import cp from 'child_process'; | ||||||
|  | import osm from 'os'; | ||||||
|  | import path from 'path'; | ||||||
|  | import * as main from '../src/main'; | ||||||
|  | import * as auth from '../src/authutil'; | ||||||
|  | import {INodeVersion} from '../src/distributions/base-models'; | ||||||
|  |  | ||||||
|  | const nodeTestManifest = require('./data/versions-manifest.json'); | ||||||
|  | const nodeTestDist = require('./data/node-dist-index.json'); | ||||||
|  | const nodeTestDistNightly = require('./data/node-nightly-index.json'); | ||||||
|  | const nodeTestDistRc = require('./data/node-rc-index.json'); | ||||||
|  | const nodeV8CanaryTestDist = require('./data/v8-canary-dist-index.json'); | ||||||
|  |  | ||||||
|  | describe('setup-node', () => { | ||||||
|  |   let inputs = {} as any; | ||||||
|  |   let os = {} as any; | ||||||
|  |  | ||||||
|  |   let inSpy: jest.SpyInstance; | ||||||
|  |   let findSpy: jest.SpyInstance; | ||||||
|  |   let findAllVersionsSpy: jest.SpyInstance; | ||||||
|  |   let cnSpy: jest.SpyInstance; | ||||||
|  |   let logSpy: jest.SpyInstance; | ||||||
|  |   let warningSpy: jest.SpyInstance; | ||||||
|  |   let getManifestSpy: jest.SpyInstance; | ||||||
|  |   let getDistSpy: jest.SpyInstance; | ||||||
|  |   let platSpy: jest.SpyInstance; | ||||||
|  |   let archSpy: jest.SpyInstance; | ||||||
|  |   let dlSpy: jest.SpyInstance; | ||||||
|  |   let exSpy: jest.SpyInstance; | ||||||
|  |   let cacheSpy: jest.SpyInstance; | ||||||
|  |   let dbgSpy: jest.SpyInstance; | ||||||
|  |   let whichSpy: jest.SpyInstance; | ||||||
|  |   let existsSpy: jest.SpyInstance; | ||||||
|  |   let readFileSyncSpy: jest.SpyInstance; | ||||||
|  |   let mkdirpSpy: jest.SpyInstance; | ||||||
|  |   let execSpy: jest.SpyInstance; | ||||||
|  |   let authSpy: jest.SpyInstance; | ||||||
|  |   let parseNodeVersionSpy: jest.SpyInstance; | ||||||
|  |   let isCacheActionAvailable: jest.SpyInstance; | ||||||
|  |   let getExecOutputSpy: jest.SpyInstance; | ||||||
|  |   let getJsonSpy: jest.SpyInstance; | ||||||
|  |  | ||||||
|  |   beforeEach(() => { | ||||||
|  |     // @actions/core | ||||||
|  |     console.log('::stop-commands::stoptoken'); // Disable executing of runner commands when running tests in actions | ||||||
|  |     process.env['GITHUB_PATH'] = ''; // Stub out ENV file functionality so we can verify it writes to standard out | ||||||
|  |     process.env['GITHUB_OUTPUT'] = ''; // Stub out ENV file functionality so we can verify it writes to standard out | ||||||
|  |     inputs = {}; | ||||||
|  |     inSpy = jest.spyOn(core, 'getInput'); | ||||||
|  |     inSpy.mockImplementation(name => inputs[name]); | ||||||
|  |  | ||||||
|  |     // node | ||||||
|  |     os = {}; | ||||||
|  |     platSpy = jest.spyOn(osm, 'platform'); | ||||||
|  |     platSpy.mockImplementation(() => os['platform']); | ||||||
|  |     archSpy = jest.spyOn(osm, 'arch'); | ||||||
|  |     archSpy.mockImplementation(() => os['arch']); | ||||||
|  |     execSpy = jest.spyOn(cp, 'execSync'); | ||||||
|  |  | ||||||
|  |     // @actions/tool-cache | ||||||
|  |     findSpy = jest.spyOn(tc, 'find'); | ||||||
|  |     findAllVersionsSpy = jest.spyOn(tc, 'findAllVersions'); | ||||||
|  |     dlSpy = jest.spyOn(tc, 'downloadTool'); | ||||||
|  |     exSpy = jest.spyOn(tc, 'extractTar'); | ||||||
|  |     cacheSpy = jest.spyOn(tc, 'cacheDir'); | ||||||
|  |     getManifestSpy = jest.spyOn(tc, 'getManifestFromRepo'); | ||||||
|  |  | ||||||
|  |     // http-client | ||||||
|  |     getJsonSpy = jest.spyOn(httpm.HttpClient.prototype, 'getJson'); | ||||||
|  |  | ||||||
|  |     // io | ||||||
|  |     whichSpy = jest.spyOn(io, 'which'); | ||||||
|  |     existsSpy = jest.spyOn(fs, 'existsSync'); | ||||||
|  |     mkdirpSpy = jest.spyOn(io, 'mkdirP'); | ||||||
|  |  | ||||||
|  |     // @actions/tool-cache | ||||||
|  |     isCacheActionAvailable = jest.spyOn(cache, 'isFeatureAvailable'); | ||||||
|  |  | ||||||
|  |     // disable authentication portion for installer tests | ||||||
|  |     authSpy = jest.spyOn(auth, 'configAuthentication'); | ||||||
|  |     authSpy.mockImplementation(() => {}); | ||||||
|  |  | ||||||
|  |     // gets | ||||||
|  |     getManifestSpy.mockImplementation( | ||||||
|  |       () => <tc.IToolRelease[]>nodeTestManifest | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     getJsonSpy.mockImplementation(url => { | ||||||
|  |       let res: any; | ||||||
|  |       if (url.includes('/rc')) { | ||||||
|  |         res = <INodeVersion>nodeTestDistRc; | ||||||
|  |       } else if (url.includes('/nightly')) { | ||||||
|  |         res = <INodeVersion>nodeTestDistNightly; | ||||||
|  |       } else if (url.includes('/v8-canary')) { | ||||||
|  |         res = <INodeVersion>nodeV8CanaryTestDist; | ||||||
|  |       } else { | ||||||
|  |         res = <INodeVersion>nodeTestDist; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       return {result: res}; | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     // writes | ||||||
|  |     cnSpy = jest.spyOn(process.stdout, 'write'); | ||||||
|  |     logSpy = jest.spyOn(core, 'info'); | ||||||
|  |     dbgSpy = jest.spyOn(core, 'debug'); | ||||||
|  |     warningSpy = jest.spyOn(core, 'warning'); | ||||||
|  |     cnSpy.mockImplementation(line => { | ||||||
|  |       // uncomment to debug | ||||||
|  |       // process.stderr.write('write:' + line + '\n'); | ||||||
|  |     }); | ||||||
|  |     logSpy.mockImplementation(line => { | ||||||
|  |       // uncomment to debug | ||||||
|  |       // process.stderr.write('log:' + line + '\n'); | ||||||
|  |     }); | ||||||
|  |     dbgSpy.mockImplementation(msg => { | ||||||
|  |       // uncomment to see debug output | ||||||
|  |       // process.stderr.write(msg + '\n'); | ||||||
|  |     }); | ||||||
|  |     warningSpy.mockImplementation(msg => { | ||||||
|  |       // uncomment to debug | ||||||
|  |       // process.stderr.write('log:' + msg + '\n'); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     // @actions/exec | ||||||
|  |     getExecOutputSpy = jest.spyOn(exec, 'getExecOutput'); | ||||||
|  |     getExecOutputSpy.mockImplementation(() => 'v16.15.0'); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   afterEach(() => { | ||||||
|  |     jest.resetAllMocks(); | ||||||
|  |     jest.clearAllMocks(); | ||||||
|  |     //jest.restoreAllMocks(); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   afterAll(async () => { | ||||||
|  |     console.log('::stoptoken::'); // Re-enable executing of runner commands when running tests in actions | ||||||
|  |     jest.restoreAllMocks(); | ||||||
|  |   }, 100000); | ||||||
|  |  | ||||||
|  |   //-------------------------------------------------- | ||||||
|  |   // Found in cache tests | ||||||
|  |   //-------------------------------------------------- | ||||||
|  |  | ||||||
|  |   it('finds version in cache with stable true', async () => { | ||||||
|  |     inputs['node-version'] = '20-v8-canary'; | ||||||
|  |     os['arch'] = 'x64'; | ||||||
|  |     inputs.stable = 'true'; | ||||||
|  |  | ||||||
|  |     let toolPath = path.normalize( | ||||||
|  |       '/cache/node/20.0.0-v8-canary20221103f7e2421e91/x64' | ||||||
|  |     ); | ||||||
|  |     findSpy.mockImplementation(() => toolPath); | ||||||
|  |     findAllVersionsSpy.mockImplementation(() => [ | ||||||
|  |       '20.0.0-v8-canary20221103f7e2421e91', | ||||||
|  |       '20.0.0-v8-canary20221030fefe1c0879', | ||||||
|  |       '19.0.0-v8-canary202210172ec229fc56', | ||||||
|  |       '20.0.0-v8-canary2022102310ff1e5a8d' | ||||||
|  |     ]); | ||||||
|  |     await main.run(); | ||||||
|  |  | ||||||
|  |     expect(findSpy).toHaveBeenCalledWith( | ||||||
|  |       'node', | ||||||
|  |       '20.0.0-v8-canary20221103f7e2421e91', | ||||||
|  |       'x64' | ||||||
|  |     ); | ||||||
|  |     expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('finds version in cache and adds it to the path', async () => { | ||||||
|  |     inputs['node-version'] = '20-v8-canary'; | ||||||
|  |     os['arch'] = 'x64'; | ||||||
|  |  | ||||||
|  |     inSpy.mockImplementation(name => inputs[name]); | ||||||
|  |  | ||||||
|  |     let toolPath = path.normalize( | ||||||
|  |       '/cache/node/20.0.0-v8-canary20221103f7e2421e91/x64' | ||||||
|  |     ); | ||||||
|  |     findSpy.mockImplementation(() => toolPath); | ||||||
|  |     findAllVersionsSpy.mockImplementation(() => [ | ||||||
|  |       '20.0.0-v8-canary20221103f7e2421e91', | ||||||
|  |       '20.0.0-v8-canary20221030fefe1c0879', | ||||||
|  |       '19.0.0-v8-canary202210172ec229fc56', | ||||||
|  |       '20.0.0-v8-canary2022102310ff1e5a8d' | ||||||
|  |     ]); | ||||||
|  |     await main.run(); | ||||||
|  |  | ||||||
|  |     let expPath = path.join(toolPath, 'bin'); | ||||||
|  |     expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('handles unhandled find error and reports error', async () => { | ||||||
|  |     os.platform = 'linux'; | ||||||
|  |     let errMsg = 'unhandled error message'; | ||||||
|  |     inputs['node-version'] = '20.0.0-v8-canary20221103f7e2421e91'; | ||||||
|  |  | ||||||
|  |     findSpy.mockImplementation(() => { | ||||||
|  |       throw new Error(errMsg); | ||||||
|  |     }); | ||||||
|  |     findAllVersionsSpy.mockImplementation(() => [ | ||||||
|  |       '20.0.0-v8-canary20221103f7e2421e91', | ||||||
|  |       '20.0.0-v8-canary20221030fefe1c0879', | ||||||
|  |       '19.0.0-v8-canary202210172ec229fc56', | ||||||
|  |       '20.0.0-v8-canary2022102310ff1e5a8d' | ||||||
|  |     ]); | ||||||
|  |  | ||||||
|  |     await main.run(); | ||||||
|  |  | ||||||
|  |     expect(cnSpy).toHaveBeenCalledWith('::error::' + errMsg + osm.EOL); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   //-------------------------------------------------- | ||||||
|  |   // Manifest tests | ||||||
|  |   //-------------------------------------------------- | ||||||
|  |   it('falls back to a version from node dist', async () => { | ||||||
|  |     os.platform = 'linux'; | ||||||
|  |     os.arch = 'x64'; | ||||||
|  |  | ||||||
|  |     // a version which is not in the manifest but is in node dist | ||||||
|  |     let versionSpec = '11.15.0'; | ||||||
|  |  | ||||||
|  |     inputs['node-version'] = versionSpec; | ||||||
|  |     inputs['always-auth'] = false; | ||||||
|  |     inputs['token'] = 'faketoken'; | ||||||
|  |  | ||||||
|  |     // ... but not in the local cache | ||||||
|  |     findSpy.mockImplementation(() => ''); | ||||||
|  |  | ||||||
|  |     dlSpy.mockImplementation(async () => '/some/temp/path'); | ||||||
|  |     let toolPath = path.normalize('/cache/node/11.11.0/x64'); | ||||||
|  |     exSpy.mockImplementation(async () => '/some/other/temp/path'); | ||||||
|  |     cacheSpy.mockImplementation(async () => toolPath); | ||||||
|  |  | ||||||
|  |     await main.run(); | ||||||
|  |  | ||||||
|  |     let expPath = path.join(toolPath, 'bin'); | ||||||
|  |  | ||||||
|  |     expect(dlSpy).toHaveBeenCalled(); | ||||||
|  |     expect(exSpy).toHaveBeenCalled(); | ||||||
|  |     expect(logSpy).toHaveBeenCalledWith( | ||||||
|  |       'Not found in manifest. Falling back to download directly from Node' | ||||||
|  |     ); | ||||||
|  |     expect(logSpy).toHaveBeenCalledWith( | ||||||
|  |       `Attempting to download ${versionSpec}...` | ||||||
|  |     ); | ||||||
|  |     expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('does not find a version that does not exist', async () => { | ||||||
|  |     os.platform = 'linux'; | ||||||
|  |     os.arch = 'x64'; | ||||||
|  |  | ||||||
|  |     let versionSpec = '23.0.0-v8-canary20221103f7e2421e91'; | ||||||
|  |     inputs['node-version'] = versionSpec; | ||||||
|  |  | ||||||
|  |     findSpy.mockImplementation(() => ''); | ||||||
|  |     findAllVersionsSpy.mockImplementation(() => [ | ||||||
|  |       '20.0.0-v8-canary20221103f7e2421e91', | ||||||
|  |       '20.0.0-v8-canary20221030fefe1c0879', | ||||||
|  |       '19.0.0-v8-canary202210172ec229fc56', | ||||||
|  |       '20.0.0-v8-canary2022102310ff1e5a8d' | ||||||
|  |     ]); | ||||||
|  |     await main.run(); | ||||||
|  |  | ||||||
|  |     expect(cnSpy).toHaveBeenCalledWith( | ||||||
|  |       `::error::Unable to find Node version '${versionSpec}' for platform ${os.platform} and architecture ${os.arch}.${osm.EOL}` | ||||||
|  |     ); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('reports a failed download', async () => { | ||||||
|  |     let errMsg = 'unhandled download message'; | ||||||
|  |     os.platform = 'linux'; | ||||||
|  |     os.arch = 'x64'; | ||||||
|  |  | ||||||
|  |     // a version which is in the manifest | ||||||
|  |     let versionSpec = '19.0.0-v8-canary'; | ||||||
|  |  | ||||||
|  |     inputs['node-version'] = versionSpec; | ||||||
|  |     inputs['always-auth'] = false; | ||||||
|  |     inputs['token'] = 'faketoken'; | ||||||
|  |  | ||||||
|  |     findSpy.mockImplementation(() => ''); | ||||||
|  |     findAllVersionsSpy.mockImplementation(() => [ | ||||||
|  |       '20.0.0-v8-canary20221103f7e2421e91', | ||||||
|  |       '20.0.0-v8-canary20221030fefe1c0879', | ||||||
|  |       '20.0.0-v8-canary2022102310ff1e5a8d' | ||||||
|  |     ]); | ||||||
|  |     dlSpy.mockImplementation(() => { | ||||||
|  |       throw new Error(errMsg); | ||||||
|  |     }); | ||||||
|  |     await main.run(); | ||||||
|  |  | ||||||
|  |     expect(cnSpy).toHaveBeenCalledWith(`::error::${errMsg}${osm.EOL}`); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('acquires specified architecture of node', async () => { | ||||||
|  |     for (const {arch, version, osSpec} of [ | ||||||
|  |       { | ||||||
|  |         arch: 'x86', | ||||||
|  |         version: '20.0.0-v8-canary20221022e83bcb6c41', | ||||||
|  |         osSpec: 'win32' | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         arch: 'x86', | ||||||
|  |         version: '20.0.0-v8-canary20221103f7e2421e91', | ||||||
|  |         osSpec: 'win32' | ||||||
|  |       } | ||||||
|  |     ]) { | ||||||
|  |       os.platform = osSpec; | ||||||
|  |       os.arch = arch; | ||||||
|  |       const fileExtension = os.platform === 'win32' ? '7z' : 'tar.gz'; | ||||||
|  |       const platform = { | ||||||
|  |         linux: 'linux', | ||||||
|  |         darwin: 'darwin', | ||||||
|  |         win32: 'win' | ||||||
|  |       }[os.platform]; | ||||||
|  |  | ||||||
|  |       inputs['node-version'] = version; | ||||||
|  |       inputs['architecture'] = arch; | ||||||
|  |       inputs['always-auth'] = false; | ||||||
|  |       inputs['token'] = 'faketoken'; | ||||||
|  |  | ||||||
|  |       let expectedUrl = `https://nodejs.org/download/v8-canary/v${version}/node-v${version}-${platform}-${arch}.${fileExtension}`; | ||||||
|  |  | ||||||
|  |       // ... but not in the local cache | ||||||
|  |       findSpy.mockImplementation(() => ''); | ||||||
|  |       findAllVersionsSpy.mockImplementation(() => []); | ||||||
|  |  | ||||||
|  |       dlSpy.mockImplementation(async () => '/some/temp/path'); | ||||||
|  |       let toolPath = path.normalize(`/cache/node/${version}/${arch}`); | ||||||
|  |       exSpy.mockImplementation(async () => '/some/other/temp/path'); | ||||||
|  |       cacheSpy.mockImplementation(async () => toolPath); | ||||||
|  |  | ||||||
|  |       await main.run(); | ||||||
|  |       expect(dlSpy).toHaveBeenCalled(); | ||||||
|  |       expect(logSpy).toHaveBeenCalledWith( | ||||||
|  |         `Acquiring ${version} - ${arch} from ${expectedUrl}` | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |   }, 100000); | ||||||
|  |  | ||||||
|  |   describe('nightly versions', () => { | ||||||
|  |     it.each([ | ||||||
|  |       [ | ||||||
|  |         '20.0.0-v8-canary', | ||||||
|  |         '20.0.0-v8-canary20221103f7e2421e91', | ||||||
|  |         'https://nodejs.org/download/v8-canary/v20.0.0-v8-canary20221103f7e2421e91/node-v20.0.0-v8-canary20221103f7e2421e91-linux-x64.tar.gz' | ||||||
|  |       ], | ||||||
|  |       [ | ||||||
|  |         '20-v8-canary', | ||||||
|  |         '20.0.0-v8-canary20221103f7e2421e91', | ||||||
|  |         'https://nodejs.org/download/v8-canary/v20.0.0-v8-canary20221103f7e2421e91/node-v20.0.0-v8-canary20221103f7e2421e91-linux-x64.tar.gz' | ||||||
|  |       ], | ||||||
|  |       [ | ||||||
|  |         '19.0.0-v8-canary', | ||||||
|  |         '19.0.0-v8-canary202210187d6960f23f', | ||||||
|  |         'https://nodejs.org/download/v8-canary/v19.0.0-v8-canary202210187d6960f23f/node-v19.0.0-v8-canary202210187d6960f23f-linux-x64.tar.gz' | ||||||
|  |       ], | ||||||
|  |       [ | ||||||
|  |         '19-v8-canary', | ||||||
|  |         '19.0.0-v8-canary202210187d6960f23f', | ||||||
|  |         'https://nodejs.org/download/v8-canary/v19.0.0-v8-canary202210187d6960f23f/node-v19.0.0-v8-canary202210187d6960f23f-linux-x64.tar.gz' | ||||||
|  |       ], | ||||||
|  |       [ | ||||||
|  |         '19.0.0-v8-canary202210187d6960f23f', | ||||||
|  |         '19.0.0-v8-canary202210187d6960f23f', | ||||||
|  |         'https://nodejs.org/download/v8-canary/v19.0.0-v8-canary202210187d6960f23f/node-v19.0.0-v8-canary202210187d6960f23f-linux-x64.tar.gz' | ||||||
|  |       ] | ||||||
|  |     ])( | ||||||
|  |       'finds the versions in the index.json and installs it', | ||||||
|  |       async (input, expectedVersion, expectedUrl) => { | ||||||
|  |         const toolPath = path.normalize(`/cache/node/${expectedVersion}/x64`); | ||||||
|  |  | ||||||
|  |         findSpy.mockImplementation(() => ''); | ||||||
|  |         findAllVersionsSpy.mockImplementation(() => []); | ||||||
|  |         dlSpy.mockImplementation(async () => '/some/temp/path'); | ||||||
|  |         exSpy.mockImplementation(async () => '/some/other/temp/path'); | ||||||
|  |         cacheSpy.mockImplementation(async () => toolPath); | ||||||
|  |  | ||||||
|  |         inputs['node-version'] = input; | ||||||
|  |         os['arch'] = 'x64'; | ||||||
|  |         os['platform'] = 'linux'; | ||||||
|  |         // act | ||||||
|  |         await main.run(); | ||||||
|  |  | ||||||
|  |         // assert | ||||||
|  |         expect(logSpy).toHaveBeenCalledWith( | ||||||
|  |           `Acquiring ${expectedVersion} - ${os.arch} from ${expectedUrl}` | ||||||
|  |         ); | ||||||
|  |         expect(logSpy).toHaveBeenCalledWith('Extracting ...'); | ||||||
|  |         expect(logSpy).toHaveBeenCalledWith('Adding to the cache ...'); | ||||||
|  |         expect(cnSpy).toHaveBeenCalledWith( | ||||||
|  |           `::add-path::${path.join(toolPath, 'bin')}${osm.EOL}` | ||||||
|  |         ); | ||||||
|  |       } | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     it.each([ | ||||||
|  |       [ | ||||||
|  |         '20.0.0-v8-canary20221103f7e2421e91', | ||||||
|  |         '20.0.0-v8-canary20221103f7e2421e91' | ||||||
|  |       ], | ||||||
|  |       ['20.0.0-v8-canary', '20.0.0-v8-canary20221103f7e2421e91'], | ||||||
|  |       ['20-v8-canary', '20.0.0-v8-canary20221103f7e2421e91'] | ||||||
|  |     ])( | ||||||
|  |       'finds the %s version in the hostedToolcache', | ||||||
|  |       async (input, expectedVersion) => { | ||||||
|  |         const toolPath = path.normalize(`/cache/node/${expectedVersion}/x64`); | ||||||
|  |         findSpy.mockReturnValue(toolPath); | ||||||
|  |         findAllVersionsSpy.mockReturnValue([ | ||||||
|  |           '20.0.0-v8-canary20221103f7e2421e91', | ||||||
|  |           '20.0.0-v8-canary20221030fefe1c0879', | ||||||
|  |           '19.0.0-v8-canary202210172ec229fc56', | ||||||
|  |           '20.0.0-v8-canary2022102310ff1e5a8d' | ||||||
|  |         ]); | ||||||
|  |  | ||||||
|  |         inputs['node-version'] = input; | ||||||
|  |         os['arch'] = 'x64'; | ||||||
|  |         os['platform'] = 'linux'; | ||||||
|  |  | ||||||
|  |         // act | ||||||
|  |         await main.run(); | ||||||
|  |  | ||||||
|  |         // assert | ||||||
|  |         expect(findAllVersionsSpy).toHaveBeenCalled(); | ||||||
|  |         expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`); | ||||||
|  |         expect(cnSpy).toHaveBeenCalledWith( | ||||||
|  |           `::add-path::${path.join(toolPath, 'bin')}${osm.EOL}` | ||||||
|  |         ); | ||||||
|  |       } | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     it.each([ | ||||||
|  |       [ | ||||||
|  |         '20.0.0-v8-canary', | ||||||
|  |         '20.0.0-v8-canary20221103f7e2421e91', | ||||||
|  |         '20.0.0-v8-canary20221030fefe1c0879', | ||||||
|  |         'https://nodejs.org/download/v8-canary/v20.0.0-v8-canary20221103f7e2421e91/node-v20.0.0-v8-canary20221103f7e2421e91-linux-x64.tar.gz' | ||||||
|  |       ], | ||||||
|  |       [ | ||||||
|  |         '20-v8-canary', | ||||||
|  |         '20.0.0-v8-canary20221103f7e2421e91', | ||||||
|  |         '20.0.0-v8-canary20221030fefe1c0879', | ||||||
|  |         'https://nodejs.org/download/v8-canary/v20.0.0-v8-canary20221103f7e2421e91/node-v20.0.0-v8-canary20221103f7e2421e91-linux-x64.tar.gz' | ||||||
|  |       ], | ||||||
|  |       [ | ||||||
|  |         '19.0.0-v8-canary', | ||||||
|  |         '19.0.0-v8-canary202210187d6960f23f', | ||||||
|  |         '19.0.0-v8-canary202210172ec229fc56', | ||||||
|  |         'https://nodejs.org/download/v8-canary/v19.0.0-v8-canary202210187d6960f23f/node-v19.0.0-v8-canary202210187d6960f23f-linux-x64.tar.gz' | ||||||
|  |       ], | ||||||
|  |       [ | ||||||
|  |         '19-v8-canary', | ||||||
|  |         '19.0.0-v8-canary202210187d6960f23f', | ||||||
|  |         '19.0.0-v8-canary202210172ec229fc56', | ||||||
|  |         'https://nodejs.org/download/v8-canary/v19.0.0-v8-canary202210187d6960f23f/node-v19.0.0-v8-canary202210187d6960f23f-linux-x64.tar.gz' | ||||||
|  |       ] | ||||||
|  |     ])( | ||||||
|  |       'get %s version from dist if check-latest is true', | ||||||
|  |       async (input, expectedVersion, foundVersion, expectedUrl) => { | ||||||
|  |         const foundToolPath = path.normalize(`/cache/node/${foundVersion}/x64`); | ||||||
|  |         const toolPath = path.normalize(`/cache/node/${expectedVersion}/x64`); | ||||||
|  |  | ||||||
|  |         inputs['node-version'] = input; | ||||||
|  |         inputs['check-latest'] = 'true'; | ||||||
|  |         os['arch'] = 'x64'; | ||||||
|  |         os['platform'] = 'linux'; | ||||||
|  |  | ||||||
|  |         findSpy.mockReturnValue(foundToolPath); | ||||||
|  |         findAllVersionsSpy.mockReturnValue([ | ||||||
|  |           '20.0.0-v8-canary20221030fefe1c0879', | ||||||
|  |           '19.0.0-v8-canary202210172ec229fc56', | ||||||
|  |           '20.0.0-v8-canary2022102310ff1e5a8d' | ||||||
|  |         ]); | ||||||
|  |         dlSpy.mockImplementation(async () => '/some/temp/path'); | ||||||
|  |         exSpy.mockImplementation(async () => '/some/other/temp/path'); | ||||||
|  |         cacheSpy.mockImplementation(async () => toolPath); | ||||||
|  |  | ||||||
|  |         // act | ||||||
|  |         await main.run(); | ||||||
|  |  | ||||||
|  |         // assert | ||||||
|  |         expect(findAllVersionsSpy).toHaveBeenCalled(); | ||||||
|  |         expect(logSpy).toHaveBeenCalledWith( | ||||||
|  |           `Acquiring ${expectedVersion} - ${os.arch} from ${expectedUrl}` | ||||||
|  |         ); | ||||||
|  |         expect(logSpy).toHaveBeenCalledWith('Extracting ...'); | ||||||
|  |         expect(logSpy).toHaveBeenCalledWith('Adding to the cache ...'); | ||||||
|  |         expect(cnSpy).toHaveBeenCalledWith( | ||||||
|  |           `::add-path::${path.join(toolPath, 'bin')}${osm.EOL}` | ||||||
|  |         ); | ||||||
|  |       } | ||||||
|  |     ); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   describe('setup-node v8 canary tests', () => { | ||||||
|  |     it('v8 canary setup node flow with cached', async () => { | ||||||
|  |       let versionSpec = 'v20-v8-canary'; | ||||||
|  |  | ||||||
|  |       inputs['node-version'] = versionSpec; | ||||||
|  |       inputs['always-auth'] = false; | ||||||
|  |       inputs['token'] = 'faketoken'; | ||||||
|  |  | ||||||
|  |       os.platform = 'linux'; | ||||||
|  |       os.arch = 'x64'; | ||||||
|  |  | ||||||
|  |       const versionExpected = 'v20.0.0-v8-canary20221103f7e2421e91'; | ||||||
|  |       findAllVersionsSpy.mockImplementation(() => [versionExpected]); | ||||||
|  |  | ||||||
|  |       const toolPath = path.normalize(`/cache/node/${versionExpected}/x64`); | ||||||
|  |       findSpy.mockImplementation(version => toolPath); | ||||||
|  |  | ||||||
|  |       await main.run(); | ||||||
|  |  | ||||||
|  |       expect(cnSpy).toHaveBeenCalledWith( | ||||||
|  |         `::add-path::${toolPath}${path.sep}bin${osm.EOL}` | ||||||
|  |       ); | ||||||
|  |  | ||||||
|  |       expect(dlSpy).not.toHaveBeenCalled(); | ||||||
|  |       expect(exSpy).not.toHaveBeenCalled(); | ||||||
|  |       expect(cacheSpy).not.toHaveBeenCalled(); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
							
								
								
									
										537
									
								
								__tests__/data/v8-canary-dist-index.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										537
									
								
								__tests__/data/v8-canary-dist-index.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,537 @@ | |||||||
|  | [ | ||||||
|  |   { | ||||||
|  |     "version": "v20.0.0-v8-canary20221103f7e2421e91", | ||||||
|  |     "date": "2022-11-03", | ||||||
|  |     "files": [ | ||||||
|  |       "headers", | ||||||
|  |       "linux-arm64", | ||||||
|  |       "linux-armv7l", | ||||||
|  |       "linux-ppc64le", | ||||||
|  |       "linux-s390x", | ||||||
|  |       "linux-x64", | ||||||
|  |       "osx-arm64-tar", | ||||||
|  |       "osx-x64-pkg", | ||||||
|  |       "osx-x64-tar", | ||||||
|  |       "src", | ||||||
|  |       "win-x64-7z", | ||||||
|  |       "win-x64-exe", | ||||||
|  |       "win-x64-msi", | ||||||
|  |       "win-x64-zip", | ||||||
|  |       "win-x86-7z", | ||||||
|  |       "win-x86-exe", | ||||||
|  |       "win-x86-msi", | ||||||
|  |       "win-x86-zip" | ||||||
|  |     ], | ||||||
|  |     "npm": "8.19.2", | ||||||
|  |     "v8": "10.9.138.0", | ||||||
|  |     "uv": "1.43.0", | ||||||
|  |     "zlib": "1.2.11", | ||||||
|  |     "openssl": "3.0.5+quic", | ||||||
|  |     "modules": "112", | ||||||
|  |     "lts": false, | ||||||
|  |     "security": false | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     "version": "v20.0.0-v8-canary202211026bf85d0fb4", | ||||||
|  |     "date": "2022-11-02", | ||||||
|  |     "files": [ | ||||||
|  |       "headers", | ||||||
|  |       "linux-arm64", | ||||||
|  |       "linux-armv7l", | ||||||
|  |       "linux-ppc64le", | ||||||
|  |       "linux-s390x", | ||||||
|  |       "linux-x64", | ||||||
|  |       "osx-arm64-tar", | ||||||
|  |       "osx-x64-pkg", | ||||||
|  |       "osx-x64-tar", | ||||||
|  |       "src", | ||||||
|  |       "win-x64-7z", | ||||||
|  |       "win-x64-exe", | ||||||
|  |       "win-x64-msi", | ||||||
|  |       "win-x64-zip", | ||||||
|  |       "win-x86-7z", | ||||||
|  |       "win-x86-exe", | ||||||
|  |       "win-x86-msi", | ||||||
|  |       "win-x86-zip" | ||||||
|  |     ], | ||||||
|  |     "npm": "8.19.2", | ||||||
|  |     "v8": "10.9.130.0", | ||||||
|  |     "uv": "1.43.0", | ||||||
|  |     "zlib": "1.2.11", | ||||||
|  |     "openssl": "3.0.5+quic", | ||||||
|  |     "modules": "112", | ||||||
|  |     "lts": false, | ||||||
|  |     "security": false | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     "version": "v20.0.0-v8-canary20221101e50e45c9f8", | ||||||
|  |     "date": "2022-11-01", | ||||||
|  |     "files": [ | ||||||
|  |       "headers", | ||||||
|  |       "linux-arm64", | ||||||
|  |       "linux-armv7l", | ||||||
|  |       "linux-ppc64le", | ||||||
|  |       "linux-s390x", | ||||||
|  |       "linux-x64", | ||||||
|  |       "osx-arm64-tar", | ||||||
|  |       "osx-x64-tar", | ||||||
|  |       "src", | ||||||
|  |       "win-x64-7z", | ||||||
|  |       "win-x64-exe", | ||||||
|  |       "win-x64-msi", | ||||||
|  |       "win-x64-zip", | ||||||
|  |       "win-x86-7z", | ||||||
|  |       "win-x86-exe", | ||||||
|  |       "win-x86-msi", | ||||||
|  |       "win-x86-zip" | ||||||
|  |     ], | ||||||
|  |     "npm": "8.19.2", | ||||||
|  |     "v8": "10.9.129.0", | ||||||
|  |     "uv": "1.43.0", | ||||||
|  |     "zlib": "1.2.11", | ||||||
|  |     "openssl": "3.0.5+quic", | ||||||
|  |     "modules": "112", | ||||||
|  |     "lts": false, | ||||||
|  |     "security": false | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     "version": "v20.0.0-v8-canary202210311b1e675ad0", | ||||||
|  |     "date": "2022-10-31", | ||||||
|  |     "files": [ | ||||||
|  |       "headers", | ||||||
|  |       "linux-arm64", | ||||||
|  |       "linux-armv7l", | ||||||
|  |       "linux-ppc64le", | ||||||
|  |       "linux-s390x", | ||||||
|  |       "linux-x64", | ||||||
|  |       "osx-arm64-tar", | ||||||
|  |       "osx-x64-tar", | ||||||
|  |       "src", | ||||||
|  |       "win-x64-7z", | ||||||
|  |       "win-x64-exe", | ||||||
|  |       "win-x64-msi", | ||||||
|  |       "win-x64-zip", | ||||||
|  |       "win-x86-7z", | ||||||
|  |       "win-x86-exe", | ||||||
|  |       "win-x86-msi", | ||||||
|  |       "win-x86-zip" | ||||||
|  |     ], | ||||||
|  |     "npm": "8.19.2", | ||||||
|  |     "v8": "10.9.125.0", | ||||||
|  |     "uv": "1.43.0", | ||||||
|  |     "zlib": "1.2.11", | ||||||
|  |     "openssl": "3.0.5+quic", | ||||||
|  |     "modules": "112", | ||||||
|  |     "lts": false, | ||||||
|  |     "security": false | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     "version": "v20.0.0-v8-canary20221030fefe1c0879", | ||||||
|  |     "date": "2022-10-30", | ||||||
|  |     "files": [ | ||||||
|  |       "headers", | ||||||
|  |       "linux-arm64", | ||||||
|  |       "linux-armv7l", | ||||||
|  |       "linux-ppc64le", | ||||||
|  |       "linux-s390x", | ||||||
|  |       "linux-x64", | ||||||
|  |       "osx-arm64-tar", | ||||||
|  |       "osx-x64-pkg", | ||||||
|  |       "osx-x64-tar", | ||||||
|  |       "src", | ||||||
|  |       "win-x64-7z", | ||||||
|  |       "win-x64-exe", | ||||||
|  |       "win-x64-msi", | ||||||
|  |       "win-x64-zip", | ||||||
|  |       "win-x86-7z", | ||||||
|  |       "win-x86-exe", | ||||||
|  |       "win-x86-msi", | ||||||
|  |       "win-x86-zip" | ||||||
|  |     ], | ||||||
|  |     "npm": "8.19.2", | ||||||
|  |     "v8": "10.9.125.0", | ||||||
|  |     "uv": "1.43.0", | ||||||
|  |     "zlib": "1.2.11", | ||||||
|  |     "openssl": "3.0.5+quic", | ||||||
|  |     "modules": "112", | ||||||
|  |     "lts": false, | ||||||
|  |     "security": false | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     "version": "v20.0.0-v8-canary202210293881e51ba2", | ||||||
|  |     "date": "2022-10-29", | ||||||
|  |     "files": [ | ||||||
|  |       "headers", | ||||||
|  |       "linux-arm64", | ||||||
|  |       "linux-armv7l", | ||||||
|  |       "linux-ppc64le", | ||||||
|  |       "linux-s390x", | ||||||
|  |       "linux-x64", | ||||||
|  |       "osx-arm64-tar", | ||||||
|  |       "osx-x64-pkg", | ||||||
|  |       "osx-x64-tar", | ||||||
|  |       "src", | ||||||
|  |       "win-x64-7z", | ||||||
|  |       "win-x64-exe", | ||||||
|  |       "win-x64-msi", | ||||||
|  |       "win-x64-zip", | ||||||
|  |       "win-x86-7z", | ||||||
|  |       "win-x86-exe", | ||||||
|  |       "win-x86-msi", | ||||||
|  |       "win-x86-zip" | ||||||
|  |     ], | ||||||
|  |     "npm": "8.19.2", | ||||||
|  |     "v8": "10.9.122.0", | ||||||
|  |     "uv": "1.43.0", | ||||||
|  |     "zlib": "1.2.11", | ||||||
|  |     "openssl": "3.0.5+quic", | ||||||
|  |     "modules": "112", | ||||||
|  |     "lts": false, | ||||||
|  |     "security": false | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     "version": "v20.0.0-v8-canary202210286fe49d2a49", | ||||||
|  |     "date": "2022-10-28", | ||||||
|  |     "files": [ | ||||||
|  |       "osx-arm64-tar", | ||||||
|  |       "osx-x64-pkg", | ||||||
|  |       "osx-x64-tar", | ||||||
|  |       "win-x64-7z", | ||||||
|  |       "win-x64-exe", | ||||||
|  |       "win-x64-msi", | ||||||
|  |       "win-x64-zip", | ||||||
|  |       "win-x86-7z", | ||||||
|  |       "win-x86-exe", | ||||||
|  |       "win-x86-msi", | ||||||
|  |       "win-x86-zip" | ||||||
|  |     ], | ||||||
|  |     "npm": "8.19.2", | ||||||
|  |     "v8": "10.9.112.0", | ||||||
|  |     "uv": "1.43.0", | ||||||
|  |     "zlib": "1.2.11", | ||||||
|  |     "openssl": "3.0.5+quic", | ||||||
|  |     "modules": "112", | ||||||
|  |     "lts": false, | ||||||
|  |     "security": false | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     "version": "v20.0.0-v8-canary20221027c470b3108c", | ||||||
|  |     "date": "2022-10-27", | ||||||
|  |     "files": [ | ||||||
|  |       "headers", | ||||||
|  |       "linux-arm64", | ||||||
|  |       "linux-armv7l", | ||||||
|  |       "linux-ppc64le", | ||||||
|  |       "linux-s390x", | ||||||
|  |       "linux-x64", | ||||||
|  |       "osx-arm64-tar", | ||||||
|  |       "osx-x64-pkg", | ||||||
|  |       "osx-x64-tar", | ||||||
|  |       "src", | ||||||
|  |       "win-x64-7z", | ||||||
|  |       "win-x64-exe", | ||||||
|  |       "win-x64-msi", | ||||||
|  |       "win-x64-zip", | ||||||
|  |       "win-x86-7z", | ||||||
|  |       "win-x86-exe", | ||||||
|  |       "win-x86-msi", | ||||||
|  |       "win-x86-zip" | ||||||
|  |     ], | ||||||
|  |     "npm": "8.19.2", | ||||||
|  |     "v8": "10.9.101.0", | ||||||
|  |     "uv": "1.43.0", | ||||||
|  |     "zlib": "1.2.11", | ||||||
|  |     "openssl": "3.0.5+quic", | ||||||
|  |     "modules": "112", | ||||||
|  |     "lts": false, | ||||||
|  |     "security": false | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     "version": "v20.0.0-v8-canary20221026c24f7d1e4a", | ||||||
|  |     "date": "2022-10-26", | ||||||
|  |     "files": [ | ||||||
|  |       "headers", | ||||||
|  |       "linux-arm64", | ||||||
|  |       "linux-armv7l", | ||||||
|  |       "linux-ppc64le", | ||||||
|  |       "linux-s390x", | ||||||
|  |       "linux-x64", | ||||||
|  |       "osx-arm64-tar", | ||||||
|  |       "osx-x64-pkg", | ||||||
|  |       "osx-x64-tar", | ||||||
|  |       "src", | ||||||
|  |       "win-x64-7z", | ||||||
|  |       "win-x64-exe", | ||||||
|  |       "win-x64-msi", | ||||||
|  |       "win-x64-zip", | ||||||
|  |       "win-x86-7z", | ||||||
|  |       "win-x86-exe", | ||||||
|  |       "win-x86-msi", | ||||||
|  |       "win-x86-zip" | ||||||
|  |     ], | ||||||
|  |     "npm": "8.19.2", | ||||||
|  |     "v8": "10.9.88.0", | ||||||
|  |     "uv": "1.43.0", | ||||||
|  |     "zlib": "1.2.11", | ||||||
|  |     "openssl": "3.0.5+quic", | ||||||
|  |     "modules": "112", | ||||||
|  |     "lts": false, | ||||||
|  |     "security": false | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     "version": "v20.0.0-v8-canary20221025b063237e20", | ||||||
|  |     "date": "2022-10-25", | ||||||
|  |     "files": [ | ||||||
|  |       "headers", | ||||||
|  |       "linux-arm64", | ||||||
|  |       "linux-armv7l", | ||||||
|  |       "linux-ppc64le", | ||||||
|  |       "linux-x64", | ||||||
|  |       "osx-arm64-tar", | ||||||
|  |       "osx-x64-pkg", | ||||||
|  |       "osx-x64-tar", | ||||||
|  |       "src", | ||||||
|  |       "win-x64-7z", | ||||||
|  |       "win-x64-exe", | ||||||
|  |       "win-x64-msi", | ||||||
|  |       "win-x64-zip", | ||||||
|  |       "win-x86-7z", | ||||||
|  |       "win-x86-exe", | ||||||
|  |       "win-x86-msi", | ||||||
|  |       "win-x86-zip" | ||||||
|  |     ], | ||||||
|  |     "npm": "8.19.2", | ||||||
|  |     "v8": "10.9.73.0", | ||||||
|  |     "uv": "1.43.0", | ||||||
|  |     "zlib": "1.2.11", | ||||||
|  |     "openssl": "3.0.5+quic", | ||||||
|  |     "modules": "112", | ||||||
|  |     "lts": false, | ||||||
|  |     "security": false | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     "version": "v20.0.0-v8-canary2022102454996f930f", | ||||||
|  |     "date": "2022-10-24", | ||||||
|  |     "files": [ | ||||||
|  |       "headers", | ||||||
|  |       "linux-arm64", | ||||||
|  |       "linux-armv7l", | ||||||
|  |       "linux-ppc64le", | ||||||
|  |       "linux-x64", | ||||||
|  |       "osx-arm64-tar", | ||||||
|  |       "osx-x64-pkg", | ||||||
|  |       "osx-x64-tar", | ||||||
|  |       "src", | ||||||
|  |       "win-x64-7z", | ||||||
|  |       "win-x64-exe", | ||||||
|  |       "win-x64-msi", | ||||||
|  |       "win-x64-zip", | ||||||
|  |       "win-x86-7z", | ||||||
|  |       "win-x86-exe", | ||||||
|  |       "win-x86-msi", | ||||||
|  |       "win-x86-zip" | ||||||
|  |     ], | ||||||
|  |     "npm": "8.19.2", | ||||||
|  |     "v8": "10.9.61.0", | ||||||
|  |     "uv": "1.43.0", | ||||||
|  |     "zlib": "1.2.11", | ||||||
|  |     "openssl": "3.0.5+quic", | ||||||
|  |     "modules": "112", | ||||||
|  |     "lts": false, | ||||||
|  |     "security": false | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     "version": "v20.0.0-v8-canary2022102310ff1e5a8d", | ||||||
|  |     "date": "2022-10-23", | ||||||
|  |     "files": [ | ||||||
|  |       "headers", | ||||||
|  |       "linux-arm64", | ||||||
|  |       "linux-armv7l", | ||||||
|  |       "linux-ppc64le", | ||||||
|  |       "linux-x64", | ||||||
|  |       "osx-arm64-tar", | ||||||
|  |       "osx-x64-tar", | ||||||
|  |       "src", | ||||||
|  |       "win-x64-7z", | ||||||
|  |       "win-x64-exe", | ||||||
|  |       "win-x64-msi", | ||||||
|  |       "win-x64-zip", | ||||||
|  |       "win-x86-7z", | ||||||
|  |       "win-x86-exe", | ||||||
|  |       "win-x86-msi", | ||||||
|  |       "win-x86-zip" | ||||||
|  |     ], | ||||||
|  |     "npm": "8.19.2", | ||||||
|  |     "v8": "10.9.61.0", | ||||||
|  |     "uv": "1.43.0", | ||||||
|  |     "zlib": "1.2.11", | ||||||
|  |     "openssl": "3.0.5+quic", | ||||||
|  |     "modules": "112", | ||||||
|  |     "lts": false, | ||||||
|  |     "security": false | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     "version": "v20.0.0-v8-canary20221022e83bcb6c41", | ||||||
|  |     "date": "2022-10-22", | ||||||
|  |     "files": [ | ||||||
|  |       "headers", | ||||||
|  |       "linux-arm64", | ||||||
|  |       "linux-armv7l", | ||||||
|  |       "linux-x64", | ||||||
|  |       "osx-arm64-tar", | ||||||
|  |       "osx-x64-tar", | ||||||
|  |       "src", | ||||||
|  |       "win-x64-7z", | ||||||
|  |       "win-x64-exe", | ||||||
|  |       "win-x64-msi", | ||||||
|  |       "win-x64-zip", | ||||||
|  |       "win-x86-7z", | ||||||
|  |       "win-x86-exe", | ||||||
|  |       "win-x86-msi", | ||||||
|  |       "win-x86-zip" | ||||||
|  |     ], | ||||||
|  |     "npm": "8.19.2", | ||||||
|  |     "v8": "10.9.60.0", | ||||||
|  |     "uv": "1.43.0", | ||||||
|  |     "zlib": "1.2.11", | ||||||
|  |     "openssl": "3.0.5+quic", | ||||||
|  |     "modules": "112", | ||||||
|  |     "lts": false, | ||||||
|  |     "security": false | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     "version": "v20.0.0-v8-canary20221021f6d5f347fa", | ||||||
|  |     "date": "2022-10-21", | ||||||
|  |     "files": [ | ||||||
|  |       "headers", | ||||||
|  |       "linux-arm64", | ||||||
|  |       "linux-armv7l", | ||||||
|  |       "linux-x64", | ||||||
|  |       "osx-arm64-tar", | ||||||
|  |       "osx-x64-tar", | ||||||
|  |       "src", | ||||||
|  |       "win-x64-7z", | ||||||
|  |       "win-x64-exe", | ||||||
|  |       "win-x64-msi", | ||||||
|  |       "win-x64-zip" | ||||||
|  |     ], | ||||||
|  |     "npm": "8.19.2", | ||||||
|  |     "v8": "10.9.48.0", | ||||||
|  |     "uv": "1.43.0", | ||||||
|  |     "zlib": "1.2.11", | ||||||
|  |     "openssl": "3.0.5+quic", | ||||||
|  |     "modules": "112", | ||||||
|  |     "lts": false, | ||||||
|  |     "security": false | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     "version": "v20.0.0-v8-canary20221020f78c149307", | ||||||
|  |     "date": "2022-10-20", | ||||||
|  |     "files": [ | ||||||
|  |       "headers", | ||||||
|  |       "linux-arm64", | ||||||
|  |       "linux-armv7l", | ||||||
|  |       "linux-x64", | ||||||
|  |       "osx-arm64-tar", | ||||||
|  |       "osx-x64-pkg", | ||||||
|  |       "osx-x64-tar", | ||||||
|  |       "src", | ||||||
|  |       "win-x64-7z", | ||||||
|  |       "win-x64-exe", | ||||||
|  |       "win-x64-msi", | ||||||
|  |       "win-x64-zip" | ||||||
|  |     ], | ||||||
|  |     "npm": "8.19.2", | ||||||
|  |     "v8": "10.9.38.0", | ||||||
|  |     "uv": "1.43.0", | ||||||
|  |     "zlib": "1.2.11", | ||||||
|  |     "openssl": "3.0.5+quic", | ||||||
|  |     "modules": "112", | ||||||
|  |     "lts": false, | ||||||
|  |     "security": false | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     "version": "v20.0.0-v8-canary20221019d52c76f76e", | ||||||
|  |     "date": "2022-10-19", | ||||||
|  |     "files": [ | ||||||
|  |       "aix-ppc64", | ||||||
|  |       "headers", | ||||||
|  |       "linux-arm64", | ||||||
|  |       "linux-armv7l", | ||||||
|  |       "linux-ppc64le", | ||||||
|  |       "linux-x64", | ||||||
|  |       "osx-arm64-tar", | ||||||
|  |       "osx-x64-pkg", | ||||||
|  |       "osx-x64-tar", | ||||||
|  |       "src", | ||||||
|  |       "win-x64-7z", | ||||||
|  |       "win-x64-exe", | ||||||
|  |       "win-x64-msi", | ||||||
|  |       "win-x64-zip" | ||||||
|  |     ], | ||||||
|  |     "npm": "8.19.2", | ||||||
|  |     "v8": "10.9.27.0", | ||||||
|  |     "uv": "1.43.0", | ||||||
|  |     "zlib": "1.2.11", | ||||||
|  |     "openssl": "3.0.5+quic", | ||||||
|  |     "modules": "112", | ||||||
|  |     "lts": false, | ||||||
|  |     "security": false | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     "version": "v19.0.0-v8-canary202210187d6960f23f", | ||||||
|  |     "date": "2022-10-18", | ||||||
|  |     "files": [ | ||||||
|  |       "aix-ppc64", | ||||||
|  |       "headers", | ||||||
|  |       "linux-arm64", | ||||||
|  |       "linux-armv7l", | ||||||
|  |       "linux-ppc64le", | ||||||
|  |       "linux-s390x", | ||||||
|  |       "linux-x64", | ||||||
|  |       "osx-arm64-tar", | ||||||
|  |       "osx-x64-tar", | ||||||
|  |       "src", | ||||||
|  |       "win-x64-7z", | ||||||
|  |       "win-x64-exe", | ||||||
|  |       "win-x64-msi", | ||||||
|  |       "win-x64-zip" | ||||||
|  |     ], | ||||||
|  |     "npm": "8.19.2", | ||||||
|  |     "v8": "10.9.12.0", | ||||||
|  |     "uv": "1.43.0", | ||||||
|  |     "zlib": "1.2.11", | ||||||
|  |     "openssl": "3.0.5+quic", | ||||||
|  |     "modules": "112", | ||||||
|  |     "lts": false, | ||||||
|  |     "security": false | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     "version": "v19.0.0-v8-canary202210172ec229fc56", | ||||||
|  |     "date": "2022-10-17", | ||||||
|  |     "files": [ | ||||||
|  |       "aix-ppc64", | ||||||
|  |       "headers", | ||||||
|  |       "linux-arm64", | ||||||
|  |       "linux-armv7l", | ||||||
|  |       "linux-ppc64le", | ||||||
|  |       "linux-s390x", | ||||||
|  |       "linux-x64", | ||||||
|  |       "osx-arm64-tar", | ||||||
|  |       "osx-x64-tar", | ||||||
|  |       "src", | ||||||
|  |       "win-x64-7z", | ||||||
|  |       "win-x64-exe", | ||||||
|  |       "win-x64-msi", | ||||||
|  |       "win-x64-zip" | ||||||
|  |     ], | ||||||
|  |     "npm": "8.19.2", | ||||||
|  |     "v8": "10.9.6.0", | ||||||
|  |     "uv": "1.43.0", | ||||||
|  |     "zlib": "1.2.11", | ||||||
|  |     "openssl": "3.0.5+quic", | ||||||
|  |     "modules": "112", | ||||||
|  |     "lts": false, | ||||||
|  |     "security": false | ||||||
|  |   } | ||||||
|  | ] | ||||||
							
								
								
									
										303
									
								
								__tests__/main.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										303
									
								
								__tests__/main.test.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,303 @@ | |||||||
|  | import * as core from '@actions/core'; | ||||||
|  | import * as exec from '@actions/exec'; | ||||||
|  | import * as tc from '@actions/tool-cache'; | ||||||
|  | import * as cache from '@actions/cache'; | ||||||
|  |  | ||||||
|  | import fs from 'fs'; | ||||||
|  | import path from 'path'; | ||||||
|  | import osm from 'os'; | ||||||
|  |  | ||||||
|  | import each from 'jest-each'; | ||||||
|  |  | ||||||
|  | import * as main from '../src/main'; | ||||||
|  | import * as util from '../src/util'; | ||||||
|  | import OfficialBuilds from '../src/distributions/official_builds/official_builds'; | ||||||
|  |  | ||||||
|  | describe('main tests', () => { | ||||||
|  |   let inputs = {} as any; | ||||||
|  |   let os = {} as any; | ||||||
|  |  | ||||||
|  |   let infoSpy: jest.SpyInstance; | ||||||
|  |   let warningSpy: jest.SpyInstance; | ||||||
|  |   let inSpy: jest.SpyInstance; | ||||||
|  |   let setOutputSpy: jest.SpyInstance; | ||||||
|  |   let startGroupSpy: jest.SpyInstance; | ||||||
|  |   let endGroupSpy: jest.SpyInstance; | ||||||
|  |  | ||||||
|  |   let existsSpy: jest.SpyInstance; | ||||||
|  |  | ||||||
|  |   let getExecOutputSpy: jest.SpyInstance; | ||||||
|  |  | ||||||
|  |   let parseNodeVersionSpy: jest.SpyInstance; | ||||||
|  |   let cnSpy: jest.SpyInstance; | ||||||
|  |   let findSpy: jest.SpyInstance; | ||||||
|  |   let isCacheActionAvailable: jest.SpyInstance; | ||||||
|  |  | ||||||
|  |   let setupNodeJsSpy: jest.SpyInstance; | ||||||
|  |  | ||||||
|  |   beforeEach(() => { | ||||||
|  |     inputs = {}; | ||||||
|  |  | ||||||
|  |     // node | ||||||
|  |     os = {}; | ||||||
|  |     console.log('::stop-commands::stoptoken'); | ||||||
|  |     process.env['GITHUB_PATH'] = ''; // Stub out ENV file functionality so we can verify it writes to standard out | ||||||
|  |     process.env['GITHUB_OUTPUT'] = ''; // Stub out ENV file functionality so we can verify it writes to standard out | ||||||
|  |     infoSpy = jest.spyOn(core, 'info'); | ||||||
|  |     infoSpy.mockImplementation(() => {}); | ||||||
|  |     setOutputSpy = jest.spyOn(core, 'setOutput'); | ||||||
|  |     setOutputSpy.mockImplementation(() => {}); | ||||||
|  |     warningSpy = jest.spyOn(core, 'warning'); | ||||||
|  |     warningSpy.mockImplementation(() => {}); | ||||||
|  |     startGroupSpy = jest.spyOn(core, 'startGroup'); | ||||||
|  |     startGroupSpy.mockImplementation(() => {}); | ||||||
|  |     endGroupSpy = jest.spyOn(core, 'endGroup'); | ||||||
|  |     endGroupSpy.mockImplementation(() => {}); | ||||||
|  |     inSpy = jest.spyOn(core, 'getInput'); | ||||||
|  |     inSpy.mockImplementation(name => inputs[name]); | ||||||
|  |  | ||||||
|  |     getExecOutputSpy = jest.spyOn(exec, 'getExecOutput'); | ||||||
|  |  | ||||||
|  |     findSpy = jest.spyOn(tc, 'find'); | ||||||
|  |  | ||||||
|  |     isCacheActionAvailable = jest.spyOn(cache, 'isFeatureAvailable'); | ||||||
|  |  | ||||||
|  |     existsSpy = jest.spyOn(fs, 'existsSync'); | ||||||
|  |  | ||||||
|  |     cnSpy = jest.spyOn(process.stdout, 'write'); | ||||||
|  |     cnSpy.mockImplementation(line => { | ||||||
|  |       // uncomment to debug | ||||||
|  |       // process.stderr.write('write:' + line + '\n'); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     setupNodeJsSpy = jest.spyOn(OfficialBuilds.prototype, 'setupNodeJs'); | ||||||
|  |     setupNodeJsSpy.mockImplementation(() => {}); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   afterEach(() => { | ||||||
|  |     jest.resetAllMocks(); | ||||||
|  |     jest.clearAllMocks(); | ||||||
|  |     //jest.restoreAllMocks(); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   afterAll(async () => { | ||||||
|  |     console.log('::stoptoken::'); | ||||||
|  |     jest.restoreAllMocks(); | ||||||
|  |   }, 100000); | ||||||
|  |  | ||||||
|  |   describe('parseNodeVersionFile', () => { | ||||||
|  |     each` | ||||||
|  |       contents                                     | expected | ||||||
|  |       ${'12'}                                      | ${'12'} | ||||||
|  |       ${'12.3'}                                    | ${'12.3'} | ||||||
|  |       ${'12.3.4'}                                  | ${'12.3.4'} | ||||||
|  |       ${'v12.3.4'}                                 | ${'12.3.4'} | ||||||
|  |       ${'lts/erbium'}                              | ${'lts/erbium'} | ||||||
|  |       ${'lts/*'}                                   | ${'lts/*'} | ||||||
|  |       ${'nodejs 12.3.4'}                           | ${'12.3.4'} | ||||||
|  |       ${'ruby 2.3.4\nnodejs 12.3.4\npython 3.4.5'} | ${'12.3.4'} | ||||||
|  |       ${''}                                        | ${''} | ||||||
|  |       ${'unknown format'}                          | ${'unknown format'} | ||||||
|  |       ${'  14.1.0  '}                              | ${'14.1.0'} | ||||||
|  |       ${'{"volta": {"node": ">=14.0.0 <=17.0.0"}}'}| ${'>=14.0.0 <=17.0.0'} | ||||||
|  |       ${'{"engines": {"node": "17.0.0"}}'}         | ${'17.0.0'} | ||||||
|  |     `.it('parses "$contents"', ({contents, expected}) => { | ||||||
|  |       expect(util.parseNodeVersionFile(contents)).toBe(expected); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   describe('printEnvDetailsAndSetOutput', () => { | ||||||
|  |     it.each([ | ||||||
|  |       [{node: '12.0.2', npm: '6.3.3', yarn: '1.22.11'}], | ||||||
|  |       [{node: '16.0.2', npm: '7.3.3', yarn: '2.22.11'}], | ||||||
|  |       [{node: '14.0.1', npm: '8.1.0', yarn: '3.2.1'}], | ||||||
|  |       [{node: '17.0.2', npm: '6.3.3', yarn: ''}] | ||||||
|  |     ])('Tools versions %p', async obj => { | ||||||
|  |       getExecOutputSpy.mockImplementation(async command => { | ||||||
|  |         if (Reflect.has(obj, command) && !obj[command]) { | ||||||
|  |           return { | ||||||
|  |             stdout: '', | ||||||
|  |             stderr: `${command} does not exist`, | ||||||
|  |             exitCode: 1 | ||||||
|  |           }; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return {stdout: obj[command], stderr: '', exitCode: 0}; | ||||||
|  |       }); | ||||||
|  |  | ||||||
|  |       await util.printEnvDetailsAndSetOutput(); | ||||||
|  |  | ||||||
|  |       expect(setOutputSpy).toHaveBeenCalledWith('node-version', obj['node']); | ||||||
|  |       Object.getOwnPropertyNames(obj).forEach(name => { | ||||||
|  |         if (!obj[name]) { | ||||||
|  |           expect(infoSpy).toHaveBeenCalledWith( | ||||||
|  |             `[warning]${name} does not exist` | ||||||
|  |           ); | ||||||
|  |         } | ||||||
|  |         expect(infoSpy).toHaveBeenCalledWith(`${name}: ${obj[name]}`); | ||||||
|  |       }); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   describe('node-version-file flag', () => { | ||||||
|  |     beforeEach(() => { | ||||||
|  |       parseNodeVersionSpy = jest.spyOn(util, 'parseNodeVersionFile'); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     it('not used if node-version is provided', async () => { | ||||||
|  |       // Arrange | ||||||
|  |       inputs['node-version'] = '12'; | ||||||
|  |  | ||||||
|  |       // Act | ||||||
|  |       await main.run(); | ||||||
|  |  | ||||||
|  |       // Assert | ||||||
|  |       expect(parseNodeVersionSpy).toHaveBeenCalledTimes(0); | ||||||
|  |     }, 10000); | ||||||
|  |  | ||||||
|  |     it('not used if node-version-file not provided', async () => { | ||||||
|  |       // Act | ||||||
|  |       await main.run(); | ||||||
|  |  | ||||||
|  |       // Assert | ||||||
|  |       expect(parseNodeVersionSpy).toHaveBeenCalledTimes(0); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     it('reads node-version-file if provided', async () => { | ||||||
|  |       // Arrange | ||||||
|  |       const versionSpec = 'v14'; | ||||||
|  |       const versionFile = '.nvmrc'; | ||||||
|  |       const expectedVersionSpec = '14'; | ||||||
|  |       process.env['GITHUB_WORKSPACE'] = path.join(__dirname, 'data'); | ||||||
|  |       inputs['node-version-file'] = versionFile; | ||||||
|  |  | ||||||
|  |       parseNodeVersionSpy.mockImplementation(() => expectedVersionSpec); | ||||||
|  |       existsSpy.mockImplementationOnce( | ||||||
|  |         input => input === path.join(__dirname, 'data', versionFile) | ||||||
|  |       ); | ||||||
|  |  | ||||||
|  |       // Act | ||||||
|  |       await main.run(); | ||||||
|  |  | ||||||
|  |       // Assert | ||||||
|  |       expect(existsSpy).toHaveBeenCalledTimes(1); | ||||||
|  |       expect(existsSpy).toHaveReturnedWith(true); | ||||||
|  |       expect(parseNodeVersionSpy).toHaveBeenCalledWith(versionSpec); | ||||||
|  |       expect(infoSpy).toHaveBeenCalledWith( | ||||||
|  |         `Resolved ${versionFile} as ${expectedVersionSpec}` | ||||||
|  |       ); | ||||||
|  |     }, 10000); | ||||||
|  |  | ||||||
|  |     it('reads package.json as node-version-file if provided', async () => { | ||||||
|  |       // Arrange | ||||||
|  |       const versionSpec = fs.readFileSync( | ||||||
|  |         path.join(__dirname, 'data/package.json'), | ||||||
|  |         'utf-8' | ||||||
|  |       ); | ||||||
|  |       const versionFile = 'package.json'; | ||||||
|  |       const expectedVersionSpec = '14'; | ||||||
|  |       process.env['GITHUB_WORKSPACE'] = path.join(__dirname, 'data'); | ||||||
|  |       inputs['node-version-file'] = versionFile; | ||||||
|  |  | ||||||
|  |       parseNodeVersionSpy.mockImplementation(() => expectedVersionSpec); | ||||||
|  |       existsSpy.mockImplementationOnce( | ||||||
|  |         input => input === path.join(__dirname, 'data', versionFile) | ||||||
|  |       ); | ||||||
|  |       // Act | ||||||
|  |       await main.run(); | ||||||
|  |  | ||||||
|  |       // Assert | ||||||
|  |       expect(existsSpy).toHaveBeenCalledTimes(1); | ||||||
|  |       expect(existsSpy).toHaveReturnedWith(true); | ||||||
|  |       expect(parseNodeVersionSpy).toHaveBeenCalledWith(versionSpec); | ||||||
|  |       expect(infoSpy).toHaveBeenCalledWith( | ||||||
|  |         `Resolved ${versionFile} as ${expectedVersionSpec}` | ||||||
|  |       ); | ||||||
|  |     }, 10000); | ||||||
|  |  | ||||||
|  |     it('both node-version-file and node-version are provided', async () => { | ||||||
|  |       inputs['node-version'] = '12'; | ||||||
|  |       const versionSpec = 'v14'; | ||||||
|  |       const versionFile = '.nvmrc'; | ||||||
|  |       const expectedVersionSpec = '14'; | ||||||
|  |       process.env['GITHUB_WORKSPACE'] = path.join(__dirname, '..'); | ||||||
|  |       inputs['node-version-file'] = versionFile; | ||||||
|  |  | ||||||
|  |       parseNodeVersionSpy.mockImplementation(() => expectedVersionSpec); | ||||||
|  |  | ||||||
|  |       // Act | ||||||
|  |       await main.run(); | ||||||
|  |  | ||||||
|  |       // Assert | ||||||
|  |       expect(existsSpy).toHaveBeenCalledTimes(0); | ||||||
|  |       expect(parseNodeVersionSpy).not.toHaveBeenCalled(); | ||||||
|  |       expect(warningSpy).toHaveBeenCalledWith( | ||||||
|  |         'Both node-version and node-version-file inputs are specified, only node-version will be used' | ||||||
|  |       ); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     it('should throw an error if node-version-file is not found', async () => { | ||||||
|  |       const versionFile = '.nvmrc'; | ||||||
|  |       const versionFilePath = path.join(__dirname, '..', versionFile); | ||||||
|  |       inputs['node-version-file'] = versionFile; | ||||||
|  |  | ||||||
|  |       inSpy.mockImplementation(name => inputs[name]); | ||||||
|  |       existsSpy.mockImplementationOnce( | ||||||
|  |         input => input === path.join(__dirname, 'data', versionFile) | ||||||
|  |       ); | ||||||
|  |  | ||||||
|  |       // Act | ||||||
|  |       await main.run(); | ||||||
|  |  | ||||||
|  |       // Assert | ||||||
|  |       expect(existsSpy).toHaveBeenCalled(); | ||||||
|  |       expect(existsSpy).toHaveReturnedWith(false); | ||||||
|  |       expect(parseNodeVersionSpy).not.toHaveBeenCalled(); | ||||||
|  |       expect(cnSpy).toHaveBeenCalledWith( | ||||||
|  |         `::error::The specified node version file at: ${versionFilePath} does not exist${osm.EOL}` | ||||||
|  |       ); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   describe('cache on GHES', () => { | ||||||
|  |     it('Should throw an error, because cache is not supported', async () => { | ||||||
|  |       inputs['node-version'] = '12'; | ||||||
|  |       inputs['cache'] = 'npm'; | ||||||
|  |  | ||||||
|  |       inSpy.mockImplementation(name => inputs[name]); | ||||||
|  |  | ||||||
|  |       let toolPath = path.normalize('/cache/node/12.16.1/x64'); | ||||||
|  |       findSpy.mockImplementation(() => toolPath); | ||||||
|  |  | ||||||
|  |       // expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`); | ||||||
|  |       process.env['GITHUB_SERVER_URL'] = 'https://www.test.com'; | ||||||
|  |       isCacheActionAvailable.mockImplementation(() => false); | ||||||
|  |  | ||||||
|  |       await main.run(); | ||||||
|  |  | ||||||
|  |       expect(warningSpy).toHaveBeenCalledWith( | ||||||
|  |         `Cache action is only supported on GHES version >= 3.5. If you are on version >=3.5 Please check with GHES admin if Actions cache service is enabled or not.` | ||||||
|  |       ); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     it('Should throw an internal error', async () => { | ||||||
|  |       inputs['node-version'] = '12'; | ||||||
|  |       inputs['cache'] = 'npm'; | ||||||
|  |  | ||||||
|  |       inSpy.mockImplementation(name => inputs[name]); | ||||||
|  |  | ||||||
|  |       let toolPath = path.normalize('/cache/node/12.16.1/x64'); | ||||||
|  |       findSpy.mockImplementation(() => toolPath); | ||||||
|  |  | ||||||
|  |       // expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`); | ||||||
|  |       process.env['GITHUB_SERVER_URL'] = ''; | ||||||
|  |       isCacheActionAvailable.mockImplementation(() => false); | ||||||
|  |  | ||||||
|  |       await main.run(); | ||||||
|  |  | ||||||
|  |       expect(warningSpy).toHaveBeenCalledWith( | ||||||
|  |         'The runner was not able to contact the cache service. Caching will be skipped' | ||||||
|  |       ); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
							
								
								
									
										517
									
								
								__tests__/nightly-installer.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										517
									
								
								__tests__/nightly-installer.test.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,517 @@ | |||||||
|  | import * as core from '@actions/core'; | ||||||
|  | import * as io from '@actions/io'; | ||||||
|  | import * as tc from '@actions/tool-cache'; | ||||||
|  | import * as httpm from '@actions/http-client'; | ||||||
|  | import * as exec from '@actions/exec'; | ||||||
|  | import * as cache from '@actions/cache'; | ||||||
|  | import fs from 'fs'; | ||||||
|  | import cp from 'child_process'; | ||||||
|  | import osm from 'os'; | ||||||
|  | import path from 'path'; | ||||||
|  | import * as main from '../src/main'; | ||||||
|  | import * as auth from '../src/authutil'; | ||||||
|  | import {INodeVersion} from '../src/distributions/base-models'; | ||||||
|  |  | ||||||
|  | const nodeTestManifest = require('./data/versions-manifest.json'); | ||||||
|  | const nodeTestDist = require('./data/node-dist-index.json'); | ||||||
|  | const nodeTestDistNightly = require('./data/node-nightly-index.json'); | ||||||
|  | const nodeTestDistRc = require('./data/node-rc-index.json'); | ||||||
|  | const nodeV8CanaryTestDist = require('./data/v8-canary-dist-index.json'); | ||||||
|  |  | ||||||
|  | describe('setup-node', () => { | ||||||
|  |   let inputs = {} as any; | ||||||
|  |   let os = {} as any; | ||||||
|  |  | ||||||
|  |   let inSpy: jest.SpyInstance; | ||||||
|  |   let findSpy: jest.SpyInstance; | ||||||
|  |   let findAllVersionsSpy: jest.SpyInstance; | ||||||
|  |   let cnSpy: jest.SpyInstance; | ||||||
|  |   let logSpy: jest.SpyInstance; | ||||||
|  |   let warningSpy: jest.SpyInstance; | ||||||
|  |   let getManifestSpy: jest.SpyInstance; | ||||||
|  |   let getDistSpy: jest.SpyInstance; | ||||||
|  |   let platSpy: jest.SpyInstance; | ||||||
|  |   let archSpy: jest.SpyInstance; | ||||||
|  |   let dlSpy: jest.SpyInstance; | ||||||
|  |   let exSpy: jest.SpyInstance; | ||||||
|  |   let cacheSpy: jest.SpyInstance; | ||||||
|  |   let dbgSpy: jest.SpyInstance; | ||||||
|  |   let whichSpy: jest.SpyInstance; | ||||||
|  |   let existsSpy: jest.SpyInstance; | ||||||
|  |   let mkdirpSpy: jest.SpyInstance; | ||||||
|  |   let execSpy: jest.SpyInstance; | ||||||
|  |   let authSpy: jest.SpyInstance; | ||||||
|  |   let parseNodeVersionSpy: jest.SpyInstance; | ||||||
|  |   let isCacheActionAvailable: jest.SpyInstance; | ||||||
|  |   let getExecOutputSpy: jest.SpyInstance; | ||||||
|  |   let getJsonSpy: jest.SpyInstance; | ||||||
|  |  | ||||||
|  |   beforeEach(() => { | ||||||
|  |     // @actions/core | ||||||
|  |     console.log('::stop-commands::stoptoken'); // Disable executing of runner commands when running tests in actions | ||||||
|  |     process.env['GITHUB_PATH'] = ''; // Stub out ENV file functionality so we can verify it writes to standard out | ||||||
|  |     process.env['GITHUB_OUTPUT'] = ''; // Stub out ENV file functionality so we can verify it writes to standard out | ||||||
|  |     inputs = {}; | ||||||
|  |     inSpy = jest.spyOn(core, 'getInput'); | ||||||
|  |     inSpy.mockImplementation(name => inputs[name]); | ||||||
|  |  | ||||||
|  |     // node | ||||||
|  |     os = {}; | ||||||
|  |     platSpy = jest.spyOn(osm, 'platform'); | ||||||
|  |     platSpy.mockImplementation(() => os['platform']); | ||||||
|  |     archSpy = jest.spyOn(osm, 'arch'); | ||||||
|  |     archSpy.mockImplementation(() => os['arch']); | ||||||
|  |     execSpy = jest.spyOn(cp, 'execSync'); | ||||||
|  |  | ||||||
|  |     // @actions/tool-cache | ||||||
|  |     findSpy = jest.spyOn(tc, 'find'); | ||||||
|  |     findAllVersionsSpy = jest.spyOn(tc, 'findAllVersions'); | ||||||
|  |     dlSpy = jest.spyOn(tc, 'downloadTool'); | ||||||
|  |     exSpy = jest.spyOn(tc, 'extractTar'); | ||||||
|  |     cacheSpy = jest.spyOn(tc, 'cacheDir'); | ||||||
|  |     getManifestSpy = jest.spyOn(tc, 'getManifestFromRepo'); | ||||||
|  |  | ||||||
|  |     // http-client | ||||||
|  |     getJsonSpy = jest.spyOn(httpm.HttpClient.prototype, 'getJson'); | ||||||
|  |  | ||||||
|  |     // io | ||||||
|  |     whichSpy = jest.spyOn(io, 'which'); | ||||||
|  |     existsSpy = jest.spyOn(fs, 'existsSync'); | ||||||
|  |     mkdirpSpy = jest.spyOn(io, 'mkdirP'); | ||||||
|  |  | ||||||
|  |     // @actions/tool-cache | ||||||
|  |     isCacheActionAvailable = jest.spyOn(cache, 'isFeatureAvailable'); | ||||||
|  |  | ||||||
|  |     // disable authentication portion for installer tests | ||||||
|  |     authSpy = jest.spyOn(auth, 'configAuthentication'); | ||||||
|  |     authSpy.mockImplementation(() => {}); | ||||||
|  |  | ||||||
|  |     getJsonSpy.mockImplementation(url => { | ||||||
|  |       let res: any; | ||||||
|  |       if (url.includes('/rc')) { | ||||||
|  |         res = <INodeVersion>nodeTestDistRc; | ||||||
|  |       } else if (url.includes('/nightly')) { | ||||||
|  |         res = <INodeVersion>nodeTestDistNightly; | ||||||
|  |       } else { | ||||||
|  |         res = <INodeVersion>nodeTestDist; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       return {result: res}; | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     // writes | ||||||
|  |     cnSpy = jest.spyOn(process.stdout, 'write'); | ||||||
|  |     logSpy = jest.spyOn(core, 'info'); | ||||||
|  |     dbgSpy = jest.spyOn(core, 'debug'); | ||||||
|  |     warningSpy = jest.spyOn(core, 'warning'); | ||||||
|  |     cnSpy.mockImplementation(line => { | ||||||
|  |       // uncomment to debug | ||||||
|  |       // process.stderr.write('write:' + line + '\n'); | ||||||
|  |     }); | ||||||
|  |     logSpy.mockImplementation(line => { | ||||||
|  |       // uncomment to debug | ||||||
|  |       // process.stderr.write('log:' + line + '\n'); | ||||||
|  |     }); | ||||||
|  |     dbgSpy.mockImplementation(msg => { | ||||||
|  |       // uncomment to see debug output | ||||||
|  |       // process.stderr.write(msg + '\n'); | ||||||
|  |     }); | ||||||
|  |     warningSpy.mockImplementation(msg => { | ||||||
|  |       // uncomment to debug | ||||||
|  |       // process.stderr.write('log:' + msg + '\n'); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     // @actions/exec | ||||||
|  |     getExecOutputSpy = jest.spyOn(exec, 'getExecOutput'); | ||||||
|  |     getExecOutputSpy.mockImplementation(() => 'v16.15.0'); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   afterEach(() => { | ||||||
|  |     jest.resetAllMocks(); | ||||||
|  |     jest.clearAllMocks(); | ||||||
|  |     //jest.restoreAllMocks(); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   afterAll(async () => { | ||||||
|  |     console.log('::stoptoken::'); // Re-enable executing of runner commands when running tests in actions | ||||||
|  |     jest.restoreAllMocks(); | ||||||
|  |   }, 100000); | ||||||
|  |  | ||||||
|  |   //-------------------------------------------------- | ||||||
|  |   // Found in cache tests | ||||||
|  |   //-------------------------------------------------- | ||||||
|  |  | ||||||
|  |   it('finds version in cache with stable true', async () => { | ||||||
|  |     inputs['node-version'] = '16-nightly'; | ||||||
|  |     os['arch'] = 'x64'; | ||||||
|  |     inputs.stable = 'true'; | ||||||
|  |  | ||||||
|  |     let toolPath = path.normalize( | ||||||
|  |       '/cache/node/16.0.0-nightly20210417bc31dc0e0f/x64' | ||||||
|  |     ); | ||||||
|  |     findSpy.mockImplementation(() => toolPath); | ||||||
|  |     findAllVersionsSpy.mockImplementation(() => [ | ||||||
|  |       '12.0.1', | ||||||
|  |       '16.0.0-nightly20210415c3a5e15ebe', | ||||||
|  |       '16.0.0-nightly20210417bc31dc0e0f', | ||||||
|  |       '16.1.3' | ||||||
|  |     ]); | ||||||
|  |  | ||||||
|  |     await main.run(); | ||||||
|  |  | ||||||
|  |     expect(findSpy).toHaveBeenCalledWith( | ||||||
|  |       'node', | ||||||
|  |       '16.0.0-nightly20210417bc31dc0e0f', | ||||||
|  |       'x64' | ||||||
|  |     ); | ||||||
|  |     expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('finds version in cache with stable false', async () => { | ||||||
|  |     inputs['node-version'] = '16.0.0-nightly20210415c3a5e15ebe'; | ||||||
|  |     os['arch'] = 'x64'; | ||||||
|  |     inputs.stable = 'false'; | ||||||
|  |  | ||||||
|  |     let toolPath = path.normalize( | ||||||
|  |       '/cache/node/16.0.0-nightly20210415c3a5e15ebe/x64' | ||||||
|  |     ); | ||||||
|  |     findSpy.mockImplementation(() => toolPath); | ||||||
|  |     findAllVersionsSpy.mockImplementation(() => [ | ||||||
|  |       '12.0.1', | ||||||
|  |       '16.0.0-nightly20210415c3a5e15ebe', | ||||||
|  |       '16.0.0-nightly20210417bc31dc0e0f', | ||||||
|  |       '16.1.3' | ||||||
|  |     ]); | ||||||
|  |  | ||||||
|  |     await main.run(); | ||||||
|  |  | ||||||
|  |     expect(findSpy).toHaveBeenCalledWith( | ||||||
|  |       'node', | ||||||
|  |       '16.0.0-nightly20210415c3a5e15ebe', | ||||||
|  |       'x64' | ||||||
|  |     ); | ||||||
|  |     expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('finds version in cache and adds it to the path', async () => { | ||||||
|  |     inputs['node-version'] = '16-nightly'; | ||||||
|  |     os['arch'] = 'x64'; | ||||||
|  |  | ||||||
|  |     inSpy.mockImplementation(name => inputs[name]); | ||||||
|  |  | ||||||
|  |     let toolPath = path.normalize( | ||||||
|  |       '/cache/node/16.0.0-nightly20210417bc31dc0e0f/x64' | ||||||
|  |     ); | ||||||
|  |     findSpy.mockImplementation(() => toolPath); | ||||||
|  |     findAllVersionsSpy.mockImplementation(() => [ | ||||||
|  |       '12.0.1', | ||||||
|  |       '16.0.0-nightly20210415c3a5e15ebe', | ||||||
|  |       '16.0.0-nightly20210417bc31dc0e0f', | ||||||
|  |       '16.1.3' | ||||||
|  |     ]); | ||||||
|  |  | ||||||
|  |     await main.run(); | ||||||
|  |  | ||||||
|  |     expect(findSpy).toHaveBeenCalledWith( | ||||||
|  |       'node', | ||||||
|  |       '16.0.0-nightly20210417bc31dc0e0f', | ||||||
|  |       'x64' | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     let expPath = path.join(toolPath, 'bin'); | ||||||
|  |     expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('handles unhandled find error and reports error', async () => { | ||||||
|  |     let errMsg = 'unhandled error message'; | ||||||
|  |     inputs['node-version'] = '16.0.0-nightly20210417bc31dc0e0f'; | ||||||
|  |  | ||||||
|  |     findAllVersionsSpy.mockImplementation(() => [ | ||||||
|  |       '12.0.1', | ||||||
|  |       '16.0.0-nightly20210415c3a5e15ebe', | ||||||
|  |       '16.0.0-nightly20210417bc31dc0e0f', | ||||||
|  |       '16.1.3' | ||||||
|  |     ]); | ||||||
|  |  | ||||||
|  |     findSpy.mockImplementation(() => { | ||||||
|  |       throw new Error(errMsg); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     await main.run(); | ||||||
|  |  | ||||||
|  |     expect(cnSpy).toHaveBeenCalledWith('::error::' + errMsg + osm.EOL); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('falls back to a version from node dist', async () => { | ||||||
|  |     os.platform = 'linux'; | ||||||
|  |     os.arch = 'x64'; | ||||||
|  |  | ||||||
|  |     // a version which is not in the manifest but is in node dist | ||||||
|  |     let versionSpec = '13.13.1-nightly20200415947ddec091'; | ||||||
|  |  | ||||||
|  |     inputs['node-version'] = versionSpec; | ||||||
|  |     inputs['always-auth'] = false; | ||||||
|  |     inputs['token'] = 'faketoken'; | ||||||
|  |  | ||||||
|  |     // ... but not in the local cache | ||||||
|  |     findSpy.mockImplementation(() => ''); | ||||||
|  |     findAllVersionsSpy.mockImplementation(() => []); | ||||||
|  |  | ||||||
|  |     dlSpy.mockImplementation(async () => '/some/temp/path'); | ||||||
|  |     let toolPath = path.normalize( | ||||||
|  |       '/cache/node/13.13.1-nightly20200415947ddec091/x64' | ||||||
|  |     ); | ||||||
|  |     exSpy.mockImplementation(async () => '/some/other/temp/path'); | ||||||
|  |     cacheSpy.mockImplementation(async () => toolPath); | ||||||
|  |  | ||||||
|  |     await main.run(); | ||||||
|  |  | ||||||
|  |     let expPath = path.join(toolPath, 'bin'); | ||||||
|  |  | ||||||
|  |     expect(dlSpy).toHaveBeenCalled(); | ||||||
|  |     expect(exSpy).toHaveBeenCalled(); | ||||||
|  |     expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('does not find a version that does not exist', async () => { | ||||||
|  |     os.platform = 'linux'; | ||||||
|  |     os.arch = 'x64'; | ||||||
|  |  | ||||||
|  |     let versionSpec = '10.13.1-nightly20200415947ddec091'; | ||||||
|  |     inputs['node-version'] = versionSpec; | ||||||
|  |  | ||||||
|  |     findSpy.mockImplementation(() => ''); | ||||||
|  |     findAllVersionsSpy.mockImplementation(() => []); | ||||||
|  |     await main.run(); | ||||||
|  |  | ||||||
|  |     expect(cnSpy).toHaveBeenCalledWith( | ||||||
|  |       `::error::Unable to find Node version '${versionSpec}' for platform ${os.platform} and architecture ${os.arch}.${osm.EOL}` | ||||||
|  |     ); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('reports a failed download', async () => { | ||||||
|  |     let errMsg = 'unhandled download message'; | ||||||
|  |     os.platform = 'linux'; | ||||||
|  |     os.arch = 'x64'; | ||||||
|  |  | ||||||
|  |     // a version which is in the manifest | ||||||
|  |     let versionSpec = '18.0.0-nightly202204180699150267'; | ||||||
|  |  | ||||||
|  |     inputs['node-version'] = versionSpec; | ||||||
|  |     inputs['always-auth'] = false; | ||||||
|  |     inputs['token'] = 'faketoken'; | ||||||
|  |  | ||||||
|  |     findSpy.mockImplementation(() => ''); | ||||||
|  |     findAllVersionsSpy.mockImplementation(() => []); | ||||||
|  |  | ||||||
|  |     dlSpy.mockImplementation(() => { | ||||||
|  |       throw new Error(errMsg); | ||||||
|  |     }); | ||||||
|  |     await main.run(); | ||||||
|  |  | ||||||
|  |     expect(cnSpy).toHaveBeenCalledWith(`::error::${errMsg}${osm.EOL}`); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('acquires specified architecture of node', async () => { | ||||||
|  |     for (const {arch, version, osSpec} of [ | ||||||
|  |       { | ||||||
|  |         arch: 'x86', | ||||||
|  |         version: '18.0.0-nightly202110204cb3e06ed8', | ||||||
|  |         osSpec: 'win32' | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         arch: 'x86', | ||||||
|  |         version: '20.0.0-nightly2022101987cdf7d412', | ||||||
|  |         osSpec: 'win32' | ||||||
|  |       } | ||||||
|  |     ]) { | ||||||
|  |       os.platform = osSpec; | ||||||
|  |       os.arch = arch; | ||||||
|  |       const fileExtension = os.platform === 'win32' ? '7z' : 'tar.gz'; | ||||||
|  |       const platform = { | ||||||
|  |         linux: 'linux', | ||||||
|  |         darwin: 'darwin', | ||||||
|  |         win32: 'win' | ||||||
|  |       }[os.platform]; | ||||||
|  |  | ||||||
|  |       inputs['node-version'] = version; | ||||||
|  |       inputs['architecture'] = arch; | ||||||
|  |       inputs['always-auth'] = false; | ||||||
|  |       inputs['token'] = 'faketoken'; | ||||||
|  |  | ||||||
|  |       let expectedUrl = `https://nodejs.org/download/nightly/v${version}/node-v${version}-${platform}-${arch}.${fileExtension}`; | ||||||
|  |  | ||||||
|  |       // ... but not in the local cache | ||||||
|  |       findSpy.mockImplementation(() => ''); | ||||||
|  |       findAllVersionsSpy.mockImplementation(() => []); | ||||||
|  |  | ||||||
|  |       dlSpy.mockImplementation(async () => '/some/temp/path'); | ||||||
|  |       let toolPath = path.normalize(`/cache/node/${version}/${arch}`); | ||||||
|  |       exSpy.mockImplementation(async () => '/some/other/temp/path'); | ||||||
|  |       cacheSpy.mockImplementation(async () => toolPath); | ||||||
|  |  | ||||||
|  |       await main.run(); | ||||||
|  |       expect(dlSpy).toHaveBeenCalled(); | ||||||
|  |       expect(logSpy).toHaveBeenCalledWith( | ||||||
|  |         `Acquiring ${version} - ${arch} from ${expectedUrl}` | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |   }, 100000); | ||||||
|  |  | ||||||
|  |   describe('nightly versions', () => { | ||||||
|  |     it.each([ | ||||||
|  |       [ | ||||||
|  |         '17.5.0-nightly', | ||||||
|  |         '17.5.0-nightly20220209e43808936a', | ||||||
|  |         'https://nodejs.org/download/nightly/v17.5.0-nightly20220209e43808936a/node-v17.5.0-nightly20220209e43808936a-linux-x64.tar.gz' | ||||||
|  |       ], | ||||||
|  |       [ | ||||||
|  |         '17-nightly', | ||||||
|  |         '17.5.0-nightly20220209e43808936a', | ||||||
|  |         'https://nodejs.org/download/nightly/v17.5.0-nightly20220209e43808936a/node-v17.5.0-nightly20220209e43808936a-linux-x64.tar.gz' | ||||||
|  |       ], | ||||||
|  |       [ | ||||||
|  |         '18.0.0-nightly', | ||||||
|  |         '18.0.0-nightly20220419bde889bd4e', | ||||||
|  |         'https://nodejs.org/download/nightly/v18.0.0-nightly20220419bde889bd4e/node-v18.0.0-nightly20220419bde889bd4e-linux-x64.tar.gz' | ||||||
|  |       ], | ||||||
|  |       [ | ||||||
|  |         '18-nightly', | ||||||
|  |         '18.0.0-nightly20220419bde889bd4e', | ||||||
|  |         'https://nodejs.org/download/nightly/v18.0.0-nightly20220419bde889bd4e/node-v18.0.0-nightly20220419bde889bd4e-linux-x64.tar.gz' | ||||||
|  |       ], | ||||||
|  |       [ | ||||||
|  |         '20.0.0-nightly', | ||||||
|  |         '20.0.0-nightly2022101987cdf7d412', | ||||||
|  |         'https://nodejs.org/download/nightly/v20.0.0-nightly2022101987cdf7d412/node-v20.0.0-nightly2022101987cdf7d412-linux-x64.tar.gz' | ||||||
|  |       ] | ||||||
|  |     ])( | ||||||
|  |       'finds the versions in the index.json and installs it', | ||||||
|  |       async (input, expectedVersion, expectedUrl) => { | ||||||
|  |         const toolPath = path.normalize(`/cache/node/${expectedVersion}/x64`); | ||||||
|  |  | ||||||
|  |         findSpy.mockImplementation(() => ''); | ||||||
|  |         findAllVersionsSpy.mockImplementation(() => []); | ||||||
|  |         dlSpy.mockImplementation(async () => '/some/temp/path'); | ||||||
|  |         exSpy.mockImplementation(async () => '/some/other/temp/path'); | ||||||
|  |         cacheSpy.mockImplementation(async () => toolPath); | ||||||
|  |  | ||||||
|  |         inputs['node-version'] = input; | ||||||
|  |         os['arch'] = 'x64'; | ||||||
|  |         os['platform'] = 'linux'; | ||||||
|  |         // act | ||||||
|  |         await main.run(); | ||||||
|  |  | ||||||
|  |         // assert | ||||||
|  |         expect(logSpy).toHaveBeenCalledWith( | ||||||
|  |           `Acquiring ${expectedVersion} - ${os.arch} from ${expectedUrl}` | ||||||
|  |         ); | ||||||
|  |         expect(logSpy).toHaveBeenCalledWith('Extracting ...'); | ||||||
|  |         expect(logSpy).toHaveBeenCalledWith('Adding to the cache ...'); | ||||||
|  |         expect(cnSpy).toHaveBeenCalledWith( | ||||||
|  |           `::add-path::${path.join(toolPath, 'bin')}${osm.EOL}` | ||||||
|  |         ); | ||||||
|  |       } | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     it.each([ | ||||||
|  |       ['17.5.0-nightly', '17.5.0-nightly20220209e43808936a'], | ||||||
|  |       ['17-nightly', '17.5.0-nightly20220209e43808936a'], | ||||||
|  |       ['20.0.0-nightly', '20.0.0-nightly2022101987cdf7d412'] | ||||||
|  |     ])( | ||||||
|  |       'finds the %s version in the hostedToolcache', | ||||||
|  |       async (input, expectedVersion) => { | ||||||
|  |         const toolPath = path.normalize(`/cache/node/${expectedVersion}/x64`); | ||||||
|  |         findSpy.mockReturnValue(toolPath); | ||||||
|  |         findAllVersionsSpy.mockReturnValue([ | ||||||
|  |           '17.5.0-nightly20220209e43808936a', | ||||||
|  |           '17.5.0-nightly20220209e43808935a', | ||||||
|  |           '20.0.0-nightly2022101987cdf7d412', | ||||||
|  |           '20.0.0-nightly2022101987cdf7d411' | ||||||
|  |         ]); | ||||||
|  |  | ||||||
|  |         inputs['node-version'] = input; | ||||||
|  |         os['arch'] = 'x64'; | ||||||
|  |         os['platform'] = 'linux'; | ||||||
|  |  | ||||||
|  |         // act | ||||||
|  |         await main.run(); | ||||||
|  |  | ||||||
|  |         // assert | ||||||
|  |         expect(findAllVersionsSpy).toHaveBeenCalled(); | ||||||
|  |         expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`); | ||||||
|  |         expect(cnSpy).toHaveBeenCalledWith( | ||||||
|  |           `::add-path::${path.join(toolPath, 'bin')}${osm.EOL}` | ||||||
|  |         ); | ||||||
|  |       } | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     it.each([ | ||||||
|  |       [ | ||||||
|  |         '17.5.0-nightly', | ||||||
|  |         '17.5.0-nightly20220209e43808936a', | ||||||
|  |         '17.0.0-nightly202110193f11666dc7', | ||||||
|  |         'https://nodejs.org/download/nightly/v17.5.0-nightly20220209e43808936a/node-v17.5.0-nightly20220209e43808936a-linux-x64.tar.gz' | ||||||
|  |       ], | ||||||
|  |       [ | ||||||
|  |         '17-nightly', | ||||||
|  |         '17.5.0-nightly20220209e43808936a', | ||||||
|  |         '17.0.0-nightly202110193f11666dc7', | ||||||
|  |         'https://nodejs.org/download/nightly/v17.5.0-nightly20220209e43808936a/node-v17.5.0-nightly20220209e43808936a-linux-x64.tar.gz' | ||||||
|  |       ], | ||||||
|  |       [ | ||||||
|  |         '18.0.0-nightly', | ||||||
|  |         '18.0.0-nightly20220419bde889bd4e', | ||||||
|  |         '18.0.0-nightly202204180699150267', | ||||||
|  |         'https://nodejs.org/download/nightly/v18.0.0-nightly20220419bde889bd4e/node-v18.0.0-nightly20220419bde889bd4e-linux-x64.tar.gz' | ||||||
|  |       ], | ||||||
|  |       [ | ||||||
|  |         '18-nightly', | ||||||
|  |         '18.0.0-nightly20220419bde889bd4e', | ||||||
|  |         '18.0.0-nightly202204180699150267', | ||||||
|  |         'https://nodejs.org/download/nightly/v18.0.0-nightly20220419bde889bd4e/node-v18.0.0-nightly20220419bde889bd4e-linux-x64.tar.gz' | ||||||
|  |       ], | ||||||
|  |       [ | ||||||
|  |         '20.0.0-nightly', | ||||||
|  |         '20.0.0-nightly2022101987cdf7d412', | ||||||
|  |         '20.0.0-nightly2022101987cdf7d411', | ||||||
|  |         'https://nodejs.org/download/nightly/v20.0.0-nightly2022101987cdf7d412/node-v20.0.0-nightly2022101987cdf7d412-linux-x64.tar.gz' | ||||||
|  |       ] | ||||||
|  |     ])( | ||||||
|  |       'get %s version from dist if check-latest is true', | ||||||
|  |       async (input, expectedVersion, foundVersion, expectedUrl) => { | ||||||
|  |         const foundToolPath = path.normalize(`/cache/node/${foundVersion}/x64`); | ||||||
|  |         const toolPath = path.normalize(`/cache/node/${expectedVersion}/x64`); | ||||||
|  |  | ||||||
|  |         inputs['node-version'] = input; | ||||||
|  |         inputs['check-latest'] = 'true'; | ||||||
|  |         os['arch'] = 'x64'; | ||||||
|  |         os['platform'] = 'linux'; | ||||||
|  |  | ||||||
|  |         findSpy.mockReturnValue(foundToolPath); | ||||||
|  |         findAllVersionsSpy.mockReturnValue([ | ||||||
|  |           '17.0.0-nightly202110193f11666dc7', | ||||||
|  |           '18.0.0-nightly202204180699150267', | ||||||
|  |           '20.0.0-nightly2022101987cdf7d411' | ||||||
|  |         ]); | ||||||
|  |         dlSpy.mockImplementation(async () => '/some/temp/path'); | ||||||
|  |         exSpy.mockImplementation(async () => '/some/other/temp/path'); | ||||||
|  |         cacheSpy.mockImplementation(async () => toolPath); | ||||||
|  |  | ||||||
|  |         // act | ||||||
|  |         await main.run(); | ||||||
|  |  | ||||||
|  |         // assert | ||||||
|  |         expect(findAllVersionsSpy).toHaveBeenCalled(); | ||||||
|  |         expect(logSpy).toHaveBeenCalledWith( | ||||||
|  |           `Acquiring ${expectedVersion} - ${os.arch} from ${expectedUrl}` | ||||||
|  |         ); | ||||||
|  |         expect(logSpy).toHaveBeenCalledWith('Extracting ...'); | ||||||
|  |         expect(logSpy).toHaveBeenCalledWith('Adding to the cache ...'); | ||||||
|  |         expect(cnSpy).toHaveBeenCalledWith( | ||||||
|  |           `::add-path::${path.join(toolPath, 'bin')}${osm.EOL}` | ||||||
|  |         ); | ||||||
|  |       } | ||||||
|  |     ); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
| @@ -1,24 +1,26 @@ | |||||||
| import * as core from '@actions/core'; | import * as core from '@actions/core'; | ||||||
| import * as io from '@actions/io'; | import * as io from '@actions/io'; | ||||||
| import * as tc from '@actions/tool-cache'; | import * as tc from '@actions/tool-cache'; | ||||||
| import * as exec from '@actions/exec'; |  | ||||||
| import * as im from '../src/installer'; |  | ||||||
| import * as cache from '@actions/cache'; |  | ||||||
| import * as httpm from '@actions/http-client'; | import * as httpm from '@actions/http-client'; | ||||||
|  | import * as exec from '@actions/exec'; | ||||||
|  | import * as cache from '@actions/cache'; | ||||||
| import fs from 'fs'; | import fs from 'fs'; | ||||||
| import cp from 'child_process'; | import cp from 'child_process'; | ||||||
| import osm from 'os'; | import osm from 'os'; | ||||||
| import path from 'path'; | import path from 'path'; | ||||||
| import each from 'jest-each'; |  | ||||||
| import * as main from '../src/main'; | import * as main from '../src/main'; | ||||||
| import * as auth from '../src/authutil'; | import * as auth from '../src/authutil'; | ||||||
|  | import OfficialBuilds from '../src/distributions/official_builds/official_builds'; | ||||||
|  | import {INodeVersion} from '../src/distributions/base-models'; | ||||||
| 
 | 
 | ||||||
| const nodeTestManifest = require('./data/versions-manifest.json'); | const nodeTestManifest = require('./data/versions-manifest.json'); | ||||||
| const nodeTestDist = require('./data/node-dist-index.json'); | const nodeTestDist = require('./data/node-dist-index.json'); | ||||||
| const nodeTestDistNightly = require('./data/node-nightly-index.json'); | const nodeTestDistNightly = require('./data/node-nightly-index.json'); | ||||||
| const nodeTestDistRc = require('./data/node-rc-index.json'); | const nodeTestDistRc = require('./data/node-rc-index.json'); | ||||||
|  | const nodeV8CanaryTestDist = require('./data/v8-canary-dist-index.json'); | ||||||
| 
 | 
 | ||||||
| describe('setup-node', () => { | describe('setup-node', () => { | ||||||
|  |   let build: OfficialBuilds; | ||||||
|   let inputs = {} as any; |   let inputs = {} as any; | ||||||
|   let os = {} as any; |   let os = {} as any; | ||||||
| 
 | 
 | ||||||
| @@ -29,7 +31,6 @@ describe('setup-node', () => { | |||||||
|   let logSpy: jest.SpyInstance; |   let logSpy: jest.SpyInstance; | ||||||
|   let warningSpy: jest.SpyInstance; |   let warningSpy: jest.SpyInstance; | ||||||
|   let getManifestSpy: jest.SpyInstance; |   let getManifestSpy: jest.SpyInstance; | ||||||
|   let getDistSpy: jest.SpyInstance; |  | ||||||
|   let platSpy: jest.SpyInstance; |   let platSpy: jest.SpyInstance; | ||||||
|   let archSpy: jest.SpyInstance; |   let archSpy: jest.SpyInstance; | ||||||
|   let dlSpy: jest.SpyInstance; |   let dlSpy: jest.SpyInstance; | ||||||
| @@ -42,7 +43,6 @@ describe('setup-node', () => { | |||||||
|   let mkdirpSpy: jest.SpyInstance; |   let mkdirpSpy: jest.SpyInstance; | ||||||
|   let execSpy: jest.SpyInstance; |   let execSpy: jest.SpyInstance; | ||||||
|   let authSpy: jest.SpyInstance; |   let authSpy: jest.SpyInstance; | ||||||
|   let parseNodeVersionSpy: jest.SpyInstance; |  | ||||||
|   let isCacheActionAvailable: jest.SpyInstance; |   let isCacheActionAvailable: jest.SpyInstance; | ||||||
|   let getExecOutputSpy: jest.SpyInstance; |   let getExecOutputSpy: jest.SpyInstance; | ||||||
|   let getJsonSpy: jest.SpyInstance; |   let getJsonSpy: jest.SpyInstance; | ||||||
| @@ -71,8 +71,6 @@ describe('setup-node', () => { | |||||||
|     exSpy = jest.spyOn(tc, 'extractTar'); |     exSpy = jest.spyOn(tc, 'extractTar'); | ||||||
|     cacheSpy = jest.spyOn(tc, 'cacheDir'); |     cacheSpy = jest.spyOn(tc, 'cacheDir'); | ||||||
|     getManifestSpy = jest.spyOn(tc, 'getManifestFromRepo'); |     getManifestSpy = jest.spyOn(tc, 'getManifestFromRepo'); | ||||||
|     getDistSpy = jest.spyOn(im, 'getVersionsFromDist'); |  | ||||||
|     parseNodeVersionSpy = jest.spyOn(im, 'parseNodeVersionFile'); |  | ||||||
| 
 | 
 | ||||||
|     // http-client
 |     // http-client
 | ||||||
|     getJsonSpy = jest.spyOn(httpm.HttpClient.prototype, 'getJson'); |     getJsonSpy = jest.spyOn(httpm.HttpClient.prototype, 'getJson'); | ||||||
| @@ -94,25 +92,14 @@ describe('setup-node', () => { | |||||||
|       () => <tc.IToolRelease[]>nodeTestManifest |       () => <tc.IToolRelease[]>nodeTestManifest | ||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
|     getDistSpy.mockImplementation(version => { |  | ||||||
|       const initialUrl = im.getNodejsDistUrl(version); |  | ||||||
|       if (initialUrl.endsWith('/rc')) { |  | ||||||
|         return <im.INodeVersion>nodeTestDistRc; |  | ||||||
|       } else if (initialUrl.endsWith('/nightly')) { |  | ||||||
|         return <im.INodeVersion>nodeTestDistNightly; |  | ||||||
|       } else { |  | ||||||
|         return <im.INodeVersion>nodeTestDist; |  | ||||||
|       } |  | ||||||
|     }); |  | ||||||
| 
 |  | ||||||
|     getJsonSpy.mockImplementation(url => { |     getJsonSpy.mockImplementation(url => { | ||||||
|       let res: any; |       let res: any; | ||||||
|       if (url.includes('/rc')) { |       if (url.includes('/rc')) { | ||||||
|         res = <im.INodeVersion>nodeTestDistRc; |         res = <INodeVersion>nodeTestDistRc; | ||||||
|       } else if (url.includes('/nightly')) { |       } else if (url.includes('/nightly')) { | ||||||
|         res = <im.INodeVersion>nodeTestDistNightly; |         res = <INodeVersion>nodeTestDistNightly; | ||||||
|       } else { |       } else { | ||||||
|         res = <im.INodeVersion>nodeTestDist; |         res = <INodeVersion>nodeTestDist; | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       return {result: res}; |       return {result: res}; | ||||||
| @@ -125,11 +112,11 @@ describe('setup-node', () => { | |||||||
|     warningSpy = jest.spyOn(core, 'warning'); |     warningSpy = jest.spyOn(core, 'warning'); | ||||||
|     cnSpy.mockImplementation(line => { |     cnSpy.mockImplementation(line => { | ||||||
|       // uncomment to debug
 |       // uncomment to debug
 | ||||||
|       // process.stderr.write('write:' + line + '\n');
 |       process.stderr.write('write:' + line + '\n'); | ||||||
|     }); |     }); | ||||||
|     logSpy.mockImplementation(line => { |     logSpy.mockImplementation(line => { | ||||||
|       // uncomment to debug
 |       //   uncomment to debug
 | ||||||
|       // process.stderr.write('log:' + line + '\n');
 |       process.stderr.write('log:' + line + '\n'); | ||||||
|     }); |     }); | ||||||
|     dbgSpy.mockImplementation(msg => { |     dbgSpy.mockImplementation(msg => { | ||||||
|       // uncomment to see debug output
 |       // uncomment to see debug output
 | ||||||
| @@ -137,7 +124,7 @@ describe('setup-node', () => { | |||||||
|     }); |     }); | ||||||
|     warningSpy.mockImplementation(msg => { |     warningSpy.mockImplementation(msg => { | ||||||
|       // uncomment to debug
 |       // uncomment to debug
 | ||||||
|       // process.stderr.write('log:' + line + '\n');
 |       // process.stderr.write('log:' + msg + '\n');
 | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     // @actions/exec
 |     // @actions/exec
 | ||||||
| @@ -159,23 +146,6 @@ describe('setup-node', () => { | |||||||
|   //--------------------------------------------------
 |   //--------------------------------------------------
 | ||||||
|   // Manifest find tests
 |   // Manifest find tests
 | ||||||
|   //--------------------------------------------------
 |   //--------------------------------------------------
 | ||||||
|   it('can mock manifest versions', async () => { |  | ||||||
|     let versions: tc.IToolRelease[] | null = await tc.getManifestFromRepo( |  | ||||||
|       'actions', |  | ||||||
|       'node-versions', |  | ||||||
|       'mocktoken' |  | ||||||
|     ); |  | ||||||
|     expect(versions).toBeDefined(); |  | ||||||
|     expect(versions?.length).toBe(7); |  | ||||||
|   }); |  | ||||||
| 
 |  | ||||||
|   it('can mock dist versions', async () => { |  | ||||||
|     const versionSpec = '1.2.3'; |  | ||||||
|     let versions: im.INodeVersion[] = await im.getVersionsFromDist(versionSpec); |  | ||||||
|     expect(versions).toBeDefined(); |  | ||||||
|     expect(versions?.length).toBe(23); |  | ||||||
|   }); |  | ||||||
| 
 |  | ||||||
|   it.each([ |   it.each([ | ||||||
|     ['12.16.2', 'darwin', '12.16.2', 'Erbium'], |     ['12.16.2', 'darwin', '12.16.2', 'Erbium'], | ||||||
|     ['12', 'linux', '12.16.2', 'Erbium'], |     ['12', 'linux', '12.16.2', 'Erbium'], | ||||||
| @@ -315,35 +285,32 @@ describe('setup-node', () => { | |||||||
| 
 | 
 | ||||||
|     // a version which is not in the manifest but is in node dist
 |     // a version which is not in the manifest but is in node dist
 | ||||||
|     let versionSpec = '11.15.0'; |     let versionSpec = '11.15.0'; | ||||||
|     let resolvedVersion = versionSpec; |  | ||||||
| 
 | 
 | ||||||
|     inputs['node-version'] = versionSpec; |     inputs['node-version'] = versionSpec; | ||||||
|     inputs['always-auth'] = false; |     inputs['always-auth'] = false; | ||||||
|     inputs['token'] = 'faketoken'; |     inputs['token'] = 'faketoken'; | ||||||
| 
 | 
 | ||||||
|     let expectedUrl = |  | ||||||
|       'https://github.com/actions/node-versions/releases/download/12.16.2-20200507.95/node-12.16.2-linux-x64.tar.gz'; |  | ||||||
| 
 |  | ||||||
|     // ... but not in the local cache
 |     // ... but not in the local cache
 | ||||||
|     findSpy.mockImplementation(() => ''); |     findSpy.mockImplementation(() => ''); | ||||||
| 
 | 
 | ||||||
|     dlSpy.mockImplementation(async () => '/some/temp/path'); |     dlSpy.mockImplementation(async () => '/some/temp/path'); | ||||||
|     let toolPath = path.normalize('/cache/node/11.11.0/x64'); |     const toolPath = path.normalize('/cache/node/11.15.0/x64'); | ||||||
|     exSpy.mockImplementation(async () => '/some/other/temp/path'); |     exSpy.mockImplementation(async () => '/some/other/temp/path'); | ||||||
|     cacheSpy.mockImplementation(async () => toolPath); |     cacheSpy.mockImplementation(async () => toolPath); | ||||||
| 
 | 
 | ||||||
|     await main.run(); |     await main.run(); | ||||||
| 
 | 
 | ||||||
|     let expPath = path.join(toolPath, 'bin'); |     const expPath = path.join(toolPath, 'bin'); | ||||||
| 
 | 
 | ||||||
|     expect(dlSpy).toHaveBeenCalled(); |     expect(getManifestSpy).toHaveBeenCalled(); | ||||||
|     expect(exSpy).toHaveBeenCalled(); |  | ||||||
|     expect(logSpy).toHaveBeenCalledWith( |  | ||||||
|       'Not found in manifest.  Falling back to download directly from Node' |  | ||||||
|     ); |  | ||||||
|     expect(logSpy).toHaveBeenCalledWith( |     expect(logSpy).toHaveBeenCalledWith( | ||||||
|       `Attempting to download ${versionSpec}...` |       `Attempting to download ${versionSpec}...` | ||||||
|     ); |     ); | ||||||
|  |     expect(logSpy).toHaveBeenCalledWith( | ||||||
|  |       'Not found in manifest. Falling back to download directly from Node' | ||||||
|  |     ); | ||||||
|  |     expect(dlSpy).toHaveBeenCalled(); | ||||||
|  |     expect(exSpy).toHaveBeenCalled(); | ||||||
|     expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`); |     expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`); | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
| @@ -358,7 +325,7 @@ describe('setup-node', () => { | |||||||
|     await main.run(); |     await main.run(); | ||||||
| 
 | 
 | ||||||
|     expect(logSpy).toHaveBeenCalledWith( |     expect(logSpy).toHaveBeenCalledWith( | ||||||
|       'Not found in manifest.  Falling back to download directly from Node' |       'Not found in manifest. Falling back to download directly from Node' | ||||||
|     ); |     ); | ||||||
|     expect(logSpy).toHaveBeenCalledWith( |     expect(logSpy).toHaveBeenCalledWith( | ||||||
|       `Attempting to download ${versionSpec}...` |       `Attempting to download ${versionSpec}...` | ||||||
| @@ -596,165 +563,6 @@ describe('setup-node', () => { | |||||||
|     }); |     }); | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|   describe('node-version-file flag', () => { |  | ||||||
|     it('not used if node-version is provided', async () => { |  | ||||||
|       // Arrange
 |  | ||||||
|       inputs['node-version'] = '12'; |  | ||||||
| 
 |  | ||||||
|       // Act
 |  | ||||||
|       await main.run(); |  | ||||||
| 
 |  | ||||||
|       // Assert
 |  | ||||||
|       expect(parseNodeVersionSpy).toHaveBeenCalledTimes(0); |  | ||||||
|     }); |  | ||||||
| 
 |  | ||||||
|     it('not used if node-version-file not provided', async () => { |  | ||||||
|       // Act
 |  | ||||||
|       await main.run(); |  | ||||||
| 
 |  | ||||||
|       // Assert
 |  | ||||||
|       expect(parseNodeVersionSpy).toHaveBeenCalledTimes(0); |  | ||||||
|     }); |  | ||||||
| 
 |  | ||||||
|     it('reads node-version-file if provided', async () => { |  | ||||||
|       // Arrange
 |  | ||||||
|       const versionSpec = 'v14'; |  | ||||||
|       const versionFile = '.nvmrc'; |  | ||||||
|       const expectedVersionSpec = '14'; |  | ||||||
|       process.env['GITHUB_WORKSPACE'] = path.join(__dirname, 'data'); |  | ||||||
|       inputs['node-version-file'] = versionFile; |  | ||||||
| 
 |  | ||||||
|       parseNodeVersionSpy.mockImplementation(() => expectedVersionSpec); |  | ||||||
|       existsSpy.mockImplementationOnce( |  | ||||||
|         input => input === path.join(__dirname, 'data', versionFile) |  | ||||||
|       ); |  | ||||||
| 
 |  | ||||||
|       // Act
 |  | ||||||
|       await main.run(); |  | ||||||
| 
 |  | ||||||
|       // Assert
 |  | ||||||
|       expect(existsSpy).toHaveBeenCalledTimes(1); |  | ||||||
|       expect(existsSpy).toHaveReturnedWith(true); |  | ||||||
|       expect(parseNodeVersionSpy).toHaveBeenCalledWith(versionSpec); |  | ||||||
|       expect(logSpy).toHaveBeenCalledWith( |  | ||||||
|         `Resolved ${versionFile} as ${expectedVersionSpec}` |  | ||||||
|       ); |  | ||||||
|     }); |  | ||||||
| 
 |  | ||||||
|     it('reads package.json as node-version-file if provided', async () => { |  | ||||||
|       // Arrange
 |  | ||||||
|       const versionSpec = fs.readFileSync( |  | ||||||
|         path.join(__dirname, 'data/package.json'), |  | ||||||
|         'utf-8' |  | ||||||
|       ); |  | ||||||
|       const versionFile = 'package.json'; |  | ||||||
|       const expectedVersionSpec = '14'; |  | ||||||
|       process.env['GITHUB_WORKSPACE'] = path.join(__dirname, 'data'); |  | ||||||
|       inputs['node-version-file'] = versionFile; |  | ||||||
| 
 |  | ||||||
|       parseNodeVersionSpy.mockImplementation(() => expectedVersionSpec); |  | ||||||
|       existsSpy.mockImplementationOnce( |  | ||||||
|         input => input === path.join(__dirname, 'data', versionFile) |  | ||||||
|       ); |  | ||||||
|       // Act
 |  | ||||||
|       await main.run(); |  | ||||||
| 
 |  | ||||||
|       // Assert
 |  | ||||||
|       expect(existsSpy).toHaveBeenCalledTimes(1); |  | ||||||
|       expect(existsSpy).toHaveReturnedWith(true); |  | ||||||
|       expect(parseNodeVersionSpy).toHaveBeenCalledWith(versionSpec); |  | ||||||
|       expect(logSpy).toHaveBeenCalledWith( |  | ||||||
|         `Resolved ${versionFile} as ${expectedVersionSpec}` |  | ||||||
|       ); |  | ||||||
|     }); |  | ||||||
| 
 |  | ||||||
|     it('both node-version-file and node-version are provided', async () => { |  | ||||||
|       inputs['node-version'] = '12'; |  | ||||||
|       const versionSpec = 'v14'; |  | ||||||
|       const versionFile = '.nvmrc'; |  | ||||||
|       const expectedVersionSpec = '14'; |  | ||||||
|       process.env['GITHUB_WORKSPACE'] = path.join(__dirname, '..'); |  | ||||||
|       inputs['node-version-file'] = versionFile; |  | ||||||
| 
 |  | ||||||
|       parseNodeVersionSpy.mockImplementation(() => expectedVersionSpec); |  | ||||||
| 
 |  | ||||||
|       // Act
 |  | ||||||
|       await main.run(); |  | ||||||
| 
 |  | ||||||
|       // Assert
 |  | ||||||
|       expect(existsSpy).toHaveBeenCalledTimes(0); |  | ||||||
|       expect(parseNodeVersionSpy).not.toHaveBeenCalled(); |  | ||||||
|       expect(warningSpy).toHaveBeenCalledWith( |  | ||||||
|         'Both node-version and node-version-file inputs are specified, only node-version will be used' |  | ||||||
|       ); |  | ||||||
|     }); |  | ||||||
| 
 |  | ||||||
|     it('should throw an error if node-version-file is not found', async () => { |  | ||||||
|       const versionFile = '.nvmrc'; |  | ||||||
|       const versionFilePath = path.join(__dirname, '..', versionFile); |  | ||||||
|       inputs['node-version-file'] = versionFile; |  | ||||||
| 
 |  | ||||||
|       inSpy.mockImplementation(name => inputs[name]); |  | ||||||
|       existsSpy.mockImplementationOnce( |  | ||||||
|         input => input === path.join(__dirname, 'data', versionFile) |  | ||||||
|       ); |  | ||||||
| 
 |  | ||||||
|       // Act
 |  | ||||||
|       await main.run(); |  | ||||||
| 
 |  | ||||||
|       // Assert
 |  | ||||||
|       expect(existsSpy).toHaveBeenCalled(); |  | ||||||
|       expect(existsSpy).toHaveReturnedWith(false); |  | ||||||
|       expect(parseNodeVersionSpy).not.toHaveBeenCalled(); |  | ||||||
|       expect(cnSpy).toHaveBeenCalledWith( |  | ||||||
|         `::error::The specified node version file at: ${versionFilePath} does not exist${osm.EOL}` |  | ||||||
|       ); |  | ||||||
|     }); |  | ||||||
|   }); |  | ||||||
| 
 |  | ||||||
|   describe('cache on GHES', () => { |  | ||||||
|     it('Should throw an error, because cache is not supported', async () => { |  | ||||||
|       inputs['node-version'] = '12'; |  | ||||||
|       inputs['cache'] = 'npm'; |  | ||||||
| 
 |  | ||||||
|       inSpy.mockImplementation(name => inputs[name]); |  | ||||||
| 
 |  | ||||||
|       let toolPath = path.normalize('/cache/node/12.16.1/x64'); |  | ||||||
|       findSpy.mockImplementation(() => toolPath); |  | ||||||
| 
 |  | ||||||
|       // expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`);
 |  | ||||||
|       process.env['GITHUB_SERVER_URL'] = 'https://www.test.com'; |  | ||||||
|       isCacheActionAvailable.mockImplementation(() => false); |  | ||||||
| 
 |  | ||||||
|       await main.run(); |  | ||||||
| 
 |  | ||||||
|       expect(warningSpy).toHaveBeenCalledWith( |  | ||||||
|         //  `::error::Cache action is only supported on GHES version >= 3.5. If you are on version >=3.5 Please check with GHES admin if Actions cache service is enabled or not.${osm.EOL}`
 |  | ||||||
|         'Cache action is only supported on GHES version >= 3.5. If you are on version >=3.5 Please check with GHES admin if Actions cache service is enabled or not.' |  | ||||||
|       ); |  | ||||||
|     }); |  | ||||||
| 
 |  | ||||||
|     it('Should throw an internal error', async () => { |  | ||||||
|       inputs['node-version'] = '12'; |  | ||||||
|       inputs['cache'] = 'npm'; |  | ||||||
| 
 |  | ||||||
|       inSpy.mockImplementation(name => inputs[name]); |  | ||||||
| 
 |  | ||||||
|       let toolPath = path.normalize('/cache/node/12.16.1/x64'); |  | ||||||
|       findSpy.mockImplementation(() => toolPath); |  | ||||||
| 
 |  | ||||||
|       // expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`);
 |  | ||||||
|       process.env['GITHUB_SERVER_URL'] = ''; |  | ||||||
|       isCacheActionAvailable.mockImplementation(() => false); |  | ||||||
| 
 |  | ||||||
|       await main.run(); |  | ||||||
| 
 |  | ||||||
|       expect(warningSpy).toHaveBeenCalledWith( |  | ||||||
|         'The runner was not able to contact the cache service. Caching will be skipped' |  | ||||||
|       ); |  | ||||||
|     }); |  | ||||||
|   }); |  | ||||||
| 
 |  | ||||||
|   describe('LTS version', () => { |   describe('LTS version', () => { | ||||||
|     beforeEach(() => { |     beforeEach(() => { | ||||||
|       os.platform = 'linux'; |       os.platform = 'linux'; | ||||||
| @@ -930,277 +738,6 @@ describe('setup-node', () => { | |||||||
|     }); |     }); | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|   describe('rc versions', () => { |  | ||||||
|     it.each([ |  | ||||||
|       [ |  | ||||||
|         '13.10.1-rc.0', |  | ||||||
|         '13.10.1-rc.0', |  | ||||||
|         'https://nodejs.org/download/rc/v13.10.1-rc.0/node-v13.10.1-rc.0-linux-x64.tar.gz' |  | ||||||
|       ], |  | ||||||
|       [ |  | ||||||
|         '14.15.5-rc.1', |  | ||||||
|         '14.15.5-rc.1', |  | ||||||
|         'https://nodejs.org/download/rc/v14.15.5-rc.1/node-v14.15.5-rc.1-linux-x64.tar.gz' |  | ||||||
|       ], |  | ||||||
|       [ |  | ||||||
|         '16.17.0-rc.1', |  | ||||||
|         '16.17.0-rc.1', |  | ||||||
|         'https://nodejs.org/download/rc/v16.17.0-rc.1/node-v16.17.0-rc.1-linux-x64.tar.gz' |  | ||||||
|       ], |  | ||||||
|       [ |  | ||||||
|         '17.0.0-rc.1', |  | ||||||
|         '17.0.0-rc.1', |  | ||||||
|         'https://nodejs.org/download/rc/v17.0.0-rc.1/node-v17.0.0-rc.1-linux-x64.tar.gz' |  | ||||||
|       ], |  | ||||||
|       [ |  | ||||||
|         '19.0.0-rc.2', |  | ||||||
|         '19.0.0-rc.2', |  | ||||||
|         'https://nodejs.org/download/rc/v19.0.0-rc.2/node-v19.0.0-rc.2-linux-x64.tar.gz' |  | ||||||
|       ] |  | ||||||
|     ])( |  | ||||||
|       'finds the versions in the index.json and installs it', |  | ||||||
|       async (input, expectedVersion, expectedUrl) => { |  | ||||||
|         const toolPath = path.normalize(`/cache/node/${expectedVersion}/x64`); |  | ||||||
| 
 |  | ||||||
|         findSpy.mockImplementation(() => ''); |  | ||||||
|         findAllVersionsSpy.mockImplementation(() => []); |  | ||||||
|         dlSpy.mockImplementation(async () => '/some/temp/path'); |  | ||||||
|         exSpy.mockImplementation(async () => '/some/other/temp/path'); |  | ||||||
|         cacheSpy.mockImplementation(async () => toolPath); |  | ||||||
| 
 |  | ||||||
|         inputs['node-version'] = input; |  | ||||||
|         os['arch'] = 'x64'; |  | ||||||
|         os['platform'] = 'linux'; |  | ||||||
|         // act
 |  | ||||||
|         await main.run(); |  | ||||||
| 
 |  | ||||||
|         // assert
 |  | ||||||
|         expect(logSpy).toHaveBeenCalledWith( |  | ||||||
|           `Attempting to download ${input}...` |  | ||||||
|         ); |  | ||||||
| 
 |  | ||||||
|         expect(logSpy).toHaveBeenCalledWith( |  | ||||||
|           `Acquiring ${expectedVersion} - ${os.arch} from ${expectedUrl}` |  | ||||||
|         ); |  | ||||||
|         expect(logSpy).toHaveBeenCalledWith('Extracting ...'); |  | ||||||
|         expect(logSpy).toHaveBeenCalledWith('Adding to the cache ...'); |  | ||||||
|         expect(cnSpy).toHaveBeenCalledWith( |  | ||||||
|           `::add-path::${path.join(toolPath, 'bin')}${osm.EOL}` |  | ||||||
|         ); |  | ||||||
|       } |  | ||||||
|     ); |  | ||||||
| 
 |  | ||||||
|     it.each([ |  | ||||||
|       ['13.10.1-rc.0', '13.10.1-rc.0'], |  | ||||||
|       ['14.15.5-rc.1', '14.15.5-rc.1'], |  | ||||||
|       ['16.17.0-rc.1', '16.17.0-rc.1'], |  | ||||||
|       ['17.0.0-rc.1', '17.0.0-rc.1'] |  | ||||||
|     ])( |  | ||||||
|       'finds the %s version in the hostedToolcache', |  | ||||||
|       async (input, expectedVersion) => { |  | ||||||
|         const toolPath = path.normalize(`/cache/node/${expectedVersion}/x64`); |  | ||||||
|         findSpy.mockReturnValue(toolPath); |  | ||||||
| 
 |  | ||||||
|         inputs['node-version'] = input; |  | ||||||
|         os['arch'] = 'x64'; |  | ||||||
|         os['platform'] = 'linux'; |  | ||||||
| 
 |  | ||||||
|         // act
 |  | ||||||
|         await main.run(); |  | ||||||
| 
 |  | ||||||
|         // assert
 |  | ||||||
|         expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`); |  | ||||||
|         expect(cnSpy).toHaveBeenCalledWith( |  | ||||||
|           `::add-path::${path.join(toolPath, 'bin')}${osm.EOL}` |  | ||||||
|         ); |  | ||||||
|       } |  | ||||||
|     ); |  | ||||||
| 
 |  | ||||||
|     it('throws an error if version is not found', async () => { |  | ||||||
|       const versionSpec = '19.0.0-rc.3'; |  | ||||||
| 
 |  | ||||||
|       findSpy.mockImplementation(() => ''); |  | ||||||
|       findAllVersionsSpy.mockImplementation(() => []); |  | ||||||
|       dlSpy.mockImplementation(async () => '/some/temp/path'); |  | ||||||
|       exSpy.mockImplementation(async () => '/some/other/temp/path'); |  | ||||||
| 
 |  | ||||||
|       inputs['node-version'] = versionSpec; |  | ||||||
|       os['arch'] = 'x64'; |  | ||||||
|       os['platform'] = 'linux'; |  | ||||||
|       // act
 |  | ||||||
|       await main.run(); |  | ||||||
| 
 |  | ||||||
|       // assert
 |  | ||||||
|       expect(logSpy).toHaveBeenCalledWith( |  | ||||||
|         `Attempting to download ${versionSpec}...` |  | ||||||
|       ); |  | ||||||
|       expect(cnSpy).toHaveBeenCalledWith( |  | ||||||
|         `::error::Unable to find Node version '${versionSpec}' for platform ${os.platform} and architecture ${os.arch}.${osm.EOL}` |  | ||||||
|       ); |  | ||||||
|     }); |  | ||||||
|   }); |  | ||||||
| 
 |  | ||||||
|   describe('nightly versions', () => { |  | ||||||
|     it.each([ |  | ||||||
|       [ |  | ||||||
|         '17.5.0-nightly', |  | ||||||
|         '17.5.0-nightly20220209e43808936a', |  | ||||||
|         'https://nodejs.org/download/nightly/v17.5.0-nightly20220209e43808936a/node-v17.5.0-nightly20220209e43808936a-linux-x64.tar.gz' |  | ||||||
|       ], |  | ||||||
|       [ |  | ||||||
|         '17-nightly', |  | ||||||
|         '17.5.0-nightly20220209e43808936a', |  | ||||||
|         'https://nodejs.org/download/nightly/v17.5.0-nightly20220209e43808936a/node-v17.5.0-nightly20220209e43808936a-linux-x64.tar.gz' |  | ||||||
|       ], |  | ||||||
|       [ |  | ||||||
|         '18.0.0-nightly', |  | ||||||
|         '18.0.0-nightly20220419bde889bd4e', |  | ||||||
|         'https://nodejs.org/download/nightly/v18.0.0-nightly20220419bde889bd4e/node-v18.0.0-nightly20220419bde889bd4e-linux-x64.tar.gz' |  | ||||||
|       ], |  | ||||||
|       [ |  | ||||||
|         '18-nightly', |  | ||||||
|         '18.0.0-nightly20220419bde889bd4e', |  | ||||||
|         'https://nodejs.org/download/nightly/v18.0.0-nightly20220419bde889bd4e/node-v18.0.0-nightly20220419bde889bd4e-linux-x64.tar.gz' |  | ||||||
|       ], |  | ||||||
|       [ |  | ||||||
|         '20.0.0-nightly', |  | ||||||
|         '20.0.0-nightly2022101987cdf7d412', |  | ||||||
|         'https://nodejs.org/download/nightly/v20.0.0-nightly2022101987cdf7d412/node-v20.0.0-nightly2022101987cdf7d412-linux-x64.tar.gz' |  | ||||||
|       ] |  | ||||||
|     ])( |  | ||||||
|       'finds the versions in the index.json and installs it', |  | ||||||
|       async (input, expectedVersion, expectedUrl) => { |  | ||||||
|         const toolPath = path.normalize(`/cache/node/${expectedVersion}/x64`); |  | ||||||
| 
 |  | ||||||
|         findSpy.mockImplementation(() => ''); |  | ||||||
|         findAllVersionsSpy.mockImplementation(() => []); |  | ||||||
|         dlSpy.mockImplementation(async () => '/some/temp/path'); |  | ||||||
|         exSpy.mockImplementation(async () => '/some/other/temp/path'); |  | ||||||
|         cacheSpy.mockImplementation(async () => toolPath); |  | ||||||
| 
 |  | ||||||
|         inputs['node-version'] = input; |  | ||||||
|         os['arch'] = 'x64'; |  | ||||||
|         os['platform'] = 'linux'; |  | ||||||
|         // act
 |  | ||||||
|         await main.run(); |  | ||||||
| 
 |  | ||||||
|         // assert
 |  | ||||||
|         expect(logSpy).toHaveBeenCalledWith( |  | ||||||
|           `Attempting to download ${input}...` |  | ||||||
|         ); |  | ||||||
| 
 |  | ||||||
|         expect(logSpy).toHaveBeenCalledWith( |  | ||||||
|           `Acquiring ${expectedVersion} - ${os.arch} from ${expectedUrl}` |  | ||||||
|         ); |  | ||||||
|         expect(logSpy).toHaveBeenCalledWith('Extracting ...'); |  | ||||||
|         expect(logSpy).toHaveBeenCalledWith('Adding to the cache ...'); |  | ||||||
|         expect(cnSpy).toHaveBeenCalledWith( |  | ||||||
|           `::add-path::${path.join(toolPath, 'bin')}${osm.EOL}` |  | ||||||
|         ); |  | ||||||
|       } |  | ||||||
|     ); |  | ||||||
| 
 |  | ||||||
|     it.each([ |  | ||||||
|       ['17.5.0-nightly', '17.5.0-nightly20220209e43808936a'], |  | ||||||
|       ['17-nightly', '17.5.0-nightly20220209e43808936a'], |  | ||||||
|       ['20.0.0-nightly', '20.0.0-nightly2022101987cdf7d412'] |  | ||||||
|     ])( |  | ||||||
|       'finds the %s version in the hostedToolcache', |  | ||||||
|       async (input, expectedVersion) => { |  | ||||||
|         const toolPath = path.normalize(`/cache/node/${expectedVersion}/x64`); |  | ||||||
|         findSpy.mockReturnValue(toolPath); |  | ||||||
|         findAllVersionsSpy.mockReturnValue([ |  | ||||||
|           '17.5.0-nightly20220209e43808936a', |  | ||||||
|           '17.5.0-nightly20220209e43808935a', |  | ||||||
|           '20.0.0-nightly2022101987cdf7d412', |  | ||||||
|           '20.0.0-nightly2022101987cdf7d411' |  | ||||||
|         ]); |  | ||||||
| 
 |  | ||||||
|         inputs['node-version'] = input; |  | ||||||
|         os['arch'] = 'x64'; |  | ||||||
|         os['platform'] = 'linux'; |  | ||||||
| 
 |  | ||||||
|         // act
 |  | ||||||
|         await main.run(); |  | ||||||
| 
 |  | ||||||
|         // assert
 |  | ||||||
|         expect(findAllVersionsSpy).toHaveBeenCalled(); |  | ||||||
|         expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`); |  | ||||||
|         expect(cnSpy).toHaveBeenCalledWith( |  | ||||||
|           `::add-path::${path.join(toolPath, 'bin')}${osm.EOL}` |  | ||||||
|         ); |  | ||||||
|       } |  | ||||||
|     ); |  | ||||||
| 
 |  | ||||||
|     it.each([ |  | ||||||
|       [ |  | ||||||
|         '17.5.0-nightly', |  | ||||||
|         '17.5.0-nightly20220209e43808936a', |  | ||||||
|         '17.0.0-nightly202110193f11666dc7', |  | ||||||
|         'https://nodejs.org/download/nightly/v17.5.0-nightly20220209e43808936a/node-v17.5.0-nightly20220209e43808936a-linux-x64.tar.gz' |  | ||||||
|       ], |  | ||||||
|       [ |  | ||||||
|         '17-nightly', |  | ||||||
|         '17.5.0-nightly20220209e43808936a', |  | ||||||
|         '17.0.0-nightly202110193f11666dc7', |  | ||||||
|         'https://nodejs.org/download/nightly/v17.5.0-nightly20220209e43808936a/node-v17.5.0-nightly20220209e43808936a-linux-x64.tar.gz' |  | ||||||
|       ], |  | ||||||
|       [ |  | ||||||
|         '18.0.0-nightly', |  | ||||||
|         '18.0.0-nightly20220419bde889bd4e', |  | ||||||
|         '18.0.0-nightly202204180699150267', |  | ||||||
|         'https://nodejs.org/download/nightly/v18.0.0-nightly20220419bde889bd4e/node-v18.0.0-nightly20220419bde889bd4e-linux-x64.tar.gz' |  | ||||||
|       ], |  | ||||||
|       [ |  | ||||||
|         '18-nightly', |  | ||||||
|         '18.0.0-nightly20220419bde889bd4e', |  | ||||||
|         '18.0.0-nightly202204180699150267', |  | ||||||
|         'https://nodejs.org/download/nightly/v18.0.0-nightly20220419bde889bd4e/node-v18.0.0-nightly20220419bde889bd4e-linux-x64.tar.gz' |  | ||||||
|       ], |  | ||||||
|       [ |  | ||||||
|         '20.0.0-nightly', |  | ||||||
|         '20.0.0-nightly2022101987cdf7d412', |  | ||||||
|         '20.0.0-nightly2022101987cdf7d411', |  | ||||||
|         'https://nodejs.org/download/nightly/v20.0.0-nightly2022101987cdf7d412/node-v20.0.0-nightly2022101987cdf7d412-linux-x64.tar.gz' |  | ||||||
|       ] |  | ||||||
|     ])( |  | ||||||
|       'get %s version from dist if check-latest is true', |  | ||||||
|       async (input, expectedVersion, foundVersion, expectedUrl) => { |  | ||||||
|         const foundToolPath = path.normalize(`/cache/node/${foundVersion}/x64`); |  | ||||||
|         const toolPath = path.normalize(`/cache/node/${expectedVersion}/x64`); |  | ||||||
| 
 |  | ||||||
|         inputs['node-version'] = input; |  | ||||||
|         inputs['check-latest'] = 'true'; |  | ||||||
|         os['arch'] = 'x64'; |  | ||||||
|         os['platform'] = 'linux'; |  | ||||||
| 
 |  | ||||||
|         findSpy.mockReturnValue(foundToolPath); |  | ||||||
|         findAllVersionsSpy.mockReturnValue([ |  | ||||||
|           '17.0.0-nightly202110193f11666dc7', |  | ||||||
|           '18.0.0-nightly202204180699150267', |  | ||||||
|           '20.0.0-nightly2022101987cdf7d411' |  | ||||||
|         ]); |  | ||||||
|         dlSpy.mockImplementation(async () => '/some/temp/path'); |  | ||||||
|         exSpy.mockImplementation(async () => '/some/other/temp/path'); |  | ||||||
|         cacheSpy.mockImplementation(async () => toolPath); |  | ||||||
| 
 |  | ||||||
|         // act
 |  | ||||||
|         await main.run(); |  | ||||||
| 
 |  | ||||||
|         // assert
 |  | ||||||
|         expect(findAllVersionsSpy).toHaveBeenCalled(); |  | ||||||
|         expect(logSpy).toHaveBeenCalledWith( |  | ||||||
|           `Acquiring ${expectedVersion} - ${os.arch} from ${expectedUrl}` |  | ||||||
|         ); |  | ||||||
|         expect(logSpy).toHaveBeenCalledWith('Extracting ...'); |  | ||||||
|         expect(logSpy).toHaveBeenCalledWith('Adding to the cache ...'); |  | ||||||
|         expect(cnSpy).toHaveBeenCalledWith( |  | ||||||
|           `::add-path::${path.join(toolPath, 'bin')}${osm.EOL}` |  | ||||||
|         ); |  | ||||||
|       } |  | ||||||
|     ); |  | ||||||
|   }); |  | ||||||
| 
 |  | ||||||
|   describe('latest alias syntax', () => { |   describe('latest alias syntax', () => { | ||||||
|     it.each(['latest', 'current', 'node'])( |     it.each(['latest', 'current', 'node'])( | ||||||
|       'download the %s version if alias is provided', |       'download the %s version if alias is provided', | ||||||
| @@ -1241,36 +778,16 @@ describe('setup-node', () => { | |||||||
|         const toolPath = path.normalize( |         const toolPath = path.normalize( | ||||||
|           `/cache/node/${expectedVersion.version}/x64` |           `/cache/node/${expectedVersion.version}/x64` | ||||||
|         ); |         ); | ||||||
|         findSpy.mockReturnValue(toolPath); |         findSpy.mockImplementation(() => toolPath); | ||||||
| 
 | 
 | ||||||
|         // Act
 |         // Act
 | ||||||
|         await main.run(); |         await main.run(); | ||||||
| 
 | 
 | ||||||
|         // assert
 |         // assert
 | ||||||
|         expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`); |  | ||||||
| 
 | 
 | ||||||
|         expect(logSpy).toHaveBeenCalledWith('getting latest node version...'); |         expect(logSpy).toHaveBeenCalledWith('getting latest node version...'); | ||||||
|  |         expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`); | ||||||
|       } |       } | ||||||
|     ); |     ); | ||||||
|   }); |   }); | ||||||
| }); | }); | ||||||
| 
 |  | ||||||
| describe('helper methods', () => { |  | ||||||
|   describe('parseNodeVersionFile', () => { |  | ||||||
|     each` |  | ||||||
|       contents                                     | expected |  | ||||||
|       ${'12'}                                      | ${'12'} |  | ||||||
|       ${'12.3'}                                    | ${'12.3'} |  | ||||||
|       ${'12.3.4'}                                  | ${'12.3.4'} |  | ||||||
|       ${'v12.3.4'}                                 | ${'12.3.4'} |  | ||||||
|       ${'lts/erbium'}                              | ${'lts/erbium'} |  | ||||||
|       ${'lts/*'}                                   | ${'lts/*'} |  | ||||||
|       ${'nodejs 12.3.4'}                           | ${'12.3.4'} |  | ||||||
|       ${'ruby 2.3.4\nnodejs 12.3.4\npython 3.4.5'} | ${'12.3.4'} |  | ||||||
|       ${''}                                        | ${''} |  | ||||||
|       ${'unknown format'}                          | ${'unknown format'} |  | ||||||
|     `.it('parses "$contents"', ({contents, expected}) => {
 |  | ||||||
|       expect(im.parseNodeVersionFile(contents)).toBe(expected); |  | ||||||
|     }); |  | ||||||
|   }); |  | ||||||
| }); |  | ||||||
							
								
								
									
										402
									
								
								__tests__/rc-installer.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										402
									
								
								__tests__/rc-installer.test.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,402 @@ | |||||||
|  | import * as core from '@actions/core'; | ||||||
|  | import * as io from '@actions/io'; | ||||||
|  | import * as tc from '@actions/tool-cache'; | ||||||
|  | import * as httpm from '@actions/http-client'; | ||||||
|  | import * as exec from '@actions/exec'; | ||||||
|  | import * as cache from '@actions/cache'; | ||||||
|  | import fs from 'fs'; | ||||||
|  | import cp from 'child_process'; | ||||||
|  | import osm from 'os'; | ||||||
|  | import path from 'path'; | ||||||
|  | import * as main from '../src/main'; | ||||||
|  | import * as auth from '../src/authutil'; | ||||||
|  | import {INodeVersion} from '../src/distributions/base-models'; | ||||||
|  |  | ||||||
|  | const nodeTestDist = require('./data/node-dist-index.json'); | ||||||
|  | const nodeTestDistNightly = require('./data/node-nightly-index.json'); | ||||||
|  | const nodeTestDistRc = require('./data/node-rc-index.json'); | ||||||
|  | const nodeV8CanaryTestDist = require('./data/v8-canary-dist-index.json'); | ||||||
|  |  | ||||||
|  | describe('setup-node', () => { | ||||||
|  |   let inputs = {} as any; | ||||||
|  |   let os = {} as any; | ||||||
|  |  | ||||||
|  |   let inSpy: jest.SpyInstance; | ||||||
|  |   let findSpy: jest.SpyInstance; | ||||||
|  |   let findAllVersionsSpy: jest.SpyInstance; | ||||||
|  |   let cnSpy: jest.SpyInstance; | ||||||
|  |   let logSpy: jest.SpyInstance; | ||||||
|  |   let warningSpy: jest.SpyInstance; | ||||||
|  |   let platSpy: jest.SpyInstance; | ||||||
|  |   let archSpy: jest.SpyInstance; | ||||||
|  |   let dlSpy: jest.SpyInstance; | ||||||
|  |   let exSpy: jest.SpyInstance; | ||||||
|  |   let cacheSpy: jest.SpyInstance; | ||||||
|  |   let dbgSpy: jest.SpyInstance; | ||||||
|  |   let whichSpy: jest.SpyInstance; | ||||||
|  |   let existsSpy: jest.SpyInstance; | ||||||
|  |   let mkdirpSpy: jest.SpyInstance; | ||||||
|  |   let execSpy: jest.SpyInstance; | ||||||
|  |   let authSpy: jest.SpyInstance; | ||||||
|  |   let isCacheActionAvailable: jest.SpyInstance; | ||||||
|  |   let getExecOutputSpy: jest.SpyInstance; | ||||||
|  |   let getJsonSpy: jest.SpyInstance; | ||||||
|  |  | ||||||
|  |   beforeEach(() => { | ||||||
|  |     // @actions/core | ||||||
|  |     console.log('::stop-commands::stoptoken'); // Disable executing of runner commands when running tests in actions | ||||||
|  |     process.env['GITHUB_PATH'] = ''; // Stub out ENV file functionality so we can verify it writes to standard out | ||||||
|  |     process.env['GITHUB_OUTPUT'] = ''; // Stub out ENV file functionality so we can verify it writes to standard out | ||||||
|  |     inputs = {}; | ||||||
|  |     inSpy = jest.spyOn(core, 'getInput'); | ||||||
|  |     inSpy.mockImplementation(name => inputs[name]); | ||||||
|  |  | ||||||
|  |     // node | ||||||
|  |     os = {}; | ||||||
|  |     platSpy = jest.spyOn(osm, 'platform'); | ||||||
|  |     platSpy.mockImplementation(() => os['platform']); | ||||||
|  |     archSpy = jest.spyOn(osm, 'arch'); | ||||||
|  |     archSpy.mockImplementation(() => os['arch']); | ||||||
|  |     execSpy = jest.spyOn(cp, 'execSync'); | ||||||
|  |  | ||||||
|  |     // @actions/tool-cache | ||||||
|  |     findSpy = jest.spyOn(tc, 'find'); | ||||||
|  |     findAllVersionsSpy = jest.spyOn(tc, 'findAllVersions'); | ||||||
|  |     dlSpy = jest.spyOn(tc, 'downloadTool'); | ||||||
|  |     exSpy = jest.spyOn(tc, 'extractTar'); | ||||||
|  |     cacheSpy = jest.spyOn(tc, 'cacheDir'); | ||||||
|  |     // getDistSpy = jest.spyOn(im, 'getVersionsFromDist'); | ||||||
|  |  | ||||||
|  |     // http-client | ||||||
|  |     getJsonSpy = jest.spyOn(httpm.HttpClient.prototype, 'getJson'); | ||||||
|  |  | ||||||
|  |     // io | ||||||
|  |     whichSpy = jest.spyOn(io, 'which'); | ||||||
|  |     existsSpy = jest.spyOn(fs, 'existsSync'); | ||||||
|  |     mkdirpSpy = jest.spyOn(io, 'mkdirP'); | ||||||
|  |  | ||||||
|  |     // @actions/tool-cache | ||||||
|  |     isCacheActionAvailable = jest.spyOn(cache, 'isFeatureAvailable'); | ||||||
|  |     isCacheActionAvailable.mockImplementation(() => false); | ||||||
|  |  | ||||||
|  |     // disable authentication portion for installer tests | ||||||
|  |     authSpy = jest.spyOn(auth, 'configAuthentication'); | ||||||
|  |     authSpy.mockImplementation(() => {}); | ||||||
|  |  | ||||||
|  |     getJsonSpy.mockImplementation(url => { | ||||||
|  |       let res: any; | ||||||
|  |       if (url.includes('/rc')) { | ||||||
|  |         res = <INodeVersion>nodeTestDistRc; | ||||||
|  |       } else if (url.includes('/nightly')) { | ||||||
|  |         res = <INodeVersion>nodeTestDistNightly; | ||||||
|  |       } else { | ||||||
|  |         res = <INodeVersion>nodeTestDist; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       return {result: res}; | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     // writes | ||||||
|  |     cnSpy = jest.spyOn(process.stdout, 'write'); | ||||||
|  |     logSpy = jest.spyOn(core, 'info'); | ||||||
|  |     dbgSpy = jest.spyOn(core, 'debug'); | ||||||
|  |     warningSpy = jest.spyOn(core, 'warning'); | ||||||
|  |     cnSpy.mockImplementation(line => { | ||||||
|  |       // uncomment to debug | ||||||
|  |       // process.stderr.write('write:' + line + '\n'); | ||||||
|  |     }); | ||||||
|  |     logSpy.mockImplementation(line => { | ||||||
|  |       // uncomment to debug | ||||||
|  |       // process.stderr.write('log:' + line + '\n'); | ||||||
|  |     }); | ||||||
|  |     dbgSpy.mockImplementation(msg => { | ||||||
|  |       // uncomment to see debug output | ||||||
|  |       // process.stderr.write(msg + '\n'); | ||||||
|  |     }); | ||||||
|  |     warningSpy.mockImplementation(msg => { | ||||||
|  |       // uncomment to debug | ||||||
|  |       // process.stderr.write('log:' + msg + '\n'); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     // @actions/exec | ||||||
|  |     getExecOutputSpy = jest.spyOn(exec, 'getExecOutput'); | ||||||
|  |     getExecOutputSpy.mockImplementation(() => 'v16.15.0-rc.1'); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   afterEach(() => { | ||||||
|  |     jest.resetAllMocks(); | ||||||
|  |     jest.clearAllMocks(); | ||||||
|  |     //jest.restoreAllMocks(); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   afterAll(async () => { | ||||||
|  |     console.log('::stoptoken::'); // Re-enable executing of runner commands when running tests in actions | ||||||
|  |     jest.restoreAllMocks(); | ||||||
|  |   }, 100000); | ||||||
|  |  | ||||||
|  |   //-------------------------------------------------- | ||||||
|  |   // Found in cache tests | ||||||
|  |   //-------------------------------------------------- | ||||||
|  |  | ||||||
|  |   it('finds version in cache with stable true', async () => { | ||||||
|  |     inputs['node-version'] = '12.0.0-rc.1'; | ||||||
|  |     inputs.stable = 'true'; | ||||||
|  |  | ||||||
|  |     let toolPath = path.normalize('/cache/node/12.0.0-rc.1/x64'); | ||||||
|  |     findSpy.mockImplementation(() => toolPath); | ||||||
|  |     await main.run(); | ||||||
|  |  | ||||||
|  |     expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('finds version in cache with stable not supplied', async () => { | ||||||
|  |     inputs['node-version'] = '12.0.0-rc.1'; | ||||||
|  |  | ||||||
|  |     inSpy.mockImplementation(name => inputs[name]); | ||||||
|  |  | ||||||
|  |     let toolPath = path.normalize('/cache/node/12.0.0-rc.1/x64'); | ||||||
|  |     findSpy.mockImplementation(() => toolPath); | ||||||
|  |     await main.run(); | ||||||
|  |  | ||||||
|  |     expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('finds version in cache and adds it to the path', async () => { | ||||||
|  |     inputs['node-version'] = '12.0.0-rc.1'; | ||||||
|  |  | ||||||
|  |     inSpy.mockImplementation(name => inputs[name]); | ||||||
|  |  | ||||||
|  |     let toolPath = path.normalize('/cache/node/12.0.0-rc.1/x64'); | ||||||
|  |     findSpy.mockImplementation(() => toolPath); | ||||||
|  |     await main.run(); | ||||||
|  |  | ||||||
|  |     let expPath = path.join(toolPath, 'bin'); | ||||||
|  |     expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('handles unhandled find error and reports error', async () => { | ||||||
|  |     let errMsg = 'unhandled error message'; | ||||||
|  |     inputs['node-version'] = '12.0.0-rc.1'; | ||||||
|  |  | ||||||
|  |     findSpy.mockImplementation(() => { | ||||||
|  |       throw new Error(errMsg); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     await main.run(); | ||||||
|  |  | ||||||
|  |     expect(cnSpy).toHaveBeenCalledWith('::error::' + errMsg + osm.EOL); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('falls back to a version from node dist', async () => { | ||||||
|  |     os.platform = 'linux'; | ||||||
|  |     os.arch = 'x64'; | ||||||
|  |  | ||||||
|  |     let versionSpec = '13.0.0-rc.0'; | ||||||
|  |  | ||||||
|  |     inputs['node-version'] = versionSpec; | ||||||
|  |     inputs['always-auth'] = false; | ||||||
|  |     inputs['token'] = 'faketoken'; | ||||||
|  |  | ||||||
|  |     // ... but not in the local cache | ||||||
|  |     findSpy.mockImplementation(() => ''); | ||||||
|  |  | ||||||
|  |     dlSpy.mockImplementation(async () => '/some/temp/path'); | ||||||
|  |     let toolPath = path.normalize('/cache/node/13.0.0-rc.0/x64'); | ||||||
|  |     exSpy.mockImplementation(async () => '/some/other/temp/path'); | ||||||
|  |     cacheSpy.mockImplementation(async () => toolPath); | ||||||
|  |  | ||||||
|  |     await main.run(); | ||||||
|  |  | ||||||
|  |     let expPath = path.join(toolPath, 'bin'); | ||||||
|  |  | ||||||
|  |     expect(dlSpy).toHaveBeenCalled(); | ||||||
|  |     expect(exSpy).toHaveBeenCalled(); | ||||||
|  |     expect(logSpy).toHaveBeenCalledWith('Extracting ...'); | ||||||
|  |     expect(logSpy).toHaveBeenCalledWith('Done'); | ||||||
|  |     expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('does not find a version that does not exist', async () => { | ||||||
|  |     os.platform = 'linux'; | ||||||
|  |     os.arch = 'x64'; | ||||||
|  |  | ||||||
|  |     let versionSpec = '9.99.9-rc.1'; | ||||||
|  |     inputs['node-version'] = versionSpec; | ||||||
|  |  | ||||||
|  |     findSpy.mockImplementation(() => ''); | ||||||
|  |     await main.run(); | ||||||
|  |  | ||||||
|  |     expect(cnSpy).toHaveBeenCalledWith( | ||||||
|  |       `::error::Unable to find Node version '${versionSpec}' for platform ${os.platform} and architecture ${os.arch}.${osm.EOL}` | ||||||
|  |     ); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('reports a failed download', async () => { | ||||||
|  |     let errMsg = 'unhandled download message'; | ||||||
|  |     os.platform = 'linux'; | ||||||
|  |     os.arch = 'x64'; | ||||||
|  |  | ||||||
|  |     let versionSpec = '14.7.0-rc.1'; | ||||||
|  |  | ||||||
|  |     inputs['node-version'] = versionSpec; | ||||||
|  |     inputs['always-auth'] = false; | ||||||
|  |     inputs['token'] = 'faketoken'; | ||||||
|  |  | ||||||
|  |     findSpy.mockImplementation(() => ''); | ||||||
|  |     findAllVersionsSpy.mockImplementation(() => []); | ||||||
|  |     dlSpy.mockImplementation(() => { | ||||||
|  |       throw new Error(errMsg); | ||||||
|  |     }); | ||||||
|  |     await main.run(); | ||||||
|  |  | ||||||
|  |     expect(cnSpy).toHaveBeenCalledWith(`::error::${errMsg}${osm.EOL}`); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('acquires specified architecture of node', async () => { | ||||||
|  |     for (const {arch, version, osSpec} of [ | ||||||
|  |       {arch: 'x86', version: '13.4.0-rc.0', osSpec: 'win32'}, | ||||||
|  |       {arch: 'x86', version: '14.15.5-rc.0', osSpec: 'win32'} | ||||||
|  |     ]) { | ||||||
|  |       os.platform = osSpec; | ||||||
|  |       os.arch = arch; | ||||||
|  |       const fileExtension = os.platform === 'win32' ? '7z' : 'tar.gz'; | ||||||
|  |       const platform = { | ||||||
|  |         linux: 'linux', | ||||||
|  |         darwin: 'darwin', | ||||||
|  |         win32: 'win' | ||||||
|  |       }[os.platform]; | ||||||
|  |  | ||||||
|  |       inputs['node-version'] = version; | ||||||
|  |       inputs['architecture'] = arch; | ||||||
|  |       inputs['always-auth'] = false; | ||||||
|  |       inputs['token'] = 'faketoken'; | ||||||
|  |  | ||||||
|  |       let expectedUrl = `https://nodejs.org/download/rc/v${version}/node-v${version}-${platform}-${arch}.${fileExtension}`; | ||||||
|  |  | ||||||
|  |       // ... but not in the local cache | ||||||
|  |       findSpy.mockImplementation(() => ''); | ||||||
|  |       findAllVersionsSpy.mockImplementation(() => []); | ||||||
|  |  | ||||||
|  |       dlSpy.mockImplementation(async () => '/some/temp/path'); | ||||||
|  |       let toolPath = path.normalize(`/cache/node/${version}/${arch}`); | ||||||
|  |       exSpy.mockImplementation(async () => '/some/other/temp/path'); | ||||||
|  |       cacheSpy.mockImplementation(async () => toolPath); | ||||||
|  |  | ||||||
|  |       await main.run(); | ||||||
|  |       expect(dlSpy).toHaveBeenCalled(); | ||||||
|  |       expect(logSpy).toHaveBeenCalledWith( | ||||||
|  |         `Acquiring ${version} - ${arch} from ${expectedUrl}` | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |   }, 100000); | ||||||
|  |  | ||||||
|  |   describe('rc versions', () => { | ||||||
|  |     it.each([ | ||||||
|  |       [ | ||||||
|  |         '13.10.1-rc.0', | ||||||
|  |         '13.10.1-rc.0', | ||||||
|  |         'https://nodejs.org/download/rc/v13.10.1-rc.0/node-v13.10.1-rc.0-linux-x64.tar.gz' | ||||||
|  |       ], | ||||||
|  |       [ | ||||||
|  |         '14.15.5-rc.1', | ||||||
|  |         '14.15.5-rc.1', | ||||||
|  |         'https://nodejs.org/download/rc/v14.15.5-rc.1/node-v14.15.5-rc.1-linux-x64.tar.gz' | ||||||
|  |       ], | ||||||
|  |       [ | ||||||
|  |         '16.17.0-rc.1', | ||||||
|  |         '16.17.0-rc.1', | ||||||
|  |         'https://nodejs.org/download/rc/v16.17.0-rc.1/node-v16.17.0-rc.1-linux-x64.tar.gz' | ||||||
|  |       ], | ||||||
|  |       [ | ||||||
|  |         '17.0.0-rc.1', | ||||||
|  |         '17.0.0-rc.1', | ||||||
|  |         'https://nodejs.org/download/rc/v17.0.0-rc.1/node-v17.0.0-rc.1-linux-x64.tar.gz' | ||||||
|  |       ], | ||||||
|  |       [ | ||||||
|  |         '19.0.0-rc.2', | ||||||
|  |         '19.0.0-rc.2', | ||||||
|  |         'https://nodejs.org/download/rc/v19.0.0-rc.2/node-v19.0.0-rc.2-linux-x64.tar.gz' | ||||||
|  |       ] | ||||||
|  |     ])( | ||||||
|  |       'finds the versions in the index.json and installs it', | ||||||
|  |       async (input, expectedVersion, expectedUrl) => { | ||||||
|  |         const toolPath = path.normalize(`/cache/node/${expectedVersion}/x64`); | ||||||
|  |  | ||||||
|  |         findSpy.mockImplementation(() => ''); | ||||||
|  |         findAllVersionsSpy.mockImplementation(() => []); | ||||||
|  |         dlSpy.mockImplementation(async () => '/some/temp/path'); | ||||||
|  |         exSpy.mockImplementation(async () => '/some/other/temp/path'); | ||||||
|  |         cacheSpy.mockImplementation(async () => toolPath); | ||||||
|  |  | ||||||
|  |         inputs['node-version'] = input; | ||||||
|  |         os['arch'] = 'x64'; | ||||||
|  |         os['platform'] = 'linux'; | ||||||
|  |         // act | ||||||
|  |         await main.run(); | ||||||
|  |  | ||||||
|  |         // assert | ||||||
|  |         expect(logSpy).toHaveBeenCalledWith('Extracting ...'); | ||||||
|  |         expect(logSpy).toHaveBeenCalledWith('Adding to the cache ...'); | ||||||
|  |         expect(cnSpy).toHaveBeenCalledWith( | ||||||
|  |           `::add-path::${path.join(toolPath, 'bin')}${osm.EOL}` | ||||||
|  |         ); | ||||||
|  |       } | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     it.each([ | ||||||
|  |       ['13.10.1-rc.0', '13.10.1-rc.0'], | ||||||
|  |       ['14.15.5-rc.1', '14.15.5-rc.1'], | ||||||
|  |       ['16.17.0-rc.1', '16.17.0-rc.1'], | ||||||
|  |       ['17.0.0-rc.1', '17.0.0-rc.1'] | ||||||
|  |     ])( | ||||||
|  |       'finds the %s version in the hostedToolcache', | ||||||
|  |       async (input, expectedVersion) => { | ||||||
|  |         const toolPath = path.normalize(`/cache/node/${expectedVersion}/x64`); | ||||||
|  |         findSpy.mockImplementation((_, version) => | ||||||
|  |           path.normalize(`/cache/node/${version}/x64`) | ||||||
|  |         ); | ||||||
|  |         findAllVersionsSpy.mockReturnValue([ | ||||||
|  |           '2.2.2-rc.2', | ||||||
|  |           '1.1.1-rc.1', | ||||||
|  |           '99.1.1', | ||||||
|  |           expectedVersion, | ||||||
|  |           '88.1.1', | ||||||
|  |           '3.3.3-rc.3' | ||||||
|  |         ]); | ||||||
|  |  | ||||||
|  |         inputs['node-version'] = input; | ||||||
|  |         os['arch'] = 'x64'; | ||||||
|  |         os['platform'] = 'linux'; | ||||||
|  |  | ||||||
|  |         // act | ||||||
|  |         await main.run(); | ||||||
|  |  | ||||||
|  |         // assert | ||||||
|  |         expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`); | ||||||
|  |         expect(cnSpy).toHaveBeenCalledWith( | ||||||
|  |           `::add-path::${path.join(toolPath, 'bin')}${osm.EOL}` | ||||||
|  |         ); | ||||||
|  |       } | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     it('throws an error if version is not found', async () => { | ||||||
|  |       const versionSpec = '19.0.0-rc.3'; | ||||||
|  |  | ||||||
|  |       findSpy.mockImplementation(() => ''); | ||||||
|  |       findAllVersionsSpy.mockImplementation(() => []); | ||||||
|  |       dlSpy.mockImplementation(async () => '/some/temp/path'); | ||||||
|  |       exSpy.mockImplementation(async () => '/some/other/temp/path'); | ||||||
|  |  | ||||||
|  |       inputs['node-version'] = versionSpec; | ||||||
|  |       os['arch'] = 'x64'; | ||||||
|  |       os['platform'] = 'linux'; | ||||||
|  |       // act | ||||||
|  |       await main.run(); | ||||||
|  |  | ||||||
|  |       // assert | ||||||
|  |       expect(cnSpy).toHaveBeenCalledWith( | ||||||
|  |         `::error::Unable to find Node version '${versionSpec}' for platform ${os.platform} and architecture ${os.arch}.${osm.EOL}` | ||||||
|  |       ); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
							
								
								
									
										64
									
								
								dist/cache-save/index.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										64
									
								
								dist/cache-save/index.js
									
									
									
									
										vendored
									
									
								
							| @@ -61019,6 +61019,25 @@ exports.fromPromise = function (fn) { | |||||||
| 
 | 
 | ||||||
| "use strict"; | "use strict"; | ||||||
| 
 | 
 | ||||||
|  | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||||||
|  |     if (k2 === undefined) k2 = k; | ||||||
|  |     Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); | ||||||
|  | }) : (function(o, m, k, k2) { | ||||||
|  |     if (k2 === undefined) k2 = k; | ||||||
|  |     o[k2] = m[k]; | ||||||
|  | })); | ||||||
|  | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | ||||||
|  |     Object.defineProperty(o, "default", { enumerable: true, value: v }); | ||||||
|  | }) : function(o, v) { | ||||||
|  |     o["default"] = v; | ||||||
|  | }); | ||||||
|  | var __importStar = (this && this.__importStar) || function (mod) { | ||||||
|  |     if (mod && mod.__esModule) return mod; | ||||||
|  |     var result = {}; | ||||||
|  |     if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); | ||||||
|  |     __setModuleDefault(result, mod); | ||||||
|  |     return result; | ||||||
|  | }; | ||||||
| var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||||||
|     function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } |     function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||||||
|     return new (P || (P = Promise))(function (resolve, reject) { |     return new (P || (P = Promise))(function (resolve, reject) { | ||||||
| @@ -61028,17 +61047,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge | |||||||
|         step((generator = generator.apply(thisArg, _arguments || [])).next()); |         step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||||||
|     }); |     }); | ||||||
| }; | }; | ||||||
| var __importStar = (this && this.__importStar) || function (mod) { |  | ||||||
|     if (mod && mod.__esModule) return mod; |  | ||||||
|     var result = {}; |  | ||||||
|     if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; |  | ||||||
|     result["default"] = mod; |  | ||||||
|     return result; |  | ||||||
| }; |  | ||||||
| var __importDefault = (this && this.__importDefault) || function (mod) { | var __importDefault = (this && this.__importDefault) || function (mod) { | ||||||
|     return (mod && mod.__esModule) ? mod : { "default": mod }; |     return (mod && mod.__esModule) ? mod : { "default": mod }; | ||||||
| }; | }; | ||||||
| Object.defineProperty(exports, "__esModule", ({ value: true })); | Object.defineProperty(exports, "__esModule", ({ value: true })); | ||||||
|  | exports.run = void 0; | ||||||
| const core = __importStar(__nccwpck_require__(2186)); | const core = __importStar(__nccwpck_require__(2186)); | ||||||
| const cache = __importStar(__nccwpck_require__(7799)); | const cache = __importStar(__nccwpck_require__(7799)); | ||||||
| const fs_1 = __importDefault(__nccwpck_require__(7147)); | const fs_1 = __importDefault(__nccwpck_require__(7147)); | ||||||
| @@ -61095,6 +61108,25 @@ run(); | |||||||
| 
 | 
 | ||||||
| "use strict"; | "use strict"; | ||||||
| 
 | 
 | ||||||
|  | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||||||
|  |     if (k2 === undefined) k2 = k; | ||||||
|  |     Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); | ||||||
|  | }) : (function(o, m, k, k2) { | ||||||
|  |     if (k2 === undefined) k2 = k; | ||||||
|  |     o[k2] = m[k]; | ||||||
|  | })); | ||||||
|  | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | ||||||
|  |     Object.defineProperty(o, "default", { enumerable: true, value: v }); | ||||||
|  | }) : function(o, v) { | ||||||
|  |     o["default"] = v; | ||||||
|  | }); | ||||||
|  | var __importStar = (this && this.__importStar) || function (mod) { | ||||||
|  |     if (mod && mod.__esModule) return mod; | ||||||
|  |     var result = {}; | ||||||
|  |     if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); | ||||||
|  |     __setModuleDefault(result, mod); | ||||||
|  |     return result; | ||||||
|  | }; | ||||||
| var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||||||
|     function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } |     function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||||||
|     return new (P || (P = Promise))(function (resolve, reject) { |     return new (P || (P = Promise))(function (resolve, reject) { | ||||||
| @@ -61104,14 +61136,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge | |||||||
|         step((generator = generator.apply(thisArg, _arguments || [])).next()); |         step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||||||
|     }); |     }); | ||||||
| }; | }; | ||||||
| var __importStar = (this && this.__importStar) || function (mod) { |  | ||||||
|     if (mod && mod.__esModule) return mod; |  | ||||||
|     var result = {}; |  | ||||||
|     if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; |  | ||||||
|     result["default"] = mod; |  | ||||||
|     return result; |  | ||||||
| }; |  | ||||||
| Object.defineProperty(exports, "__esModule", ({ value: true })); | Object.defineProperty(exports, "__esModule", ({ value: true })); | ||||||
|  | exports.isCacheFeatureAvailable = exports.isGhes = exports.getCacheDirectoryPath = exports.getPackageManagerInfo = exports.getCommandOutput = exports.supportedPackageManagers = void 0; | ||||||
| const core = __importStar(__nccwpck_require__(2186)); | const core = __importStar(__nccwpck_require__(2186)); | ||||||
| const exec = __importStar(__nccwpck_require__(1514)); | const exec = __importStar(__nccwpck_require__(1514)); | ||||||
| const cache = __importStar(__nccwpck_require__(7799)); | const cache = __importStar(__nccwpck_require__(7799)); | ||||||
| @@ -61133,7 +61159,7 @@ exports.supportedPackageManagers = { | |||||||
|         getCacheFolderCommand: 'yarn config get cacheFolder' |         getCacheFolderCommand: 'yarn config get cacheFolder' | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
| exports.getCommandOutput = (toolCommand) => __awaiter(void 0, void 0, void 0, function* () { | const getCommandOutput = (toolCommand) => __awaiter(void 0, void 0, void 0, function* () { | ||||||
|     let { stdout, stderr, exitCode } = yield exec.getExecOutput(toolCommand, undefined, { ignoreReturnCode: true }); |     let { stdout, stderr, exitCode } = yield exec.getExecOutput(toolCommand, undefined, { ignoreReturnCode: true }); | ||||||
|     if (exitCode) { |     if (exitCode) { | ||||||
|         stderr = !stderr.trim() |         stderr = !stderr.trim() | ||||||
| @@ -61143,6 +61169,7 @@ exports.getCommandOutput = (toolCommand) => __awaiter(void 0, void 0, void 0, fu | |||||||
|     } |     } | ||||||
|     return stdout.trim(); |     return stdout.trim(); | ||||||
| }); | }); | ||||||
|  | exports.getCommandOutput = getCommandOutput; | ||||||
| const getPackageManagerVersion = (packageManager, command) => __awaiter(void 0, void 0, void 0, function* () { | const getPackageManagerVersion = (packageManager, command) => __awaiter(void 0, void 0, void 0, function* () { | ||||||
|     const stdOut = yield exports.getCommandOutput(`${packageManager} ${command}`); |     const stdOut = yield exports.getCommandOutput(`${packageManager} ${command}`); | ||||||
|     if (!stdOut) { |     if (!stdOut) { | ||||||
| @@ -61150,7 +61177,7 @@ const getPackageManagerVersion = (packageManager, command) => __awaiter(void 0, | |||||||
|     } |     } | ||||||
|     return stdOut; |     return stdOut; | ||||||
| }); | }); | ||||||
| exports.getPackageManagerInfo = (packageManager) => __awaiter(void 0, void 0, void 0, function* () { | const getPackageManagerInfo = (packageManager) => __awaiter(void 0, void 0, void 0, function* () { | ||||||
|     if (packageManager === 'npm') { |     if (packageManager === 'npm') { | ||||||
|         return exports.supportedPackageManagers.npm; |         return exports.supportedPackageManagers.npm; | ||||||
|     } |     } | ||||||
| @@ -61171,7 +61198,8 @@ exports.getPackageManagerInfo = (packageManager) => __awaiter(void 0, void 0, vo | |||||||
|         return null; |         return null; | ||||||
|     } |     } | ||||||
| }); | }); | ||||||
| exports.getCacheDirectoryPath = (packageManagerInfo, packageManager) => __awaiter(void 0, void 0, void 0, function* () { | exports.getPackageManagerInfo = getPackageManagerInfo; | ||||||
|  | const getCacheDirectoryPath = (packageManagerInfo, packageManager) => __awaiter(void 0, void 0, void 0, function* () { | ||||||
|     const stdOut = yield exports.getCommandOutput(packageManagerInfo.getCacheFolderCommand); |     const stdOut = yield exports.getCommandOutput(packageManagerInfo.getCacheFolderCommand); | ||||||
|     if (!stdOut) { |     if (!stdOut) { | ||||||
|         throw new Error(`Could not get cache folder path for ${packageManager}`); |         throw new Error(`Could not get cache folder path for ${packageManager}`); | ||||||
| @@ -61179,6 +61207,7 @@ exports.getCacheDirectoryPath = (packageManagerInfo, packageManager) => __awaite | |||||||
|     core.debug(`${packageManager} path is ${stdOut}`); |     core.debug(`${packageManager} path is ${stdOut}`); | ||||||
|     return stdOut.trim(); |     return stdOut.trim(); | ||||||
| }); | }); | ||||||
|  | exports.getCacheDirectoryPath = getCacheDirectoryPath; | ||||||
| function isGhes() { | function isGhes() { | ||||||
|     const ghUrl = new URL(process.env['GITHUB_SERVER_URL'] || 'https://github.com'); |     const ghUrl = new URL(process.env['GITHUB_SERVER_URL'] || 'https://github.com'); | ||||||
|     return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM'; |     return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM'; | ||||||
| @@ -61205,6 +61234,7 @@ exports.isCacheFeatureAvailable = isCacheFeatureAvailable; | |||||||
| "use strict"; | "use strict"; | ||||||
| 
 | 
 | ||||||
| Object.defineProperty(exports, "__esModule", ({ value: true })); | Object.defineProperty(exports, "__esModule", ({ value: true })); | ||||||
|  | exports.Outputs = exports.State = exports.LockType = void 0; | ||||||
| var LockType; | var LockType; | ||||||
| (function (LockType) { | (function (LockType) { | ||||||
|     LockType["Npm"] = "npm"; |     LockType["Npm"] = "npm"; | ||||||
|   | |||||||
							
								
								
									
										1184
									
								
								dist/setup/index.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1184
									
								
								dist/setup/index.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -104,6 +104,57 @@ jobs: | |||||||
|       - run: npm test |       - run: npm test | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
|  | ## V8 Canary versions | ||||||
|  |  | ||||||
|  | You can specify a nightly version to download it from https://nodejs.org/download/v8-canary. | ||||||
|  |  | ||||||
|  | ### Install v8 canary build for specific node version | ||||||
|  |  | ||||||
|  | ```yaml | ||||||
|  | jobs: | ||||||
|  |   build: | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  |     name: Node sample | ||||||
|  |     steps: | ||||||
|  |       - uses: actions/checkout@v3 | ||||||
|  |       - uses: actions/setup-node@v3 | ||||||
|  |         with: | ||||||
|  |           node-version: '20.0.0-v8-canary' # it will install the latest v8 canary release for node 20.0.0 | ||||||
|  |       - run: npm ci | ||||||
|  |       - run: npm test | ||||||
|  | ``` | ||||||
|  | ### Install v8 canary build for major node version | ||||||
|  |  | ||||||
|  | ```yaml | ||||||
|  | jobs: | ||||||
|  |   build: | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  |     name: Node sample | ||||||
|  |     steps: | ||||||
|  |       - uses: actions/checkout@v3 | ||||||
|  |       - uses: actions/setup-node@v3 | ||||||
|  |         with: | ||||||
|  |           node-version: '20-v8-canary' # it will install the latest v8 canary release for node 20 | ||||||
|  |       - run: npm ci | ||||||
|  |       - run: npm test | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ### Install the exact v8 canary version | ||||||
|  |  | ||||||
|  | ```yaml | ||||||
|  | jobs: | ||||||
|  |   build: | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  |     name: Node sample | ||||||
|  |     steps: | ||||||
|  |       - uses: actions/checkout@v3 | ||||||
|  |       - uses: actions/setup-node@v3 | ||||||
|  |         with: | ||||||
|  |           node-version: 'v20.1.1-v8-canary20221103f7e2421e91' | ||||||
|  |       - run: npm ci | ||||||
|  |       - run: npm test | ||||||
|  | ``` | ||||||
|  |  | ||||||
| ## Nightly versions | ## Nightly versions | ||||||
|  |  | ||||||
| You can specify a nightly version to download it from https://nodejs.org/download/nightly.  | You can specify a nightly version to download it from https://nodejs.org/download/nightly.  | ||||||
|   | |||||||
							
								
								
									
										46
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										46
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -28,7 +28,7 @@ | |||||||
|         "jest-circus": "^27.2.5", |         "jest-circus": "^27.2.5", | ||||||
|         "prettier": "^1.19.1", |         "prettier": "^1.19.1", | ||||||
|         "ts-jest": "^27.0.5", |         "ts-jest": "^27.0.5", | ||||||
|         "typescript": "^3.8.3" |         "typescript": "^4.2.3" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/@actions/cache": { |     "node_modules/@actions/cache": { | ||||||
| @@ -3779,13 +3779,10 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/json5": { |     "node_modules/json5": { | ||||||
|       "version": "2.2.0", |       "version": "2.2.2", | ||||||
|       "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", |       "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.2.tgz", | ||||||
|       "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", |       "integrity": "sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "dependencies": { |  | ||||||
|         "minimist": "^1.2.5" |  | ||||||
|       }, |  | ||||||
|       "bin": { |       "bin": { | ||||||
|         "json5": "lib/cli.js" |         "json5": "lib/cli.js" | ||||||
|       }, |       }, | ||||||
| @@ -3965,12 +3962,6 @@ | |||||||
|         "node": "*" |         "node": "*" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/minimist": { |  | ||||||
|       "version": "1.2.6", |  | ||||||
|       "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", |  | ||||||
|       "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", |  | ||||||
|       "dev": true |  | ||||||
|     }, |  | ||||||
|     "node_modules/ms": { |     "node_modules/ms": { | ||||||
|       "version": "2.1.2", |       "version": "2.1.2", | ||||||
|       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", |       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", | ||||||
| @@ -4813,9 +4804,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/typescript": { |     "node_modules/typescript": { | ||||||
|       "version": "3.8.3", |       "version": "4.2.3", | ||||||
|       "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz", |       "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", | ||||||
|       "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==", |       "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "bin": { |       "bin": { | ||||||
|         "tsc": "bin/tsc", |         "tsc": "bin/tsc", | ||||||
| @@ -8088,13 +8079,10 @@ | |||||||
|       "dev": true |       "dev": true | ||||||
|     }, |     }, | ||||||
|     "json5": { |     "json5": { | ||||||
|       "version": "2.2.0", |       "version": "2.2.2", | ||||||
|       "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", |       "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.2.tgz", | ||||||
|       "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", |       "integrity": "sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ==", | ||||||
|       "dev": true, |       "dev": true | ||||||
|       "requires": { |  | ||||||
|         "minimist": "^1.2.5" |  | ||||||
|       } |  | ||||||
|     }, |     }, | ||||||
|     "kleur": { |     "kleur": { | ||||||
|       "version": "3.0.3", |       "version": "3.0.3", | ||||||
| @@ -8229,12 +8217,6 @@ | |||||||
|         "brace-expansion": "^1.1.7" |         "brace-expansion": "^1.1.7" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "minimist": { |  | ||||||
|       "version": "1.2.6", |  | ||||||
|       "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", |  | ||||||
|       "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", |  | ||||||
|       "dev": true |  | ||||||
|     }, |  | ||||||
|     "ms": { |     "ms": { | ||||||
|       "version": "2.1.2", |       "version": "2.1.2", | ||||||
|       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", |       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", | ||||||
| @@ -8861,9 +8843,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "typescript": { |     "typescript": { | ||||||
|       "version": "3.8.3", |       "version": "4.2.3", | ||||||
|       "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz", |       "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", | ||||||
|       "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==", |       "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==", | ||||||
|       "dev": true |       "dev": true | ||||||
|     }, |     }, | ||||||
|     "universal-user-agent": { |     "universal-user-agent": { | ||||||
|   | |||||||
| @@ -43,6 +43,6 @@ | |||||||
|     "jest-circus": "^27.2.5", |     "jest-circus": "^27.2.5", | ||||||
|     "prettier": "^1.19.1", |     "prettier": "^1.19.1", | ||||||
|     "ts-jest": "^27.0.5", |     "ts-jest": "^27.0.5", | ||||||
|     "typescript": "^3.8.3" |     "typescript": "^4.2.3" | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										53
									
								
								src/distributions/base-distribution-prerelease.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/distributions/base-distribution-prerelease.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | |||||||
|  | import * as tc from '@actions/tool-cache'; | ||||||
|  |  | ||||||
|  | import semver from 'semver'; | ||||||
|  |  | ||||||
|  | import BaseDistribution from './base-distribution'; | ||||||
|  | import {NodeInputs} from './base-models'; | ||||||
|  |  | ||||||
|  | export default abstract class BasePrereleaseNodejs extends BaseDistribution { | ||||||
|  |   protected abstract distribution: string; | ||||||
|  |   constructor(nodeInfo: NodeInputs) { | ||||||
|  |     super(nodeInfo); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected findVersionInHostedToolCacheDirectory(): string { | ||||||
|  |     let toolPath = ''; | ||||||
|  |     const localVersionPaths = tc | ||||||
|  |       .findAllVersions('node', this.nodeInfo.arch) | ||||||
|  |       .filter(i => { | ||||||
|  |         const prerelease = semver.prerelease(i); | ||||||
|  |         if (!prerelease) { | ||||||
|  |           return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return prerelease[0].includes(this.distribution); | ||||||
|  |       }); | ||||||
|  |     localVersionPaths.sort(semver.rcompare); | ||||||
|  |     const localVersion = this.evaluateVersions(localVersionPaths); | ||||||
|  |     if (localVersion) { | ||||||
|  |       toolPath = tc.find('node', localVersion, this.nodeInfo.arch); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return toolPath; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected validRange(versionSpec: string) { | ||||||
|  |     let range: string; | ||||||
|  |     const [raw, prerelease] = this.splitVersionSpec(versionSpec); | ||||||
|  |     const isValidVersion = semver.valid(raw); | ||||||
|  |     const rawVersion = (isValidVersion ? raw : semver.coerce(raw))!; | ||||||
|  |  | ||||||
|  |     if (prerelease !== this.distribution) { | ||||||
|  |       range = versionSpec; | ||||||
|  |     } else { | ||||||
|  |       range = `${semver.validRange(`^${rawVersion}-${this.distribution}`)}-0`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return {range, options: {includePrerelease: !isValidVersion}}; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected splitVersionSpec(versionSpec: string) { | ||||||
|  |     return versionSpec.split(/-(.*)/s); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										287
									
								
								src/distributions/base-distribution.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										287
									
								
								src/distributions/base-distribution.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,287 @@ | |||||||
|  | import * as tc from '@actions/tool-cache'; | ||||||
|  | import * as hc from '@actions/http-client'; | ||||||
|  | import * as core from '@actions/core'; | ||||||
|  | import * as io from '@actions/io'; | ||||||
|  |  | ||||||
|  | import semver from 'semver'; | ||||||
|  | import * as assert from 'assert'; | ||||||
|  |  | ||||||
|  | import * as path from 'path'; | ||||||
|  | import os from 'os'; | ||||||
|  | import fs from 'fs'; | ||||||
|  |  | ||||||
|  | import {NodeInputs, INodeVersion, INodeVersionInfo} from './base-models'; | ||||||
|  |  | ||||||
|  | export default abstract class BaseDistribution { | ||||||
|  |   protected httpClient: hc.HttpClient; | ||||||
|  |   protected osPlat = os.platform(); | ||||||
|  |  | ||||||
|  |   constructor(protected nodeInfo: NodeInputs) { | ||||||
|  |     this.httpClient = new hc.HttpClient('setup-node', [], { | ||||||
|  |       allowRetries: true, | ||||||
|  |       maxRetries: 3 | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected abstract getDistributionUrl(): string; | ||||||
|  |  | ||||||
|  |   public async setupNodeJs() { | ||||||
|  |     let nodeJsVersions: INodeVersion[] | undefined; | ||||||
|  |     if (this.nodeInfo.checkLatest) { | ||||||
|  |       const evaluatedVersion = await this.findVersionInDist(nodeJsVersions); | ||||||
|  |       this.nodeInfo.versionSpec = evaluatedVersion; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     let toolPath = this.findVersionInHostedToolCacheDirectory(); | ||||||
|  |     if (toolPath) { | ||||||
|  |       core.info(`Found in cache @ ${toolPath}`); | ||||||
|  |     } else { | ||||||
|  |       const evaluatedVersion = await this.findVersionInDist(nodeJsVersions); | ||||||
|  |       const toolName = this.getNodejsDistInfo(evaluatedVersion); | ||||||
|  |       toolPath = await this.downloadNodejs(toolName); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (this.osPlat != 'win32') { | ||||||
|  |       toolPath = path.join(toolPath, 'bin'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     core.addPath(toolPath); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected async findVersionInDist(nodeJsVersions?: INodeVersion[]) { | ||||||
|  |     if (!nodeJsVersions) { | ||||||
|  |       nodeJsVersions = await this.getNodeJsVersions(); | ||||||
|  |     } | ||||||
|  |     const versions = this.filterVersions(nodeJsVersions); | ||||||
|  |     const evaluatedVersion = this.evaluateVersions(versions); | ||||||
|  |     if (!evaluatedVersion) { | ||||||
|  |       throw new Error( | ||||||
|  |         `Unable to find Node version '${this.nodeInfo.versionSpec}' for platform ${this.osPlat} and architecture ${this.nodeInfo.arch}.` | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return evaluatedVersion; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected evaluateVersions(versions: string[]): string { | ||||||
|  |     let version = ''; | ||||||
|  |  | ||||||
|  |     const {range, options} = this.validRange(this.nodeInfo.versionSpec); | ||||||
|  |  | ||||||
|  |     core.debug(`evaluating ${versions.length} versions`); | ||||||
|  |  | ||||||
|  |     for (let potential of versions) { | ||||||
|  |       const satisfied: boolean = semver.satisfies(potential, range, options); | ||||||
|  |       if (satisfied) { | ||||||
|  |         version = potential; | ||||||
|  |         break; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (version) { | ||||||
|  |       core.debug(`matched: ${version}`); | ||||||
|  |     } else { | ||||||
|  |       core.debug('match not found'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return version; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected findVersionInHostedToolCacheDirectory() { | ||||||
|  |     return tc.find('node', this.nodeInfo.versionSpec, this.nodeInfo.arch); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected async getNodeJsVersions(): Promise<INodeVersion[]> { | ||||||
|  |     const initialUrl = this.getDistributionUrl(); | ||||||
|  |     const dataUrl = `${initialUrl}/index.json`; | ||||||
|  |  | ||||||
|  |     let response = await this.httpClient.getJson<INodeVersion[]>(dataUrl); | ||||||
|  |     return response.result || []; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected getNodejsDistInfo(version: string) { | ||||||
|  |     let osArch: string = this.translateArchToDistUrl(this.nodeInfo.arch); | ||||||
|  |     version = semver.clean(version) || ''; | ||||||
|  |     let fileName: string = | ||||||
|  |       this.osPlat == 'win32' | ||||||
|  |         ? `node-v${version}-win-${osArch}` | ||||||
|  |         : `node-v${version}-${this.osPlat}-${osArch}`; | ||||||
|  |     let urlFileName: string = | ||||||
|  |       this.osPlat == 'win32' ? `${fileName}.7z` : `${fileName}.tar.gz`; | ||||||
|  |     const initialUrl = this.getDistributionUrl(); | ||||||
|  |     const url = `${initialUrl}/v${version}/${urlFileName}`; | ||||||
|  |  | ||||||
|  |     return <INodeVersionInfo>{ | ||||||
|  |       downloadUrl: url, | ||||||
|  |       resolvedVersion: version, | ||||||
|  |       arch: osArch, | ||||||
|  |       fileName: fileName | ||||||
|  |     }; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected async downloadNodejs(info: INodeVersionInfo) { | ||||||
|  |     let downloadPath = ''; | ||||||
|  |     core.info( | ||||||
|  |       `Acquiring ${info.resolvedVersion} - ${info.arch} from ${info.downloadUrl}` | ||||||
|  |     ); | ||||||
|  |     try { | ||||||
|  |       downloadPath = await tc.downloadTool(info.downloadUrl); | ||||||
|  |     } catch (err) { | ||||||
|  |       if (err instanceof tc.HTTPError && err.httpStatusCode == 404) { | ||||||
|  |         return await this.acquireNodeFromFallbackLocation( | ||||||
|  |           info.resolvedVersion, | ||||||
|  |           info.arch | ||||||
|  |         ); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       throw err; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     let toolPath = await this.extractArchive(downloadPath, info); | ||||||
|  |     core.info('Done'); | ||||||
|  |  | ||||||
|  |     return toolPath; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected validRange(versionSpec: string) { | ||||||
|  |     let options: semver.Options | undefined; | ||||||
|  |     const c = semver.clean(versionSpec) || ''; | ||||||
|  |     const valid = semver.valid(c) ?? versionSpec; | ||||||
|  |  | ||||||
|  |     return {range: valid, options}; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected async acquireNodeFromFallbackLocation( | ||||||
|  |     version: string, | ||||||
|  |     arch: string = os.arch() | ||||||
|  |   ): Promise<string> { | ||||||
|  |     const initialUrl = this.getDistributionUrl(); | ||||||
|  |     let osArch: string = this.translateArchToDistUrl(arch); | ||||||
|  |  | ||||||
|  |     // Create temporary folder to download in to | ||||||
|  |     const tempDownloadFolder: string = | ||||||
|  |       'temp_' + Math.floor(Math.random() * 2000000000); | ||||||
|  |     const tempDirectory = process.env['RUNNER_TEMP'] || ''; | ||||||
|  |     assert.ok(tempDirectory, 'Expected RUNNER_TEMP to be defined'); | ||||||
|  |     const tempDir: string = path.join(tempDirectory, tempDownloadFolder); | ||||||
|  |     await io.mkdirP(tempDir); | ||||||
|  |     let exeUrl: string; | ||||||
|  |     let libUrl: string; | ||||||
|  |     try { | ||||||
|  |       exeUrl = `${initialUrl}/v${version}/win-${osArch}/node.exe`; | ||||||
|  |       libUrl = `${initialUrl}/v${version}/win-${osArch}/node.lib`; | ||||||
|  |  | ||||||
|  |       core.info(`Downloading only node binary from ${exeUrl}`); | ||||||
|  |  | ||||||
|  |       const exePath = await tc.downloadTool(exeUrl); | ||||||
|  |       await io.cp(exePath, path.join(tempDir, 'node.exe')); | ||||||
|  |       const libPath = await tc.downloadTool(libUrl); | ||||||
|  |       await io.cp(libPath, path.join(tempDir, 'node.lib')); | ||||||
|  |     } catch (err) { | ||||||
|  |       if (err instanceof tc.HTTPError && err.httpStatusCode == 404) { | ||||||
|  |         exeUrl = `${initialUrl}/v${version}/node.exe`; | ||||||
|  |         libUrl = `${initialUrl}/v${version}/node.lib`; | ||||||
|  |  | ||||||
|  |         const exePath = await tc.downloadTool(exeUrl); | ||||||
|  |         await io.cp(exePath, path.join(tempDir, 'node.exe')); | ||||||
|  |         const libPath = await tc.downloadTool(libUrl); | ||||||
|  |         await io.cp(libPath, path.join(tempDir, 'node.lib')); | ||||||
|  |       } else { | ||||||
|  |         throw err; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const toolPath = await tc.cacheDir(tempDir, 'node', version, arch); | ||||||
|  |  | ||||||
|  |     return toolPath; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected async extractArchive( | ||||||
|  |     downloadPath: string, | ||||||
|  |     info: INodeVersionInfo | null | ||||||
|  |   ) { | ||||||
|  |     // | ||||||
|  |     // Extract | ||||||
|  |     // | ||||||
|  |     core.info('Extracting ...'); | ||||||
|  |     let extPath: string; | ||||||
|  |     info = info || ({} as INodeVersionInfo); // satisfy compiler, never null when reaches here | ||||||
|  |     if (this.osPlat == 'win32') { | ||||||
|  |       const _7zPath = path.join(__dirname, '../..', 'externals', '7zr.exe'); | ||||||
|  |       extPath = await tc.extract7z(downloadPath, undefined, _7zPath); | ||||||
|  |       // 7z extracts to folder matching file name | ||||||
|  |       const nestedPath = path.join( | ||||||
|  |         extPath, | ||||||
|  |         path.basename(info.fileName, '.7z') | ||||||
|  |       ); | ||||||
|  |       if (fs.existsSync(nestedPath)) { | ||||||
|  |         extPath = nestedPath; | ||||||
|  |       } | ||||||
|  |     } else { | ||||||
|  |       extPath = await tc.extractTar(downloadPath, undefined, [ | ||||||
|  |         'xz', | ||||||
|  |         '--strip', | ||||||
|  |         '1' | ||||||
|  |       ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // | ||||||
|  |     // Install into the local tool cache - node extracts with a root folder that matches the fileName downloaded | ||||||
|  |     // | ||||||
|  |     core.info('Adding to the cache ...'); | ||||||
|  |     const toolPath = await tc.cacheDir( | ||||||
|  |       extPath, | ||||||
|  |       'node', | ||||||
|  |       info.resolvedVersion, | ||||||
|  |       info.arch | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     return toolPath; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected getDistFileName(): string { | ||||||
|  |     let osArch: string = this.translateArchToDistUrl(this.nodeInfo.arch); | ||||||
|  |  | ||||||
|  |     // node offers a json list of versions | ||||||
|  |     let dataFileName: string; | ||||||
|  |     switch (this.osPlat) { | ||||||
|  |       case 'linux': | ||||||
|  |         dataFileName = `linux-${osArch}`; | ||||||
|  |         break; | ||||||
|  |       case 'darwin': | ||||||
|  |         dataFileName = `osx-${osArch}-tar`; | ||||||
|  |         break; | ||||||
|  |       case 'win32': | ||||||
|  |         dataFileName = `win-${osArch}-exe`; | ||||||
|  |         break; | ||||||
|  |       default: | ||||||
|  |         throw new Error(`Unexpected OS '${this.osPlat}'`); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return dataFileName; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected filterVersions(nodeJsVersions: INodeVersion[]) { | ||||||
|  |     const versions: string[] = []; | ||||||
|  |  | ||||||
|  |     const dataFileName = this.getDistFileName(); | ||||||
|  |  | ||||||
|  |     nodeJsVersions.forEach((nodeVersion: INodeVersion) => { | ||||||
|  |       // ensure this version supports your os and platform | ||||||
|  |       if (nodeVersion.files.indexOf(dataFileName) >= 0) { | ||||||
|  |         versions.push(nodeVersion.version); | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     return versions.sort(semver.rcompare); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected translateArchToDistUrl(arch: string): string { | ||||||
|  |     switch (arch) { | ||||||
|  |       case 'arm': | ||||||
|  |         return 'armv7l'; | ||||||
|  |       default: | ||||||
|  |         return arch; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										19
									
								
								src/distributions/base-models.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/distributions/base-models.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | export interface NodeInputs { | ||||||
|  |   versionSpec: string; | ||||||
|  |   arch: string; | ||||||
|  |   auth?: string; | ||||||
|  |   checkLatest: boolean; | ||||||
|  |   stable: boolean; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export interface INodeVersionInfo { | ||||||
|  |   downloadUrl: string; | ||||||
|  |   resolvedVersion: string; | ||||||
|  |   arch: string; | ||||||
|  |   fileName: string; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export interface INodeVersion { | ||||||
|  |   version: string; | ||||||
|  |   files: string[]; | ||||||
|  | } | ||||||
							
								
								
									
										31
									
								
								src/distributions/installer-factory.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/distributions/installer-factory.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | |||||||
|  | import BaseDistribution from './base-distribution'; | ||||||
|  | import {NodeInputs} from './base-models'; | ||||||
|  | import NightlyNodejs from './nightly/nightly_builds'; | ||||||
|  | import OfficialBuilds from './official_builds/official_builds'; | ||||||
|  | import RcBuild from './rc/rc_builds'; | ||||||
|  | import CanaryBuild from './v8-canary/canary_builds'; | ||||||
|  |  | ||||||
|  | enum Distributions { | ||||||
|  |   DEFAULT = '', | ||||||
|  |   CANARY = 'v8-canary', | ||||||
|  |   NIGHTLY = 'nightly', | ||||||
|  |   RC = 'rc' | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function getNodejsDistribution( | ||||||
|  |   installerOptions: NodeInputs | ||||||
|  | ): BaseDistribution { | ||||||
|  |   const versionSpec = installerOptions.versionSpec; | ||||||
|  |   let distribution: BaseDistribution; | ||||||
|  |   if (versionSpec.includes(Distributions.NIGHTLY)) { | ||||||
|  |     distribution = new NightlyNodejs(installerOptions); | ||||||
|  |   } else if (versionSpec.includes(Distributions.CANARY)) { | ||||||
|  |     distribution = new CanaryBuild(installerOptions); | ||||||
|  |   } else if (versionSpec.includes(Distributions.RC)) { | ||||||
|  |     distribution = new RcBuild(installerOptions); | ||||||
|  |   } else { | ||||||
|  |     distribution = new OfficialBuilds(installerOptions); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return distribution; | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								src/distributions/nightly/nightly_builds.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/distributions/nightly/nightly_builds.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | import BasePrereleaseNodejs from '../base-distribution-prerelease'; | ||||||
|  | import {NodeInputs} from '../base-models'; | ||||||
|  |  | ||||||
|  | export default class NightlyNodejs extends BasePrereleaseNodejs { | ||||||
|  |   protected distribution = 'nightly'; | ||||||
|  |   constructor(nodeInfo: NodeInputs) { | ||||||
|  |     super(nodeInfo); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected getDistributionUrl(): string { | ||||||
|  |     return 'https://nodejs.org/download/nightly'; | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										258
									
								
								src/distributions/official_builds/official_builds.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										258
									
								
								src/distributions/official_builds/official_builds.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,258 @@ | |||||||
|  | import * as core from '@actions/core'; | ||||||
|  | import * as tc from '@actions/tool-cache'; | ||||||
|  | import path from 'path'; | ||||||
|  |  | ||||||
|  | import BaseDistribution from '../base-distribution'; | ||||||
|  | import {NodeInputs, INodeVersion, INodeVersionInfo} from '../base-models'; | ||||||
|  |  | ||||||
|  | interface INodeRelease extends tc.IToolRelease { | ||||||
|  |   lts?: string; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default class OfficialBuilds extends BaseDistribution { | ||||||
|  |   constructor(nodeInfo: NodeInputs) { | ||||||
|  |     super(nodeInfo); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public async setupNodeJs() { | ||||||
|  |     let manifest: tc.IToolRelease[] | undefined; | ||||||
|  |     let nodeJsVersions: INodeVersion[] | undefined; | ||||||
|  |     const osArch = this.translateArchToDistUrl(this.nodeInfo.arch); | ||||||
|  |     if (this.isLtsAlias(this.nodeInfo.versionSpec)) { | ||||||
|  |       core.info('Attempt to resolve LTS alias from manifest...'); | ||||||
|  |  | ||||||
|  |       // No try-catch since it's not possible to resolve LTS alias without manifest | ||||||
|  |       manifest = await this.getManifest(); | ||||||
|  |  | ||||||
|  |       this.nodeInfo.versionSpec = this.resolveLtsAliasFromManifest( | ||||||
|  |         this.nodeInfo.versionSpec, | ||||||
|  |         this.nodeInfo.stable, | ||||||
|  |         manifest | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (this.isLatestSyntax(this.nodeInfo.versionSpec)) { | ||||||
|  |       nodeJsVersions = await this.getNodeJsVersions(); | ||||||
|  |       const versions = this.filterVersions(nodeJsVersions); | ||||||
|  |       this.nodeInfo.versionSpec = this.evaluateVersions(versions); | ||||||
|  |  | ||||||
|  |       core.info('getting latest node version...'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (this.nodeInfo.checkLatest) { | ||||||
|  |       core.info('Attempt to resolve the latest version from manifest...'); | ||||||
|  |       const resolvedVersion = await this.resolveVersionFromManifest( | ||||||
|  |         this.nodeInfo.versionSpec, | ||||||
|  |         this.nodeInfo.stable, | ||||||
|  |         osArch, | ||||||
|  |         manifest | ||||||
|  |       ); | ||||||
|  |       if (resolvedVersion) { | ||||||
|  |         this.nodeInfo.versionSpec = resolvedVersion; | ||||||
|  |         core.info(`Resolved as '${resolvedVersion}'`); | ||||||
|  |       } else { | ||||||
|  |         core.info( | ||||||
|  |           `Failed to resolve version ${this.nodeInfo.versionSpec} from manifest` | ||||||
|  |         ); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     let toolPath = this.findVersionInHostedToolCacheDirectory(); | ||||||
|  |  | ||||||
|  |     if (toolPath) { | ||||||
|  |       core.info(`Found in cache @ ${toolPath}`); | ||||||
|  |     } else { | ||||||
|  |       let downloadPath = ''; | ||||||
|  |       try { | ||||||
|  |         core.info(`Attempting to download ${this.nodeInfo.versionSpec}...`); | ||||||
|  |  | ||||||
|  |         const versionInfo = await this.getInfoFromManifest( | ||||||
|  |           this.nodeInfo.versionSpec, | ||||||
|  |           this.nodeInfo.stable, | ||||||
|  |           osArch, | ||||||
|  |           manifest | ||||||
|  |         ); | ||||||
|  |         if (versionInfo) { | ||||||
|  |           core.info( | ||||||
|  |             `Acquiring ${versionInfo.resolvedVersion} - ${versionInfo.arch} from ${versionInfo.downloadUrl}` | ||||||
|  |           ); | ||||||
|  |           downloadPath = await tc.downloadTool( | ||||||
|  |             versionInfo.downloadUrl, | ||||||
|  |             undefined, | ||||||
|  |             this.nodeInfo.auth | ||||||
|  |           ); | ||||||
|  |  | ||||||
|  |           if (downloadPath) { | ||||||
|  |             toolPath = await this.extractArchive(downloadPath, versionInfo); | ||||||
|  |           } | ||||||
|  |         } else { | ||||||
|  |           core.info( | ||||||
|  |             'Not found in manifest. Falling back to download directly from Node' | ||||||
|  |           ); | ||||||
|  |         } | ||||||
|  |       } catch (err) { | ||||||
|  |         // Rate limit? | ||||||
|  |         if ( | ||||||
|  |           err instanceof tc.HTTPError && | ||||||
|  |           (err.httpStatusCode === 403 || err.httpStatusCode === 429) | ||||||
|  |         ) { | ||||||
|  |           core.info( | ||||||
|  |             `Received HTTP status code ${err.httpStatusCode}. This usually indicates the rate limit has been exceeded` | ||||||
|  |           ); | ||||||
|  |         } else { | ||||||
|  |           core.info(err.message); | ||||||
|  |         } | ||||||
|  |         core.debug(err.stack); | ||||||
|  |         core.info('Falling back to download directly from Node'); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       if (!toolPath) { | ||||||
|  |         const nodeJsVersions = await this.getNodeJsVersions(); | ||||||
|  |         const versions = this.filterVersions(nodeJsVersions); | ||||||
|  |         const evaluatedVersion = this.evaluateVersions(versions); | ||||||
|  |         if (!evaluatedVersion) { | ||||||
|  |           throw new Error( | ||||||
|  |             `Unable to find Node version '${this.nodeInfo.versionSpec}' for platform ${this.osPlat} and architecture ${this.nodeInfo.arch}.` | ||||||
|  |           ); | ||||||
|  |         } | ||||||
|  |         const toolName = this.getNodejsDistInfo(evaluatedVersion); | ||||||
|  |         toolPath = await this.downloadNodejs(toolName); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (this.osPlat != 'win32') { | ||||||
|  |       toolPath = path.join(toolPath, 'bin'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     core.addPath(toolPath); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected evaluateVersions(versions: string[]): string { | ||||||
|  |     let version = ''; | ||||||
|  |  | ||||||
|  |     if (this.isLatestSyntax(this.nodeInfo.versionSpec)) { | ||||||
|  |       core.info(`getting latest node version...`); | ||||||
|  |       return versions[0]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     version = super.evaluateVersions(versions); | ||||||
|  |  | ||||||
|  |     return version; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected getDistributionUrl(): string { | ||||||
|  |     return `https://nodejs.org/dist`; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private getManifest(): Promise<tc.IToolRelease[]> { | ||||||
|  |     core.debug('Getting manifest from actions/node-versions@main'); | ||||||
|  |     return tc.getManifestFromRepo( | ||||||
|  |       'actions', | ||||||
|  |       'node-versions', | ||||||
|  |       this.nodeInfo.auth, | ||||||
|  |       'main' | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private resolveLtsAliasFromManifest( | ||||||
|  |     versionSpec: string, | ||||||
|  |     stable: boolean, | ||||||
|  |     manifest: INodeRelease[] | ||||||
|  |   ): string { | ||||||
|  |     const alias = versionSpec.split('lts/')[1]?.toLowerCase(); | ||||||
|  |  | ||||||
|  |     if (!alias) { | ||||||
|  |       throw new Error( | ||||||
|  |         `Unable to parse LTS alias for Node version '${versionSpec}'` | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     core.debug(`LTS alias '${alias}' for Node version '${versionSpec}'`); | ||||||
|  |  | ||||||
|  |     // Supported formats are `lts/<alias>`, `lts/*`, and `lts/-n`. Where asterisk means highest possible LTS and -n means the nth-highest. | ||||||
|  |     const n = Number(alias); | ||||||
|  |     const aliases = Object.fromEntries( | ||||||
|  |       manifest | ||||||
|  |         .filter(x => x.lts && x.stable === stable) | ||||||
|  |         .map(x => [x.lts!.toLowerCase(), x]) | ||||||
|  |         .reverse() | ||||||
|  |     ); | ||||||
|  |     const numbered = Object.values(aliases); | ||||||
|  |     const release = | ||||||
|  |       alias === '*' | ||||||
|  |         ? numbered[numbered.length - 1] | ||||||
|  |         : n < 0 | ||||||
|  |         ? numbered[numbered.length - 1 + n] | ||||||
|  |         : aliases[alias]; | ||||||
|  |  | ||||||
|  |     if (!release) { | ||||||
|  |       throw new Error( | ||||||
|  |         `Unable to find LTS release '${alias}' for Node version '${versionSpec}'.` | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     core.debug( | ||||||
|  |       `Found LTS release '${release.version}' for Node version '${versionSpec}'` | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     return release.version.split('.')[0]; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private async resolveVersionFromManifest( | ||||||
|  |     versionSpec: string, | ||||||
|  |     stable: boolean, | ||||||
|  |     osArch: string, | ||||||
|  |     manifest: tc.IToolRelease[] | undefined | ||||||
|  |   ): Promise<string | undefined> { | ||||||
|  |     try { | ||||||
|  |       const info = await this.getInfoFromManifest( | ||||||
|  |         versionSpec, | ||||||
|  |         stable, | ||||||
|  |         osArch, | ||||||
|  |         manifest | ||||||
|  |       ); | ||||||
|  |       return info?.resolvedVersion; | ||||||
|  |     } catch (err) { | ||||||
|  |       core.info('Unable to resolve version from manifest...'); | ||||||
|  |       core.debug(err.message); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private async getInfoFromManifest( | ||||||
|  |     versionSpec: string, | ||||||
|  |     stable: boolean, | ||||||
|  |     osArch: string, | ||||||
|  |     manifest: tc.IToolRelease[] | undefined | ||||||
|  |   ): Promise<INodeVersionInfo | null> { | ||||||
|  |     let info: INodeVersionInfo | null = null; | ||||||
|  |     if (!manifest) { | ||||||
|  |       core.debug('No manifest cached'); | ||||||
|  |       manifest = await this.getManifest(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const rel = await tc.findFromManifest( | ||||||
|  |       versionSpec, | ||||||
|  |       stable, | ||||||
|  |       manifest, | ||||||
|  |       osArch | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     if (rel && rel.files.length > 0) { | ||||||
|  |       info = <INodeVersionInfo>{}; | ||||||
|  |       info.resolvedVersion = rel.version; | ||||||
|  |       info.arch = rel.files[0].arch; | ||||||
|  |       info.downloadUrl = rel.files[0].download_url; | ||||||
|  |       info.fileName = rel.files[0].filename; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return info; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private isLtsAlias(versionSpec: string): boolean { | ||||||
|  |     return versionSpec.startsWith('lts/'); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private isLatestSyntax(versionSpec): boolean { | ||||||
|  |     return ['current', 'latest', 'node'].includes(versionSpec); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										12
									
								
								src/distributions/rc/rc_builds.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/distributions/rc/rc_builds.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | import BaseDistribution from '../base-distribution'; | ||||||
|  | import {NodeInputs} from '../base-models'; | ||||||
|  |  | ||||||
|  | export default class RcBuild extends BaseDistribution { | ||||||
|  |   constructor(nodeInfo: NodeInputs) { | ||||||
|  |     super(nodeInfo); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   getDistributionUrl(): string { | ||||||
|  |     return 'https://nodejs.org/download/rc'; | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								src/distributions/v8-canary/canary_builds.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/distributions/v8-canary/canary_builds.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | import BasePrereleaseNodejs from '../base-distribution-prerelease'; | ||||||
|  | import {NodeInputs} from '../base-models'; | ||||||
|  |  | ||||||
|  | export default class CanaryBuild extends BasePrereleaseNodejs { | ||||||
|  |   protected distribution = 'v8-canary'; | ||||||
|  |   constructor(nodeInfo: NodeInputs) { | ||||||
|  |     super(nodeInfo); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected getDistributionUrl(): string { | ||||||
|  |     return 'https://nodejs.org/download/v8-canary'; | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										606
									
								
								src/installer.ts
									
									
									
									
									
								
							
							
						
						
									
										606
									
								
								src/installer.ts
									
									
									
									
									
								
							| @@ -1,606 +0,0 @@ | |||||||
| import os from 'os'; |  | ||||||
| import * as assert from 'assert'; |  | ||||||
| import * as core from '@actions/core'; |  | ||||||
| import * as hc from '@actions/http-client'; |  | ||||||
| import * as io from '@actions/io'; |  | ||||||
| import * as tc from '@actions/tool-cache'; |  | ||||||
| import * as path from 'path'; |  | ||||||
| import * as semver from 'semver'; |  | ||||||
| import fs from 'fs'; |  | ||||||
|  |  | ||||||
| // |  | ||||||
| // Node versions interface |  | ||||||
| // see https://nodejs.org/dist/index.json |  | ||||||
| // for nightly https://nodejs.org/download/nightly/index.json |  | ||||||
| // for rc https://nodejs.org/download/rc/index.json |  | ||||||
| // |  | ||||||
| export interface INodeVersion { |  | ||||||
|   version: string; |  | ||||||
|   files: string[]; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| interface INodeVersionInfo { |  | ||||||
|   downloadUrl: string; |  | ||||||
|   resolvedVersion: string; |  | ||||||
|   arch: string; |  | ||||||
|   fileName: string; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| interface INodeRelease extends tc.IToolRelease { |  | ||||||
|   lts?: string; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export async function getNode( |  | ||||||
|   versionSpec: string, |  | ||||||
|   stable: boolean, |  | ||||||
|   checkLatest: boolean, |  | ||||||
|   auth: string | undefined, |  | ||||||
|   arch: string = os.arch() |  | ||||||
| ) { |  | ||||||
|   // Store manifest data to avoid multiple calls |  | ||||||
|   let manifest: INodeRelease[] | undefined; |  | ||||||
|   let nodeVersions: INodeVersion[] | undefined; |  | ||||||
|   let isNightly = versionSpec.includes('nightly'); |  | ||||||
|   let osPlat: string = os.platform(); |  | ||||||
|   let osArch: string = translateArchToDistUrl(arch); |  | ||||||
|  |  | ||||||
|   if (isLtsAlias(versionSpec)) { |  | ||||||
|     core.info('Attempt to resolve LTS alias from manifest...'); |  | ||||||
|  |  | ||||||
|     // No try-catch since it's not possible to resolve LTS alias without manifest |  | ||||||
|     manifest = await getManifest(auth); |  | ||||||
|  |  | ||||||
|     versionSpec = resolveLtsAliasFromManifest(versionSpec, stable, manifest); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if (isLatestSyntax(versionSpec)) { |  | ||||||
|     nodeVersions = await getVersionsFromDist(versionSpec); |  | ||||||
|     versionSpec = await queryDistForMatch(versionSpec, arch, nodeVersions); |  | ||||||
|     core.info(`getting latest node version...`); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if (isNightly && checkLatest) { |  | ||||||
|     nodeVersions = await getVersionsFromDist(versionSpec); |  | ||||||
|     versionSpec = await queryDistForMatch(versionSpec, arch, nodeVersions); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if (checkLatest && !isNightly) { |  | ||||||
|     core.info('Attempt to resolve the latest version from manifest...'); |  | ||||||
|     const resolvedVersion = await resolveVersionFromManifest( |  | ||||||
|       versionSpec, |  | ||||||
|       stable, |  | ||||||
|       auth, |  | ||||||
|       osArch, |  | ||||||
|       manifest |  | ||||||
|     ); |  | ||||||
|     if (resolvedVersion) { |  | ||||||
|       versionSpec = resolvedVersion; |  | ||||||
|       core.info(`Resolved as '${versionSpec}'`); |  | ||||||
|     } else { |  | ||||||
|       core.info(`Failed to resolve version ${versionSpec} from manifest`); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // check cache |  | ||||||
|   let toolPath: string; |  | ||||||
|   if (isNightly) { |  | ||||||
|     const nightlyVersion = findNightlyVersionInHostedToolcache( |  | ||||||
|       versionSpec, |  | ||||||
|       osArch |  | ||||||
|     ); |  | ||||||
|     toolPath = nightlyVersion && tc.find('node', nightlyVersion, osArch); |  | ||||||
|   } else { |  | ||||||
|     toolPath = tc.find('node', versionSpec, osArch); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // If not found in cache, download |  | ||||||
|   if (toolPath) { |  | ||||||
|     core.info(`Found in cache @ ${toolPath}`); |  | ||||||
|   } else { |  | ||||||
|     core.info(`Attempting to download ${versionSpec}...`); |  | ||||||
|     let downloadPath = ''; |  | ||||||
|     let info: INodeVersionInfo | null = null; |  | ||||||
|  |  | ||||||
|     // |  | ||||||
|     // Try download from internal distribution (popular versions only) |  | ||||||
|     // |  | ||||||
|     try { |  | ||||||
|       info = await getInfoFromManifest( |  | ||||||
|         versionSpec, |  | ||||||
|         stable, |  | ||||||
|         auth, |  | ||||||
|         osArch, |  | ||||||
|         manifest |  | ||||||
|       ); |  | ||||||
|       if (info) { |  | ||||||
|         core.info( |  | ||||||
|           `Acquiring ${info.resolvedVersion} - ${info.arch} from ${info.downloadUrl}` |  | ||||||
|         ); |  | ||||||
|         downloadPath = await tc.downloadTool(info.downloadUrl, undefined, auth); |  | ||||||
|       } else { |  | ||||||
|         core.info( |  | ||||||
|           'Not found in manifest.  Falling back to download directly from Node' |  | ||||||
|         ); |  | ||||||
|       } |  | ||||||
|     } catch (err) { |  | ||||||
|       // Rate limit? |  | ||||||
|       if ( |  | ||||||
|         err instanceof tc.HTTPError && |  | ||||||
|         (err.httpStatusCode === 403 || err.httpStatusCode === 429) |  | ||||||
|       ) { |  | ||||||
|         core.info( |  | ||||||
|           `Received HTTP status code ${err.httpStatusCode}.  This usually indicates the rate limit has been exceeded` |  | ||||||
|         ); |  | ||||||
|       } else { |  | ||||||
|         core.info(err.message); |  | ||||||
|       } |  | ||||||
|       core.debug(err.stack); |  | ||||||
|       core.info('Falling back to download directly from Node'); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // |  | ||||||
|     // Download from nodejs.org |  | ||||||
|     // |  | ||||||
|     if (!downloadPath) { |  | ||||||
|       info = await getInfoFromDist(versionSpec, arch, nodeVersions); |  | ||||||
|       if (!info) { |  | ||||||
|         throw new Error( |  | ||||||
|           `Unable to find Node version '${versionSpec}' for platform ${osPlat} and architecture ${osArch}.` |  | ||||||
|         ); |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       core.info( |  | ||||||
|         `Acquiring ${info.resolvedVersion} - ${info.arch} from ${info.downloadUrl}` |  | ||||||
|       ); |  | ||||||
|       try { |  | ||||||
|         downloadPath = await tc.downloadTool(info.downloadUrl); |  | ||||||
|       } catch (err) { |  | ||||||
|         if (err instanceof tc.HTTPError && err.httpStatusCode == 404) { |  | ||||||
|           return await acquireNodeFromFallbackLocation( |  | ||||||
|             info.resolvedVersion, |  | ||||||
|             info.arch |  | ||||||
|           ); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         throw err; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // |  | ||||||
|     // Extract |  | ||||||
|     // |  | ||||||
|     core.info('Extracting ...'); |  | ||||||
|     let extPath: string; |  | ||||||
|     info = info || ({} as INodeVersionInfo); // satisfy compiler, never null when reaches here |  | ||||||
|     if (osPlat == 'win32') { |  | ||||||
|       let _7zPath = path.join(__dirname, '../..', 'externals', '7zr.exe'); |  | ||||||
|       extPath = await tc.extract7z(downloadPath, undefined, _7zPath); |  | ||||||
|       // 7z extracts to folder matching file name |  | ||||||
|       let nestedPath = path.join(extPath, path.basename(info.fileName, '.7z')); |  | ||||||
|       if (fs.existsSync(nestedPath)) { |  | ||||||
|         extPath = nestedPath; |  | ||||||
|       } |  | ||||||
|     } else { |  | ||||||
|       extPath = await tc.extractTar(downloadPath, undefined, [ |  | ||||||
|         'xz', |  | ||||||
|         '--strip', |  | ||||||
|         '1' |  | ||||||
|       ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // |  | ||||||
|     // Install into the local tool cache - node extracts with a root folder that matches the fileName downloaded |  | ||||||
|     // |  | ||||||
|     core.info('Adding to the cache ...'); |  | ||||||
|     toolPath = await tc.cacheDir( |  | ||||||
|       extPath, |  | ||||||
|       'node', |  | ||||||
|       info.resolvedVersion, |  | ||||||
|       info.arch |  | ||||||
|     ); |  | ||||||
|     core.info('Done'); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // |  | ||||||
|   // a tool installer initimately knows details about the layout of that tool |  | ||||||
|   // for example, node binary is in the bin folder after the extract on Mac/Linux. |  | ||||||
|   // layouts could change by version, by platform etc... but that's the tool installers job |  | ||||||
|   // |  | ||||||
|   if (osPlat != 'win32') { |  | ||||||
|     toolPath = path.join(toolPath, 'bin'); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // |  | ||||||
|   // prepend the tools path. instructs the agent to prepend for future tasks |  | ||||||
|   core.addPath(toolPath); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function findNightlyVersionInHostedToolcache( |  | ||||||
|   versionsSpec: string, |  | ||||||
|   osArch: string |  | ||||||
| ) { |  | ||||||
|   const foundAllVersions = tc.findAllVersions('node', osArch); |  | ||||||
|   const version = evaluateVersions(foundAllVersions, versionsSpec); |  | ||||||
|  |  | ||||||
|   return version; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function isLtsAlias(versionSpec: string): boolean { |  | ||||||
|   return versionSpec.startsWith('lts/'); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function getManifest(auth: string | undefined): Promise<tc.IToolRelease[]> { |  | ||||||
|   core.debug('Getting manifest from actions/node-versions@main'); |  | ||||||
|   return tc.getManifestFromRepo('actions', 'node-versions', auth, 'main'); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function resolveLtsAliasFromManifest( |  | ||||||
|   versionSpec: string, |  | ||||||
|   stable: boolean, |  | ||||||
|   manifest: INodeRelease[] |  | ||||||
| ): string { |  | ||||||
|   const alias = versionSpec.split('lts/')[1]?.toLowerCase(); |  | ||||||
|  |  | ||||||
|   if (!alias) { |  | ||||||
|     throw new Error( |  | ||||||
|       `Unable to parse LTS alias for Node version '${versionSpec}'` |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   core.debug(`LTS alias '${alias}' for Node version '${versionSpec}'`); |  | ||||||
|  |  | ||||||
|   // Supported formats are `lts/<alias>`, `lts/*`, and `lts/-n`. Where asterisk means highest possible LTS and -n means the nth-highest. |  | ||||||
|   const n = Number(alias); |  | ||||||
|   const aliases = Object.fromEntries( |  | ||||||
|     manifest |  | ||||||
|       .filter(x => x.lts && x.stable === stable) |  | ||||||
|       .map(x => [x.lts!.toLowerCase(), x]) |  | ||||||
|       .reverse() |  | ||||||
|   ); |  | ||||||
|   const numbered = Object.values(aliases); |  | ||||||
|   const release = |  | ||||||
|     alias === '*' |  | ||||||
|       ? numbered[numbered.length - 1] |  | ||||||
|       : n < 0 |  | ||||||
|       ? numbered[numbered.length - 1 + n] |  | ||||||
|       : aliases[alias]; |  | ||||||
|  |  | ||||||
|   if (!release) { |  | ||||||
|     throw new Error( |  | ||||||
|       `Unable to find LTS release '${alias}' for Node version '${versionSpec}'.` |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   core.debug( |  | ||||||
|     `Found LTS release '${release.version}' for Node version '${versionSpec}'` |  | ||||||
|   ); |  | ||||||
|  |  | ||||||
|   return release.version.split('.')[0]; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| async function getInfoFromManifest( |  | ||||||
|   versionSpec: string, |  | ||||||
|   stable: boolean, |  | ||||||
|   auth: string | undefined, |  | ||||||
|   osArch: string = translateArchToDistUrl(os.arch()), |  | ||||||
|   manifest: tc.IToolRelease[] | undefined |  | ||||||
| ): Promise<INodeVersionInfo | null> { |  | ||||||
|   let info: INodeVersionInfo | null = null; |  | ||||||
|   if (!manifest) { |  | ||||||
|     core.debug('No manifest cached'); |  | ||||||
|     manifest = await getManifest(auth); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   const rel = await tc.findFromManifest(versionSpec, stable, manifest, osArch); |  | ||||||
|  |  | ||||||
|   if (rel && rel.files.length > 0) { |  | ||||||
|     info = <INodeVersionInfo>{}; |  | ||||||
|     info.resolvedVersion = rel.version; |  | ||||||
|     info.arch = rel.files[0].arch; |  | ||||||
|     info.downloadUrl = rel.files[0].download_url; |  | ||||||
|     info.fileName = rel.files[0].filename; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   return info; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| async function getInfoFromDist( |  | ||||||
|   versionSpec: string, |  | ||||||
|   arch: string = os.arch(), |  | ||||||
|   nodeVersions?: INodeVersion[] |  | ||||||
| ): Promise<INodeVersionInfo | null> { |  | ||||||
|   let osPlat: string = os.platform(); |  | ||||||
|   let osArch: string = translateArchToDistUrl(arch); |  | ||||||
|  |  | ||||||
|   let version: string = await queryDistForMatch( |  | ||||||
|     versionSpec, |  | ||||||
|     arch, |  | ||||||
|     nodeVersions |  | ||||||
|   ); |  | ||||||
|  |  | ||||||
|   if (!version) { |  | ||||||
|     return null; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // |  | ||||||
|   // Download - a tool installer intimately knows how to get the tool (and construct urls) |  | ||||||
|   // |  | ||||||
|   version = semver.clean(version) || ''; |  | ||||||
|   let fileName: string = |  | ||||||
|     osPlat == 'win32' |  | ||||||
|       ? `node-v${version}-win-${osArch}` |  | ||||||
|       : `node-v${version}-${osPlat}-${osArch}`; |  | ||||||
|   let urlFileName: string = |  | ||||||
|     osPlat == 'win32' ? `${fileName}.7z` : `${fileName}.tar.gz`; |  | ||||||
|   const initialUrl = getNodejsDistUrl(versionSpec); |  | ||||||
|   const url = `${initialUrl}/v${version}/${urlFileName}`; |  | ||||||
|  |  | ||||||
|   return <INodeVersionInfo>{ |  | ||||||
|     downloadUrl: url, |  | ||||||
|     resolvedVersion: version, |  | ||||||
|     arch: arch, |  | ||||||
|     fileName: fileName |  | ||||||
|   }; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| async function resolveVersionFromManifest( |  | ||||||
|   versionSpec: string, |  | ||||||
|   stable: boolean, |  | ||||||
|   auth: string | undefined, |  | ||||||
|   osArch: string = translateArchToDistUrl(os.arch()), |  | ||||||
|   manifest: tc.IToolRelease[] | undefined |  | ||||||
| ): Promise<string | undefined> { |  | ||||||
|   try { |  | ||||||
|     const info = await getInfoFromManifest( |  | ||||||
|       versionSpec, |  | ||||||
|       stable, |  | ||||||
|       auth, |  | ||||||
|       osArch, |  | ||||||
|       manifest |  | ||||||
|     ); |  | ||||||
|     return info?.resolvedVersion; |  | ||||||
|   } catch (err) { |  | ||||||
|     core.info('Unable to resolve version from manifest...'); |  | ||||||
|     core.debug(err.message); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function evaluateNightlyVersions( |  | ||||||
|   versions: string[], |  | ||||||
|   versionSpec: string |  | ||||||
| ): string { |  | ||||||
|   let version = ''; |  | ||||||
|   let range: string | undefined; |  | ||||||
|   const [raw, prerelease] = versionSpec.split('-'); |  | ||||||
|   const isValidVersion = semver.valid(raw); |  | ||||||
|   const rawVersion = isValidVersion ? raw : semver.coerce(raw); |  | ||||||
|   if (rawVersion) { |  | ||||||
|     if (prerelease !== 'nightly') { |  | ||||||
|       range = `${rawVersion}-${prerelease.replace('nightly', 'nightly.')}`; |  | ||||||
|     } else { |  | ||||||
|       range = `${semver.validRange(`^${rawVersion}-0`)}-0`; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if (range) { |  | ||||||
|     versions.sort(semver.rcompare); |  | ||||||
|     for (const currentVersion of versions) { |  | ||||||
|       const satisfied: boolean = |  | ||||||
|         semver.satisfies( |  | ||||||
|           currentVersion.replace('-nightly', '-nightly.'), |  | ||||||
|           range, |  | ||||||
|           {includePrerelease: true} |  | ||||||
|         ) && currentVersion.includes('nightly'); |  | ||||||
|       if (satisfied) { |  | ||||||
|         version = currentVersion; |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if (version) { |  | ||||||
|     core.debug(`matched: ${version}`); |  | ||||||
|   } else { |  | ||||||
|     core.debug('match not found'); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   return version; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // TODO - should we just export this from @actions/tool-cache? Lifted directly from there |  | ||||||
| function evaluateVersions(versions: string[], versionSpec: string): string { |  | ||||||
|   let version = ''; |  | ||||||
|   core.debug(`evaluating ${versions.length} versions`); |  | ||||||
|  |  | ||||||
|   if (versionSpec.includes('nightly')) { |  | ||||||
|     return evaluateNightlyVersions(versions, versionSpec); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   versions = versions.sort(semver.rcompare); |  | ||||||
|   for (let i = versions.length - 1; i >= 0; i--) { |  | ||||||
|     const potential: string = versions[i]; |  | ||||||
|     const satisfied: boolean = semver.satisfies(potential, versionSpec); |  | ||||||
|     if (satisfied) { |  | ||||||
|       version = potential; |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if (version) { |  | ||||||
|     core.debug(`matched: ${version}`); |  | ||||||
|   } else { |  | ||||||
|     core.debug('match not found'); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   return version; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function getNodejsDistUrl(version: string) { |  | ||||||
|   const prerelease = semver.prerelease(version); |  | ||||||
|   if (version.includes('nightly')) { |  | ||||||
|     return 'https://nodejs.org/download/nightly'; |  | ||||||
|   } else if (prerelease) { |  | ||||||
|     return 'https://nodejs.org/download/rc'; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   return 'https://nodejs.org/dist'; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| async function queryDistForMatch( |  | ||||||
|   versionSpec: string, |  | ||||||
|   arch: string = os.arch(), |  | ||||||
|   nodeVersions?: INodeVersion[] |  | ||||||
| ): Promise<string> { |  | ||||||
|   let osPlat: string = os.platform(); |  | ||||||
|   let osArch: string = translateArchToDistUrl(arch); |  | ||||||
|  |  | ||||||
|   // node offers a json list of versions |  | ||||||
|   let dataFileName: string; |  | ||||||
|   switch (osPlat) { |  | ||||||
|     case 'linux': |  | ||||||
|       dataFileName = `linux-${osArch}`; |  | ||||||
|       break; |  | ||||||
|     case 'darwin': |  | ||||||
|       dataFileName = `osx-${osArch}-tar`; |  | ||||||
|       break; |  | ||||||
|     case 'win32': |  | ||||||
|       dataFileName = `win-${osArch}-exe`; |  | ||||||
|       break; |  | ||||||
|     default: |  | ||||||
|       throw new Error(`Unexpected OS '${osPlat}'`); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if (!nodeVersions) { |  | ||||||
|     core.debug('No dist manifest cached'); |  | ||||||
|     nodeVersions = await getVersionsFromDist(versionSpec); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   let versions: string[] = []; |  | ||||||
|  |  | ||||||
|   if (isLatestSyntax(versionSpec)) { |  | ||||||
|     core.info(`getting latest node version...`); |  | ||||||
|     return nodeVersions[0].version; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   nodeVersions.forEach((nodeVersion: INodeVersion) => { |  | ||||||
|     // ensure this version supports your os and platform |  | ||||||
|     if (nodeVersion.files.indexOf(dataFileName) >= 0) { |  | ||||||
|       versions.push(nodeVersion.version); |  | ||||||
|     } |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
|   // get the latest version that matches the version spec |  | ||||||
|   let version = evaluateVersions(versions, versionSpec); |  | ||||||
|   return version; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export async function getVersionsFromDist( |  | ||||||
|   versionSpec: string |  | ||||||
| ): Promise<INodeVersion[]> { |  | ||||||
|   const initialUrl = getNodejsDistUrl(versionSpec); |  | ||||||
|   const dataUrl = `${initialUrl}/index.json`; |  | ||||||
|   let httpClient = new hc.HttpClient('setup-node', [], { |  | ||||||
|     allowRetries: true, |  | ||||||
|     maxRetries: 3 |  | ||||||
|   }); |  | ||||||
|   let response = await httpClient.getJson<INodeVersion[]>(dataUrl); |  | ||||||
|   return response.result || []; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // For non LTS versions of Node, the files we need (for Windows) are sometimes located |  | ||||||
| // in a different folder than they normally are for other versions. |  | ||||||
| // Normally the format is similar to: https://nodejs.org/dist/v5.10.1/node-v5.10.1-win-x64.7z |  | ||||||
| // In this case, there will be two files located at: |  | ||||||
| //      /dist/v5.10.1/win-x64/node.exe |  | ||||||
| //      /dist/v5.10.1/win-x64/node.lib |  | ||||||
| // If this is not the structure, there may also be two files located at: |  | ||||||
| //      /dist/v0.12.18/node.exe |  | ||||||
| //      /dist/v0.12.18/node.lib |  | ||||||
| // This method attempts to download and cache the resources from these alternative locations. |  | ||||||
| // Note also that the files are normally zipped but in this case they are just an exe |  | ||||||
| // and lib file in a folder, not zipped. |  | ||||||
| async function acquireNodeFromFallbackLocation( |  | ||||||
|   version: string, |  | ||||||
|   arch: string = os.arch() |  | ||||||
| ): Promise<string> { |  | ||||||
|   const initialUrl = getNodejsDistUrl(version); |  | ||||||
|   let osPlat: string = os.platform(); |  | ||||||
|   let osArch: string = translateArchToDistUrl(arch); |  | ||||||
|  |  | ||||||
|   // Create temporary folder to download in to |  | ||||||
|   const tempDownloadFolder: string = |  | ||||||
|     'temp_' + Math.floor(Math.random() * 2000000000); |  | ||||||
|   const tempDirectory = process.env['RUNNER_TEMP'] || ''; |  | ||||||
|   assert.ok(tempDirectory, 'Expected RUNNER_TEMP to be defined'); |  | ||||||
|   const tempDir: string = path.join(tempDirectory, tempDownloadFolder); |  | ||||||
|   await io.mkdirP(tempDir); |  | ||||||
|   let exeUrl: string; |  | ||||||
|   let libUrl: string; |  | ||||||
|   try { |  | ||||||
|     exeUrl = `${initialUrl}/v${version}/win-${osArch}/node.exe`; |  | ||||||
|     libUrl = `${initialUrl}/v${version}/win-${osArch}/node.lib`; |  | ||||||
|  |  | ||||||
|     core.info(`Downloading only node binary from ${exeUrl}`); |  | ||||||
|  |  | ||||||
|     const exePath = await tc.downloadTool(exeUrl); |  | ||||||
|     await io.cp(exePath, path.join(tempDir, 'node.exe')); |  | ||||||
|     const libPath = await tc.downloadTool(libUrl); |  | ||||||
|     await io.cp(libPath, path.join(tempDir, 'node.lib')); |  | ||||||
|   } catch (err) { |  | ||||||
|     if (err instanceof tc.HTTPError && err.httpStatusCode == 404) { |  | ||||||
|       exeUrl = `${initialUrl}/v${version}/node.exe`; |  | ||||||
|       libUrl = `${initialUrl}/v${version}/node.lib`; |  | ||||||
|  |  | ||||||
|       const exePath = await tc.downloadTool(exeUrl); |  | ||||||
|       await io.cp(exePath, path.join(tempDir, 'node.exe')); |  | ||||||
|       const libPath = await tc.downloadTool(libUrl); |  | ||||||
|       await io.cp(libPath, path.join(tempDir, 'node.lib')); |  | ||||||
|     } else { |  | ||||||
|       throw err; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   let toolPath = await tc.cacheDir(tempDir, 'node', version, arch); |  | ||||||
|   core.addPath(toolPath); |  | ||||||
|   return toolPath; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // os.arch does not always match the relative download url, e.g. |  | ||||||
| // os.arch == 'arm' != node-v12.13.1-linux-armv7l.tar.gz |  | ||||||
| // All other currently supported architectures match, e.g.: |  | ||||||
| //   os.arch = arm64 => https://nodejs.org/dist/v{VERSION}/node-v{VERSION}-{OS}-arm64.tar.gz |  | ||||||
| //   os.arch = x64 => https://nodejs.org/dist/v{VERSION}/node-v{VERSION}-{OS}-x64.tar.gz |  | ||||||
| function translateArchToDistUrl(arch: string): string { |  | ||||||
|   switch (arch) { |  | ||||||
|     case 'arm': |  | ||||||
|       return 'armv7l'; |  | ||||||
|     default: |  | ||||||
|       return arch; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function parseNodeVersionFile(contents: string): string { |  | ||||||
|   let nodeVersion: string | undefined; |  | ||||||
|  |  | ||||||
|   // Try parsing the file as an NPM `package.json` file. |  | ||||||
|   try { |  | ||||||
|     nodeVersion = JSON.parse(contents).volta?.node; |  | ||||||
|     if (!nodeVersion) nodeVersion = JSON.parse(contents).engines?.node; |  | ||||||
|   } catch { |  | ||||||
|     core.info('Node version file is not JSON file'); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if (!nodeVersion) { |  | ||||||
|     const found = contents.match(/^(?:nodejs\s+)?v?(?<version>[^\s]+)$/m); |  | ||||||
|     nodeVersion = found?.groups?.version; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // In the case of an unknown format, |  | ||||||
|   // return as is and evaluate the version separately. |  | ||||||
|   if (!nodeVersion) nodeVersion = contents.trim(); |  | ||||||
|  |  | ||||||
|   return nodeVersion as string; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function isLatestSyntax(versionSpec): boolean { |  | ||||||
|   return ['current', 'latest', 'node'].includes(versionSpec); |  | ||||||
| } |  | ||||||
							
								
								
									
										60
									
								
								src/main.ts
									
									
									
									
									
								
							
							
						
						
									
										60
									
								
								src/main.ts
									
									
									
									
									
								
							| @@ -1,12 +1,14 @@ | |||||||
| import * as core from '@actions/core'; | import * as core from '@actions/core'; | ||||||
| import * as exec from '@actions/exec'; |  | ||||||
| import * as installer from './installer'; |  | ||||||
| import fs from 'fs'; | import fs from 'fs'; | ||||||
|  | import os from 'os'; | ||||||
|  |  | ||||||
| import * as auth from './authutil'; | import * as auth from './authutil'; | ||||||
| import * as path from 'path'; | import * as path from 'path'; | ||||||
| import {restoreCache} from './cache-restore'; | import {restoreCache} from './cache-restore'; | ||||||
| import {isGhes, isCacheFeatureAvailable} from './cache-utils'; | import {isCacheFeatureAvailable} from './cache-utils'; | ||||||
| import os from 'os'; | import {getNodejsDistribution} from './distributions/installer-factory'; | ||||||
|  | import {parseNodeVersionFile, printEnvDetailsAndSetOutput} from './util'; | ||||||
|  |  | ||||||
| export async function run() { | export async function run() { | ||||||
|   try { |   try { | ||||||
| @@ -38,7 +40,15 @@ export async function run() { | |||||||
|         (core.getInput('stable') || 'true').toUpperCase() === 'TRUE'; |         (core.getInput('stable') || 'true').toUpperCase() === 'TRUE'; | ||||||
|       const checkLatest = |       const checkLatest = | ||||||
|         (core.getInput('check-latest') || 'false').toUpperCase() === 'TRUE'; |         (core.getInput('check-latest') || 'false').toUpperCase() === 'TRUE'; | ||||||
|       await installer.getNode(version, stable, checkLatest, auth, arch); |       const nodejsInfo = { | ||||||
|  |         versionSpec: version, | ||||||
|  |         checkLatest, | ||||||
|  |         auth, | ||||||
|  |         stable, | ||||||
|  |         arch | ||||||
|  |       }; | ||||||
|  |       const nodeDistribution = getNodejsDistribution(nodejsInfo); | ||||||
|  |       await nodeDistribution.setupNodeJs(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     await printEnvDetailsAndSetOutput(); |     await printEnvDetailsAndSetOutput(); | ||||||
| @@ -93,48 +103,10 @@ function resolveVersionInput(): string { | |||||||
|       ); |       ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     version = installer.parseNodeVersionFile( |     version = parseNodeVersionFile(fs.readFileSync(versionFilePath, 'utf8')); | ||||||
|       fs.readFileSync(versionFilePath, 'utf8') |  | ||||||
|     ); |  | ||||||
|  |  | ||||||
|     core.info(`Resolved ${versionFileInput} as ${version}`); |     core.info(`Resolved ${versionFileInput} as ${version}`); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   return version; |   return version; | ||||||
| } | } | ||||||
|  |  | ||||||
| export async function printEnvDetailsAndSetOutput() { |  | ||||||
|   core.startGroup('Environment details'); |  | ||||||
|  |  | ||||||
|   const promises = ['node', 'npm', 'yarn'].map(async tool => { |  | ||||||
|     const output = await getToolVersion(tool, ['--version']); |  | ||||||
|  |  | ||||||
|     if (tool === 'node') { |  | ||||||
|       core.setOutput(`${tool}-version`, output); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     core.info(`${tool}: ${output}`); |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
|   await Promise.all(promises); |  | ||||||
|  |  | ||||||
|   core.endGroup(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| async function getToolVersion(tool: string, options: string[]) { |  | ||||||
|   try { |  | ||||||
|     const {stdout, stderr, exitCode} = await exec.getExecOutput(tool, options, { |  | ||||||
|       ignoreReturnCode: true, |  | ||||||
|       silent: true |  | ||||||
|     }); |  | ||||||
|  |  | ||||||
|     if (exitCode > 0) { |  | ||||||
|       core.warning(`[warning]${stderr}`); |  | ||||||
|       return ''; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return stdout.trim(); |  | ||||||
|   } catch (err) { |  | ||||||
|     return ''; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|   | |||||||
							
								
								
									
										63
									
								
								src/util.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/util.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | |||||||
|  | import * as core from '@actions/core'; | ||||||
|  | import * as exec from '@actions/exec'; | ||||||
|  |  | ||||||
|  | export function parseNodeVersionFile(contents: string): string { | ||||||
|  |   let nodeVersion: string | undefined; | ||||||
|  |  | ||||||
|  |   // Try parsing the file as an NPM `package.json` file. | ||||||
|  |   try { | ||||||
|  |     nodeVersion = JSON.parse(contents).volta?.node; | ||||||
|  |     if (!nodeVersion) nodeVersion = JSON.parse(contents).engines?.node; | ||||||
|  |   } catch { | ||||||
|  |     core.info('Node version file is not JSON file'); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (!nodeVersion) { | ||||||
|  |     const found = contents.match(/^(?:nodejs\s+)?v?(?<version>[^\s]+)$/m); | ||||||
|  |     nodeVersion = found?.groups?.version; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // In the case of an unknown format, | ||||||
|  |   // return as is and evaluate the version separately. | ||||||
|  |   if (!nodeVersion) nodeVersion = contents.trim(); | ||||||
|  |  | ||||||
|  |   return nodeVersion as string; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export async function printEnvDetailsAndSetOutput() { | ||||||
|  |   core.startGroup('Environment details'); | ||||||
|  |  | ||||||
|  |   const promises = ['node', 'npm', 'yarn'].map(async tool => { | ||||||
|  |     const output = await getToolVersion(tool, ['--version']); | ||||||
|  |  | ||||||
|  |     return {tool, output}; | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   const tools = await Promise.all(promises); | ||||||
|  |   tools.forEach(({tool, output}) => { | ||||||
|  |     if (tool === 'node') { | ||||||
|  |       core.setOutput(`${tool}-version`, output); | ||||||
|  |     } | ||||||
|  |     core.info(`${tool}: ${output}`); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   core.endGroup(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | async function getToolVersion(tool: string, options: string[]) { | ||||||
|  |   try { | ||||||
|  |     const {stdout, stderr, exitCode} = await exec.getExecOutput(tool, options, { | ||||||
|  |       ignoreReturnCode: true, | ||||||
|  |       silent: true | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     if (exitCode > 0) { | ||||||
|  |       core.info(`[warning]${stderr}`); | ||||||
|  |       return ''; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return stdout.trim(); | ||||||
|  |   } catch (err) { | ||||||
|  |     return ''; | ||||||
|  |   } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user