实现从官方下载并安装nodejs,并实现nodejs缓存

实现npm、yarn、pnpm等包管理的依赖包缓存
This commit is contained in:
soul-walker 2024-03-20 20:36:03 +08:00
parent 27cb05b70f
commit 625cb7a64e
18 changed files with 1311 additions and 48 deletions

34
.gitea/workflows/ci.yml Normal file
View File

@ -0,0 +1,34 @@
name: Continuous Integration
on:
pull_request:
branches:
- main
push:
branches:
- main
permissions:
contents: read
jobs:
test-action:
name: GitHub Actions Test
runs-on: local-test
steps:
- name: Checkout
id: checkout
uses: https://gitea.joylink.club/actions/checkout@v4
- name: Test Local Action
id: test-action
uses: ./
with:
version: 'v18.19.1'
cache: 'npm'
cache-dependency-path: 'package-lock.json'
- name: Print Output
id: output
run: echo "${{ steps.test-action.outputs.version }}"

View File

@ -36,6 +36,9 @@ extends:
rules: rules:
{ {
'prefer-const': 'off',
'no-shadow': 'off',
'github/array-foreach': 'off',
'camelcase': 'off', 'camelcase': 'off',
'eslint-comments/no-use': 'off', 'eslint-comments/no-use': 'off',
'eslint-comments/no-unused-disable': 'off', 'eslint-comments/no-unused-disable': 'off',

View File

@ -1,6 +1,7 @@
name: 'The name of your action here' name: 'Setup Node.js env'
description: 'Provide a description here' description:
author: 'Your name or organization here' 'Setup a Node.js environment by downloading and adding it to the PATH.'
author: 'walker-sheng'
# Add your action's branding here. This will appear on the GitHub Marketplace. # Add your action's branding here. This will appear on the GitHub Marketplace.
branding: branding:
@ -9,16 +10,32 @@ branding:
# Define your inputs here. # Define your inputs here.
inputs: inputs:
milliseconds: version:
description: 'Your input description here' description:
'Version Spec of the version to use. Examples: 12.x, 10.15.1, >=10.15.0.'
cache:
description:
'Used to specify a package manager for caching in the default directory.
Supported values: npm, yarn, pnpm.'
required: true required: true
default: '1000' default: 'npm'
cache-dependency-path:
description:
'Used to specify the path to a dependency file: package-lock.json,
yarn.lock, etc. Supports wildcards or a list of file names for caching
multiple dependencies.'
required: true
default: 'package-lock.json'
# Define your outputs here. # Define your outputs here.
outputs: outputs:
time: cache-hit:
description: 'Your output description here' description: 'A boolean value to indicate if a cache was hit.'
version:
description: 'The installed node version.'
runs: runs:
using: node20 using: node20
main: dist/index.js main: dist/index.js
post: 'dist/cache-save/index.js'
post-if: success()

BIN
dist/cache-save/index.js generated vendored Normal file

Binary file not shown.

BIN
dist/index.js generated vendored

Binary file not shown.

BIN
dist/index.js.map generated vendored

Binary file not shown.

BIN
dist/licenses.txt generated vendored

Binary file not shown.

BIN
dist/sourcemap-register.js generated vendored

Binary file not shown.

545
package-lock.json generated
View File

@ -9,7 +9,12 @@
"version": "0.0.0", "version": "0.0.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^1.10.1" "@actions/cache": "^3.2.4",
"@actions/core": "^1.10.1",
"@actions/glob": "^0.4.0",
"@actions/http-client": "^2.2.1",
"@actions/io": "^1.1.3",
"@actions/tool-cache": "^2.0.1"
}, },
"devDependencies": { "devDependencies": {
"@types/jest": "^29.5.12", "@types/jest": "^29.5.12",
@ -42,6 +47,69 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/@actions/cache": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/@actions/cache/-/cache-3.2.4.tgz",
"integrity": "sha512-RuHnwfcDagtX+37s0ZWy7clbOfnZ7AlDJQ7k/9rzt2W4Gnwde3fa/qjSjVuz4vLcLIpc7fUob27CMrqiWZytYA==",
"dependencies": {
"@actions/core": "^1.10.0",
"@actions/exec": "^1.0.1",
"@actions/glob": "^0.1.0",
"@actions/http-client": "^2.1.1",
"@actions/io": "^1.0.1",
"@azure/abort-controller": "^1.1.0",
"@azure/ms-rest-js": "^2.6.0",
"@azure/storage-blob": "^12.13.0",
"semver": "^6.3.1",
"uuid": "^3.3.3"
}
},
"node_modules/@actions/cache/node_modules/@actions/glob": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/@actions/glob/-/glob-0.1.2.tgz",
"integrity": "sha512-SclLR7Ia5sEqjkJTPs7Sd86maMDw43p769YxBOxvPvEWuPEhpAnBsQfENOpXjFYMmhCqd127bmf+YdvJqVqR4A==",
"dependencies": {
"@actions/core": "^1.2.6",
"minimatch": "^3.0.4"
}
},
"node_modules/@actions/cache/node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/@actions/cache/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/@actions/cache/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/@actions/cache/node_modules/uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
"bin": {
"uuid": "bin/uuid"
}
},
"node_modules/@actions/core": { "node_modules/@actions/core": {
"version": "1.10.1", "version": "1.10.1",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.1.tgz", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.1.tgz",
@ -51,15 +119,87 @@
"uuid": "^8.3.2" "uuid": "^8.3.2"
} }
}, },
"node_modules/@actions/exec": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz",
"integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==",
"dependencies": {
"@actions/io": "^1.0.1"
}
},
"node_modules/@actions/glob": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/@actions/glob/-/glob-0.4.0.tgz",
"integrity": "sha512-+eKIGFhsFa4EBwaf/GMyzCdWrXWymGXfFmZU3FHQvYS8mPcHtTtZONbkcqqUMzw9mJ/pImEBFET1JNifhqGsAQ==",
"dependencies": {
"@actions/core": "^1.9.1",
"minimatch": "^3.0.4"
}
},
"node_modules/@actions/glob/node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/@actions/glob/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/@actions/http-client": { "node_modules/@actions/http-client": {
"version": "2.2.0", "version": "2.2.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.0.tgz", "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.1.tgz",
"integrity": "sha512-q+epW0trjVUUHboliPb4UF9g2msf+w61b32tAkFEwL/IwP0DQWgbCMM0Hbe3e3WXSKz5VcUXbzJQgy8Hkra/Lg==", "integrity": "sha512-KhC/cZsq7f8I4LfZSJKgCvEwfkE8o1538VoBeoGzokVLLnbFDEAdFD3UhoMklxo2un9NJVBdANOresx7vTHlHw==",
"dependencies": { "dependencies": {
"tunnel": "^0.0.6", "tunnel": "^0.0.6",
"undici": "^5.25.4" "undici": "^5.25.4"
} }
}, },
"node_modules/@actions/io": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz",
"integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q=="
},
"node_modules/@actions/tool-cache": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@actions/tool-cache/-/tool-cache-2.0.1.tgz",
"integrity": "sha512-iPU+mNwrbA8jodY8eyo/0S/QqCKDajiR8OxWTnSk/SnYg0sj8Hp4QcUEVC1YFpHWXtrfbQrE13Jz4k4HXJQKcA==",
"dependencies": {
"@actions/core": "^1.2.6",
"@actions/exec": "^1.0.0",
"@actions/http-client": "^2.0.1",
"@actions/io": "^1.1.1",
"semver": "^6.1.0",
"uuid": "^3.3.2"
}
},
"node_modules/@actions/tool-cache/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/@actions/tool-cache/node_modules/uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
"bin": {
"uuid": "bin/uuid"
}
},
"node_modules/@ampproject/remapping": { "node_modules/@ampproject/remapping": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
@ -73,6 +213,198 @@
"node": ">=6.0.0" "node": ">=6.0.0"
} }
}, },
"node_modules/@azure/abort-controller": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.1.0.tgz",
"integrity": "sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw==",
"dependencies": {
"tslib": "^2.2.0"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/@azure/core-auth": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.7.0.tgz",
"integrity": "sha512-OuDVn9z2LjyYbpu6e7crEwSipa62jX7/ObV/pmXQfnOG8cHwm363jYtg3FSX3GB1V7jsIKri1zgq7mfXkFk/qw==",
"dependencies": {
"@azure/abort-controller": "^2.0.0",
"@azure/core-util": "^1.1.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@azure/core-auth/node_modules/@azure/abort-controller": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.0.tgz",
"integrity": "sha512-SYtcG13aiV7znycu6plCClWUzD9BBtfnsbIxT89nkkRvQRB4n0kuZyJJvJ7hqdKOn7x7YoGKZ9lVStLJpLnOFw==",
"dependencies": {
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@azure/core-http": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/@azure/core-http/-/core-http-3.0.4.tgz",
"integrity": "sha512-Fok9VVhMdxAFOtqiiAtg74fL0UJkt0z3D+ouUUxcRLzZNBioPRAMJFVxiWoJljYpXsRi4GDQHzQHDc9AiYaIUQ==",
"dependencies": {
"@azure/abort-controller": "^1.0.0",
"@azure/core-auth": "^1.3.0",
"@azure/core-tracing": "1.0.0-preview.13",
"@azure/core-util": "^1.1.1",
"@azure/logger": "^1.0.0",
"@types/node-fetch": "^2.5.0",
"@types/tunnel": "^0.0.3",
"form-data": "^4.0.0",
"node-fetch": "^2.6.7",
"process": "^0.11.10",
"tslib": "^2.2.0",
"tunnel": "^0.0.6",
"uuid": "^8.3.0",
"xml2js": "^0.5.0"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/@azure/core-http/node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/@azure/core-lro": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.7.0.tgz",
"integrity": "sha512-oj7d8vWEvOREIByH1+BnoiFwszzdE7OXUEd6UTv+cmx5HvjBBlkVezm3uZgpXWaxDj5ATL/k89+UMeGx1Ou9TQ==",
"dependencies": {
"@azure/abort-controller": "^2.0.0",
"@azure/core-util": "^1.2.0",
"@azure/logger": "^1.0.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@azure/core-lro/node_modules/@azure/abort-controller": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.0.tgz",
"integrity": "sha512-SYtcG13aiV7znycu6plCClWUzD9BBtfnsbIxT89nkkRvQRB4n0kuZyJJvJ7hqdKOn7x7YoGKZ9lVStLJpLnOFw==",
"dependencies": {
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@azure/core-paging": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@azure/core-paging/-/core-paging-1.6.0.tgz",
"integrity": "sha512-W8eRv7MVFx/jbbYfcRT5+pGnZ9St/P1UvOi+63vxPwuQ3y+xj+wqWTGxpkXUETv3szsqGu0msdxVtjszCeB4zA==",
"dependencies": {
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@azure/core-tracing": {
"version": "1.0.0-preview.13",
"resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.0.0-preview.13.tgz",
"integrity": "sha512-KxDlhXyMlh2Jhj2ykX6vNEU0Vou4nHr025KoSEiz7cS3BNiHNaZcdECk/DmLkEB0as5T7b/TpRcehJ5yV6NeXQ==",
"dependencies": {
"@opentelemetry/api": "^1.0.1",
"tslib": "^2.2.0"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/@azure/core-util": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.8.0.tgz",
"integrity": "sha512-w8NrGnrlGDF7fj36PBnJhGXDK2Y3kpTOgL7Ksb5snEHXq/3EAbKYOp1yqme0yWCUlSDq5rjqvxSBAJmsqYac3w==",
"dependencies": {
"@azure/abort-controller": "^2.0.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@azure/core-util/node_modules/@azure/abort-controller": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.0.tgz",
"integrity": "sha512-SYtcG13aiV7znycu6plCClWUzD9BBtfnsbIxT89nkkRvQRB4n0kuZyJJvJ7hqdKOn7x7YoGKZ9lVStLJpLnOFw==",
"dependencies": {
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@azure/logger": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.1.0.tgz",
"integrity": "sha512-BnfkfzVEsrgbVCtqq0RYRMePSH2lL/cgUUR5sYRF4yNN10zJZq/cODz0r89k3ykY83MqeM3twR292a3YBNgC3w==",
"dependencies": {
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@azure/ms-rest-js": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/@azure/ms-rest-js/-/ms-rest-js-2.7.0.tgz",
"integrity": "sha512-ngbzWbqF+NmztDOpLBVDxYM+XLcUj7nKhxGbSU9WtIsXfRB//cf2ZbAG5HkOrhU9/wd/ORRB6lM/d69RKVjiyA==",
"dependencies": {
"@azure/core-auth": "^1.1.4",
"abort-controller": "^3.0.0",
"form-data": "^2.5.0",
"node-fetch": "^2.6.7",
"tslib": "^1.10.0",
"tunnel": "0.0.6",
"uuid": "^8.3.2",
"xml2js": "^0.5.0"
}
},
"node_modules/@azure/ms-rest-js/node_modules/tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
},
"node_modules/@azure/storage-blob": {
"version": "12.17.0",
"resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-12.17.0.tgz",
"integrity": "sha512-sM4vpsCpcCApagRW5UIjQNlNylo02my2opgp0Emi8x888hZUvJ3dN69Oq20cEGXkMUWnoCrBaB0zyS3yeB87sQ==",
"dependencies": {
"@azure/abort-controller": "^1.0.0",
"@azure/core-http": "^3.0.0",
"@azure/core-lro": "^2.2.0",
"@azure/core-paging": "^1.1.1",
"@azure/core-tracing": "1.0.0-preview.13",
"@azure/logger": "^1.0.0",
"events": "^3.0.0",
"tslib": "^2.2.0"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/@babel/code-frame": { "node_modules/@babel/code-frame": {
"version": "7.23.5", "version": "7.23.5",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz",
@ -1350,6 +1682,14 @@
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/@opentelemetry/api": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.8.0.tgz",
"integrity": "sha512-I/s6F7yKUDdtMsoBWXJe8Qz40Tui5vsuKCWJEWVL+5q9sSWRzzx6v2KeNsOBEwd94j0eWkpWCH4yB6rZg9Mf0w==",
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/@pkgr/core": { "node_modules/@pkgr/core": {
"version": "0.1.1", "version": "0.1.1",
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz",
@ -1486,11 +1826,32 @@
"version": "20.11.28", "version": "20.11.28",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.28.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.28.tgz",
"integrity": "sha512-M/GPWVS2wLkSkNHVeLkrF2fD5Lx5UC4PxA0uZcKc6QqbIQUJyW1jVjueJYi1z8n0I5PxYrtpnPnWglE+y9A0KA==", "integrity": "sha512-M/GPWVS2wLkSkNHVeLkrF2fD5Lx5UC4PxA0uZcKc6QqbIQUJyW1jVjueJYi1z8n0I5PxYrtpnPnWglE+y9A0KA==",
"dev": true,
"dependencies": { "dependencies": {
"undici-types": "~5.26.4" "undici-types": "~5.26.4"
} }
}, },
"node_modules/@types/node-fetch": {
"version": "2.6.11",
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz",
"integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==",
"dependencies": {
"@types/node": "*",
"form-data": "^4.0.0"
}
},
"node_modules/@types/node-fetch/node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/@types/semver": { "node_modules/@types/semver": {
"version": "7.5.8", "version": "7.5.8",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz",
@ -1503,6 +1864,14 @@
"integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==",
"dev": true "dev": true
}, },
"node_modules/@types/tunnel": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/@types/tunnel/-/tunnel-0.0.3.tgz",
"integrity": "sha512-sOUTGn6h1SfQ+gbgqC364jLFBw2lnFqkgF3q0WovEHRLMrVD1sd5aufqi/aJObLekJO+Aq5z646U4Oxy6shXMA==",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/yargs": { "node_modules/@types/yargs": {
"version": "17.0.32", "version": "17.0.32",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz",
@ -1723,6 +2092,17 @@
"ncc": "dist/ncc/cli.js" "ncc": "dist/ncc/cli.js"
} }
}, },
"node_modules/abort-controller": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
"dependencies": {
"event-target-shim": "^5.0.0"
},
"engines": {
"node": ">=6.5"
}
},
"node_modules/acorn": { "node_modules/acorn": {
"version": "8.11.3", "version": "8.11.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
@ -1994,6 +2374,11 @@
"has-symbols": "^1.0.3" "has-symbols": "^1.0.3"
} }
}, },
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/available-typed-arrays": { "node_modules/available-typed-arrays": {
"version": "1.0.7", "version": "1.0.7",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
@ -2146,8 +2531,7 @@
"node_modules/balanced-match": { "node_modules/balanced-match": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
"dev": true
}, },
"node_modules/brace-expansion": { "node_modules/brace-expansion": {
"version": "2.0.1", "version": "2.0.1",
@ -2380,6 +2764,17 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true "dev": true
}, },
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/common-tags": { "node_modules/common-tags": {
"version": "1.8.2", "version": "1.8.2",
"resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz",
@ -2392,8 +2787,7 @@
"node_modules/concat-map": { "node_modules/concat-map": {
"version": "0.0.1", "version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
"dev": true
}, },
"node_modules/convert-source-map": { "node_modules/convert-source-map": {
"version": "2.0.0", "version": "2.0.0",
@ -2522,6 +2916,14 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/dequal": { "node_modules/dequal": {
"version": "2.0.3", "version": "2.0.3",
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
@ -3496,6 +3898,22 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/event-target-shim": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
"engines": {
"node": ">=6"
}
},
"node_modules/events": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
"engines": {
"node": ">=0.8.x"
}
},
"node_modules/execa": { "node_modules/execa": {
"version": "5.1.1", "version": "5.1.1",
"resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
@ -3683,6 +4101,19 @@
"is-callable": "^1.1.3" "is-callable": "^1.1.3"
} }
}, },
"node_modules/form-data": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
"integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.6",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 0.12"
}
},
"node_modules/fs.realpath": { "node_modules/fs.realpath": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@ -5542,6 +5973,25 @@
"node": ">=8.6" "node": ">=8.6"
} }
}, },
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mimic-fn": { "node_modules/mimic-fn": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
@ -5596,6 +6046,25 @@
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
"dev": true "dev": true
}, },
"node_modules/node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/node-int64": { "node_modules/node-int64": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
@ -6178,6 +6647,14 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1" "url": "https://github.com/chalk/ansi-styles?sponsor=1"
} }
}, },
"node_modules/process": {
"version": "0.11.10",
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
"integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
"engines": {
"node": ">= 0.6.0"
}
},
"node_modules/prompts": { "node_modules/prompts": {
"version": "2.4.2", "version": "2.4.2",
"resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
@ -6441,6 +6918,11 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/sax": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz",
"integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA=="
},
"node_modules/semver": { "node_modules/semver": {
"version": "7.6.0", "version": "7.6.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
@ -6847,6 +7329,11 @@
"node": ">=8.0" "node": ">=8.0"
} }
}, },
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"node_modules/ts-api-utils": { "node_modules/ts-api-utils": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz",
@ -6938,8 +7425,7 @@
"node_modules/tslib": { "node_modules/tslib": {
"version": "2.6.2", "version": "2.6.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
"dev": true
}, },
"node_modules/tsutils": { "node_modules/tsutils": {
"version": "3.21.0", "version": "3.21.0",
@ -7118,8 +7604,7 @@
"node_modules/undici-types": { "node_modules/undici-types": {
"version": "5.26.5", "version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
"dev": true
}, },
"node_modules/update-browserslist-db": { "node_modules/update-browserslist-db": {
"version": "1.0.13", "version": "1.0.13",
@ -7215,6 +7700,20 @@
"makeerror": "1.0.12" "makeerror": "1.0.12"
} }
}, },
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"node_modules/which": { "node_modules/which": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@ -7342,6 +7841,26 @@
"node": "^12.13.0 || ^14.15.0 || >=16.0.0" "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
} }
}, },
"node_modules/xml2js": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz",
"integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==",
"dependencies": {
"sax": ">=0.6.0",
"xmlbuilder": "~11.0.0"
},
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/xmlbuilder": {
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
"engines": {
"node": ">=4.0"
}
},
"node_modules/y18n": { "node_modules/y18n": {
"version": "5.0.8", "version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",

View File

@ -30,10 +30,11 @@
"format:write": "npx prettier --write .", "format:write": "npx prettier --write .",
"format:check": "npx prettier --check .", "format:check": "npx prettier --check .",
"lint": "npx eslint . -c ./.github/linters/.eslintrc.yml", "lint": "npx eslint . -c ./.github/linters/.eslintrc.yml",
"package": "npx ncc build src/index.ts -o dist --source-map --license licenses.txt", "package": "npx ncc build src/index.ts -o dist && npx ncc build -o dist/cache-save src/cache-save.ts",
"package:watch": "npm run package -- --watch", "package:watch": "npm run package -- --watch",
"test": "npx jest", "test": "npx jest",
"all": "npm run format:write && npm run lint && npm run test && npm run coverage && npm run package" "all": "npm run format:write && npm run lint && npm run package",
"all-all": "npm run format:write && npm run lint && npm run test && npm run coverage && npm run package"
}, },
"license": "MIT", "license": "MIT",
"jest": { "jest": {
@ -66,7 +67,12 @@
] ]
}, },
"dependencies": { "dependencies": {
"@actions/core": "^1.10.1" "@actions/cache": "^3.2.4",
"@actions/core": "^1.10.1",
"@actions/glob": "^0.4.0",
"@actions/http-client": "^2.2.1",
"@actions/io": "^1.1.3",
"@actions/tool-cache": "^2.0.1"
}, },
"devDependencies": { "devDependencies": {
"@types/jest": "^29.5.12", "@types/jest": "^29.5.12",

86
src/cache-restore.ts Normal file
View File

@ -0,0 +1,86 @@
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 { State } from './constants'
import {
getCacheDirectories,
getPackageManagerInfo,
repoHasYarnBerryManagedDependencies,
PackageManagerInfo
} from './cache-utils'
export const restoreCache = async (
packageManager: string,
cacheDependencyPath: string
): Promise<void> => {
const packageManagerInfo = await getPackageManagerInfo(packageManager)
if (!packageManagerInfo) {
throw new Error(`Caching for '${packageManager}' is not supported`)
}
const platform = process.env.RUNNER_OS
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}-${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): string => {
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)
}

71
src/cache-save.ts Normal file
View File

@ -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): Promise<void> {
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): Promise<void> => {
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)

