diff --git a/.github/workflows/basic-validation.yml b/.github/workflows/basic-validation.yml deleted file mode 100644 index a4b1c0f26..000000000 --- a/.github/workflows/basic-validation.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: Basic validation - -on: - pull_request: - paths-ignore: - - '**.md' - push: - branches: - - main - - releases/* - paths-ignore: - - '**.md' - -jobs: - call-basic-validation: - name: Basic validation - uses: actions/reusable-workflows/.github/workflows/basic-validation.yml@main diff --git a/.github/workflows/check-dist.yml b/.github/workflows/check-dist.yml deleted file mode 100644 index c95229131..000000000 --- a/.github/workflows/check-dist.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: Check dist/ - -on: - push: - branches: - - main - paths-ignore: - - '**.md' - pull_request: - paths-ignore: - - '**.md' - workflow_dispatch: - -jobs: - call-check-dist: - name: Check dist/ - uses: actions/reusable-workflows/.github/workflows/check-dist.yml@main diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index 7a8261238..000000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: CodeQL analysis - -on: - push: - branches: [main] - pull_request: - branches: [main] - schedule: - - cron: '0 3 * * 0' - -jobs: - call-codeQL-analysis: - name: CodeQL analysis - uses: actions/reusable-workflows/.github/workflows/codeql-analysis.yml@main diff --git a/.github/workflows/e2e-cache.yml b/.github/workflows/e2e-cache.yml deleted file mode 100644 index fab3dcd74..000000000 --- a/.github/workflows/e2e-cache.yml +++ /dev/null @@ -1,136 +0,0 @@ -name: e2e-cache - -on: - pull_request: - paths-ignore: - - '**.md' - push: - branches: - - main - - releases/* - paths-ignore: - - '**.md' - -jobs: - node-npm-depencies-caching: - name: Test npm (Node ${{ matrix.node-version}}, ${{ matrix.os }}) - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - node-version: [12, 14, 16] - steps: - - uses: actions/checkout@v3 - - name: Clean global cache - run: npm cache clean --force - - name: Setup Node - uses: ./ - with: - node-version: ${{ matrix.node-version }} - cache: 'npm' - - name: Install dependencies - run: npm install - - name: Verify node and npm - run: __tests__/verify-node.sh "${{ matrix.node-version }}" - shell: bash - - node-pnpm-depencies-caching: - name: Test pnpm (Node ${{ matrix.node-version}}, ${{ matrix.os }}) - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - node-version: [12, 14, 16] - steps: - - uses: actions/checkout@v3 - - name: Install pnpm - uses: pnpm/action-setup@v2 - with: - version: 6.10.0 - - name: Generate pnpm file - run: pnpm install - - name: Remove dependencies - shell: pwsh - run: Remove-Item node_modules -Force -Recurse - - name: Clean global cache - run: rm -rf ~/.pnpm-store - shell: bash - - name: Setup Node - uses: ./ - with: - node-version: ${{ matrix.node-version }} - cache: 'pnpm' - - name: Install dependencies - run: pnpm install - - name: Verify node and pnpm - run: __tests__/verify-node.sh "${{ matrix.node-version }}" - shell: bash - - node-yarn1-depencies-caching: - name: Test yarn 1 (Node ${{ matrix.node-version}}, ${{ matrix.os }}) - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - node-version: [14, 16] - steps: - - uses: actions/checkout@v3 - - name: Yarn version - run: yarn --version - - name: Generate yarn file - run: yarn install - - name: Remove dependencies - shell: pwsh - run: Remove-Item node_modules -Force -Recurse - - name: Clean global cache - run: yarn cache clean - - name: Setup Node - uses: ./ - with: - node-version: ${{ matrix.node-version }} - cache: 'yarn' - - name: Install dependencies - run: yarn install - - name: Verify node and yarn - run: __tests__/verify-node.sh "${{ matrix.node-version }}" - shell: bash - - node-yarn2-depencies-caching: - name: Test yarn 2 (Node ${{ matrix.node-version}}, ${{ matrix.os }}) - runs-on: ${{ matrix.os }} - env: - YARN_ENABLE_IMMUTABLE_INSTALLS: false - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - node-version: [12, 14, 16] - steps: - - uses: actions/checkout@v3 - - name: Update yarn - run: yarn set version berry - - name: Yarn version - run: yarn --version - - name: Generate simple .yarnrc.yml - run: | - echo "nodeLinker: node-modules" >> .yarnrc.yml - - name: Generate yarn file - run: yarn install - - name: Remove dependencies - shell: pwsh - run: Remove-Item node_modules -Force -Recurse - - name: Clean global cache - run: yarn cache clean --all - - name: Setup Node - uses: ./ - with: - node-version: ${{ matrix.node-version }} - cache: 'yarn' - - name: Install dependencies - run: yarn install - - name: Verify node and yarn - run: __tests__/verify-node.sh "${{ matrix.node-version }}" - shell: bash diff --git a/.github/workflows/licensed.yml b/.github/workflows/licensed.yml deleted file mode 100644 index 37f1560c3..000000000 --- a/.github/workflows/licensed.yml +++ /dev/null @@ -1,15 +0,0 @@ -name: Licensed - -on: - push: - branches: - - main - pull_request: - branches: - - main - workflow_dispatch: - -jobs: - call-licensed: - name: Licensed - uses: actions/reusable-workflows/.github/workflows/licensed.yml@main diff --git a/.github/workflows/proxy.yml b/.github/workflows/proxy.yml deleted file mode 100644 index d37d46a71..000000000 --- a/.github/workflows/proxy.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: proxy - -on: - pull_request: - paths-ignore: - - '**.md' - push: - branches: - - main - - releases/* - paths-ignore: - - '**.md' - -jobs: - test-proxy: - runs-on: ubuntu-latest - container: - image: ubuntu:latest - options: --dns 127.0.0.1 - services: - squid-proxy: - image: ubuntu/squid:latest - ports: - - 3128:3128 - env: - https_proxy: http://squid-proxy:3128 - steps: - - uses: actions/checkout@v3 - - name: Clear tool cache - run: rm -rf $RUNNER_TOOL_CACHE/* - - name: Setup node 14 - uses: ./ - with: - node-version: 14.x - - name: Verify node and npm - run: __tests__/verify-node.sh 14 - - test-bypass-proxy: - runs-on: ubuntu-latest - env: - https_proxy: http://no-such-proxy:3128 - no_proxy: api.github.com,github.com,nodejs.org,registry.npmjs.org,*.s3.amazonaws.com,s3.amazonaws.com - steps: - - uses: actions/checkout@v3 - - name: Clear tool cache - run: rm -rf $RUNNER_TOOL_CACHE/* - - name: Setup node 11 - uses: ./ - with: - node-version: 11 - - name: Verify node and npm - run: __tests__/verify-node.sh 11 diff --git a/.github/workflows/release-new-action-version.yml b/.github/workflows/release-new-action-version.yml deleted file mode 100644 index d8171ef88..000000000 --- a/.github/workflows/release-new-action-version.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Release new action version - -on: - release: - types: [released] - workflow_dispatch: - inputs: - TAG_NAME: - description: 'Tag name that the major tag will point to' - required: true - -env: - TAG_NAME: ${{ github.event.inputs.TAG_NAME || github.event.release.tag_name }} -permissions: - contents: write - -jobs: - update_tag: - name: Update the major tag to include the ${{ github.event.inputs.TAG_NAME || github.event.release.tag_name }} changes - environment: - name: releaseNewActionVersion - runs-on: ubuntu-latest - steps: - - name: Update the ${{ env.TAG_NAME }} tag - uses: actions/publish-action@v0.2.2 - with: - source-tag: ${{ env.TAG_NAME }} - slack-webhook: ${{ secrets.SLACK_WEBHOOK }} diff --git a/.github/workflows/update-config-files.yml b/.github/workflows/update-config-files.yml deleted file mode 100644 index 87af50042..000000000 --- a/.github/workflows/update-config-files.yml +++ /dev/null @@ -1,11 +0,0 @@ -name: Update configuration files - -on: - schedule: - - cron: '0 3 * * 0' - workflow_dispatch: - -jobs: - call-update-configuration-files: - name: Update configuration files - uses: actions/reusable-workflows/.github/workflows/update-config-files.yml@main diff --git a/.github/workflows/versions.yml b/.github/workflows/versions.yml index ad5a1ccd5..baa697f64 100644 --- a/.github/workflows/versions.yml +++ b/.github/workflows/versions.yml @@ -10,256 +10,20 @@ on: - releases/* paths-ignore: - '**.md' + workflow_dispatch: jobs: - local-cache: - runs-on: ${{ matrix.os }} + resolve-stable-test: + runs-on: self-hosted strategy: fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] - node-version: [10, 12, 14] + node-version: [15.0.0, 16.0.0, 16.8.1, 17.9.1, 18.15.0] steps: - uses: actions/checkout@v3 - name: Setup Node uses: ./ with: - node-version: ${{ matrix.node-version }} - - name: Verify node and npm - run: __tests__/verify-node.sh "${{ matrix.node-version }}" - shell: bash - - lts-syntax: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - node-version: [lts/dubnium, lts/erbium, lts/fermium, lts/*, lts/-1] - steps: - - uses: actions/checkout@v3 - - name: Setup Node - uses: ./ - with: - node-version: ${{ matrix.node-version }} check-latest: true - - if: runner.os != 'Windows' - name: Verify node and npm - run: | - . "$NVM_DIR/nvm.sh" - [[ $(nvm version-remote "${{ matrix.node-version }}") =~ ^v([^.]+) ]] - __tests__/verify-node.sh "${BASH_REMATCH[1]}" - 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: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - node-version: - [16.0.0-nightly20210420a0261d231c, 17-nightly, 18.0.0-nightly] - steps: - - uses: actions/checkout@v3 - - name: Setup Node - uses: ./ - with: - node-version: ${{ matrix.node-version }} - - name: Verify node and npm - run: | - nightlyVersion="${{ matrix.node-version }}" - majorVersion=$(echo $nightlyVersion | cut -d- -f1) - __tests__/verify-node.sh "$majorVersion" - shell: bash - - rc-syntax: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - node-version: [16.0.0-rc.1, 18.0.0-rc.2, 19.0.0-rc.0] - steps: - - uses: actions/checkout@v3 - - name: Setup Node - uses: ./ - with: - node-version: ${{ matrix.node-version }} - - name: Verify node and npm - run: | - rcVersion="${{ matrix.node-version }}" - majorVersion=$(echo $rcVersion | cut -d- -f1) - __tests__/verify-node.sh "$majorVersion" - shell: bash - - manifest: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - node-version: [10.15, 12.16.0, 14.2.0, 16.3.0] - steps: - - uses: actions/checkout@v3 - - name: Setup Node - uses: ./ - with: - node-version: ${{ matrix.node-version }} - - name: Verify node and npm - run: __tests__/verify-node.sh "${{ matrix.node-version }}" - shell: bash - - check-latest: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - node-version: [10, 12, 14] - steps: - - uses: actions/checkout@v3 - - name: Setup Node and check latest - uses: ./ - with: - node-version: ${{ matrix.node-version }} - check-latest: true - - name: Verify node and npm - run: __tests__/verify-node.sh "${{ matrix.node-version }}" - shell: bash - - version-file: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - node-version-file: [.nvmrc, .tool-versions, package.json] - steps: - - uses: actions/checkout@v3 - - name: Remove volta from package.json - shell: bash - run: cat <<< "$(jq 'del(.volta)' ./__tests__/data/package.json)" > ./__tests__/data/package.json - - name: Setup node from node version file - uses: ./ - with: - node-version-file: '__tests__/data/${{ matrix.node-version-file }}' - - name: Verify node - run: __tests__/verify-node.sh 14 - - version-file-volta: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - steps: - - uses: actions/checkout@v3 - - name: Setup node from node version file - uses: ./ - with: - node-version-file: '__tests__/data/package.json' - - name: Verify node - run: __tests__/verify-node.sh 16 - - node-dist: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - node-version: [11, 13] - steps: - - uses: actions/checkout@v3 - - name: Setup Node from dist - uses: ./ - with: - node-version: ${{ matrix.node-version }} - - name: Verify node and npm - run: __tests__/verify-node.sh "${{ matrix.node-version }}" - shell: bash - - old-versions: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - steps: - - uses: actions/checkout@v3 - # test old versions which didn't have npm and layout different - - name: Setup node 0.12.18 from dist - uses: ./ - with: - node-version: 0.12.18 - - name: Verify node - run: __tests__/verify-node.sh 0.12.18 SKIP_NPM - shell: bash - - arch: - runs-on: windows-latest - steps: - - uses: actions/checkout@v3 - - name: Setup node 14 x86 from dist - uses: ./ - with: - node-version: '14' - architecture: 'x86' - - name: Verify node - run: __tests__/verify-arch.sh "ia32" - shell: bash - - node-latest-aliases: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - node-version: [current, latest, node] - steps: - - name: Get node version - run: | - latestNodeVersion=$(curl https://nodejs.org/dist/index.json | jq -r '. [0].version') - echo "LATEST_NODE_VERSION=$latestNodeVersion" >> $GITHUB_OUTPUT - id: version - shell: bash - - uses: actions/checkout@v3 - - name: Setup Node - uses: ./ - with: - node-version: ${{ matrix.node-version }} - - name: Retrieve version after install - run: | - updatedVersion=$(echo $(node --version)) - echo "NODE_VERSION_UPDATED=$updatedVersion" >> $GITHUB_OUTPUT - id: updatedVersion - shell: bash - - name: Compare versions - if: ${{ steps.version.outputs.LATEST_NODE_VERSION != steps.updatedVersion.outputs.NODE_VERSION_UPDATED}} - run: | - echo "Latest node version failed to download." - exit 1 + resolve-stable: true \ No newline at end of file diff --git a/__tests__/canary-installer.test.ts b/__tests__/canary-installer.test.ts index 6d141fc3c..8915c16f6 100644 --- a/__tests__/canary-installer.test.ts +++ b/__tests__/canary-installer.test.ts @@ -151,6 +151,7 @@ describe('setup-node', () => { it('finds version in cache with stable true', async () => { inputs['node-version'] = '20-v8-canary'; + inputs['resolve-stable'] = 'false'; os['arch'] = 'x64'; inputs.stable = 'true'; @@ -176,6 +177,7 @@ describe('setup-node', () => { it('finds version in cache and adds it to the path', async () => { inputs['node-version'] = '20-v8-canary'; + inputs['resolve-stable'] = 'false'; os['arch'] = 'x64'; inSpy.mockImplementation(name => inputs[name]); @@ -200,6 +202,7 @@ describe('setup-node', () => { os.platform = 'linux'; const errMsg = 'unhandled error message'; inputs['node-version'] = '20.0.0-v8-canary20221103f7e2421e91'; + inputs['resolve-stable'] = 'false'; findSpy.mockImplementation(() => { throw new Error(errMsg); @@ -229,6 +232,7 @@ describe('setup-node', () => { inputs['node-version'] = versionSpec; inputs['always-auth'] = false; inputs['token'] = 'faketoken'; + inputs['resolve-stable'] = 'false'; // ... but not in the local cache findSpy.mockImplementation(() => ''); @@ -259,6 +263,7 @@ describe('setup-node', () => { const versionSpec = '23.0.0-v8-canary20221103f7e2421e91'; inputs['node-version'] = versionSpec; + inputs['resolve-stable'] = 'false'; findSpy.mockImplementation(() => ''); findAllVersionsSpy.mockImplementation(() => [ @@ -285,6 +290,7 @@ describe('setup-node', () => { inputs['node-version'] = versionSpec; inputs['always-auth'] = false; inputs['token'] = 'faketoken'; + inputs['resolve-stable'] = 'false'; findSpy.mockImplementation(() => ''); findAllVersionsSpy.mockImplementation(() => [ @@ -326,6 +332,7 @@ describe('setup-node', () => { inputs['architecture'] = arch; inputs['always-auth'] = false; inputs['token'] = 'faketoken'; + inputs['resolve-stable'] = 'false'; const expectedUrl = `https://nodejs.org/download/v8-canary/v${version}/node-v${version}-${platform}-${arch}.${fileExtension}`; @@ -385,6 +392,7 @@ describe('setup-node', () => { cacheSpy.mockImplementation(async () => toolPath); inputs['node-version'] = input; + inputs['resolve-stable'] = 'false'; os['arch'] = 'x64'; os['platform'] = 'linux'; // act @@ -422,6 +430,7 @@ describe('setup-node', () => { ]); inputs['node-version'] = input; + inputs['resolve-stable'] = 'false'; os['arch'] = 'x64'; os['platform'] = 'linux'; @@ -470,6 +479,7 @@ describe('setup-node', () => { inputs['node-version'] = input; inputs['check-latest'] = 'true'; + inputs['resolve-stable'] = 'false'; os['arch'] = 'x64'; os['platform'] = 'linux'; @@ -507,6 +517,7 @@ describe('setup-node', () => { inputs['node-version'] = versionSpec; inputs['always-auth'] = false; inputs['token'] = 'faketoken'; + inputs['resolve-stable'] = 'false'; os.platform = 'linux'; os.arch = 'x64'; diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts index b57248757..116c452e9 100644 --- a/__tests__/main.test.ts +++ b/__tests__/main.test.ts @@ -240,6 +240,7 @@ describe('main tests', () => { const versionFile = '.nvmrc'; const versionFilePath = path.join(__dirname, '..', versionFile); inputs['node-version-file'] = versionFile; + inputs['resolve-stable'] = 'false'; inSpy.mockImplementation(name => inputs[name]); existsSpy.mockImplementationOnce( @@ -262,6 +263,7 @@ describe('main tests', () => { describe('cache on GHES', () => { it('Should throw an error, because cache is not supported', async () => { inputs['node-version'] = '12'; + inputs['resolve-stable'] = 'false'; inputs['cache'] = 'npm'; inSpy.mockImplementation(name => inputs[name]); @@ -282,6 +284,7 @@ describe('main tests', () => { it('Should throw an internal error', async () => { inputs['node-version'] = '12'; + inputs['resolve-stable'] = 'false'; inputs['cache'] = 'npm'; inSpy.mockImplementation(name => inputs[name]); diff --git a/__tests__/nightly-installer.test.ts b/__tests__/nightly-installer.test.ts index d88f5093c..5953ddb01 100644 --- a/__tests__/nightly-installer.test.ts +++ b/__tests__/nightly-installer.test.ts @@ -143,6 +143,7 @@ describe('setup-node', () => { it('finds version in cache with stable true', async () => { inputs['node-version'] = '16-nightly'; + inputs['resolve-stable'] = 'false'; os['arch'] = 'x64'; inputs.stable = 'true'; @@ -170,6 +171,7 @@ describe('setup-node', () => { it('finds version in cache with stable false', async () => { inputs['node-version'] = '16.0.0-nightly20210415c3a5e15ebe'; os['arch'] = 'x64'; + inputs['resolve-stable'] = 'false'; inputs.stable = 'false'; const toolPath = path.normalize( @@ -195,6 +197,7 @@ describe('setup-node', () => { it('finds version in cache and adds it to the path', async () => { inputs['node-version'] = '16-nightly'; + inputs['resolve-stable'] = 'false'; os['arch'] = 'x64'; inSpy.mockImplementation(name => inputs[name]); @@ -225,6 +228,7 @@ describe('setup-node', () => { it('handles unhandled find error and reports error', async () => { const errMsg = 'unhandled error message'; inputs['node-version'] = '16.0.0-nightly20210417bc31dc0e0f'; + inputs['resolve-stable'] = 'false'; findAllVersionsSpy.mockImplementation(() => [ '12.0.1', @@ -252,6 +256,7 @@ describe('setup-node', () => { inputs['node-version'] = versionSpec; inputs['always-auth'] = false; inputs['token'] = 'faketoken'; + inputs['resolve-stable'] = 'false'; // ... but not in the local cache findSpy.mockImplementation(() => ''); @@ -279,6 +284,7 @@ describe('setup-node', () => { const versionSpec = '10.13.1-nightly20200415947ddec091'; inputs['node-version'] = versionSpec; + inputs['resolve-stable'] = 'false'; findSpy.mockImplementation(() => ''); findAllVersionsSpy.mockImplementation(() => []); @@ -299,6 +305,7 @@ describe('setup-node', () => { inputs['node-version'] = versionSpec; inputs['always-auth'] = false; + inputs['resolve-stable'] = 'false'; inputs['token'] = 'faketoken'; findSpy.mockImplementation(() => ''); @@ -338,6 +345,7 @@ describe('setup-node', () => { inputs['architecture'] = arch; inputs['always-auth'] = false; inputs['token'] = 'faketoken'; + inputs['resolve-stable'] = 'false'; const expectedUrl = `https://nodejs.org/download/nightly/v${version}/node-v${version}-${platform}-${arch}.${fileExtension}`; @@ -397,6 +405,7 @@ describe('setup-node', () => { cacheSpy.mockImplementation(async () => toolPath); inputs['node-version'] = input; + inputs['resolve-stable'] = 'false'; os['arch'] = 'x64'; os['platform'] = 'linux'; // act @@ -431,6 +440,7 @@ describe('setup-node', () => { ]); inputs['node-version'] = input; + inputs['resolve-stable'] = 'false'; os['arch'] = 'x64'; os['platform'] = 'linux'; @@ -485,6 +495,7 @@ describe('setup-node', () => { inputs['node-version'] = input; inputs['check-latest'] = 'true'; + inputs['resolve-stable'] = 'false'; os['arch'] = 'x64'; os['platform'] = 'linux'; diff --git a/__tests__/official-installer.test.ts b/__tests__/official-installer.test.ts index 474fb5b98..86ea5a6af 100644 --- a/__tests__/official-installer.test.ts +++ b/__tests__/official-installer.test.ts @@ -175,6 +175,7 @@ describe('setup-node', () => { it('finds version in cache with stable true', async () => { inputs['node-version'] = '12'; + inputs['resolve-stable'] = 'false'; inputs.stable = 'true'; const toolPath = path.normalize('/cache/node/12.16.1/x64'); @@ -186,6 +187,7 @@ describe('setup-node', () => { it('finds version in cache with stable not supplied', async () => { inputs['node-version'] = '12'; + inputs['resolve-stable'] = 'false'; inSpy.mockImplementation(name => inputs[name]); @@ -198,6 +200,7 @@ describe('setup-node', () => { it('finds version in cache and adds it to the path', async () => { inputs['node-version'] = '12'; + inputs['resolve-stable'] = 'false'; inSpy.mockImplementation(name => inputs[name]); @@ -212,6 +215,7 @@ describe('setup-node', () => { it('handles unhandled find error and reports error', async () => { const errMsg = 'unhandled error message'; inputs['node-version'] = '12'; + inputs['resolve-stable'] = 'false'; findSpy.mockImplementation(() => { throw new Error(errMsg); @@ -237,6 +241,7 @@ describe('setup-node', () => { inputs['node-version'] = versionSpec; inputs['always-auth'] = false; inputs['token'] = 'faketoken'; + inputs['resolve-stable'] = 'false'; const expectedUrl = 'https://github.com/actions/node-versions/releases/download/12.16.2-20200507.95/node-12.16.2-linux-x64.tar.gz'; @@ -289,6 +294,7 @@ describe('setup-node', () => { inputs['node-version'] = versionSpec; inputs['always-auth'] = false; inputs['token'] = 'faketoken'; + inputs['resolve-stable'] = 'false'; // ... but not in the local cache findSpy.mockImplementation(() => ''); @@ -320,6 +326,7 @@ describe('setup-node', () => { const versionSpec = '9.99.9'; inputs['node-version'] = versionSpec; + inputs['resolve-stable'] = 'false'; findSpy.mockImplementation(() => ''); await main.run(); @@ -347,6 +354,7 @@ describe('setup-node', () => { inputs['node-version'] = versionSpec; inputs['always-auth'] = false; inputs['token'] = 'faketoken'; + inputs['resolve-stable'] = 'false'; findSpy.mockImplementation(() => ''); dlSpy.mockImplementation(() => { @@ -375,6 +383,7 @@ describe('setup-node', () => { inputs['architecture'] = arch; inputs['always-auth'] = false; inputs['token'] = 'faketoken'; + inputs['resolve-stable'] = 'false'; const expectedUrl = arch === 'x64' @@ -404,6 +413,7 @@ describe('setup-node', () => { inputs['node-version'] = '12'; inputs['check-latest'] = 'false'; + inputs['resolve-stable'] = 'false'; const toolPath = path.normalize('/cache/node/12.16.1/x64'); findSpy.mockReturnValue(toolPath); @@ -425,6 +435,7 @@ describe('setup-node', () => { inputs['node-version'] = '12'; inputs['check-latest'] = 'true'; + inputs['resolve-stable'] = 'false'; const toolPath = path.normalize('/cache/node/12.16.2/x64'); findSpy.mockReturnValue(toolPath); @@ -451,6 +462,7 @@ describe('setup-node', () => { inputs['node-version'] = '12'; inputs['check-latest'] = 'true'; + inputs['resolve-stable'] = 'false'; findSpy.mockImplementation(() => ''); dlSpy.mockImplementation(async () => '/some/temp/path'); @@ -487,6 +499,7 @@ describe('setup-node', () => { inputs['check-latest'] = 'true'; inputs['always-auth'] = false; inputs['token'] = 'faketoken'; + inputs['resolve-stable'] = 'false'; // ... but not in the local cache findSpy.mockImplementation(() => ''); @@ -529,6 +542,7 @@ describe('setup-node', () => { inputs['check-latest'] = 'true'; inputs['always-auth'] = false; inputs['token'] = 'faketoken'; + inputs['resolve-stable'] = 'false'; // ... but not in the local cache findSpy.mockImplementation(() => ''); @@ -579,6 +593,7 @@ describe('setup-node', () => { async (lts, expectedVersion) => { // arrange inputs['node-version'] = `lts/${lts}`; + inputs['resolve-stable'] = 'false'; const toolPath = path.normalize(`/cache/node/${expectedVersion}/x64`); findSpy.mockReturnValue(toolPath); @@ -628,6 +643,7 @@ describe('setup-node', () => { async (lts, expectedVersion, expectedUrl) => { // arrange inputs['node-version'] = `lts/${lts}`; + inputs['resolve-stable'] = 'false'; const toolPath = path.normalize(`/cache/node/${expectedVersion}/x64`); findSpy.mockImplementation(() => ''); @@ -670,6 +686,7 @@ describe('setup-node', () => { it('fail with unable to parse LTS alias (lts/)', async () => { // arrange inputs['node-version'] = 'lts/'; + inputs['resolve-stable'] = 'false'; findSpy.mockImplementation(() => ''); @@ -691,6 +708,7 @@ describe('setup-node', () => { it('fail to find LTS version (lts/unknown)', async () => { // arrange inputs['node-version'] = 'lts/unknown'; + inputs['resolve-stable'] = 'false'; findSpy.mockImplementation(() => ''); @@ -715,6 +733,7 @@ describe('setup-node', () => { it('fail if manifest is not available', async () => { // arrange inputs['node-version'] = 'lts/erbium'; + inputs['resolve-stable'] = 'false'; // ... but not in the local cache findSpy.mockImplementation(() => ''); @@ -744,6 +763,7 @@ describe('setup-node', () => { async inputVersion => { // Arrange inputs['node-version'] = inputVersion; + inputs['resolve-stable'] = 'false'; os.platform = 'darwin'; os.arch = 'x64'; @@ -770,6 +790,7 @@ describe('setup-node', () => { async inputVersion => { // Arrange inputs['node-version'] = inputVersion; + inputs['resolve-stable'] = 'false'; const expectedVersion = nodeTestDist[0]; os.platform = 'darwin'; diff --git a/__tests__/rc-installer.test.ts b/__tests__/rc-installer.test.ts index 736260a4d..e79f6ad41 100644 --- a/__tests__/rc-installer.test.ts +++ b/__tests__/rc-installer.test.ts @@ -140,6 +140,7 @@ describe('setup-node', () => { it('finds version in cache with stable true', async () => { inputs['node-version'] = '12.0.0-rc.1'; + inputs['resolve-stable'] = 'false'; inputs.stable = 'true'; const toolPath = path.normalize('/cache/node/12.0.0-rc.1/x64'); @@ -151,6 +152,7 @@ describe('setup-node', () => { it('finds version in cache with stable not supplied', async () => { inputs['node-version'] = '12.0.0-rc.1'; + inputs['resolve-stable'] = 'false'; inSpy.mockImplementation(name => inputs[name]); @@ -163,6 +165,7 @@ describe('setup-node', () => { it('finds version in cache and adds it to the path', async () => { inputs['node-version'] = '12.0.0-rc.1'; + inputs['resolve-stable'] = 'false'; inSpy.mockImplementation(name => inputs[name]); @@ -177,6 +180,7 @@ describe('setup-node', () => { it('handles unhandled find error and reports error', async () => { const errMsg = 'unhandled error message'; inputs['node-version'] = '12.0.0-rc.1'; + inputs['resolve-stable'] = 'false'; findSpy.mockImplementation(() => { throw new Error(errMsg); @@ -196,6 +200,7 @@ describe('setup-node', () => { inputs['node-version'] = versionSpec; inputs['always-auth'] = false; inputs['token'] = 'faketoken'; + inputs['resolve-stable'] = 'false'; // ... but not in the local cache findSpy.mockImplementation(() => ''); @@ -222,6 +227,7 @@ describe('setup-node', () => { const versionSpec = '9.99.9-rc.1'; inputs['node-version'] = versionSpec; + inputs['resolve-stable'] = 'false'; findSpy.mockImplementation(() => ''); await main.run(); @@ -241,6 +247,7 @@ describe('setup-node', () => { inputs['node-version'] = versionSpec; inputs['always-auth'] = false; inputs['token'] = 'faketoken'; + inputs['resolve-stable'] = 'false'; findSpy.mockImplementation(() => ''); findAllVersionsSpy.mockImplementation(() => []); @@ -270,6 +277,7 @@ describe('setup-node', () => { inputs['architecture'] = arch; inputs['always-auth'] = false; inputs['token'] = 'faketoken'; + inputs['resolve-stable'] = 'false'; const expectedUrl = `https://nodejs.org/download/rc/v${version}/node-v${version}-${platform}-${arch}.${fileExtension}`; @@ -329,6 +337,7 @@ describe('setup-node', () => { cacheSpy.mockImplementation(async () => toolPath); inputs['node-version'] = input; + inputs['resolve-stable'] = 'false'; os['arch'] = 'x64'; os['platform'] = 'linux'; // act @@ -365,6 +374,7 @@ describe('setup-node', () => { ]); inputs['node-version'] = input; + inputs['resolve-stable'] = 'false'; os['arch'] = 'x64'; os['platform'] = 'linux'; @@ -388,6 +398,7 @@ describe('setup-node', () => { exSpy.mockImplementation(async () => '/some/other/temp/path'); inputs['node-version'] = versionSpec; + inputs['resolve-stable'] = 'false'; os['arch'] = 'x64'; os['platform'] = 'linux'; // act diff --git a/action.yml b/action.yml index b22de1ef6..c1a17c4ad 100644 --- a/action.yml +++ b/action.yml @@ -11,9 +11,11 @@ inputs: description: 'File containing the version Spec of the version to use. Examples: .nvmrc, .node-version, .tool-versions.' architecture: description: 'Target architecture for Node to use. Examples: x86, x64. Will use system architecture by default.' + resolve-stable: + description: 'Checks if the provided repository is stable and switches it to a stable one if not.' check-latest: description: 'Set this option if you want the action to check for the latest available version that satisfies the version spec.' - default: false + default: 'false' registry-url: description: 'Optional registry to set up for auth. Will set the registry in a project level .npmrc and .yarnrc file, and set up auth to read in from env.NODE_AUTH_TOKEN.' scope: diff --git a/dist/setup/index.js b/dist/setup/index.js index fd6023475..ff14d7912 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -73417,6 +73417,62 @@ class BaseDistribution { return response.result || []; }); } + stableNodeVersionsList(list) { + const stableVersions = list + .filter(item => semver_1.default.major(item.version) % 2 === 0) + .map(item => item.version); + const versionsSorted = semver_1.default.sort(stableVersions).reverse(); + return versionsSorted; + } + // Experimental + getTotalLatestNodeVersion() { + return __awaiter(this, void 0, void 0, function* () { + const nodejsVersionObjectList = yield this.getNodeJsVersions(); + const versions = nodejsVersionObjectList.map(item => item.version); + const sortedVersionsDesc = semver_1.default.sort(versions).reverse(); + return sortedVersionsDesc[0]; + }); + } + determineStableNodeVersion(providedNodeVersion) { + return __awaiter(this, void 0, void 0, function* () { + const versionsDataList = yield this.getNodeJsVersions(); + const versionsList = this.stableNodeVersionsList(versionsDataList); + if (semver_1.default.major(providedNodeVersion) % 2 === 0) { + const highestCurrent = semver_1.default.maxSatisfying(versionsList, `^${semver_1.default.major(providedNodeVersion)}.x.x`); + core.info(`Switching to the latest stable major version... (${highestCurrent})`); + return highestCurrent; + } + else { + const searchedVersion = semver_1.default.maxSatisfying(versionsList, `^${semver_1.default.major(providedNodeVersion) + 1}.x.x`); + core.info(`Switching to the highest version of the next stable release... (${searchedVersion})`); + return searchedVersion; + } + }); + } + resolveStableVersionOfNode(providedNodeVersion) { + return __awaiter(this, void 0, void 0, function* () { + const versionsDataList = yield this.getNodeJsVersions(); + const lowestStableBoundary = '10.24.1'; + const highestStableBoundary = this.stableNodeVersionsList(versionsDataList)[0]; + const highestTotalNodeVersion = yield this.getTotalLatestNodeVersion(); + let errorMessage; + if (providedNodeVersion) { + if (semver_1.default.lt(providedNodeVersion, lowestStableBoundary)) { + errorMessage = `node-version specified is lower than the lowest supported stable version (${lowestStableBoundary}).`; + core.setFailed(errorMessage); + } + if (semver_1.default.gt(providedNodeVersion, highestStableBoundary) || semver_1.default.gte(providedNodeVersion, highestTotalNodeVersion)) { + errorMessage = `node-version specified is higher than the highest supported stable version (${highestStableBoundary}) or total version (${highestTotalNodeVersion}).`; + core.setFailed(errorMessage); + } + const version = yield this.determineStableNodeVersion(providedNodeVersion); + return version; + } + errorMessage = 'No Node version provided'; + core.setFailed(errorMessage); + throw new Error(errorMessage); + }); + } getNodejsDistInfo(version) { const osArch = this.translateArchToDistUrl(this.nodeInfo.arch); version = semver_1.default.clean(version) || ''; @@ -73945,7 +74001,7 @@ function run() { // Version is optional. If supplied, install / use from the tool cache // If not supplied then task is still used to setup proxy, auth, etc... // - const version = resolveVersionInput(); + const version = resolveVersionInput(); // changed const to let as it may change versions later on in an if block let arch = core.getInput('architecture'); const cache = core.getInput('cache'); // if architecture supplied but node-version is not @@ -73959,6 +74015,7 @@ function run() { if (version) { const token = core.getInput('token'); const auth = !token ? undefined : `token ${token}`; + const resolveStable = (core.getInput('resolve-stable')).toUpperCase() === 'TRUE'; const stable = (core.getInput('stable') || 'true').toUpperCase() === 'TRUE'; const checkLatest = (core.getInput('check-latest') || 'false').toUpperCase() === 'TRUE'; const nodejsInfo = { @@ -73968,7 +74025,16 @@ function run() { stable, arch }; - const nodeDistribution = installer_factory_1.getNodejsDistribution(nodejsInfo); + let nodeDistribution = installer_factory_1.getNodejsDistribution(nodejsInfo); + if (resolveStable === true) { + const updatedVersion = yield nodeDistribution.resolveStableVersionOfNode(version); + if (updatedVersion) { + nodeDistribution = installer_factory_1.getNodejsDistribution(Object.assign(Object.assign({}, nodejsInfo), { versionSpec: updatedVersion })); + } + else { + core.setFailed('The returned version value is undefined.'); + } + } yield nodeDistribution.setupNodeJs(); } yield util_1.printEnvDetailsAndSetOutput(); diff --git a/src/distributions/base-distribution.ts b/src/distributions/base-distribution.ts index bcfe2fc8e..d6509d2ce 100644 --- a/src/distributions/base-distribution.ts +++ b/src/distributions/base-distribution.ts @@ -99,6 +99,73 @@ export default abstract class BaseDistribution { return response.result || []; } + private stableNodeVersionsList(list: INodeVersion[]): string[] { + const stableVersions = list + .filter(item => semver.major(item.version) % 2 === 0) + .map(item => item.version); + const versionsSorted = semver.sort(stableVersions).reverse(); + return versionsSorted; + } + + // Experimental + private async getTotalLatestNodeVersion(): Promise { + const nodejsVersionObjectList = await this.getNodeJsVersions(); + const versions = nodejsVersionObjectList.map(item => item.version); + const sortedVersionsDesc = semver.sort(versions).reverse(); + + return sortedVersionsDesc[0]; + } + + private async determineStableNodeVersion(providedNodeVersion: string): Promise { + const versionsDataList: INodeVersion[] = await this.getNodeJsVersions(); + const versionsList: string[] = this.stableNodeVersionsList(versionsDataList); + + if (semver.major(providedNodeVersion) % 2 === 0) { + const highestCurrent = semver.maxSatisfying(versionsList, `^${semver.major(providedNodeVersion)}.x.x`); + core.info(`Switching to the latest stable major version... (${highestCurrent})`); + + return highestCurrent; + } + else { + const searchedVersion = semver.maxSatisfying(versionsList, `^${semver.major(providedNodeVersion)+1}.x.x`); + core.info(`Switching to the highest version of the next stable release... (${searchedVersion})`); + + return searchedVersion; + } + } + + + async resolveStableVersionOfNode(providedNodeVersion: string): Promise { + const versionsDataList: INodeVersion[] = await this.getNodeJsVersions(); + const lowestStableBoundary = '10.24.1'; + const highestStableBoundary = this.stableNodeVersionsList(versionsDataList)[0]; + const highestTotalNodeVersion = await this.getTotalLatestNodeVersion(); + let errorMessage: string; + + if (providedNodeVersion) { + + if (semver.lt(providedNodeVersion, lowestStableBoundary)) { + errorMessage = `node-version specified is lower than the lowest supported stable version (${lowestStableBoundary}).`; + core.setFailed(errorMessage); + } + + if (semver.gt(providedNodeVersion, highestStableBoundary) || semver.gte(providedNodeVersion, highestTotalNodeVersion)) { + errorMessage = `node-version specified is higher than the highest supported stable version (${highestStableBoundary}) or total version (${highestTotalNodeVersion}).`; + core.setFailed(errorMessage); + } + + const version = await this.determineStableNodeVersion(providedNodeVersion); + return version; + + } + + errorMessage = 'No Node version provided'; + + core.setFailed(errorMessage); + throw new Error(errorMessage); + + } + protected getNodejsDistInfo(version: string) { const osArch: string = this.translateArchToDistUrl(this.nodeInfo.arch); version = semver.clean(version) || ''; diff --git a/src/main.ts b/src/main.ts index 90cd1d9d9..f9d05498f 100644 --- a/src/main.ts +++ b/src/main.ts @@ -16,7 +16,7 @@ export async function run() { // Version is optional. If supplied, install / use from the tool cache // If not supplied then task is still used to setup proxy, auth, etc... // - const version = resolveVersionInput(); + const version: string = resolveVersionInput(); // changed const to let as it may change versions later on in an if block let arch = core.getInput('architecture'); const cache = core.getInput('cache'); @@ -34,10 +34,12 @@ export async function run() { } if (version) { + const token = core.getInput('token'); const auth = !token ? undefined : `token ${token}`; + const resolveStable = (core.getInput('resolve-stable')).toUpperCase() === 'TRUE'; const stable = - (core.getInput('stable') || 'true').toUpperCase() === 'TRUE'; + (core.getInput('stable') || 'true').toUpperCase() === 'TRUE'; const checkLatest = (core.getInput('check-latest') || 'false').toUpperCase() === 'TRUE'; const nodejsInfo = { @@ -47,7 +49,19 @@ export async function run() { stable, arch }; - const nodeDistribution = getNodejsDistribution(nodejsInfo); + + let nodeDistribution = getNodejsDistribution(nodejsInfo); + + if (resolveStable === true) { + const updatedVersion = await nodeDistribution.resolveStableVersionOfNode(version); + if (updatedVersion) { + nodeDistribution = getNodejsDistribution({...nodejsInfo, versionSpec: updatedVersion}) + } + else { + core.setFailed('The returned version value is undefined.'); + } + } + await nodeDistribution.setupNodeJs(); } @@ -77,6 +91,7 @@ export async function run() { } } + function resolveVersionInput(): string { let version = core.getInput('node-version'); const versionFileInput = core.getInput('node-version-file'); diff --git a/src/util.ts b/src/util.ts index 60f2649c2..8efcabc19 100644 --- a/src/util.ts +++ b/src/util.ts @@ -60,4 +60,4 @@ async function getToolVersion(tool: string, options: string[]) { } catch (err) { return ''; } -} +} \ No newline at end of file