mirror actions/setup-node @ 49933ea5288caeca8642d1e84afbd3f7d6820020
e2e-cache / Test npm (Node 18, ubuntu-latest) (push) Failing after 3s
e2e-cache / Test npm (Node 20, ubuntu-latest) (push) Failing after 2s
e2e-cache / Test npm (Node 22, ubuntu-latest) (push) Failing after 1s
e2e-cache / Test pnpm (Node 18, ubuntu-latest) (push) Failing after 1s
e2e-cache / Test pnpm (Node 20, ubuntu-latest) (push) Failing after 2s
e2e-cache / Test pnpm (Node 22, ubuntu-latest) (push) Failing after 1s
e2e-cache / Test yarn 1 (Node 18, ubuntu-latest) (push) Failing after 0s
e2e-cache / Test yarn 1 (Node 20, ubuntu-latest) (push) Failing after 1s
e2e-cache / Test yarn 3 (Node 18, ubuntu-latest) (push) Failing after 1s
e2e-cache / Test yarn 3 (Node 20, ubuntu-latest) (push) Failing after 1s
e2e-cache / Test yarn 3 (Node 22, ubuntu-latest) (push) Failing after 1s
e2e-cache / Test yarn subprojects (18) (push) Failing after 1s
e2e-cache / Test yarn subprojects (20) (push) Failing after 1s
e2e-cache / Test yarn subprojects (22) (push) Failing after 1s
e2e-cache / Test yarn subprojects all locally managed (18) (push) Failing after 1s
e2e-cache / Test yarn subprojects all locally managed (20) (push) Failing after 0s
e2e-cache / Test yarn subprojects all locally managed (22) (push) Failing after 1s
e2e-cache / Test yarn subprojects some locally managed (18) (push) Failing after 1s
e2e-cache / Test yarn subprojects some locally managed (20) (push) Failing after 0s
e2e-cache / Test yarn subprojects some locally managed (22) (push) Failing after 1s
e2e-cache / Test yarn subprojects managed by git (18) (push) Failing after 1s
e2e-cache / Test yarn subprojects managed by git (20) (push) Failing after 1s
e2e-cache / Test yarn subprojects managed by git (22) (push) Failing after 1s
proxy / test-proxy (push) Failing after 2s
proxy / test-bypass-proxy (push) Failing after 1s
versions / local-cache (18, ubuntu-latest) (push) Failing after 1s
versions / local-cache (20, ubuntu-latest) (push) Failing after 1s
versions / local-cache (22, ubuntu-latest) (push) Failing after 1s
versions / lts-syntax (lts/*, ubuntu-latest) (push) Failing after 2s
versions / lts-syntax (lts/-1, ubuntu-latest) (push) Failing after 1s
versions / lts-syntax (lts/dubnium, ubuntu-latest) (push) Failing after 2s
versions / lts-syntax (lts/erbium, ubuntu-latest) (push) Failing after 1s
versions / lts-syntax (lts/fermium, ubuntu-latest) (push) Failing after 4s
versions / v8-canary-syntax (20-v8-canary, ubuntu-latest) (push) Failing after 3s
versions / v8-canary-syntax (20.0.0-v8-canary, ubuntu-latest) (push) Failing after 4s
versions / v8-canary-syntax (20.0.0-v8-canary20221101e50e45c9f8, ubuntu-latest) (push) Failing after 4s
versions / nightly-syntax (18.0.0-nightly, ubuntu-latest) (push) Failing after 6s
versions / nightly-syntax (20-nightly, ubuntu-latest) (push) Failing after 1s
versions / nightly-syntax (21-nightly, ubuntu-latest) (push) Failing after 1s
versions / rc-syntax (18.0.0-rc.2, ubuntu-latest) (push) Failing after 0s
versions / rc-syntax (19.0.0-rc.0, ubuntu-latest) (push) Failing after 1s
versions / rc-syntax (20.0.0-rc.1, ubuntu-latest) (push) Failing after 1s
versions / manifest (18.20.0, ubuntu-latest) (push) Failing after 1s
versions / manifest (20.10.0, ubuntu-latest) (push) Failing after 1s
versions / manifest (22.0.0, ubuntu-latest) (push) Failing after 2s
versions / local-cache (18, macos-13) (push) Canceled after 0s
versions / local-cache (18, macos-latest) (push) Canceled after 0s
versions / local-cache (18, windows-latest) (push) Canceled after 0s
versions / local-cache (20, macos-13) (push) Canceled after 0s
versions / local-cache (20, macos-latest) (push) Canceled after 0s
versions / local-cache (20, windows-latest) (push) Canceled after 0s
e2e-cache / Test npm (Node 18, macos-13) (push) Canceled after 0s
e2e-cache / Test npm (Node 18, macos-latest) (push) Canceled after 0s
versions / local-cache (22, macos-13) (push) Canceled after 0s
e2e-cache / Test npm (Node 18, windows-latest) (push) Canceled after 0s
versions / local-cache (22, macos-latest) (push) Canceled after 0s
e2e-cache / Test npm (Node 20, macos-13) (push) Canceled after 0s
e2e-cache / Test npm (Node 20, macos-latest) (push) Canceled after 0s
versions / local-cache (22, windows-latest) (push) Canceled after 0s
e2e-cache / Test npm (Node 20, windows-latest) (push) Canceled after 0s
e2e-cache / Test npm (Node 22, macos-13) (push) Canceled after 0s
versions / lts-syntax (lts/-1, macos-13) (push) Canceled after 0s
e2e-cache / Test npm (Node 22, macos-latest) (push) Canceled after 0s
versions / lts-syntax (lts/-1, windows-latest) (push) Canceled after 0s
e2e-cache / Test npm (Node 22, windows-latest) (push) Canceled after 0s
versions / lts-syntax (lts/*, macos-13) (push) Canceled after 0s
e2e-cache / Test pnpm (Node 18, macos-13) (push) Canceled after 0s
versions / lts-syntax (lts/*, windows-latest) (push) Canceled after 0s
e2e-cache / Test pnpm (Node 18, macos-latest) (push) Canceled after 0s
versions / lts-syntax (lts/dubnium, macos-13) (push) Canceled after 0s
versions / lts-syntax (lts/dubnium, windows-latest) (push) Canceled after 0s
versions / lts-syntax (lts/erbium, macos-13) (push) Canceled after 0s
versions / lts-syntax (lts/erbium, windows-latest) (push) Canceled after 0s
versions / lts-syntax (lts/fermium, macos-13) (push) Canceled after 0s
versions / lts-syntax (lts/fermium, windows-latest) (push) Canceled after 0s
e2e-cache / Test pnpm (Node 18, windows-latest) (push) Canceled after 0s
e2e-cache / Test pnpm (Node 20, macos-13) (push) Canceled after 0s
versions / v8-canary-syntax (20-v8-canary, macos-13) (push) Canceled after 0s
e2e-cache / Test pnpm (Node 20, macos-latest) (push) Canceled after 0s
versions / v8-canary-syntax (20-v8-canary, macos-latest) (push) Canceled after 0s
e2e-cache / Test pnpm (Node 20, windows-latest) (push) Canceled after 0s
versions / v8-canary-syntax (20-v8-canary, windows-latest) (push) Canceled after 0s
e2e-cache / Test pnpm (Node 22, macos-13) (push) Canceled after 0s
versions / v8-canary-syntax (20.0.0-v8-canary20221101e50e45c9f8, macos-13) (push) Canceled after 0s
e2e-cache / Test pnpm (Node 22, macos-latest) (push) Canceled after 0s
versions / v8-canary-syntax (20.0.0-v8-canary20221101e50e45c9f8, macos-latest) (push) Canceled after 0s
e2e-cache / Test pnpm (Node 22, windows-latest) (push) Canceled after 0s
versions / v8-canary-syntax (20.0.0-v8-canary20221101e50e45c9f8, windows-latest) (push) Canceled after 0s
e2e-cache / Test yarn 1 (Node 18, macos-13) (push) Canceled after 0s
versions / v8-canary-syntax (20.0.0-v8-canary, macos-13) (push) Canceled after 0s
e2e-cache / Test yarn 1 (Node 18, macos-latest) (push) Canceled after 0s
versions / v8-canary-syntax (20.0.0-v8-canary, macos-latest) (push) Canceled after 0s
e2e-cache / Test yarn 1 (Node 18, windows-latest) (push) Canceled after 0s
versions / v8-canary-syntax (20.0.0-v8-canary, windows-latest) (push) Canceled after 0s
e2e-cache / Test yarn 1 (Node 20, macos-13) (push) Canceled after 0s
versions / nightly-syntax (18.0.0-nightly, macos-13) (push) Canceled after 0s
e2e-cache / Test yarn 1 (Node 20, macos-latest) (push) Canceled after 0s
versions / nightly-syntax (18.0.0-nightly, macos-latest) (push) Canceled after 0s
versions / nightly-syntax (18.0.0-nightly, windows-latest) (push) Canceled after 0s
e2e-cache / Test yarn 1 (Node 20, windows-latest) (push) Canceled after 0s
versions / nightly-syntax (20-nightly, macos-13) (push) Canceled after 0s
e2e-cache / Test yarn 3 (Node 18, macos-13) (push) Canceled after 0s
e2e-cache / Test yarn 3 (Node 18, macos-latest) (push) Canceled after 0s
versions / nightly-syntax (20-nightly, macos-latest) (push) Canceled after 0s
e2e-cache / Test yarn 3 (Node 18, windows-latest) (push) Canceled after 0s
versions / nightly-syntax (20-nightly, windows-latest) (push) Canceled after 0s
versions / nightly-syntax (21-nightly, macos-13) (push) Canceled after 0s
e2e-cache / Test yarn 3 (Node 20, macos-13) (push) Canceled after 0s
versions / nightly-syntax (21-nightly, macos-latest) (push) Canceled after 0s
e2e-cache / Test yarn 3 (Node 20, macos-latest) (push) Canceled after 0s
versions / nightly-syntax (21-nightly, windows-latest) (push) Canceled after 0s
e2e-cache / Test yarn 3 (Node 20, windows-latest) (push) Canceled after 0s
versions / rc-syntax (18.0.0-rc.2, macos-13) (push) Canceled after 0s
e2e-cache / Test yarn 3 (Node 22, macos-13) (push) Canceled after 0s
versions / rc-syntax (18.0.0-rc.2, macos-latest) (push) Canceled after 0s
e2e-cache / Test yarn 3 (Node 22, macos-latest) (push) Canceled after 0s
versions / rc-syntax (19.0.0-rc.0, macos-13) (push) Canceled after 0s
versions / rc-syntax (18.0.0-rc.2, windows-latest) (push) Canceled after 0s
versions / rc-syntax (19.0.0-rc.0, macos-latest) (push) Canceled after 0s
e2e-cache / Test yarn 3 (Node 22, windows-latest) (push) Canceled after 0s
versions / rc-syntax (19.0.0-rc.0, windows-latest) (push) Canceled after 0s
versions / rc-syntax (20.0.0-rc.1, macos-13) (push) Canceled after 0s
versions / rc-syntax (20.0.0-rc.1, macos-latest) (push) Canceled after 0s
versions / rc-syntax (20.0.0-rc.1, windows-latest) (push) Canceled after 0s
versions / manifest (18.20.0, macos-13) (push) Canceled after 0s
versions / manifest (18.20.0, macos-latest) (push) Canceled after 0s
versions / manifest (18.20.0, windows-latest) (push) Canceled after 0s
versions / manifest (20.10.0, macos-13) (push) Canceled after 0s
versions / manifest (20.10.0, macos-latest) (push) Canceled after 0s
versions / manifest (20.10.0, windows-latest) (push) Canceled after 0s
versions / manifest (22.0.0, macos-13) (push) Canceled after 0s
versions / manifest (22.0.0, macos-latest) (push) Canceled after 0s
versions / manifest (22.0.0, windows-latest) (push) Canceled after 0s
versions / check-latest (18, macos-13) (push) Canceled after 0s
versions / check-latest (18, macos-latest) (push) Canceled after 0s
versions / check-latest (18, ubuntu-latest) (push) Failing after 1s
versions / check-latest (18, windows-latest) (push) Canceled after 0s
versions / check-latest (20, macos-13) (push) Canceled after 0s
versions / check-latest (20, macos-latest) (push) Canceled after 0s
versions / check-latest (20, windows-latest) (push) Canceled after 0s
versions / check-latest (22, macos-13) (push) Canceled after 0s
versions / check-latest (22, macos-latest) (push) Canceled after 0s
versions / check-latest (22, ubuntu-latest) (push) Canceled after 0s
versions / check-latest (22, windows-latest) (push) Canceled after 0s
versions / version-file (.nvmrc, macos-latest) (push) Canceled after 0s
versions / version-file (.nvmrc, macos-13) (push) Canceled after 0s
versions / version-file (.nvmrc, ubuntu-latest) (push) Canceled after 0s
versions / version-file (.nvmrc, windows-latest) (push) Canceled after 0s
versions / version-file (.tool-versions, macos-13) (push) Canceled after 0s
versions / version-file (.tool-versions-node, macos-13) (push) Canceled after 0s
versions / version-file (.tool-versions, macos-latest) (push) Canceled after 0s
versions / version-file (.tool-versions-node, macos-latest) (push) Canceled after 0s
versions / version-file (.tool-versions, ubuntu-latest) (push) Canceled after 0s
versions / version-file (.tool-versions-node, ubuntu-latest) (push) Canceled after 0s
versions / version-file (.tool-versions, windows-latest) (push) Canceled after 0s
versions / version-file (.tool-versions-node, windows-latest) (push) Canceled after 0s
versions / version-file (package.json, macos-13) (push) Canceled after 0s
versions / version-file (package.json, macos-latest) (push) Canceled after 0s
versions / version-file (package.json, windows-latest) (push) Canceled after 0s
versions / version-file (package.json, ubuntu-latest) (push) Canceled after 0s
versions / version-file-volta (macos-13) (push) Canceled after 0s
versions / version-file-volta (ubuntu-latest) (push) Canceled after 0s
versions / version-file-volta (windows-latest) (push) Canceled after 0s
versions / version-file-volta-extends (macos-13) (push) Canceled after 0s
versions / version-file-volta (macos-latest) (push) Canceled after 0s
versions / version-file-volta-extends (macos-latest) (push) Canceled after 0s
versions / version-file-volta-extends (ubuntu-latest) (push) Canceled after 0s
versions / version-file-volta-extends (windows-latest) (push) Canceled after 0s
versions / node-dist (17, macos-13) (push) Canceled after 0s
versions / node-dist (17, macos-latest) (push) Canceled after 0s
versions / node-dist (17, ubuntu-latest) (push) Canceled after 0s
versions / node-dist (17, windows-latest) (push) Canceled after 0s
versions / node-dist (19, macos-13) (push) Canceled after 0s
versions / node-dist (19, macos-latest) (push) Canceled after 0s
versions / node-dist (19, ubuntu-latest) (push) Canceled after 0s
versions / node-dist (19, windows-latest) (push) Canceled after 0s
versions / old-versions (macos-13) (push) Canceled after 0s
versions / old-versions (ubuntu-latest) (push) Canceled after 0s
versions / old-versions (windows-latest) (push) Canceled after 0s
versions / arch (push) Canceled after 0s
versions / node-latest-aliases (current, macos-13) (push) Canceled after 0s
versions / node-latest-aliases (current, macos-latest) (push) Canceled after 0s
versions / node-latest-aliases (current, ubuntu-latest) (push) Canceled after 0s
versions / node-latest-aliases (current, windows-latest) (push) Canceled after 0s
versions / node-latest-aliases (latest, macos-13) (push) Canceled after 0s
versions / node-latest-aliases (latest, macos-latest) (push) Canceled after 0s
versions / node-latest-aliases (latest, ubuntu-latest) (push) Canceled after 0s
versions / node-latest-aliases (latest, windows-latest) (push) Canceled after 0s
versions / node-latest-aliases (node, macos-13) (push) Canceled after 0s
versions / node-latest-aliases (node, macos-latest) (push) Canceled after 0s
versions / node-latest-aliases (node, windows-latest) (push) Canceled after 0s
versions / node-latest-aliases (node, ubuntu-latest) (push) Canceled after 0s
versions / check-latest (20, ubuntu-latest) (push) Failing after 1s
e2e-cache / Test npm (Node 18, ubuntu-latest) (push) Failing after 3s
e2e-cache / Test npm (Node 20, ubuntu-latest) (push) Failing after 2s
e2e-cache / Test npm (Node 22, ubuntu-latest) (push) Failing after 1s
e2e-cache / Test pnpm (Node 18, ubuntu-latest) (push) Failing after 1s
e2e-cache / Test pnpm (Node 20, ubuntu-latest) (push) Failing after 2s
e2e-cache / Test pnpm (Node 22, ubuntu-latest) (push) Failing after 1s
e2e-cache / Test yarn 1 (Node 18, ubuntu-latest) (push) Failing after 0s
e2e-cache / Test yarn 1 (Node 20, ubuntu-latest) (push) Failing after 1s
e2e-cache / Test yarn 3 (Node 18, ubuntu-latest) (push) Failing after 1s
e2e-cache / Test yarn 3 (Node 20, ubuntu-latest) (push) Failing after 1s
e2e-cache / Test yarn 3 (Node 22, ubuntu-latest) (push) Failing after 1s
e2e-cache / Test yarn subprojects (18) (push) Failing after 1s
e2e-cache / Test yarn subprojects (20) (push) Failing after 1s
e2e-cache / Test yarn subprojects (22) (push) Failing after 1s
e2e-cache / Test yarn subprojects all locally managed (18) (push) Failing after 1s
e2e-cache / Test yarn subprojects all locally managed (20) (push) Failing after 0s
e2e-cache / Test yarn subprojects all locally managed (22) (push) Failing after 1s
e2e-cache / Test yarn subprojects some locally managed (18) (push) Failing after 1s
e2e-cache / Test yarn subprojects some locally managed (20) (push) Failing after 0s
e2e-cache / Test yarn subprojects some locally managed (22) (push) Failing after 1s
e2e-cache / Test yarn subprojects managed by git (18) (push) Failing after 1s
e2e-cache / Test yarn subprojects managed by git (20) (push) Failing after 1s
e2e-cache / Test yarn subprojects managed by git (22) (push) Failing after 1s
proxy / test-proxy (push) Failing after 2s
proxy / test-bypass-proxy (push) Failing after 1s
versions / local-cache (18, ubuntu-latest) (push) Failing after 1s
versions / local-cache (20, ubuntu-latest) (push) Failing after 1s
versions / local-cache (22, ubuntu-latest) (push) Failing after 1s
versions / lts-syntax (lts/*, ubuntu-latest) (push) Failing after 2s
versions / lts-syntax (lts/-1, ubuntu-latest) (push) Failing after 1s
versions / lts-syntax (lts/dubnium, ubuntu-latest) (push) Failing after 2s
versions / lts-syntax (lts/erbium, ubuntu-latest) (push) Failing after 1s
versions / lts-syntax (lts/fermium, ubuntu-latest) (push) Failing after 4s
versions / v8-canary-syntax (20-v8-canary, ubuntu-latest) (push) Failing after 3s
versions / v8-canary-syntax (20.0.0-v8-canary, ubuntu-latest) (push) Failing after 4s
versions / v8-canary-syntax (20.0.0-v8-canary20221101e50e45c9f8, ubuntu-latest) (push) Failing after 4s
versions / nightly-syntax (18.0.0-nightly, ubuntu-latest) (push) Failing after 6s
versions / nightly-syntax (20-nightly, ubuntu-latest) (push) Failing after 1s
versions / nightly-syntax (21-nightly, ubuntu-latest) (push) Failing after 1s
versions / rc-syntax (18.0.0-rc.2, ubuntu-latest) (push) Failing after 0s
versions / rc-syntax (19.0.0-rc.0, ubuntu-latest) (push) Failing after 1s
versions / rc-syntax (20.0.0-rc.1, ubuntu-latest) (push) Failing after 1s
versions / manifest (18.20.0, ubuntu-latest) (push) Failing after 1s
versions / manifest (20.10.0, ubuntu-latest) (push) Failing after 1s
versions / manifest (22.0.0, ubuntu-latest) (push) Failing after 2s
versions / local-cache (18, macos-13) (push) Canceled after 0s
versions / local-cache (18, macos-latest) (push) Canceled after 0s
versions / local-cache (18, windows-latest) (push) Canceled after 0s
versions / local-cache (20, macos-13) (push) Canceled after 0s
versions / local-cache (20, macos-latest) (push) Canceled after 0s
versions / local-cache (20, windows-latest) (push) Canceled after 0s
e2e-cache / Test npm (Node 18, macos-13) (push) Canceled after 0s
e2e-cache / Test npm (Node 18, macos-latest) (push) Canceled after 0s
versions / local-cache (22, macos-13) (push) Canceled after 0s
e2e-cache / Test npm (Node 18, windows-latest) (push) Canceled after 0s
versions / local-cache (22, macos-latest) (push) Canceled after 0s
e2e-cache / Test npm (Node 20, macos-13) (push) Canceled after 0s
e2e-cache / Test npm (Node 20, macos-latest) (push) Canceled after 0s
versions / local-cache (22, windows-latest) (push) Canceled after 0s
e2e-cache / Test npm (Node 20, windows-latest) (push) Canceled after 0s
e2e-cache / Test npm (Node 22, macos-13) (push) Canceled after 0s
versions / lts-syntax (lts/-1, macos-13) (push) Canceled after 0s
e2e-cache / Test npm (Node 22, macos-latest) (push) Canceled after 0s
versions / lts-syntax (lts/-1, windows-latest) (push) Canceled after 0s
e2e-cache / Test npm (Node 22, windows-latest) (push) Canceled after 0s
versions / lts-syntax (lts/*, macos-13) (push) Canceled after 0s
e2e-cache / Test pnpm (Node 18, macos-13) (push) Canceled after 0s
versions / lts-syntax (lts/*, windows-latest) (push) Canceled after 0s
e2e-cache / Test pnpm (Node 18, macos-latest) (push) Canceled after 0s
versions / lts-syntax (lts/dubnium, macos-13) (push) Canceled after 0s
versions / lts-syntax (lts/dubnium, windows-latest) (push) Canceled after 0s
versions / lts-syntax (lts/erbium, macos-13) (push) Canceled after 0s
versions / lts-syntax (lts/erbium, windows-latest) (push) Canceled after 0s
versions / lts-syntax (lts/fermium, macos-13) (push) Canceled after 0s
versions / lts-syntax (lts/fermium, windows-latest) (push) Canceled after 0s
e2e-cache / Test pnpm (Node 18, windows-latest) (push) Canceled after 0s
e2e-cache / Test pnpm (Node 20, macos-13) (push) Canceled after 0s
versions / v8-canary-syntax (20-v8-canary, macos-13) (push) Canceled after 0s
e2e-cache / Test pnpm (Node 20, macos-latest) (push) Canceled after 0s
versions / v8-canary-syntax (20-v8-canary, macos-latest) (push) Canceled after 0s
e2e-cache / Test pnpm (Node 20, windows-latest) (push) Canceled after 0s
versions / v8-canary-syntax (20-v8-canary, windows-latest) (push) Canceled after 0s
e2e-cache / Test pnpm (Node 22, macos-13) (push) Canceled after 0s
versions / v8-canary-syntax (20.0.0-v8-canary20221101e50e45c9f8, macos-13) (push) Canceled after 0s
e2e-cache / Test pnpm (Node 22, macos-latest) (push) Canceled after 0s
versions / v8-canary-syntax (20.0.0-v8-canary20221101e50e45c9f8, macos-latest) (push) Canceled after 0s
e2e-cache / Test pnpm (Node 22, windows-latest) (push) Canceled after 0s
versions / v8-canary-syntax (20.0.0-v8-canary20221101e50e45c9f8, windows-latest) (push) Canceled after 0s
e2e-cache / Test yarn 1 (Node 18, macos-13) (push) Canceled after 0s
versions / v8-canary-syntax (20.0.0-v8-canary, macos-13) (push) Canceled after 0s
e2e-cache / Test yarn 1 (Node 18, macos-latest) (push) Canceled after 0s
versions / v8-canary-syntax (20.0.0-v8-canary, macos-latest) (push) Canceled after 0s
e2e-cache / Test yarn 1 (Node 18, windows-latest) (push) Canceled after 0s
versions / v8-canary-syntax (20.0.0-v8-canary, windows-latest) (push) Canceled after 0s
e2e-cache / Test yarn 1 (Node 20, macos-13) (push) Canceled after 0s
versions / nightly-syntax (18.0.0-nightly, macos-13) (push) Canceled after 0s
e2e-cache / Test yarn 1 (Node 20, macos-latest) (push) Canceled after 0s
versions / nightly-syntax (18.0.0-nightly, macos-latest) (push) Canceled after 0s
versions / nightly-syntax (18.0.0-nightly, windows-latest) (push) Canceled after 0s
e2e-cache / Test yarn 1 (Node 20, windows-latest) (push) Canceled after 0s
versions / nightly-syntax (20-nightly, macos-13) (push) Canceled after 0s
e2e-cache / Test yarn 3 (Node 18, macos-13) (push) Canceled after 0s
e2e-cache / Test yarn 3 (Node 18, macos-latest) (push) Canceled after 0s
versions / nightly-syntax (20-nightly, macos-latest) (push) Canceled after 0s
e2e-cache / Test yarn 3 (Node 18, windows-latest) (push) Canceled after 0s
versions / nightly-syntax (20-nightly, windows-latest) (push) Canceled after 0s
versions / nightly-syntax (21-nightly, macos-13) (push) Canceled after 0s
e2e-cache / Test yarn 3 (Node 20, macos-13) (push) Canceled after 0s
versions / nightly-syntax (21-nightly, macos-latest) (push) Canceled after 0s
e2e-cache / Test yarn 3 (Node 20, macos-latest) (push) Canceled after 0s
versions / nightly-syntax (21-nightly, windows-latest) (push) Canceled after 0s
e2e-cache / Test yarn 3 (Node 20, windows-latest) (push) Canceled after 0s
versions / rc-syntax (18.0.0-rc.2, macos-13) (push) Canceled after 0s
e2e-cache / Test yarn 3 (Node 22, macos-13) (push) Canceled after 0s
versions / rc-syntax (18.0.0-rc.2, macos-latest) (push) Canceled after 0s
e2e-cache / Test yarn 3 (Node 22, macos-latest) (push) Canceled after 0s
versions / rc-syntax (19.0.0-rc.0, macos-13) (push) Canceled after 0s
versions / rc-syntax (18.0.0-rc.2, windows-latest) (push) Canceled after 0s
versions / rc-syntax (19.0.0-rc.0, macos-latest) (push) Canceled after 0s
e2e-cache / Test yarn 3 (Node 22, windows-latest) (push) Canceled after 0s
versions / rc-syntax (19.0.0-rc.0, windows-latest) (push) Canceled after 0s
versions / rc-syntax (20.0.0-rc.1, macos-13) (push) Canceled after 0s
versions / rc-syntax (20.0.0-rc.1, macos-latest) (push) Canceled after 0s
versions / rc-syntax (20.0.0-rc.1, windows-latest) (push) Canceled after 0s
versions / manifest (18.20.0, macos-13) (push) Canceled after 0s
versions / manifest (18.20.0, macos-latest) (push) Canceled after 0s
versions / manifest (18.20.0, windows-latest) (push) Canceled after 0s
versions / manifest (20.10.0, macos-13) (push) Canceled after 0s
versions / manifest (20.10.0, macos-latest) (push) Canceled after 0s
versions / manifest (20.10.0, windows-latest) (push) Canceled after 0s
versions / manifest (22.0.0, macos-13) (push) Canceled after 0s
versions / manifest (22.0.0, macos-latest) (push) Canceled after 0s
versions / manifest (22.0.0, windows-latest) (push) Canceled after 0s
versions / check-latest (18, macos-13) (push) Canceled after 0s
versions / check-latest (18, macos-latest) (push) Canceled after 0s
versions / check-latest (18, ubuntu-latest) (push) Failing after 1s
versions / check-latest (18, windows-latest) (push) Canceled after 0s
versions / check-latest (20, macos-13) (push) Canceled after 0s
versions / check-latest (20, macos-latest) (push) Canceled after 0s
versions / check-latest (20, windows-latest) (push) Canceled after 0s
versions / check-latest (22, macos-13) (push) Canceled after 0s
versions / check-latest (22, macos-latest) (push) Canceled after 0s
versions / check-latest (22, ubuntu-latest) (push) Canceled after 0s
versions / check-latest (22, windows-latest) (push) Canceled after 0s
versions / version-file (.nvmrc, macos-latest) (push) Canceled after 0s
versions / version-file (.nvmrc, macos-13) (push) Canceled after 0s
versions / version-file (.nvmrc, ubuntu-latest) (push) Canceled after 0s
versions / version-file (.nvmrc, windows-latest) (push) Canceled after 0s
versions / version-file (.tool-versions, macos-13) (push) Canceled after 0s
versions / version-file (.tool-versions-node, macos-13) (push) Canceled after 0s
versions / version-file (.tool-versions, macos-latest) (push) Canceled after 0s
versions / version-file (.tool-versions-node, macos-latest) (push) Canceled after 0s
versions / version-file (.tool-versions, ubuntu-latest) (push) Canceled after 0s
versions / version-file (.tool-versions-node, ubuntu-latest) (push) Canceled after 0s
versions / version-file (.tool-versions, windows-latest) (push) Canceled after 0s
versions / version-file (.tool-versions-node, windows-latest) (push) Canceled after 0s
versions / version-file (package.json, macos-13) (push) Canceled after 0s
versions / version-file (package.json, macos-latest) (push) Canceled after 0s
versions / version-file (package.json, windows-latest) (push) Canceled after 0s
versions / version-file (package.json, ubuntu-latest) (push) Canceled after 0s
versions / version-file-volta (macos-13) (push) Canceled after 0s
versions / version-file-volta (ubuntu-latest) (push) Canceled after 0s
versions / version-file-volta (windows-latest) (push) Canceled after 0s
versions / version-file-volta-extends (macos-13) (push) Canceled after 0s
versions / version-file-volta (macos-latest) (push) Canceled after 0s
versions / version-file-volta-extends (macos-latest) (push) Canceled after 0s
versions / version-file-volta-extends (ubuntu-latest) (push) Canceled after 0s
versions / version-file-volta-extends (windows-latest) (push) Canceled after 0s
versions / node-dist (17, macos-13) (push) Canceled after 0s
versions / node-dist (17, macos-latest) (push) Canceled after 0s
versions / node-dist (17, ubuntu-latest) (push) Canceled after 0s
versions / node-dist (17, windows-latest) (push) Canceled after 0s
versions / node-dist (19, macos-13) (push) Canceled after 0s
versions / node-dist (19, macos-latest) (push) Canceled after 0s
versions / node-dist (19, ubuntu-latest) (push) Canceled after 0s
versions / node-dist (19, windows-latest) (push) Canceled after 0s
versions / old-versions (macos-13) (push) Canceled after 0s
versions / old-versions (ubuntu-latest) (push) Canceled after 0s
versions / old-versions (windows-latest) (push) Canceled after 0s
versions / arch (push) Canceled after 0s
versions / node-latest-aliases (current, macos-13) (push) Canceled after 0s
versions / node-latest-aliases (current, macos-latest) (push) Canceled after 0s
versions / node-latest-aliases (current, ubuntu-latest) (push) Canceled after 0s
versions / node-latest-aliases (current, windows-latest) (push) Canceled after 0s
versions / node-latest-aliases (latest, macos-13) (push) Canceled after 0s
versions / node-latest-aliases (latest, macos-latest) (push) Canceled after 0s
versions / node-latest-aliases (latest, ubuntu-latest) (push) Canceled after 0s
versions / node-latest-aliases (latest, windows-latest) (push) Canceled after 0s
versions / node-latest-aliases (node, macos-13) (push) Canceled after 0s
versions / node-latest-aliases (node, macos-latest) (push) Canceled after 0s
versions / node-latest-aliases (node, windows-latest) (push) Canceled after 0s
versions / node-latest-aliases (node, ubuntu-latest) (push) Canceled after 0s
versions / check-latest (20, ubuntu-latest) (push) Failing after 1s
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import * as core from '@actions/core';
|
||||
import * as github from '@actions/github';
|
||||
|
||||
export function configAuthentication(registryUrl: string, alwaysAuth: string) {
|
||||
const npmrc: string = path.resolve(
|
||||
process.env['RUNNER_TEMP'] || process.cwd(),
|
||||
'.npmrc'
|
||||
);
|
||||
if (!registryUrl.endsWith('/')) {
|
||||
registryUrl += '/';
|
||||
}
|
||||
|
||||
writeRegistryToFile(registryUrl, npmrc, alwaysAuth);
|
||||
}
|
||||
|
||||
function writeRegistryToFile(
|
||||
registryUrl: string,
|
||||
fileLocation: string,
|
||||
alwaysAuth: string
|
||||
) {
|
||||
let scope: string = core.getInput('scope');
|
||||
if (!scope && registryUrl.indexOf('npm.pkg.github.com') > -1) {
|
||||
scope = github.context.repo.owner;
|
||||
}
|
||||
if (scope && scope[0] != '@') {
|
||||
scope = '@' + scope;
|
||||
}
|
||||
if (scope) {
|
||||
scope = scope.toLowerCase() + ':';
|
||||
}
|
||||
|
||||
core.debug(`Setting auth in ${fileLocation}`);
|
||||
let newContents = '';
|
||||
if (fs.existsSync(fileLocation)) {
|
||||
const curContents: string = fs.readFileSync(fileLocation, 'utf8');
|
||||
curContents.split(os.EOL).forEach((line: string) => {
|
||||
// Add current contents unless they are setting the registry
|
||||
if (!line.toLowerCase().startsWith(`${scope}registry`)) {
|
||||
newContents += line + os.EOL;
|
||||
}
|
||||
});
|
||||
}
|
||||
// Remove http: or https: from front of registry.
|
||||
const authString: string =
|
||||
registryUrl.replace(/(^\w+:|^)/, '') + ':_authToken=${NODE_AUTH_TOKEN}';
|
||||
const registryString = `${scope}registry=${registryUrl}`;
|
||||
const alwaysAuthString = `always-auth=${alwaysAuth}`;
|
||||
newContents += `${authString}${os.EOL}${registryString}${os.EOL}${alwaysAuthString}`;
|
||||
fs.writeFileSync(fileLocation, newContents);
|
||||
core.exportVariable('NPM_CONFIG_USERCONFIG', fileLocation);
|
||||
// Export empty node_auth_token if didn't exist so npm doesn't complain about not being able to find it
|
||||
core.exportVariable(
|
||||
'NODE_AUTH_TOKEN',
|
||||
process.env.NODE_AUTH_TOKEN || 'XXXXX-XXXXX-XXXXX-XXXXX'
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
import * as cache from '@actions/cache';
|
||||
import * as core from '@actions/core';
|
||||
import * as glob from '@actions/glob';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import os from 'os';
|
||||
|
||||
import {State} from './constants';
|
||||
import {
|
||||
getCacheDirectories,
|
||||
getPackageManagerInfo,
|
||||
repoHasYarnBerryManagedDependencies,
|
||||
PackageManagerInfo
|
||||
} from './cache-utils';
|
||||
|
||||
export const restoreCache = async (
|
||||
packageManager: string,
|
||||
cacheDependencyPath: string
|
||||
) => {
|
||||
const packageManagerInfo = await getPackageManagerInfo(packageManager);
|
||||
if (!packageManagerInfo) {
|
||||
throw new Error(`Caching for '${packageManager}' is not supported`);
|
||||
}
|
||||
const platform = process.env.RUNNER_OS;
|
||||
const arch = os.arch();
|
||||
|
||||
const cachePaths = await getCacheDirectories(
|
||||
packageManagerInfo,
|
||||
cacheDependencyPath
|
||||
);
|
||||
core.saveState(State.CachePaths, cachePaths);
|
||||
const lockFilePath = cacheDependencyPath
|
||||
? cacheDependencyPath
|
||||
: findLockFile(packageManagerInfo);
|
||||
const fileHash = await glob.hashFiles(lockFilePath);
|
||||
|
||||
if (!fileHash) {
|
||||
throw new Error(
|
||||
'Some specified paths were not resolved, unable to cache dependencies.'
|
||||
);
|
||||
}
|
||||
|
||||
const keyPrefix = `node-cache-${platform}-${arch}-${packageManager}`;
|
||||
const primaryKey = `${keyPrefix}-${fileHash}`;
|
||||
core.debug(`primary key is ${primaryKey}`);
|
||||
|
||||
core.saveState(State.CachePrimaryKey, primaryKey);
|
||||
|
||||
const isManagedByYarnBerry = await repoHasYarnBerryManagedDependencies(
|
||||
packageManagerInfo,
|
||||
cacheDependencyPath
|
||||
);
|
||||
let cacheKey: string | undefined;
|
||||
if (isManagedByYarnBerry) {
|
||||
core.info(
|
||||
'All dependencies are managed locally by yarn3, the previous cache can be used'
|
||||
);
|
||||
cacheKey = await cache.restoreCache(cachePaths, primaryKey, [keyPrefix]);
|
||||
} else {
|
||||
cacheKey = await cache.restoreCache(cachePaths, primaryKey);
|
||||
}
|
||||
|
||||
core.setOutput('cache-hit', Boolean(cacheKey));
|
||||
|
||||
if (!cacheKey) {
|
||||
core.info(`${packageManager} cache is not found`);
|
||||
return;
|
||||
}
|
||||
|
||||
core.saveState(State.CacheMatchedKey, cacheKey);
|
||||
core.info(`Cache restored from key: ${cacheKey}`);
|
||||
};
|
||||
|
||||
const findLockFile = (packageManager: PackageManagerInfo) => {
|
||||
const lockFiles = packageManager.lockFilePatterns;
|
||||
const workspace = process.env.GITHUB_WORKSPACE!;
|
||||
|
||||
const rootContent = fs.readdirSync(workspace);
|
||||
|
||||
const lockFile = lockFiles.find(item => rootContent.includes(item));
|
||||
if (!lockFile) {
|
||||
throw new Error(
|
||||
`Dependencies lock file is not found in ${workspace}. Supported file patterns: ${lockFiles.toString()}`
|
||||
);
|
||||
}
|
||||
|
||||
return path.join(workspace, lockFile);
|
||||
};
|
||||
@@ -0,0 +1,71 @@
|
||||
import * as core from '@actions/core';
|
||||
import * as cache from '@actions/cache';
|
||||
|
||||
import {State} from './constants';
|
||||
import {getPackageManagerInfo} from './cache-utils';
|
||||
|
||||
// Catch and log any unhandled exceptions. These exceptions can leak out of the uploadChunk method in
|
||||
// @actions/toolkit when a failed upload closes the file descriptor causing any in-process reads to
|
||||
// throw an uncaught exception. Instead of failing this action, just warn.
|
||||
process.on('uncaughtException', e => {
|
||||
const warningPrefix = '[warning]';
|
||||
core.info(`${warningPrefix}${e.message}`);
|
||||
});
|
||||
|
||||
// Added early exit to resolve issue with slow post action step:
|
||||
export async function run(earlyExit?: boolean) {
|
||||
try {
|
||||
const cacheLock = core.getState(State.CachePackageManager);
|
||||
|
||||
if (cacheLock) {
|
||||
await cachePackages(cacheLock);
|
||||
|
||||
if (earlyExit) {
|
||||
process.exit(0);
|
||||
}
|
||||
} else {
|
||||
core.debug(`Caching for '${cacheLock}' is not supported`);
|
||||
}
|
||||
} catch (error) {
|
||||
core.setFailed((error as Error).message);
|
||||
}
|
||||
}
|
||||
|
||||
const cachePackages = async (packageManager: string) => {
|
||||
const state = core.getState(State.CacheMatchedKey);
|
||||
const primaryKey = core.getState(State.CachePrimaryKey);
|
||||
const cachePaths = JSON.parse(
|
||||
core.getState(State.CachePaths) || '[]'
|
||||
) as string[];
|
||||
|
||||
const packageManagerInfo = await getPackageManagerInfo(packageManager);
|
||||
if (!packageManagerInfo) {
|
||||
core.debug(`Caching for '${packageManager}' is not supported`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cachePaths.length) {
|
||||
// TODO: core.getInput has a bug - it can return undefined despite its definition (tests only?)
|
||||
// export declare function getInput(name: string, options?: InputOptions): string;
|
||||
const cacheDependencyPath = core.getInput('cache-dependency-path') || '';
|
||||
throw new Error(
|
||||
`Cache folder paths are not retrieved for ${packageManager} with cache-dependency-path = ${cacheDependencyPath}`
|
||||
);
|
||||
}
|
||||
|
||||
if (primaryKey === state) {
|
||||
core.info(
|
||||
`Cache hit occurred on the primary key ${primaryKey}, not saving cache.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const cacheId = await cache.saveCache(cachePaths, primaryKey);
|
||||
if (cacheId == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
core.info(`Cache saved with the key: ${primaryKey}`);
|
||||
};
|
||||
|
||||
run(true);
|
||||
@@ -0,0 +1,322 @@
|
||||
import * as core from '@actions/core';
|
||||
import * as exec from '@actions/exec';
|
||||
import * as cache from '@actions/cache';
|
||||
import * as glob from '@actions/glob';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import {unique} from './util';
|
||||
|
||||
export interface PackageManagerInfo {
|
||||
name: string;
|
||||
lockFilePatterns: Array<string>;
|
||||
getCacheFolderPath: (projectDir?: string) => Promise<string>;
|
||||
}
|
||||
|
||||
interface SupportedPackageManagers {
|
||||
npm: PackageManagerInfo;
|
||||
pnpm: PackageManagerInfo;
|
||||
yarn: PackageManagerInfo;
|
||||
}
|
||||
export const supportedPackageManagers: SupportedPackageManagers = {
|
||||
npm: {
|
||||
name: 'npm',
|
||||
lockFilePatterns: ['package-lock.json', 'npm-shrinkwrap.json', 'yarn.lock'],
|
||||
getCacheFolderPath: () =>
|
||||
getCommandOutputNotEmpty(
|
||||
'npm config get cache',
|
||||
'Could not get npm cache folder path'
|
||||
)
|
||||
},
|
||||
pnpm: {
|
||||
name: 'pnpm',
|
||||
lockFilePatterns: ['pnpm-lock.yaml'],
|
||||
getCacheFolderPath: () =>
|
||||
getCommandOutputNotEmpty(
|
||||
'pnpm store path --silent',
|
||||
'Could not get pnpm cache folder path'
|
||||
)
|
||||
},
|
||||
yarn: {
|
||||
name: 'yarn',
|
||||
lockFilePatterns: ['yarn.lock'],
|
||||
getCacheFolderPath: async projectDir => {
|
||||
const yarnVersion = await getCommandOutputNotEmpty(
|
||||
`yarn --version`,
|
||||
'Could not retrieve version of yarn',
|
||||
projectDir
|
||||
);
|
||||
|
||||
core.debug(
|
||||
`Consumed yarn version is ${yarnVersion} (working dir: "${
|
||||
projectDir || ''
|
||||
}")`
|
||||
);
|
||||
|
||||
const stdOut = yarnVersion.startsWith('1.')
|
||||
? await getCommandOutput('yarn cache dir', projectDir)
|
||||
: await getCommandOutput('yarn config get cacheFolder', projectDir);
|
||||
|
||||
if (!stdOut) {
|
||||
throw new Error(
|
||||
`Could not get yarn cache folder path for ${projectDir}`
|
||||
);
|
||||
}
|
||||
return stdOut;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const getCommandOutput = async (
|
||||
toolCommand: string,
|
||||
cwd?: string
|
||||
): Promise<string> => {
|
||||
let {stdout, stderr, exitCode} = await exec.getExecOutput(
|
||||
toolCommand,
|
||||
undefined,
|
||||
{ignoreReturnCode: true, ...(cwd && {cwd})}
|
||||
);
|
||||
|
||||
if (exitCode) {
|
||||
stderr = !stderr.trim()
|
||||
? `The '${toolCommand}' command failed with exit code: ${exitCode}`
|
||||
: stderr;
|
||||
throw new Error(stderr);
|
||||
}
|
||||
|
||||
return stdout.trim();
|
||||
};
|
||||
|
||||
export const getCommandOutputNotEmpty = async (
|
||||
toolCommand: string,
|
||||
error: string,
|
||||
cwd?: string
|
||||
): Promise<string> => {
|
||||
const stdOut = getCommandOutput(toolCommand, cwd);
|
||||
if (!stdOut) {
|
||||
throw new Error(error);
|
||||
}
|
||||
return stdOut;
|
||||
};
|
||||
|
||||
export const getPackageManagerInfo = async (packageManager: string) => {
|
||||
if (packageManager === 'npm') {
|
||||
return supportedPackageManagers.npm;
|
||||
} else if (packageManager === 'pnpm') {
|
||||
return supportedPackageManagers.pnpm;
|
||||
} else if (packageManager === 'yarn') {
|
||||
return supportedPackageManagers.yarn;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* getProjectDirectoriesFromCacheDependencyPath is called twice during `restoreCache`
|
||||
* - first through `getCacheDirectories`
|
||||
* - second from `repoHasYarn3ManagedCache`
|
||||
*
|
||||
* it contains expensive IO operation and thus should be memoized
|
||||
*/
|
||||
|
||||
let projectDirectoriesMemoized: string[] | null = null;
|
||||
/**
|
||||
* unit test must reset memoized variables
|
||||
*/
|
||||
export const resetProjectDirectoriesMemoized = () =>
|
||||
(projectDirectoriesMemoized = null);
|
||||
/**
|
||||
* Expands (converts) the string input `cache-dependency-path` to list of directories that
|
||||
* may be project roots
|
||||
* @param cacheDependencyPath - either a single string or multiline string with possible glob patterns
|
||||
* expected to be the result of `core.getInput('cache-dependency-path')`
|
||||
* @return list of directories and possible
|
||||
*/
|
||||
const getProjectDirectoriesFromCacheDependencyPath = async (
|
||||
cacheDependencyPath: string
|
||||
): Promise<string[]> => {
|
||||
if (projectDirectoriesMemoized !== null) {
|
||||
return projectDirectoriesMemoized;
|
||||
}
|
||||
|
||||
const globber = await glob.create(cacheDependencyPath);
|
||||
const cacheDependenciesPaths = await globber.glob();
|
||||
|
||||
const existingDirectories: string[] = cacheDependenciesPaths
|
||||
.map(path.dirname)
|
||||
.filter(unique())
|
||||
.map(dirName => fs.realpathSync(dirName))
|
||||
.filter(directory => fs.lstatSync(directory).isDirectory());
|
||||
|
||||
if (!existingDirectories.length)
|
||||
core.warning(
|
||||
`No existing directories found containing cache-dependency-path="${cacheDependencyPath}"`
|
||||
);
|
||||
|
||||
projectDirectoriesMemoized = existingDirectories;
|
||||
return existingDirectories;
|
||||
};
|
||||
|
||||
/**
|
||||
* Finds the cache directories configured for the repo if cache-dependency-path is not empty
|
||||
* @param packageManagerInfo - an object having getCacheFolderPath method specific to given PM
|
||||
* @param cacheDependencyPath - either a single string or multiline string with possible glob patterns
|
||||
* expected to be the result of `core.getInput('cache-dependency-path')`
|
||||
* @return list of files on which the cache depends
|
||||
*/
|
||||
const getCacheDirectoriesFromCacheDependencyPath = async (
|
||||
packageManagerInfo: PackageManagerInfo,
|
||||
cacheDependencyPath: string
|
||||
): Promise<string[]> => {
|
||||
const projectDirectories = await getProjectDirectoriesFromCacheDependencyPath(
|
||||
cacheDependencyPath
|
||||
);
|
||||
const cacheFoldersPaths = await Promise.all(
|
||||
projectDirectories.map(async projectDirectory => {
|
||||
const cacheFolderPath = await packageManagerInfo.getCacheFolderPath(
|
||||
projectDirectory
|
||||
);
|
||||
core.debug(
|
||||
`${packageManagerInfo.name}'s cache folder "${cacheFolderPath}" configured for the directory "${projectDirectory}"`
|
||||
);
|
||||
return cacheFolderPath;
|
||||
})
|
||||
);
|
||||
// uniq in order to do not cache the same directories twice
|
||||
return cacheFoldersPaths.filter(unique());
|
||||
};
|
||||
|
||||
/**
|
||||
* Finds the cache directories configured for the repo ignoring cache-dependency-path
|
||||
* @param packageManagerInfo - an object having getCacheFolderPath method specific to given PM
|
||||
* @return list of files on which the cache depends
|
||||
*/
|
||||
const getCacheDirectoriesForRootProject = async (
|
||||
packageManagerInfo: PackageManagerInfo
|
||||
): Promise<string[]> => {
|
||||
const cacheFolderPath = await packageManagerInfo.getCacheFolderPath();
|
||||
core.debug(
|
||||
`${packageManagerInfo.name}'s cache folder "${cacheFolderPath}" configured for the root directory`
|
||||
);
|
||||
return [cacheFolderPath];
|
||||
};
|
||||
|
||||
/**
|
||||
* A function to find the cache directories configured for the repo
|
||||
* currently it handles only the case of PM=yarn && cacheDependencyPath is not empty
|
||||
* @param packageManagerInfo - an object having getCacheFolderPath method specific to given PM
|
||||
* @param cacheDependencyPath - either a single string or multiline string with possible glob patterns
|
||||
* expected to be the result of `core.getInput('cache-dependency-path')`
|
||||
* @return list of files on which the cache depends
|
||||
*/
|
||||
export const getCacheDirectories = async (
|
||||
packageManagerInfo: PackageManagerInfo,
|
||||
cacheDependencyPath: string
|
||||
): Promise<string[]> => {
|
||||
// For yarn, if cacheDependencyPath is set, ask information about cache folders in each project
|
||||
// folder satisfied by cacheDependencyPath https://github.com/actions/setup-node/issues/488
|
||||
if (packageManagerInfo.name === 'yarn' && cacheDependencyPath) {
|
||||
return getCacheDirectoriesFromCacheDependencyPath(
|
||||
packageManagerInfo,
|
||||
cacheDependencyPath
|
||||
);
|
||||
}
|
||||
return getCacheDirectoriesForRootProject(packageManagerInfo);
|
||||
};
|
||||
|
||||
/**
|
||||
* A function to check if the directory is a yarn project configured to manage
|
||||
* obsolete dependencies in the local cache
|
||||
* @param directory - a path to the folder
|
||||
* @return - true if the directory's project is yarn managed
|
||||
* - if there's .yarn/cache folder do not mess with the dependencies kept in the repo, return false
|
||||
* - global cache is not managed by yarn @see https://yarnpkg.com/features/offline-cache, return false
|
||||
* - if local cache is not explicitly enabled (not yarn3), return false
|
||||
* - return true otherwise
|
||||
*/
|
||||
const projectHasYarnBerryManagedDependencies = async (
|
||||
directory: string
|
||||
): Promise<boolean> => {
|
||||
const workDir = directory || process.env.GITHUB_WORKSPACE || '.';
|
||||
core.debug(`check if "${workDir}" has locally managed yarn3 dependencies`);
|
||||
|
||||
// if .yarn/cache directory exists the cache is managed by version control system
|
||||
const yarnCacheFile = path.join(workDir, '.yarn', 'cache');
|
||||
if (
|
||||
fs.existsSync(yarnCacheFile) &&
|
||||
fs.lstatSync(yarnCacheFile).isDirectory()
|
||||
) {
|
||||
core.debug(
|
||||
`"${workDir}" has .yarn/cache - dependencies are kept in the repository`
|
||||
);
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
// NOTE: yarn1 returns 'undefined' with return code = 0
|
||||
const enableGlobalCache = await getCommandOutput(
|
||||
'yarn config get enableGlobalCache',
|
||||
workDir
|
||||
);
|
||||
// only local cache is not managed by yarn
|
||||
const managed = enableGlobalCache.includes('false');
|
||||
if (managed) {
|
||||
core.debug(`"${workDir}" dependencies are managed by yarn 3 locally`);
|
||||
return true;
|
||||
} else {
|
||||
core.debug(`"${workDir}" dependencies are not managed by yarn 3 locally`);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A function to report the repo contains Yarn managed projects
|
||||
* @param packageManagerInfo - used to make sure current package manager is yarn
|
||||
* @param cacheDependencyPath - either a single string or multiline string with possible glob patterns
|
||||
* expected to be the result of `core.getInput('cache-dependency-path')`
|
||||
* @return - true if all project directories configured to be Yarn managed
|
||||
*/
|
||||
export const repoHasYarnBerryManagedDependencies = async (
|
||||
packageManagerInfo: PackageManagerInfo,
|
||||
cacheDependencyPath: string
|
||||
): Promise<boolean> => {
|
||||
if (packageManagerInfo.name !== 'yarn') return false;
|
||||
|
||||
const yarnDirs = cacheDependencyPath
|
||||
? await getProjectDirectoriesFromCacheDependencyPath(cacheDependencyPath)
|
||||
: [''];
|
||||
|
||||
const isManagedList = await Promise.all(
|
||||
yarnDirs.map(projectHasYarnBerryManagedDependencies)
|
||||
);
|
||||
|
||||
return isManagedList.every(Boolean);
|
||||
};
|
||||
|
||||
export function isGhes(): boolean {
|
||||
const ghUrl = new URL(
|
||||
process.env['GITHUB_SERVER_URL'] || 'https://github.com'
|
||||
);
|
||||
|
||||
const hostname = ghUrl.hostname.trimEnd().toUpperCase();
|
||||
const isGitHubHost = hostname === 'GITHUB.COM';
|
||||
const isGitHubEnterpriseCloudHost = hostname.endsWith('.GHE.COM');
|
||||
const isLocalHost = hostname.endsWith('.LOCALHOST');
|
||||
|
||||
return !isGitHubHost && !isGitHubEnterpriseCloudHost && !isLocalHost;
|
||||
}
|
||||
|
||||
export function isCacheFeatureAvailable(): boolean {
|
||||
if (cache.isFeatureAvailable()) return true;
|
||||
|
||||
if (isGhes()) {
|
||||
core.warning(
|
||||
'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.'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
core.warning(
|
||||
'The runner was not able to contact the cache service. Caching will be skipped'
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
export enum LockType {
|
||||
Npm = 'npm',
|
||||
Pnpm = 'pnpm',
|
||||
Yarn = 'yarn'
|
||||
}
|
||||
|
||||
export enum State {
|
||||
CachePackageManager = 'SETUP_NODE_CACHE_PACKAGE_MANAGER',
|
||||
CachePrimaryKey = 'CACHE_KEY',
|
||||
CacheMatchedKey = 'CACHE_RESULT',
|
||||
CachePaths = 'CACHE_PATHS'
|
||||
}
|
||||
|
||||
export enum Outputs {
|
||||
CacheHit = 'cache-hit'
|
||||
}
|
||||
@@ -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].toString().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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,345 @@
|
||||
import {v4 as uuidv4} from 'uuid';
|
||||
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(mirror: string): 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 (const 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.translateArchToDistUrl(this.nodeInfo.arch)
|
||||
);
|
||||
}
|
||||
|
||||
protected async getNodeJsVersions(): Promise<INodeVersion[]> {
|
||||
const initialUrl = this.getDistributionUrl(this.nodeInfo.mirror);
|
||||
const dataUrl = `${initialUrl}/index.json`;
|
||||
|
||||
const headers = {};
|
||||
|
||||
if (this.nodeInfo.mirrorToken) {
|
||||
headers['Authorization'] = `Bearer ${this.nodeInfo.mirrorToken}`;
|
||||
}
|
||||
|
||||
const response = await this.httpClient.getJson<INodeVersion[]>(
|
||||
dataUrl,
|
||||
headers
|
||||
);
|
||||
return response.result || [];
|
||||
}
|
||||
|
||||
protected getNodejsDistInfo(version: string) {
|
||||
const osArch: string = this.translateArchToDistUrl(this.nodeInfo.arch);
|
||||
version = semver.clean(version) || '';
|
||||
const fileName: string =
|
||||
this.osPlat == 'win32'
|
||||
? `node-v${version}-win-${osArch}`
|
||||
: `node-v${version}-${this.osPlat}-${osArch}`;
|
||||
const urlFileName: string =
|
||||
this.osPlat == 'win32'
|
||||
? this.nodeInfo.arch === 'arm64'
|
||||
? `${fileName}.zip`
|
||||
: `${fileName}.7z`
|
||||
: `${fileName}.tar.gz`;
|
||||
const initialUrl = this.getDistributionUrl(this.nodeInfo.mirror);
|
||||
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,
|
||||
undefined,
|
||||
this.nodeInfo.mirrorToken
|
||||
);
|
||||
} catch (err) {
|
||||
if (
|
||||
err instanceof tc.HTTPError &&
|
||||
err.httpStatusCode == 404 &&
|
||||
this.osPlat == 'win32'
|
||||
) {
|
||||
return await this.acquireWindowsNodeFromFallbackLocation(
|
||||
info.resolvedVersion,
|
||||
info.arch
|
||||
);
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
|
||||
const toolPath = await this.extractArchive(downloadPath, info, true);
|
||||
core.info('Done');
|
||||
|
||||
return toolPath;
|
||||
}
|
||||
|
||||
protected validRange(versionSpec: string) {
|
||||
let options: semver.RangeOptions | undefined;
|
||||
const c = semver.clean(versionSpec) || '';
|
||||
const valid = semver.valid(c) ?? versionSpec;
|
||||
|
||||
return {range: valid, options};
|
||||
}
|
||||
|
||||
protected async acquireWindowsNodeFromFallbackLocation(
|
||||
version: string,
|
||||
arch: string = os.arch()
|
||||
): Promise<string> {
|
||||
const initialUrl = this.getDistributionUrl(this.nodeInfo.mirror);
|
||||
const osArch: string = this.translateArchToDistUrl(arch);
|
||||
|
||||
// Create temporary folder to download to
|
||||
const tempDownloadFolder = `temp_${uuidv4()}`;
|
||||
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,
|
||||
undefined,
|
||||
this.nodeInfo.mirrorToken
|
||||
);
|
||||
await io.cp(exePath, path.join(tempDir, 'node.exe'));
|
||||
const libPath = await tc.downloadTool(
|
||||
libUrl,
|
||||
undefined,
|
||||
this.nodeInfo.mirrorToken
|
||||
);
|
||||
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,
|
||||
undefined,
|
||||
this.nodeInfo.mirrorToken
|
||||
);
|
||||
await io.cp(exePath, path.join(tempDir, 'node.exe'));
|
||||
const libPath = await tc.downloadTool(
|
||||
libUrl,
|
||||
undefined,
|
||||
this.nodeInfo.mirrorToken
|
||||
);
|
||||
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,
|
||||
isOfficialArchive?: boolean
|
||||
) {
|
||||
//
|
||||
// Extract
|
||||
//
|
||||
core.info('Extracting ...');
|
||||
let extPath: string;
|
||||
info = info || ({} as INodeVersionInfo); // satisfy compiler, never null when reaches here
|
||||
if (this.osPlat == 'win32') {
|
||||
const extension = this.nodeInfo.arch === 'arm64' ? '.zip' : '.7z';
|
||||
// Rename archive to add extension because after downloading
|
||||
// archive does not contain extension type and it leads to some issues
|
||||
// on Windows runners without PowerShell Core.
|
||||
//
|
||||
// For default PowerShell Windows it should contain extension type to unpack it.
|
||||
if (extension === '.zip' && isOfficialArchive) {
|
||||
const renamedArchive = `${downloadPath}.zip`;
|
||||
fs.renameSync(downloadPath, renamedArchive);
|
||||
extPath = await tc.extractZip(renamedArchive);
|
||||
} else {
|
||||
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, extension)
|
||||
);
|
||||
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 {
|
||||
const 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':
|
||||
if (this.nodeInfo.arch === 'arm64') {
|
||||
dataFileName = `win-${osArch}-zip`;
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
export interface NodeInputs {
|
||||
versionSpec: string;
|
||||
arch: string;
|
||||
auth?: string;
|
||||
checkLatest: boolean;
|
||||
stable: boolean;
|
||||
mirror: string;
|
||||
mirrorToken: string;
|
||||
}
|
||||
|
||||
export interface INodeVersionInfo {
|
||||
downloadUrl: string;
|
||||
resolvedVersion: string;
|
||||
arch: string;
|
||||
fileName: string;
|
||||
}
|
||||
|
||||
export interface INodeVersion {
|
||||
version: string;
|
||||
files: string[];
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
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(mirror: string): string {
|
||||
const url = mirror || 'https://nodejs.org';
|
||||
return `${url}/download/nightly`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,297 @@
|
||||
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}`);
|
||||
this.addToolPath(toolPath);
|
||||
return;
|
||||
}
|
||||
|
||||
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.mirror ? this.nodeInfo.mirrorToken : this.nodeInfo.auth
|
||||
);
|
||||
|
||||
if (downloadPath) {
|
||||
toolPath = await this.extractArchive(
|
||||
downloadPath,
|
||||
versionInfo,
|
||||
false
|
||||
);
|
||||
}
|
||||
} else {
|
||||
core.info(
|
||||
`Not found in manifest. Falling back to download directly from ${
|
||||
this.nodeInfo.mirror || '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 as Error).message);
|
||||
}
|
||||
core.debug((err as Error).stack ?? 'empty stack');
|
||||
core.info('Falling back to download directly from Node');
|
||||
}
|
||||
|
||||
if (!toolPath) {
|
||||
toolPath = await this.downloadDirectlyFromNode();
|
||||
}
|
||||
|
||||
if (this.osPlat != 'win32') {
|
||||
toolPath = path.join(toolPath, 'bin');
|
||||
}
|
||||
|
||||
core.addPath(toolPath);
|
||||
}
|
||||
|
||||
protected addToolPath(toolPath: string) {
|
||||
if (this.osPlat != 'win32') {
|
||||
toolPath = path.join(toolPath, 'bin');
|
||||
}
|
||||
|
||||
core.addPath(toolPath);
|
||||
}
|
||||
|
||||
protected async downloadDirectlyFromNode() {
|
||||
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);
|
||||
|
||||
try {
|
||||
const toolPath = await this.downloadNodejs(toolName);
|
||||
return toolPath;
|
||||
} catch (error) {
|
||||
if (error instanceof tc.HTTPError && error.httpStatusCode === 404) {
|
||||
core.warning(
|
||||
`Node version ${this.nodeInfo.versionSpec} for platform ${this.osPlat} and architecture ${this.nodeInfo.arch} was found but failed to download. ` +
|
||||
'This usually happens when downloadable binaries are not fully updated at https://nodejs.org/. ' +
|
||||
'To resolve this issue you may either fall back to the older version or try again later.'
|
||||
);
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
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(mirror: string): string {
|
||||
const url = mirror || 'https://nodejs.org';
|
||||
return `${url}/dist`;
|
||||
}
|
||||
|
||||
private getManifest(): Promise<tc.IToolRelease[]> {
|
||||
core.debug('Getting manifest from actions/node-versions@main');
|
||||
return tc.getManifestFromRepo(
|
||||
'actions',
|
||||
'node-versions',
|
||||
this.nodeInfo.mirror ? this.nodeInfo.mirrorToken : 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 as Error).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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import BaseDistribution from '../base-distribution';
|
||||
import {NodeInputs} from '../base-models';
|
||||
|
||||
export default class RcBuild extends BaseDistribution {
|
||||
constructor(nodeInfo: NodeInputs) {
|
||||
super(nodeInfo);
|
||||
}
|
||||
|
||||
getDistributionUrl(mirror: string): string {
|
||||
const url = mirror || 'https://nodejs.org';
|
||||
return `${url}/download/rc`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
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(mirror: string): string {
|
||||
const url = mirror || 'https://nodejs.org';
|
||||
return `${url}/download/v8-canary`;
|
||||
}
|
||||
}
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
import * as core from '@actions/core';
|
||||
|
||||
import os from 'os';
|
||||
|
||||
import * as auth from './authutil';
|
||||
import * as path from 'path';
|
||||
import {restoreCache} from './cache-restore';
|
||||
import {isCacheFeatureAvailable} from './cache-utils';
|
||||
import {getNodejsDistribution} from './distributions/installer-factory';
|
||||
import {getNodeVersionFromFile, printEnvDetailsAndSetOutput} from './util';
|
||||
import {State} from './constants';
|
||||
|
||||
export async function run() {
|
||||
try {
|
||||
//
|
||||
// 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();
|
||||
|
||||
let arch = core.getInput('architecture');
|
||||
const cache = core.getInput('cache');
|
||||
|
||||
// if architecture supplied but node-version is not
|
||||
// if we don't throw a warning, the already installed x64 node will be used which is not probably what user meant.
|
||||
if (arch && !version) {
|
||||
core.warning(
|
||||
'`architecture` is provided but `node-version` is missing. In this configuration, the version/architecture of Node will not be changed. To fix this, provide `architecture` in combination with `node-version`'
|
||||
);
|
||||
}
|
||||
|
||||
if (!arch) {
|
||||
arch = os.arch();
|
||||
}
|
||||
|
||||
if (version) {
|
||||
const token = core.getInput('token');
|
||||
const auth = !token ? undefined : `token ${token}`;
|
||||
const mirror = core.getInput('mirror');
|
||||
const mirrorToken = core.getInput('mirror-token');
|
||||
const stable =
|
||||
(core.getInput('stable') || 'true').toUpperCase() === 'TRUE';
|
||||
const checkLatest =
|
||||
(core.getInput('check-latest') || 'false').toUpperCase() === 'TRUE';
|
||||
const nodejsInfo = {
|
||||
versionSpec: version,
|
||||
checkLatest,
|
||||
auth,
|
||||
stable,
|
||||
arch,
|
||||
mirror,
|
||||
mirrorToken
|
||||
};
|
||||
const nodeDistribution = getNodejsDistribution(nodejsInfo);
|
||||
await nodeDistribution.setupNodeJs();
|
||||
}
|
||||
|
||||
await printEnvDetailsAndSetOutput();
|
||||
|
||||
const registryUrl: string = core.getInput('registry-url');
|
||||
const alwaysAuth: string = core.getInput('always-auth');
|
||||
if (registryUrl) {
|
||||
auth.configAuthentication(registryUrl, alwaysAuth);
|
||||
}
|
||||
|
||||
if (cache && isCacheFeatureAvailable()) {
|
||||
core.saveState(State.CachePackageManager, cache);
|
||||
const cacheDependencyPath = core.getInput('cache-dependency-path');
|
||||
await restoreCache(cache, cacheDependencyPath);
|
||||
}
|
||||
|
||||
const matchersPath = path.join(__dirname, '../..', '.github');
|
||||
core.info(`##[add-matcher]${path.join(matchersPath, 'tsc.json')}`);
|
||||
core.info(
|
||||
`##[add-matcher]${path.join(matchersPath, 'eslint-stylish.json')}`
|
||||
);
|
||||
core.info(
|
||||
`##[add-matcher]${path.join(matchersPath, 'eslint-compact.json')}`
|
||||
);
|
||||
} catch (err) {
|
||||
core.setFailed((err as Error).message);
|
||||
}
|
||||
}
|
||||
|
||||
function resolveVersionInput(): string {
|
||||
let version = core.getInput('node-version');
|
||||
const versionFileInput = core.getInput('node-version-file');
|
||||
|
||||
if (version && versionFileInput) {
|
||||
core.warning(
|
||||
'Both node-version and node-version-file inputs are specified, only node-version will be used'
|
||||
);
|
||||
}
|
||||
|
||||
if (version) {
|
||||
return version;
|
||||
}
|
||||
|
||||
if (versionFileInput) {
|
||||
const versionFilePath = path.join(
|
||||
process.env.GITHUB_WORKSPACE!,
|
||||
versionFileInput
|
||||
);
|
||||
|
||||
const parsedVersion = getNodeVersionFromFile(versionFilePath);
|
||||
|
||||
if (parsedVersion) {
|
||||
version = parsedVersion;
|
||||
} else {
|
||||
core.warning(
|
||||
`Could not determine node version from ${versionFilePath}. Falling back`
|
||||
);
|
||||
}
|
||||
|
||||
core.info(`Resolved ${versionFileInput} as ${version}`);
|
||||
}
|
||||
|
||||
return version;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import {run} from './main';
|
||||
|
||||
run();
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
import * as core from '@actions/core';
|
||||
import * as exec from '@actions/exec';
|
||||
import * as io from '@actions/io';
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
export function getNodeVersionFromFile(versionFilePath: string): string | null {
|
||||
if (!fs.existsSync(versionFilePath)) {
|
||||
throw new Error(
|
||||
`The specified node version file at: ${versionFilePath} does not exist`
|
||||
);
|
||||
}
|
||||
|
||||
const contents = fs.readFileSync(versionFilePath, 'utf8');
|
||||
|
||||
// Try parsing the file as an NPM `package.json` file.
|
||||
try {
|
||||
const manifest = JSON.parse(contents);
|
||||
|
||||
// Presume package.json file.
|
||||
if (typeof manifest === 'object' && !!manifest) {
|
||||
// Support Volta.
|
||||
// See https://docs.volta.sh/guide/understanding#managing-your-project
|
||||
if (manifest.volta?.node) {
|
||||
return manifest.volta.node;
|
||||
}
|
||||
|
||||
if (manifest.engines?.node) {
|
||||
return manifest.engines.node;
|
||||
}
|
||||
|
||||
// Support Volta workspaces.
|
||||
// See https://docs.volta.sh/advanced/workspaces
|
||||
if (manifest.volta?.extends) {
|
||||
const extendedFilePath = path.resolve(
|
||||
path.dirname(versionFilePath),
|
||||
manifest.volta.extends
|
||||
);
|
||||
core.info('Resolving node version from ' + extendedFilePath);
|
||||
return getNodeVersionFromFile(extendedFilePath);
|
||||
}
|
||||
|
||||
// If contents are an object, we parsed JSON
|
||||
// this can happen if node-version-file is a package.json
|
||||
// yet contains no volta.node or engines.node
|
||||
//
|
||||
// If node-version file is _not_ JSON, control flow
|
||||
// will not have reached these lines.
|
||||
//
|
||||
// And because we've reached here, we know the contents
|
||||
// *are* JSON, so no further string parsing makes sense.
|
||||
return null;
|
||||
}
|
||||
} catch {
|
||||
core.info('Node version file is not JSON file');
|
||||
}
|
||||
|
||||
const found = contents.match(/^(?:node(js)?\s+)?v?(?<version>[^\s]+)$/m);
|
||||
return found?.groups?.version ?? contents.trim();
|
||||
}
|
||||
|
||||
export async function printEnvDetailsAndSetOutput() {
|
||||
core.startGroup('Environment details');
|
||||
const promises = ['node', 'npm', 'yarn'].map(async tool => {
|
||||
const pathTool = await io.which(tool, false);
|
||||
const output = pathTool ? 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 '';
|
||||
}
|
||||
}
|
||||
|
||||
export const unique = () => {
|
||||
const encountered = new Set();
|
||||
return (value: unknown): boolean => {
|
||||
if (encountered.has(value)) return false;
|
||||
encountered.add(value);
|
||||
return true;
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user