316
src/cache-utils.ts Normal file
View File

@ -0,0 +1,316 @@
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: 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: async () =>
getCommandOutputNotEmpty(
'npm config get cache',
'Could not get npm cache folder path'
)
},
pnpm: {
name: 'pnpm',
lockFilePatterns: ['pnpm-lock.yaml'],
getCacheFolderPath: async () =>
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
): Promise<PackageManagerInfo | null> => {
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 = (): null =>
(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(dirName => path.dirname(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'
)
return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM'
}
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
}

16
src/constants.ts Normal file
View File

@ -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'
}

47
src/install.ts Normal file
View File

@ -0,0 +1,47 @@
import * as core from '@actions/core'
import * as tc from '@actions/tool-cache'
import os from 'os'
const BinBaseUrl = 'https://nodejs.org/dist/'
const DestDir = '/denv'
export function getFileName(version: string, arch = os.arch()): string {
return `node-${version}-${os.platform()}-${arch}.tar.gz`
}
export function getRootPath(version: string): string {
return `${DestDir}/node-${version}`
}
export async function getInstalledPath(
version: string,
fileName: string
): Promise<string> {
const downloadUrl = `${BinBaseUrl}${version}/${fileName}`
core.info(`Downloading from ${downloadUrl}`)
const downloadPath = await tc.downloadTool(downloadUrl)
core.info(`Extracting from ${downloadPath}`)
const extPath = await extractArchive(downloadPath, version)
core.info(`Successfully extracted to ${extPath}`)
return extPath
}
async function extractArchive(
archivePath: string,
version: string
): Promise<string> {
const platform = os.platform()
let extPath: string
if (platform === 'win32') {
extPath = await tc.extractZip(archivePath, getRootPath(version))
} else {
extPath = await tc.extractTar(archivePath, getRootPath(version), [
'xz',
'--strip',
'1'
])
}
return extPath
}

View File

@ -1,5 +1,12 @@
import * as core from '@actions/core' import * as core from '@actions/core'
import { wait } from './wait' import * as io from '@actions/io'
import * as ac from '@actions/cache'
import os from 'os'
import path from 'path'
import cp from 'child_process'
import { getFileName, getRootPath, getInstalledPath } from './install'
import { restoreCache } from './cache-restore'
import { State } from './constants'
/** /**
* The main function for the action. * The main function for the action.
@ -7,20 +14,59 @@ import { wait } from './wait'
*/ */
export async function run(): Promise<void> { export async function run(): Promise<void> {
try { try {
const ms: string = core.getInput('milliseconds') // 获取输入的version
const version: string = resolveVersionInput()
// Debug logs are only output if the `ACTIONS_STEP_DEBUG` secret is true // Debug logs are only output if the `ACTIONS_STEP_DEBUG` secret is true
core.debug(`Waiting ${ms} milliseconds ...`) core.debug(`The input version is: ${version}`)
// 获取输入的architecture
let arch = core.getInput('architecture')
if (!arch) {
arch = os.arch()
}
if (arch === 'x64') {
arch = 'amd64'
}
// 构建文件名
const dlgfName = getFileName(version, arch)
let installedPath = getRootPath(version)
// 尝试从缓存中恢复
const rcr = await ac.restoreCache([installedPath], dlgfName)
if (!rcr) {
core.info(`Cache not found for input key: ${dlgfName}`)
// 缓存中没有找到,下载解压安装
installedPath = await getInstalledPath(version, dlgfName)
core.info(`Success Installed to ${installedPath}`)
// 保存到缓存
await ac.saveCache([installedPath], dlgfName)
}
// Log the current timestamp, wait, then log the new timestamp // 将bin目录添加到PATH
core.debug(new Date().toTimeString()) const binPath = path.join(installedPath, 'bin')
await wait(parseInt(ms, 10)) core.addPath(binPath)
core.debug(new Date().toTimeString()) // 测试输出版本
const bp = await io.which('node')
const execVersion = (cp.execSync(`${bp} -v`) || '').toString()
core.info(`version cmd result is: ${execVersion}`)
// Set outputs for other workflow steps to use // 尝试从缓存中恢复依赖包
core.setOutput('time', new Date().toTimeString()) const cache = core.getInput('cache')
core.saveState(State.CachePackageManager, cache)
const cacheDependencyPath = core.getInput('cache-dependency-path')
await restoreCache(cache, cacheDependencyPath)
// 设置输出参数
core.setOutput('version', execVersion)
} catch (error) { } catch (error) {
// Fail the workflow run if an error occurs // Fail the workflow run if an error occurs
if (error instanceof Error) core.setFailed(error.message) if (error instanceof Error) core.setFailed(error.message)
} }
} }
function resolveVersionInput(): string {
const version = core.getInput('version')
if (version) {
return version
}
throw new Error(`没有指定版本`)
}

116
src/util.ts Normal file
View File

@ -0,0 +1,116 @@
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(): Promise<void> {
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[]
): Promise<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 ''
}
}
type uniqueFn = (value: unknown) => boolean
export const unique = (): uniqueFn => {
const encountered = new Set()
return (value: unknown): boolean => {
if (encountered.has(value)) return false
encountered.add(value)
return true
}
}

View File

@ -1,14 +0,0 @@
/**
* Wait for a number of milliseconds.
* @param milliseconds The number of milliseconds to wait.
* @returns {Promise<string>} Resolves with 'done!' after the wait is over.
*/
export async function wait(milliseconds: number): Promise<string> {
return new Promise(resolve => {
if (isNaN(milliseconds)) {
throw new Error('milliseconds not a number')
}
setTimeout(() => resolve('done!'), milliseconds)
})
}