Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d3ad3eeb7f |
@@ -0,0 +1,43 @@
|
|||||||
|
name: Publish NPM
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
package:
|
||||||
|
required: true
|
||||||
|
description: 'core, artifact, cache, exec, github, glob, io, tool-cache'
|
||||||
|
version:
|
||||||
|
required: true
|
||||||
|
description: 'the version of the package to publish'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: macos-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Setup repo
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: npm install
|
||||||
|
run: npm install
|
||||||
|
|
||||||
|
- name: bootstrap
|
||||||
|
run: npm run bootstrap
|
||||||
|
|
||||||
|
- name: build
|
||||||
|
run: npm run build
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: npm run test
|
||||||
|
|
||||||
|
- name: echo inputs
|
||||||
|
run: echo ${{ github.event.inputs.package }} ${{ github.event.inputs.version }}
|
||||||
|
|
||||||
|
publish:
|
||||||
|
runs-on: macos-latest
|
||||||
|
needs: test
|
||||||
|
environment: npm-publish
|
||||||
|
steps:
|
||||||
|
- name: Testing
|
||||||
|
run: echo 'this is where we publish'
|
||||||
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
name: Publish NPM
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
package:
|
|
||||||
required: true
|
|
||||||
description: 'core, artifact, cache, exec, github, glob, io, tool-cache'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test:
|
|
||||||
runs-on: macos-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: setup repo
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: verify package exists
|
|
||||||
run: ls packages/${{ github.event.inputs.package }}
|
|
||||||
|
|
||||||
- name: npm install
|
|
||||||
run: npm install
|
|
||||||
|
|
||||||
- name: bootstrap
|
|
||||||
run: npm run bootstrap
|
|
||||||
|
|
||||||
- name: build
|
|
||||||
run: npm run build
|
|
||||||
|
|
||||||
- name: test
|
|
||||||
run: npm run test
|
|
||||||
|
|
||||||
- name: pack
|
|
||||||
run: npm pack
|
|
||||||
working-directory: packages/${{ github.event.inputs.package }}
|
|
||||||
|
|
||||||
- name: upload artifact
|
|
||||||
uses: actions/upload-artifact@v2
|
|
||||||
with:
|
|
||||||
name: ${{ github.event.inputs.package }}
|
|
||||||
path: packages/${{ github.event.inputs.package }}/*.tgz
|
|
||||||
|
|
||||||
publish:
|
|
||||||
runs-on: macos-latest
|
|
||||||
needs: test
|
|
||||||
environment: npm-publish
|
|
||||||
steps:
|
|
||||||
|
|
||||||
- name: download artifact
|
|
||||||
uses: actions/download-artifact@v2
|
|
||||||
with:
|
|
||||||
name: ${{ github.event.inputs.package }}
|
|
||||||
|
|
||||||
- name: setup authentication
|
|
||||||
run: echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" >> .npmrc
|
|
||||||
env:
|
|
||||||
NPM_TOKEN: ${{ secrets.TOKEN }}
|
|
||||||
|
|
||||||
- name: publish
|
|
||||||
run: npm publish *.tgz
|
|
||||||
|
|
||||||
- name: notify slack on failure
|
|
||||||
if: failure()
|
|
||||||
run: |
|
|
||||||
curl -X POST -H 'Content-type: application/json' --data '{"text":":pb__failed: Failed to publish a new version of ${{ github.event.inputs.package }}"}' $SLACK_WEBHOOK
|
|
||||||
env:
|
|
||||||
SLACK_WEBHOOK: ${{ secrets.SLACK }}
|
|
||||||
|
|
||||||
- name: notify slack on success
|
|
||||||
if: success()
|
|
||||||
run: |
|
|
||||||
curl -X POST -H 'Content-type: application/json' --data '{"text":":dance: Successfully published a new version of ${{ github.event.inputs.package }}"}' $SLACK_WEBHOOK
|
|
||||||
env:
|
|
||||||
SLACK_WEBHOOK: ${{ secrets.SLACK }}
|
|
||||||
|
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
name: "UpdateOctokit"
|
name: "UpdateOctokit"
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
schedule:
|
||||||
|
- cron: '0 18 * * 0' # sunday at 18 UTC
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
UpdateOctokit:
|
UpdateOctokit:
|
||||||
|
|||||||
@@ -2,3 +2,4 @@
|
|||||||
|
|
||||||
/packages/artifact/ @actions/actions-service
|
/packages/artifact/ @actions/actions-service
|
||||||
/packages/cache/ @actions/actions-service
|
/packages/cache/ @actions/actions-service
|
||||||
|
/packages/tool-cache/ @actions/spark
|
||||||
+4
-11
@@ -57,7 +57,7 @@ For example, if you mask the letter `l`, running `echo "Hello FOO BAR World"` wi
|
|||||||
|
|
||||||
### Group and Ungroup Log Lines
|
### Group and Ungroup Log Lines
|
||||||
|
|
||||||
Emitting a group with a title will instruct the logs to create a collapsible region up to the next endgroup command.
|
Emitting a group with a title will instruct the logs to create a collapsable region up to the next ungroup command.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
echo "::group::my title"
|
echo "::group::my title"
|
||||||
@@ -72,7 +72,6 @@ function endGroup(): void {}
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Problem Matchers
|
### Problem Matchers
|
||||||
|
|
||||||
Problems matchers can be used to scan a build's output to automatically surface lines to the user that matches the provided pattern. A file path to a .json Problem Matcher must be provided. See [Problem Matchers](problem-matchers.md) for more information on how to define a Problem Matcher.
|
Problems matchers can be used to scan a build's output to automatically surface lines to the user that matches the provided pattern. A file path to a .json Problem Matcher must be provided. See [Problem Matchers](problem-matchers.md) for more information on how to define a Problem Matcher.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -82,7 +81,6 @@ echo "::remove-matcher owner=eslint-compact::"
|
|||||||
|
|
||||||
`add-matcher` takes a path to a Problem Matcher file
|
`add-matcher` takes a path to a Problem Matcher file
|
||||||
`remove-matcher` removes a Problem Matcher by owner
|
`remove-matcher` removes a Problem Matcher by owner
|
||||||
|
|
||||||
### Save State
|
### Save State
|
||||||
|
|
||||||
Save a state to an environmental variable that can later be used in the main or post action.
|
Save a state to an environmental variable that can later be used in the main or post action.
|
||||||
@@ -104,7 +102,6 @@ There are several commands to emit different levels of log output:
|
|||||||
| error | `echo "::error::My error message"` |
|
| error | `echo "::error::My error message"` |
|
||||||
|
|
||||||
### Command Echoing
|
### Command Echoing
|
||||||
|
|
||||||
By default, the echoing of commands to stdout only occurs if [Step Debugging is enabled](./action-debugging.md#How-to-Access-Step-Debug-Logs)
|
By default, the echoing of commands to stdout only occurs if [Step Debugging is enabled](./action-debugging.md#How-to-Access-Step-Debug-Logs)
|
||||||
|
|
||||||
You can enable or disable this for the current step by using the `echo` command.
|
You can enable or disable this for the current step by using the `echo` command.
|
||||||
@@ -130,12 +127,12 @@ The `add-mask`, `debug`, `warning` and `error` commands do not support echoing.
|
|||||||
### Command Prompt
|
### Command Prompt
|
||||||
|
|
||||||
CMD processes the `"` character differently from other shells when echoing. In CMD, the above snippets should have the `"` characters removed in order to correctly process. For example, the set output command would be:
|
CMD processes the `"` character differently from other shells when echoing. In CMD, the above snippets should have the `"` characters removed in order to correctly process. For example, the set output command would be:
|
||||||
|
|
||||||
```cmd
|
```cmd
|
||||||
echo ::set-output name=FOO::BAR
|
echo ::set-output name=FOO::BAR
|
||||||
```
|
```
|
||||||
|
|
||||||
## Environment files
|
|
||||||
|
# Environment files
|
||||||
|
|
||||||
During the execution of a workflow, the runner generates temporary files that can be used to perform certain actions. The path to these files are exposed via environment variables. You will need to use the `utf-8` encoding when writing to these files to ensure proper processing of the commands. Multiple commands can be written to the same file, separated by newlines.
|
During the execution of a workflow, the runner generates temporary files that can be used to perform certain actions. The path to these files are exposed via environment variables. You will need to use the `utf-8` encoding when writing to these files to ensure proper processing of the commands. Multiple commands can be written to the same file, separated by newlines.
|
||||||
|
|
||||||
@@ -149,8 +146,7 @@ echo "FOO=BAR" >> $GITHUB_ENV
|
|||||||
|
|
||||||
Running `$FOO` in a future step will now return `BAR`
|
Running `$FOO` in a future step will now return `BAR`
|
||||||
|
|
||||||
For multiline strings, you may use a heredoc style syntax with your choice of delimeter. In the below example, we use `EOF`.
|
For multiline strings, you may use a heredoc style syntax with your choice of delimeter. In the below example, we use `EOF`
|
||||||
|
|
||||||
```
|
```
|
||||||
steps:
|
steps:
|
||||||
- name: Set the value
|
- name: Set the value
|
||||||
@@ -164,7 +160,6 @@ steps:
|
|||||||
This would set the value of the `JSON_RESPONSE` env variable to the value of the curl response.
|
This would set the value of the `JSON_RESPONSE` env variable to the value of the curl response.
|
||||||
|
|
||||||
The expected syntax for the heredoc style is:
|
The expected syntax for the heredoc style is:
|
||||||
|
|
||||||
```
|
```
|
||||||
{VARIABLE_NAME}<<{DELIMETER}
|
{VARIABLE_NAME}<<{DELIMETER}
|
||||||
{VARIABLE_VALUE}
|
{VARIABLE_VALUE}
|
||||||
@@ -188,7 +183,6 @@ echo "/Users/test/.nvm/versions/node/v12.18.3/bin" >> $GITHUB_PATH
|
|||||||
Running `$PATH` in a future step will now return `/Users/test/.nvm/versions/node/v12.18.3/bin:{Previous Path}`;
|
Running `$PATH` in a future step will now return `/Users/test/.nvm/versions/node/v12.18.3/bin:{Previous Path}`;
|
||||||
|
|
||||||
This is wrapped by the core addPath method:
|
This is wrapped by the core addPath method:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
export function addPath(inputPath: string): void {}
|
export function addPath(inputPath: string): void {}
|
||||||
```
|
```
|
||||||
@@ -196,7 +190,6 @@ export function addPath(inputPath: string): void {}
|
|||||||
### Powershell
|
### Powershell
|
||||||
|
|
||||||
Powershell does not use UTF8 by default. You will want to make sure you write in the correct encoding. For example, to set the path:
|
Powershell does not use UTF8 by default. You will want to make sure you write in the correct encoding. For example, to set the path:
|
||||||
|
|
||||||
```
|
```
|
||||||
steps:
|
steps:
|
||||||
- run: echo "mypath" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
- run: echo "mypath" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||||
|
|||||||
@@ -2,16 +2,6 @@
|
|||||||
|
|
||||||
Problem Matchers are a way to scan the output of actions for a specified regex pattern and surface that information prominently in the UI. Both [GitHub Annotations](https://developer.github.com/v3/checks/runs/#annotations-object-1) and log file decorations are created when a match is detected.
|
Problem Matchers are a way to scan the output of actions for a specified regex pattern and surface that information prominently in the UI. Both [GitHub Annotations](https://developer.github.com/v3/checks/runs/#annotations-object-1) and log file decorations are created when a match is detected.
|
||||||
|
|
||||||
## Limitations
|
|
||||||
|
|
||||||
Currently, GitHub Actions limit the annotation count in a workflow run.
|
|
||||||
|
|
||||||
- 10 warning annotations and 10 error annotations per step
|
|
||||||
- 50 annotations per job (sum of annotations from all the steps)
|
|
||||||
- 50 annotations per run (separate from the job annotations, these annotations aren’t created by users)
|
|
||||||
|
|
||||||
If your workflow may exceed these annotation counts, consider filtering of the log messages which the Problem Matcher is exposed to (e.g. by PR touched files, lines, or other).
|
|
||||||
|
|
||||||
## Single Line Matchers
|
## Single Line Matchers
|
||||||
|
|
||||||
Let's consider the ESLint compact output:
|
Let's consider the ESLint compact output:
|
||||||
@@ -110,16 +100,6 @@ The eslint-stylish problem matcher defined below catches that output, and create
|
|||||||
The first pattern matches the `test.js` line and records the file information. This line is not decorated in the UI.
|
The first pattern matches the `test.js` line and records the file information. This line is not decorated in the UI.
|
||||||
The second pattern loops through the remaining lines with `loop: true` until it fails to find a match, and surfaces these lines prominently in the UI.
|
The second pattern loops through the remaining lines with `loop: true` until it fails to find a match, and surfaces these lines prominently in the UI.
|
||||||
|
|
||||||
Note that the pattern matches must be on consecutive lines. The following would not result in any match findings.
|
|
||||||
|
|
||||||
```
|
|
||||||
test.js
|
|
||||||
extraneous log line of no interest
|
|
||||||
1:0 error Missing "use strict" statement strict
|
|
||||||
5:10 error 'addOne' is defined but never used no-unused-vars
|
|
||||||
✖ 2 problems (2 errors, 0 warnings)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Adding and Removing Problem Matchers
|
## Adding and Removing Problem Matchers
|
||||||
|
|
||||||
Problem Matchers are enabled and removed via the toolkit [commands](commands.md#problem-matchers).
|
Problem Matchers are enabled and removed via the toolkit [commands](commands.md#problem-matchers).
|
||||||
|
|||||||
Generated
+9
-9
@@ -18684,9 +18684,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ssri": {
|
"ssri": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz",
|
||||||
"integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==",
|
"integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"figgy-pudding": "^3.5.1"
|
"figgy-pudding": "^3.5.1"
|
||||||
@@ -19336,9 +19336,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "3.9.9",
|
"version": "3.7.4",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.4.tgz",
|
||||||
"integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==",
|
"integrity": "sha512-A25xv5XCtarLwXpcDNZzCGvW2D1S3/bACratYBx2sax8PefsFhlYmkQicKHvpYflFS8if4zne5zT5kpJ7pzuvw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"uglify-js": {
|
"uglify-js": {
|
||||||
@@ -19859,9 +19859,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"y18n": {
|
"y18n": {
|
||||||
"version": "4.0.1",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
|
||||||
"integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==",
|
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"yallist": {
|
"yallist": {
|
||||||
|
|||||||
+1
-1
@@ -27,6 +27,6 @@
|
|||||||
"lerna": "^3.18.4",
|
"lerna": "^3.18.4",
|
||||||
"prettier": "^1.19.1",
|
"prettier": "^1.19.1",
|
||||||
"ts-jest": "^25.4.0",
|
"ts-jest": "^25.4.0",
|
||||||
"typescript": "^3.9.9"
|
"typescript": "^3.7.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,3 @@
|
|||||||
|
|
||||||
- Improved retry-ability for all http calls during artifact upload and download if an error is encountered
|
- Improved retry-ability for all http calls during artifact upload and download if an error is encountered
|
||||||
|
|
||||||
### 0.5.1
|
|
||||||
|
|
||||||
- Bump @actions/http-client to version 1.0.11 to fix proxy related issues during artifact upload and download
|
|
||||||
|
|
||||||
|
|||||||
Generated
+4
-4
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@actions/artifact",
|
"name": "@actions/artifact",
|
||||||
"version": "0.5.1",
|
"version": "0.5.0",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -10,9 +10,9 @@
|
|||||||
"integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA=="
|
"integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA=="
|
||||||
},
|
},
|
||||||
"@actions/http-client": {
|
"@actions/http-client": {
|
||||||
"version": "1.0.11",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.8.tgz",
|
||||||
"integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==",
|
"integrity": "sha512-G4JjJ6f9Hb3Zvejj+ewLLKLf99ZC+9v+yCxoYf9vSyH+WkzPLB2LuUtRMGNkooMqdugGBFStIKXOuvH1W+EctA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"tunnel": "0.0.6"
|
"tunnel": "0.0.6"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@actions/artifact",
|
"name": "@actions/artifact",
|
||||||
"version": "0.5.1",
|
"version": "0.5.0",
|
||||||
"preview": true,
|
"preview": true,
|
||||||
"description": "Actions artifact lib",
|
"description": "Actions artifact lib",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.2.6",
|
"@actions/core": "^1.2.6",
|
||||||
"@actions/http-client": "^1.0.11",
|
"@actions/http-client": "^1.0.7",
|
||||||
"@types/tmp": "^0.1.0",
|
"@types/tmp": "^0.1.0",
|
||||||
"tmp": "^0.1.0",
|
"tmp": "^0.1.0",
|
||||||
"tmp-promise": "^2.0.2"
|
"tmp-promise": "^2.0.2"
|
||||||
|
|||||||
Vendored
+14
-14
@@ -10,20 +10,6 @@ Note that GitHub will remove any cache entries that have not been accessed in ov
|
|||||||
|
|
||||||
This package is used by the v2+ versions of our first party cache action. You can find an example implementation in the cache repo [here](https://github.com/actions/cache).
|
This package is used by the v2+ versions of our first party cache action. You can find an example implementation in the cache repo [here](https://github.com/actions/cache).
|
||||||
|
|
||||||
#### Save Cache
|
|
||||||
|
|
||||||
Saves a cache containing the files in `paths` using the `key` provided. The files would be compressed using zstandard compression algorithm if zstd is installed, otherwise gzip is used. Function returns the cache id if the cache was saved succesfully and throws an error if cache upload fails.
|
|
||||||
|
|
||||||
```js
|
|
||||||
const cache = require('@actions/cache');
|
|
||||||
const paths = [
|
|
||||||
'node_modules',
|
|
||||||
'packages/*/node_modules/'
|
|
||||||
]
|
|
||||||
const key = 'npm-foobar-d5ea0750'
|
|
||||||
const cacheId = await cache.saveCache(paths, key)
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Restore Cache
|
#### Restore Cache
|
||||||
|
|
||||||
Restores a cache based on `key` and `restoreKeys` to the `paths` provided. Function returns the cache key for cache hit and returns undefined if cache not found.
|
Restores a cache based on `key` and `restoreKeys` to the `paths` provided. Function returns the cache key for cache hit and returns undefined if cache not found.
|
||||||
@@ -42,3 +28,17 @@ const restoreKeys = [
|
|||||||
const cacheKey = await cache.restoreCache(paths, key, restoreKeys)
|
const cacheKey = await cache.restoreCache(paths, key, restoreKeys)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Save Cache
|
||||||
|
|
||||||
|
Saves a cache containing the files in `paths` using the `key` provided. The files would be compressed using zstandard compression algorithm if zstd is installed, otherwise gzip is used. Function returns the cache id if the cache was saved succesfully and throws an error if cache upload fails.
|
||||||
|
|
||||||
|
```js
|
||||||
|
const cache = require('@actions/cache');
|
||||||
|
const paths = [
|
||||||
|
'node_modules',
|
||||||
|
'packages/*/node_modules/'
|
||||||
|
]
|
||||||
|
const key = 'npm-foobar-d5ea0750'
|
||||||
|
const cacheId = await cache.saveCache(paths, key)
|
||||||
|
```
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-4
@@ -36,7 +36,4 @@
|
|||||||
|
|
||||||
### 1.0.6
|
### 1.0.6
|
||||||
- Make caching more verbose [#650](https://github.com/actions/toolkit/pull/650)
|
- Make caching more verbose [#650](https://github.com/actions/toolkit/pull/650)
|
||||||
- Use GNU tar on macOS if available [#701](https://github.com/actions/toolkit/pull/701)
|
- Use GNU tar on macOS if available [#701](https://github.com/actions/toolkit/pull/701)
|
||||||
|
|
||||||
### 1.0.7
|
|
||||||
- Fixes permissions issue extracting archives with GNU tar on macOS ([issue](https://github.com/actions/cache/issues/527))
|
|
||||||
+2
-2
@@ -2,10 +2,10 @@ import {promises as fs} from 'fs'
|
|||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
import * as cacheUtils from '../src/internal/cacheUtils'
|
import * as cacheUtils from '../src/internal/cacheUtils'
|
||||||
|
|
||||||
test('getArchiveFileSizeInBytes returns file size', () => {
|
test('getArchiveFileSizeIsBytes returns file size', () => {
|
||||||
const filePath = path.join(__dirname, '__fixtures__', 'helloWorld.txt')
|
const filePath = path.join(__dirname, '__fixtures__', 'helloWorld.txt')
|
||||||
|
|
||||||
const size = cacheUtils.getArchiveFileSizeInBytes(filePath)
|
const size = cacheUtils.getArchiveFileSizeIsBytes(filePath)
|
||||||
|
|
||||||
expect(size).toBe(11)
|
expect(size).toBe(11)
|
||||||
})
|
})
|
||||||
|
|||||||
+9
-9
@@ -123,8 +123,8 @@ test('restore with gzip compressed cache found', async () => {
|
|||||||
const downloadCacheMock = jest.spyOn(cacheHttpClient, 'downloadCache')
|
const downloadCacheMock = jest.spyOn(cacheHttpClient, 'downloadCache')
|
||||||
|
|
||||||
const fileSize = 142
|
const fileSize = 142
|
||||||
const getArchiveFileSizeInBytesMock = jest
|
const getArchiveFileSizeIsBytesMock = jest
|
||||||
.spyOn(cacheUtils, 'getArchiveFileSizeInBytes')
|
.spyOn(cacheUtils, 'getArchiveFileSizeIsBytes')
|
||||||
.mockReturnValue(fileSize)
|
.mockReturnValue(fileSize)
|
||||||
|
|
||||||
const extractTarMock = jest.spyOn(tar, 'extractTar')
|
const extractTarMock = jest.spyOn(tar, 'extractTar')
|
||||||
@@ -147,7 +147,7 @@ test('restore with gzip compressed cache found', async () => {
|
|||||||
archivePath,
|
archivePath,
|
||||||
undefined
|
undefined
|
||||||
)
|
)
|
||||||
expect(getArchiveFileSizeInBytesMock).toHaveBeenCalledWith(archivePath)
|
expect(getArchiveFileSizeIsBytesMock).toHaveBeenCalledWith(archivePath)
|
||||||
|
|
||||||
expect(extractTarMock).toHaveBeenCalledTimes(1)
|
expect(extractTarMock).toHaveBeenCalledTimes(1)
|
||||||
expect(extractTarMock).toHaveBeenCalledWith(archivePath, compression)
|
expect(extractTarMock).toHaveBeenCalledWith(archivePath, compression)
|
||||||
@@ -184,8 +184,8 @@ test('restore with zstd compressed cache found', async () => {
|
|||||||
const downloadCacheMock = jest.spyOn(cacheHttpClient, 'downloadCache')
|
const downloadCacheMock = jest.spyOn(cacheHttpClient, 'downloadCache')
|
||||||
|
|
||||||
const fileSize = 62915000
|
const fileSize = 62915000
|
||||||
const getArchiveFileSizeInBytesMock = jest
|
const getArchiveFileSizeIsBytesMock = jest
|
||||||
.spyOn(cacheUtils, 'getArchiveFileSizeInBytes')
|
.spyOn(cacheUtils, 'getArchiveFileSizeIsBytes')
|
||||||
.mockReturnValue(fileSize)
|
.mockReturnValue(fileSize)
|
||||||
|
|
||||||
const extractTarMock = jest.spyOn(tar, 'extractTar')
|
const extractTarMock = jest.spyOn(tar, 'extractTar')
|
||||||
@@ -206,7 +206,7 @@ test('restore with zstd compressed cache found', async () => {
|
|||||||
archivePath,
|
archivePath,
|
||||||
undefined
|
undefined
|
||||||
)
|
)
|
||||||
expect(getArchiveFileSizeInBytesMock).toHaveBeenCalledWith(archivePath)
|
expect(getArchiveFileSizeIsBytesMock).toHaveBeenCalledWith(archivePath)
|
||||||
expect(infoMock).toHaveBeenCalledWith(`Cache Size: ~60 MB (62915000 B)`)
|
expect(infoMock).toHaveBeenCalledWith(`Cache Size: ~60 MB (62915000 B)`)
|
||||||
|
|
||||||
expect(extractTarMock).toHaveBeenCalledTimes(1)
|
expect(extractTarMock).toHaveBeenCalledTimes(1)
|
||||||
@@ -241,8 +241,8 @@ test('restore with cache found for restore key', async () => {
|
|||||||
const downloadCacheMock = jest.spyOn(cacheHttpClient, 'downloadCache')
|
const downloadCacheMock = jest.spyOn(cacheHttpClient, 'downloadCache')
|
||||||
|
|
||||||
const fileSize = 142
|
const fileSize = 142
|
||||||
const getArchiveFileSizeInBytesMock = jest
|
const getArchiveFileSizeIsBytesMock = jest
|
||||||
.spyOn(cacheUtils, 'getArchiveFileSizeInBytes')
|
.spyOn(cacheUtils, 'getArchiveFileSizeIsBytes')
|
||||||
.mockReturnValue(fileSize)
|
.mockReturnValue(fileSize)
|
||||||
|
|
||||||
const extractTarMock = jest.spyOn(tar, 'extractTar')
|
const extractTarMock = jest.spyOn(tar, 'extractTar')
|
||||||
@@ -263,7 +263,7 @@ test('restore with cache found for restore key', async () => {
|
|||||||
archivePath,
|
archivePath,
|
||||||
undefined
|
undefined
|
||||||
)
|
)
|
||||||
expect(getArchiveFileSizeInBytesMock).toHaveBeenCalledWith(archivePath)
|
expect(getArchiveFileSizeIsBytesMock).toHaveBeenCalledWith(archivePath)
|
||||||
expect(infoMock).toHaveBeenCalledWith(`Cache Size: ~0 MB (142 B)`)
|
expect(infoMock).toHaveBeenCalledWith(`Cache Size: ~0 MB (142 B)`)
|
||||||
|
|
||||||
expect(extractTarMock).toHaveBeenCalledTimes(1)
|
expect(extractTarMock).toHaveBeenCalledTimes(1)
|
||||||
|
|||||||
+1
-1
@@ -49,7 +49,7 @@ test('save with large cache outputs should fail', async () => {
|
|||||||
|
|
||||||
const cacheSize = 6 * 1024 * 1024 * 1024 //~6GB, over the 5GB limit
|
const cacheSize = 6 * 1024 * 1024 * 1024 //~6GB, over the 5GB limit
|
||||||
jest
|
jest
|
||||||
.spyOn(cacheUtils, 'getArchiveFileSizeInBytes')
|
.spyOn(cacheUtils, 'getArchiveFileSizeIsBytes')
|
||||||
.mockReturnValueOnce(cacheSize)
|
.mockReturnValueOnce(cacheSize)
|
||||||
const compression = CompressionMethod.Gzip
|
const compression = CompressionMethod.Gzip
|
||||||
const getCompressionMock = jest
|
const getCompressionMock = jest
|
||||||
|
|||||||
Vendored
+7
-16
@@ -11,7 +11,6 @@ jest.mock('@actions/exec')
|
|||||||
jest.mock('@actions/io')
|
jest.mock('@actions/io')
|
||||||
|
|
||||||
const IS_WINDOWS = process.platform === 'win32'
|
const IS_WINDOWS = process.platform === 'win32'
|
||||||
const IS_MAC = process.platform === 'darwin'
|
|
||||||
|
|
||||||
const defaultTarPath = process.platform === 'darwin' ? 'gtar' : 'tar'
|
const defaultTarPath = process.platform === 'darwin' ? 'gtar' : 'tar'
|
||||||
|
|
||||||
@@ -56,9 +55,7 @@ test('zstd extract tar', async () => {
|
|||||||
'-P',
|
'-P',
|
||||||
'-C',
|
'-C',
|
||||||
IS_WINDOWS ? workspace?.replace(/\\/g, '/') : workspace
|
IS_WINDOWS ? workspace?.replace(/\\/g, '/') : workspace
|
||||||
]
|
].concat(IS_WINDOWS ? ['--force-local'] : []),
|
||||||
.concat(IS_WINDOWS ? ['--force-local'] : [])
|
|
||||||
.concat(IS_MAC ? ['--delay-directory-restore'] : []),
|
|
||||||
{cwd: undefined}
|
{cwd: undefined}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -87,7 +84,7 @@ test('gzip extract tar', async () => {
|
|||||||
'-P',
|
'-P',
|
||||||
'-C',
|
'-C',
|
||||||
IS_WINDOWS ? workspace?.replace(/\\/g, '/') : workspace
|
IS_WINDOWS ? workspace?.replace(/\\/g, '/') : workspace
|
||||||
].concat(IS_MAC ? ['--delay-directory-restore'] : []),
|
],
|
||||||
{cwd: undefined}
|
{cwd: undefined}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -148,9 +145,7 @@ test('zstd create tar', async () => {
|
|||||||
IS_WINDOWS ? workspace?.replace(/\\/g, '/') : workspace,
|
IS_WINDOWS ? workspace?.replace(/\\/g, '/') : workspace,
|
||||||
'--files-from',
|
'--files-from',
|
||||||
'manifest.txt'
|
'manifest.txt'
|
||||||
]
|
].concat(IS_WINDOWS ? ['--force-local'] : []),
|
||||||
.concat(IS_WINDOWS ? ['--force-local'] : [])
|
|
||||||
.concat(IS_MAC ? ['--delay-directory-restore'] : []),
|
|
||||||
{
|
{
|
||||||
cwd: archiveFolder
|
cwd: archiveFolder
|
||||||
}
|
}
|
||||||
@@ -185,7 +180,7 @@ test('gzip create tar', async () => {
|
|||||||
IS_WINDOWS ? workspace?.replace(/\\/g, '/') : workspace,
|
IS_WINDOWS ? workspace?.replace(/\\/g, '/') : workspace,
|
||||||
'--files-from',
|
'--files-from',
|
||||||
'manifest.txt'
|
'manifest.txt'
|
||||||
].concat(IS_MAC ? ['--delay-directory-restore'] : []),
|
],
|
||||||
{
|
{
|
||||||
cwd: archiveFolder
|
cwd: archiveFolder
|
||||||
}
|
}
|
||||||
@@ -210,9 +205,7 @@ test('zstd list tar', async () => {
|
|||||||
'-tf',
|
'-tf',
|
||||||
IS_WINDOWS ? archivePath.replace(/\\/g, '/') : archivePath,
|
IS_WINDOWS ? archivePath.replace(/\\/g, '/') : archivePath,
|
||||||
'-P'
|
'-P'
|
||||||
]
|
].concat(IS_WINDOWS ? ['--force-local'] : []),
|
||||||
.concat(IS_WINDOWS ? ['--force-local'] : [])
|
|
||||||
.concat(IS_MAC ? ['--delay-directory-restore'] : []),
|
|
||||||
{cwd: undefined}
|
{cwd: undefined}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -235,9 +228,7 @@ test('zstdWithoutLong list tar', async () => {
|
|||||||
'-tf',
|
'-tf',
|
||||||
IS_WINDOWS ? archivePath.replace(/\\/g, '/') : archivePath,
|
IS_WINDOWS ? archivePath.replace(/\\/g, '/') : archivePath,
|
||||||
'-P'
|
'-P'
|
||||||
]
|
].concat(IS_WINDOWS ? ['--force-local'] : []),
|
||||||
.concat(IS_WINDOWS ? ['--force-local'] : [])
|
|
||||||
.concat(IS_MAC ? ['--delay-directory-restore'] : []),
|
|
||||||
{cwd: undefined}
|
{cwd: undefined}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -261,7 +252,7 @@ test('gzip list tar', async () => {
|
|||||||
'-tf',
|
'-tf',
|
||||||
IS_WINDOWS ? archivePath.replace(/\\/g, '/') : archivePath,
|
IS_WINDOWS ? archivePath.replace(/\\/g, '/') : archivePath,
|
||||||
'-P'
|
'-P'
|
||||||
].concat(IS_MAC ? ['--delay-directory-restore'] : []),
|
],
|
||||||
{cwd: undefined}
|
{cwd: undefined}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
+7
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@actions/cache",
|
"name": "@actions/cache",
|
||||||
"version": "1.0.7",
|
"version": "1.0.6",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -4199,6 +4199,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
|
||||||
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
|
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
|
||||||
},
|
},
|
||||||
|
"y18n": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w=="
|
||||||
|
},
|
||||||
"yargs": {
|
"yargs": {
|
||||||
"version": "15.3.1",
|
"version": "15.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz",
|
||||||
@@ -4213,6 +4218,7 @@
|
|||||||
"set-blocking": "^2.0.0",
|
"set-blocking": "^2.0.0",
|
||||||
"string-width": "^4.2.0",
|
"string-width": "^4.2.0",
|
||||||
"which-module": "^2.0.0",
|
"which-module": "^2.0.0",
|
||||||
|
"y18n": "^4.0.0",
|
||||||
"yargs-parser": "^18.1.1"
|
"yargs-parser": "^18.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@actions/cache",
|
"name": "@actions/cache",
|
||||||
"version": "1.0.7",
|
"version": "1.0.6",
|
||||||
"preview": true,
|
"preview": true,
|
||||||
"description": "Actions cache lib",
|
"description": "Actions cache lib",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
|||||||
Vendored
+2
-2
@@ -104,7 +104,7 @@ export async function restoreCache(
|
|||||||
await listTar(archivePath, compressionMethod)
|
await listTar(archivePath, compressionMethod)
|
||||||
}
|
}
|
||||||
|
|
||||||
const archiveFileSize = utils.getArchiveFileSizeInBytes(archivePath)
|
const archiveFileSize = utils.getArchiveFileSizeIsBytes(archivePath)
|
||||||
core.info(
|
core.info(
|
||||||
`Cache Size: ~${Math.round(
|
`Cache Size: ~${Math.round(
|
||||||
archiveFileSize / (1024 * 1024)
|
archiveFileSize / (1024 * 1024)
|
||||||
@@ -172,7 +172,7 @@ export async function saveCache(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const fileSizeLimit = 5 * 1024 * 1024 * 1024 // 5GB per repo limit
|
const fileSizeLimit = 5 * 1024 * 1024 * 1024 // 5GB per repo limit
|
||||||
const archiveFileSize = utils.getArchiveFileSizeInBytes(archivePath)
|
const archiveFileSize = utils.getArchiveFileSizeIsBytes(archivePath)
|
||||||
core.debug(`File Size: ${archiveFileSize}`)
|
core.debug(`File Size: ${archiveFileSize}`)
|
||||||
if (archiveFileSize > fileSizeLimit) {
|
if (archiveFileSize > fileSizeLimit) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
|||||||
+2
-2
@@ -219,7 +219,7 @@ async function uploadFile(
|
|||||||
options?: UploadOptions
|
options?: UploadOptions
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
// Upload Chunks
|
// Upload Chunks
|
||||||
const fileSize = utils.getArchiveFileSizeInBytes(archivePath)
|
const fileSize = fs.statSync(archivePath).size
|
||||||
const resourceUrl = getCacheApiUrl(`caches/${cacheId.toString()}`)
|
const resourceUrl = getCacheApiUrl(`caches/${cacheId.toString()}`)
|
||||||
const fd = fs.openSync(archivePath, 'r')
|
const fd = fs.openSync(archivePath, 'r')
|
||||||
const uploadOptions = getUploadOptions(options)
|
const uploadOptions = getUploadOptions(options)
|
||||||
@@ -300,7 +300,7 @@ export async function saveCache(
|
|||||||
|
|
||||||
// Commit Cache
|
// Commit Cache
|
||||||
core.debug('Commiting cache')
|
core.debug('Commiting cache')
|
||||||
const cacheSize = utils.getArchiveFileSizeInBytes(archivePath)
|
const cacheSize = utils.getArchiveFileSizeIsBytes(archivePath)
|
||||||
core.info(
|
core.info(
|
||||||
`Cache Size: ~${Math.round(cacheSize / (1024 * 1024))} MB (${cacheSize} B)`
|
`Cache Size: ~${Math.round(cacheSize / (1024 * 1024))} MB (${cacheSize} B)`
|
||||||
)
|
)
|
||||||
|
|||||||
+1
-1
@@ -35,7 +35,7 @@ export async function createTempDirectory(): Promise<string> {
|
|||||||
return dest
|
return dest
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getArchiveFileSizeInBytes(filePath: string): number {
|
export function getArchiveFileSizeIsBytes(filePath: string): number {
|
||||||
return fs.statSync(filePath).size
|
return fs.statSync(filePath).size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -190,7 +190,7 @@ export async function downloadCacheHttpClient(
|
|||||||
|
|
||||||
if (contentLengthHeader) {
|
if (contentLengthHeader) {
|
||||||
const expectedLength = parseInt(contentLengthHeader)
|
const expectedLength = parseInt(contentLengthHeader)
|
||||||
const actualLength = utils.getArchiveFileSizeInBytes(archivePath)
|
const actualLength = utils.getArchiveFileSizeIsBytes(archivePath)
|
||||||
|
|
||||||
if (actualLength !== expectedLength) {
|
if (actualLength !== expectedLength) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
|||||||
Vendored
-2
@@ -26,8 +26,6 @@ async function getTarPath(
|
|||||||
case 'darwin': {
|
case 'darwin': {
|
||||||
const gnuTar = await io.which('gtar', false)
|
const gnuTar = await io.which('gtar', false)
|
||||||
if (gnuTar) {
|
if (gnuTar) {
|
||||||
// fix permission denied errors when extracting BSD tar archive with GNU tar - https://github.com/actions/cache/issues/527
|
|
||||||
args.push('--delay-directory-restore')
|
|
||||||
return gnuTar
|
return gnuTar
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
|||||||
+6
-12
@@ -16,13 +16,11 @@ import * as core from '@actions/core';
|
|||||||
|
|
||||||
#### Inputs/Outputs
|
#### Inputs/Outputs
|
||||||
|
|
||||||
Action inputs can be read with `getInput` which returns a `string` or `getBooleanInput` which parses a boolean based on the [yaml 1.2 specification](https://yaml.org/spec/1.2/spec.html#id2804923). If `required` set to be false, the input should have a default value in `action.yml`.
|
Action inputs can be read with `getInput`. Outputs can be set with `setOutput` which makes them available to be mapped into inputs of other actions to ensure they are decoupled.
|
||||||
|
|
||||||
Outputs can be set with `setOutput` which makes them available to be mapped into inputs of other actions to ensure they are decoupled.
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const myInput = core.getInput('inputName', { required: true });
|
const myInput = core.getInput('inputName', { required: true });
|
||||||
const myBooleanInput = core.getBooleanInput('booleanInputName', { required: true });
|
|
||||||
core.setOutput('outputKey', 'outputVal');
|
core.setOutput('outputKey', 'outputVal');
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -64,10 +62,11 @@ catch (err) {
|
|||||||
// setFailed logs the message and sets a failing exit code
|
// setFailed logs the message and sets a failing exit code
|
||||||
core.setFailed(`Action failed with error ${err}`);
|
core.setFailed(`Action failed with error ${err}`);
|
||||||
}
|
}
|
||||||
```
|
|
||||||
|
|
||||||
Note that `setNeutral` is not yet implemented in actions V2 but equivalent functionality is being planned.
|
Note that `setNeutral` is not yet implemented in actions V2 but equivalent functionality is being planned.
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
#### Logging
|
#### Logging
|
||||||
|
|
||||||
Finally, this library provides some utilities for logging. Note that debug logging is hidden from the logs by default. This behavior can be toggled by enabling the [Step Debug Logs](../../docs/action-debugging.md#step-debug-logs).
|
Finally, this library provides some utilities for logging. Note that debug logging is hidden from the logs by default. This behavior can be toggled by enabling the [Step Debug Logs](../../docs/action-debugging.md#step-debug-logs).
|
||||||
@@ -119,7 +118,6 @@ const result = await core.group('Do something async', async () => {
|
|||||||
Colored output is supported in the Action logs via standard [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code). 3/4 bit, 8 bit and 24 bit colors are all supported.
|
Colored output is supported in the Action logs via standard [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code). 3/4 bit, 8 bit and 24 bit colors are all supported.
|
||||||
|
|
||||||
Foreground colors:
|
Foreground colors:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// 3/4 bit
|
// 3/4 bit
|
||||||
core.info('\u001b[35mThis foreground will be magenta')
|
core.info('\u001b[35mThis foreground will be magenta')
|
||||||
@@ -132,7 +130,6 @@ core.info('\u001b[38;2;255;0;0mThis foreground will be bright red')
|
|||||||
```
|
```
|
||||||
|
|
||||||
Background colors:
|
Background colors:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// 3/4 bit
|
// 3/4 bit
|
||||||
core.info('\u001b[43mThis background will be yellow');
|
core.info('\u001b[43mThis background will be yellow');
|
||||||
@@ -159,7 +156,6 @@ core.info('\u001b[31;46mRed foreground with a cyan background and \u001b[1mbold
|
|||||||
```
|
```
|
||||||
|
|
||||||
> Note: Escape codes reset at the start of each line
|
> Note: Escape codes reset at the start of each line
|
||||||
|
|
||||||
```js
|
```js
|
||||||
core.info('\u001b[35mThis foreground will be magenta')
|
core.info('\u001b[35mThis foreground will be magenta')
|
||||||
core.info('This foreground will reset to the default')
|
core.info('This foreground will reset to the default')
|
||||||
@@ -174,10 +170,9 @@ core.info(style.color.ansi16m.hex('#abcdef') + 'Hello world!')
|
|||||||
|
|
||||||
#### Action state
|
#### Action state
|
||||||
|
|
||||||
You can use this library to save state and get state for sharing information between a given wrapper action:
|
You can use this library to save state and get state for sharing information between a given wrapper action:
|
||||||
|
|
||||||
**action.yml**:
|
|
||||||
|
|
||||||
|
**action.yml**
|
||||||
```yaml
|
```yaml
|
||||||
name: 'Wrapper action sample'
|
name: 'Wrapper action sample'
|
||||||
inputs:
|
inputs:
|
||||||
@@ -198,7 +193,6 @@ core.saveState("pidToKill", 12345);
|
|||||||
```
|
```
|
||||||
|
|
||||||
In action's `cleanup.js`:
|
In action's `cleanup.js`:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const core = require('@actions/core');
|
const core = require('@actions/core');
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
# @actions/core Releases
|
# @actions/core Releases
|
||||||
|
|
||||||
### 1.2.7
|
|
||||||
- [Prepend newline for set-output](https://github.com/actions/toolkit/pull/772)
|
|
||||||
|
|
||||||
### 1.2.6
|
### 1.2.6
|
||||||
- [Update `exportVariable` and `addPath` to use environment files](https://github.com/actions/toolkit/pull/571)
|
- [Update `exportVariable` and `addPath` to use environment files](https://github.com/actions/toolkit/pull/571)
|
||||||
|
|
||||||
|
|||||||
@@ -19,14 +19,6 @@ const testEnvVars = {
|
|||||||
INPUT_MISSING: '',
|
INPUT_MISSING: '',
|
||||||
'INPUT_SPECIAL_CHARS_\'\t"\\': '\'\t"\\ response ',
|
'INPUT_SPECIAL_CHARS_\'\t"\\': '\'\t"\\ response ',
|
||||||
INPUT_MULTIPLE_SPACES_VARIABLE: 'I have multiple spaces',
|
INPUT_MULTIPLE_SPACES_VARIABLE: 'I have multiple spaces',
|
||||||
INPUT_BOOLEAN_INPUT: 'true',
|
|
||||||
INPUT_BOOLEAN_INPUT_TRUE1: 'true',
|
|
||||||
INPUT_BOOLEAN_INPUT_TRUE2: 'True',
|
|
||||||
INPUT_BOOLEAN_INPUT_TRUE3: 'TRUE',
|
|
||||||
INPUT_BOOLEAN_INPUT_FALSE1: 'false',
|
|
||||||
INPUT_BOOLEAN_INPUT_FALSE2: 'False',
|
|
||||||
INPUT_BOOLEAN_INPUT_FALSE3: 'FALSE',
|
|
||||||
INPUT_WRONG_BOOLEAN_INPUT: 'wrong',
|
|
||||||
|
|
||||||
// Save inputs
|
// Save inputs
|
||||||
STATE_TEST_1: 'state_val',
|
STATE_TEST_1: 'state_val',
|
||||||
@@ -165,46 +157,19 @@ describe('@actions/core', () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('getInput gets non-required boolean input', () => {
|
|
||||||
expect(core.getBooleanInput('boolean input')).toBe(true)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('getInput gets required input', () => {
|
|
||||||
expect(core.getBooleanInput('boolean input', {required: true})).toBe(true)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('getBooleanInput handles boolean input', () => {
|
|
||||||
expect(core.getBooleanInput('boolean input true1')).toBe(true)
|
|
||||||
expect(core.getBooleanInput('boolean input true2')).toBe(true)
|
|
||||||
expect(core.getBooleanInput('boolean input true3')).toBe(true)
|
|
||||||
expect(core.getBooleanInput('boolean input false1')).toBe(false)
|
|
||||||
expect(core.getBooleanInput('boolean input false2')).toBe(false)
|
|
||||||
expect(core.getBooleanInput('boolean input false3')).toBe(false)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('getBooleanInput handles wrong boolean input', () => {
|
|
||||||
expect(() => core.getBooleanInput('wrong boolean input')).toThrow(
|
|
||||||
'Input does not meet YAML 1.2 "Core Schema" specification: wrong boolean input\n' +
|
|
||||||
`Support boolean input list: \`true | True | TRUE | false | False | FALSE\``
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('setOutput produces the correct command', () => {
|
it('setOutput produces the correct command', () => {
|
||||||
core.setOutput('some output', 'some value')
|
core.setOutput('some output', 'some value')
|
||||||
assertWriteCalls([
|
assertWriteCalls([`::set-output name=some output::some value${os.EOL}`])
|
||||||
os.EOL,
|
|
||||||
`::set-output name=some output::some value${os.EOL}`
|
|
||||||
])
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('setOutput handles bools', () => {
|
it('setOutput handles bools', () => {
|
||||||
core.setOutput('some output', false)
|
core.setOutput('some output', false)
|
||||||
assertWriteCalls([os.EOL, `::set-output name=some output::false${os.EOL}`])
|
assertWriteCalls([`::set-output name=some output::false${os.EOL}`])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('setOutput handles numbers', () => {
|
it('setOutput handles numbers', () => {
|
||||||
core.setOutput('some output', 1.01)
|
core.setOutput('some output', 1.01)
|
||||||
assertWriteCalls([os.EOL, `::set-output name=some output::1.01${os.EOL}`])
|
assertWriteCalls([`::set-output name=some output::1.01${os.EOL}`])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('setFailed sets the correct exit code and failure message', () => {
|
it('setFailed sets the correct exit code and failure message', () => {
|
||||||
|
|||||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@actions/core",
|
"name": "@actions/core",
|
||||||
"version": "1.2.7",
|
"version": "1.2.6",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@actions/core",
|
"name": "@actions/core",
|
||||||
"version": "1.2.7",
|
"version": "1.2.6",
|
||||||
"description": "Actions core lib",
|
"description": "Actions core lib",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"github",
|
"github",
|
||||||
|
|||||||
@@ -91,28 +91,6 @@ export function getInput(name: string, options?: InputOptions): string {
|
|||||||
return val.trim()
|
return val.trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the input value of the boolean type in the YAML 1.2 "core schema" specification.
|
|
||||||
* Support boolean input list: `true | True | TRUE | false | False | FALSE` .
|
|
||||||
* The return value is also in boolean type.
|
|
||||||
* ref: https://yaml.org/spec/1.2/spec.html#id2804923
|
|
||||||
*
|
|
||||||
* @param name name of the input to get
|
|
||||||
* @param options optional. See InputOptions.
|
|
||||||
* @returns boolean
|
|
||||||
*/
|
|
||||||
export function getBooleanInput(name: string, options?: InputOptions): boolean {
|
|
||||||
const trueValue = ['true', 'True', 'TRUE']
|
|
||||||
const falseValue = ['false', 'False', 'FALSE']
|
|
||||||
const val = getInput(name, options)
|
|
||||||
if (trueValue.includes(val)) return true
|
|
||||||
if (falseValue.includes(val)) return false
|
|
||||||
throw new TypeError(
|
|
||||||
`Input does not meet YAML 1.2 "Core Schema" specification: ${name}\n` +
|
|
||||||
`Support boolean input list: \`true | True | TRUE | false | False | FALSE\``
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the value of an output.
|
* Sets the value of an output.
|
||||||
*
|
*
|
||||||
@@ -121,7 +99,6 @@ export function getBooleanInput(name: string, options?: InputOptions): boolean {
|
|||||||
*/
|
*/
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
export function setOutput(name: string, value: any): void {
|
export function setOutput(name: string, value: any): void {
|
||||||
process.stdout.write(os.EOL)
|
|
||||||
issueCommand('set-output', {name}, value)
|
issueCommand('set-output', {name}, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import * as exec from '../src/exec'
|
import * as exec from '../src/exec'
|
||||||
import * as tr from '../src/toolrunner'
|
|
||||||
import * as im from '../src/interfaces'
|
import * as im from '../src/interfaces'
|
||||||
|
|
||||||
import * as childProcess from 'child_process'
|
import * as childProcess from 'child_process'
|
||||||
@@ -621,14 +620,6 @@ describe('@actions/exec', () => {
|
|||||||
expect(output.trim()).toBe(`args[0]: "hello"${os.EOL}args[1]: "world"`)
|
expect(output.trim()).toBe(`args[0]: "hello"${os.EOL}args[1]: "world"`)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('tool runner strips INPUT_ params from environment for child process', () => {
|
|
||||||
const env = {INPUT_TEST: 'input value', SOME_OTHER_ENV: 'some other value'}
|
|
||||||
const sanitizedEnv = tr.stripInputEnvironmentVariables(env)
|
|
||||||
|
|
||||||
expect(sanitizedEnv).not.toHaveProperty('INPUT_TEST')
|
|
||||||
expect(sanitizedEnv).toHaveProperty('SOME_OTHER_ENV')
|
|
||||||
})
|
|
||||||
|
|
||||||
if (IS_WINDOWS) {
|
if (IS_WINDOWS) {
|
||||||
it('Exec roots relative tool path using process.cwd (Windows path separator)', async () => {
|
it('Exec roots relative tool path using process.cwd (Windows path separator)', async () => {
|
||||||
let exitCode: number
|
let exitCode: number
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ export interface ExecOptions {
|
|||||||
/** optional working directory. defaults to current */
|
/** optional working directory. defaults to current */
|
||||||
cwd?: string
|
cwd?: string
|
||||||
|
|
||||||
/** optional envvar dictionary. defaults to current process's env with `INPUT_*` variables removed */
|
/** optional envvar dictionary. defaults to current process's env */
|
||||||
env?: {[key: string]: string}
|
env?: {[key: string]: string}
|
||||||
|
|
||||||
/** optional. defaults to false */
|
/** optional. defaults to false */
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import * as stream from 'stream'
|
|||||||
import * as im from './interfaces'
|
import * as im from './interfaces'
|
||||||
import * as io from '@actions/io'
|
import * as io from '@actions/io'
|
||||||
import * as ioUtil from '@actions/io/lib/io-util'
|
import * as ioUtil from '@actions/io/lib/io-util'
|
||||||
import {setTimeout} from 'timers'
|
|
||||||
|
|
||||||
/* eslint-disable @typescript-eslint/unbound-method */
|
/* eslint-disable @typescript-eslint/unbound-method */
|
||||||
|
|
||||||
@@ -377,7 +376,7 @@ export class ToolRunner extends events.EventEmitter {
|
|||||||
options = options || <im.ExecOptions>{}
|
options = options || <im.ExecOptions>{}
|
||||||
const result = <child.SpawnOptions>{}
|
const result = <child.SpawnOptions>{}
|
||||||
result.cwd = options.cwd
|
result.cwd = options.cwd
|
||||||
result.env = options.env || stripInputEnvironmentVariables(process.env)
|
result.env = options.env
|
||||||
result['windowsVerbatimArguments'] =
|
result['windowsVerbatimArguments'] =
|
||||||
options.windowsVerbatimArguments || this._isCmdFile()
|
options.windowsVerbatimArguments || this._isCmdFile()
|
||||||
if (options.windowsVerbatimArguments) {
|
if (options.windowsVerbatimArguments) {
|
||||||
@@ -600,20 +599,6 @@ export function argStringToArray(argString: string): string[] {
|
|||||||
return args
|
return args
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strips INPUT_ environment variables to prevent them leaking to child processes
|
|
||||||
export function stripInputEnvironmentVariables(
|
|
||||||
env: NodeJS.ProcessEnv
|
|
||||||
): NodeJS.ProcessEnv {
|
|
||||||
return Object.entries(env)
|
|
||||||
.filter(([key]) => {
|
|
||||||
return !key.startsWith('INPUT_')
|
|
||||||
})
|
|
||||||
.reduce((obj: NodeJS.ProcessEnv, [key, value]) => {
|
|
||||||
obj[key] = value
|
|
||||||
return obj
|
|
||||||
}, {})
|
|
||||||
}
|
|
||||||
|
|
||||||
class ExecState extends events.EventEmitter {
|
class ExecState extends events.EventEmitter {
|
||||||
constructor(options: im.ExecOptions, toolPath: string) {
|
constructor(options: im.ExecOptions, toolPath: string) {
|
||||||
super()
|
super()
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ async function run() {
|
|||||||
// You can also pass in additional options as a second parameter to getOctokit
|
// You can also pass in additional options as a second parameter to getOctokit
|
||||||
// const octokit = github.getOctokit(myToken, {userAgent: "MyActionVersion1"});
|
// const octokit = github.getOctokit(myToken, {userAgent: "MyActionVersion1"});
|
||||||
|
|
||||||
const { data: pullRequest } = await octokit.rest.pulls.get({
|
const { data: pullRequest } = await octokit.pulls.get({
|
||||||
owner: 'octokit',
|
owner: 'octokit',
|
||||||
repo: 'rest.js',
|
repo: 'rest.js',
|
||||||
pull_number: 123,
|
pull_number: 123,
|
||||||
@@ -50,7 +50,7 @@ const github = require('@actions/github');
|
|||||||
|
|
||||||
const context = github.context;
|
const context = github.context;
|
||||||
|
|
||||||
const newIssue = await octokit.rest.issues.create({
|
const newIssue = await octokit.issues.create({
|
||||||
...context.repo,
|
...context.repo,
|
||||||
title: 'New issue!',
|
title: 'New issue!',
|
||||||
body: 'Hello Universe!'
|
body: 'Hello Universe!'
|
||||||
@@ -90,7 +90,7 @@ const octokit = GitHub.plugin(enterpriseServer220Admin)
|
|||||||
const myToken = core.getInput('myToken');
|
const myToken = core.getInput('myToken');
|
||||||
const myOctokit = new octokit(getOctokitOptions(token))
|
const myOctokit = new octokit(getOctokitOptions(token))
|
||||||
// Create a new user
|
// Create a new user
|
||||||
myOctokit.rest.enterpriseAdmin.createUser({
|
myOctokit.enterpriseAdmin.createUser({
|
||||||
login: "testuser",
|
login: "testuser",
|
||||||
email: "[email protected]",
|
email: "[email protected]",
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
# @actions/github Releases
|
# @actions/github Releases
|
||||||
|
|
||||||
### 5.0.0
|
|
||||||
- [Update @actions/github to include latest octokit definitions](https://github.com/actions/toolkit/pull/783)
|
|
||||||
|
|
||||||
### 4.0.0
|
### 4.0.0
|
||||||
- [Add execution state information to context](https://github.com/actions/toolkit/pull/499)
|
- [Add execution state information to context](https://github.com/actions/toolkit/pull/499)
|
||||||
- [Update Octokit Dependencies with some api breaking changes](https://github.com/actions/toolkit/pull/498)
|
- [Update Octokit Dependencies with some api breaking changes](https://github.com/actions/toolkit/pull/498)
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ describe('@actions/github', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const octokit = getOctokit(token)
|
const octokit = getOctokit(token)
|
||||||
const branch = await octokit.rest.repos.getBranch({
|
const branch = await octokit.repos.getBranch({
|
||||||
owner: 'actions',
|
owner: 'actions',
|
||||||
repo: 'toolkit',
|
repo: 'toolkit',
|
||||||
branch: 'main'
|
branch: 'main'
|
||||||
@@ -85,7 +85,7 @@ describe('@actions/github', () => {
|
|||||||
agent: new https.Agent()
|
agent: new https.Agent()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const branch = await octokit.rest.repos.getBranch({
|
const branch = await octokit.repos.getBranch({
|
||||||
owner: 'actions',
|
owner: 'actions',
|
||||||
repo: 'toolkit',
|
repo: 'toolkit',
|
||||||
branch: 'main'
|
branch: 'main'
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ describe('@actions/github', () => {
|
|||||||
proxyServer = proxy()
|
proxyServer = proxy()
|
||||||
await new Promise(resolve => {
|
await new Promise(resolve => {
|
||||||
const port = Number(proxyUrl.split(':')[2])
|
const port = Number(proxyUrl.split(':')[2])
|
||||||
proxyServer.listen(port, () => resolve(null))
|
proxyServer.listen(port, () => resolve())
|
||||||
})
|
})
|
||||||
proxyServer.on('connect', req => {
|
proxyServer.on('connect', req => {
|
||||||
proxyConnects.push(req.url)
|
proxyConnects.push(req.url)
|
||||||
@@ -30,7 +30,7 @@ describe('@actions/github', () => {
|
|||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
// Stop proxy server
|
// Stop proxy server
|
||||||
await new Promise(resolve => {
|
await new Promise(resolve => {
|
||||||
proxyServer.once('close', () => resolve(null))
|
proxyServer.once('close', () => resolve())
|
||||||
proxyServer.close()
|
proxyServer.close()
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ describe('@actions/github', () => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
const octokit = new GitHub(getOctokitOptions(token))
|
const octokit = new GitHub(getOctokitOptions(token))
|
||||||
const branch = await octokit.rest.repos.getBranch({
|
const branch = await octokit.repos.getBranch({
|
||||||
owner: 'actions',
|
owner: 'actions',
|
||||||
repo: 'toolkit',
|
repo: 'toolkit',
|
||||||
branch: 'main'
|
branch: 'main'
|
||||||
@@ -60,7 +60,7 @@ describe('@actions/github', () => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
const octokit = getOctokit(token)
|
const octokit = getOctokit(token)
|
||||||
const branch = await octokit.rest.repos.getBranch({
|
const branch = await octokit.repos.getBranch({
|
||||||
owner: 'actions',
|
owner: 'actions',
|
||||||
repo: 'toolkit',
|
repo: 'toolkit',
|
||||||
branch: 'main'
|
branch: 'main'
|
||||||
@@ -77,7 +77,7 @@ describe('@actions/github', () => {
|
|||||||
|
|
||||||
// Valid token
|
// Valid token
|
||||||
let octokit = new GitHub({auth: `token ${token}`})
|
let octokit = new GitHub({auth: `token ${token}`})
|
||||||
const branch = await octokit.rest.repos.getBranch({
|
const branch = await octokit.repos.getBranch({
|
||||||
owner: 'actions',
|
owner: 'actions',
|
||||||
repo: 'toolkit',
|
repo: 'toolkit',
|
||||||
branch: 'main'
|
branch: 'main'
|
||||||
@@ -89,7 +89,7 @@ describe('@actions/github', () => {
|
|||||||
octokit = new GitHub({auth: `token asdf`})
|
octokit = new GitHub({auth: `token asdf`})
|
||||||
let failed = false
|
let failed = false
|
||||||
try {
|
try {
|
||||||
await octokit.rest.repos.getBranch({
|
await octokit.repos.getBranch({
|
||||||
owner: 'actions',
|
owner: 'actions',
|
||||||
repo: 'toolkit',
|
repo: 'toolkit',
|
||||||
branch: 'main'
|
branch: 'main'
|
||||||
|
|||||||
Generated
+26
-24
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@actions/github",
|
"name": "@actions/github",
|
||||||
"version": "5.0.0",
|
"version": "4.0.0",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -465,9 +465,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@octokit/core": {
|
"@octokit/core": {
|
||||||
"version": "3.4.0",
|
"version": "3.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.3.1.tgz",
|
||||||
"integrity": "sha512-6/vlKPP8NF17cgYXqucdshWqmMZGXkuvtcrWCgU5NOI0Pl2GjlmZyWgBMrU8zJ3v2MJlM6++CiB45VKYmhiWWg==",
|
"integrity": "sha512-Dc5NNQOYjgZU5S1goN6A/E500yXOfDUFRGQB8/2Tl16AcfvS3H9PudyOe3ZNE/MaVyHPIfC0htReHMJb1tMrvw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@octokit/auth-token": "^2.4.4",
|
"@octokit/auth-token": "^2.4.4",
|
||||||
"@octokit/graphql": "^4.5.8",
|
"@octokit/graphql": "^4.5.8",
|
||||||
@@ -499,9 +499,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@octokit/openapi-types": {
|
"@octokit/openapi-types": {
|
||||||
"version": "7.0.0",
|
"version": "6.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-7.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-6.0.0.tgz",
|
||||||
"integrity": "sha512-gV/8DJhAL/04zjTI95a7FhQwS6jlEE0W/7xeYAzuArD0KVAVWDLP2f3vi98hs3HLTczxXdRK/mF0tRoQPpolEw=="
|
"integrity": "sha512-CnDdK7ivHkBtJYzWzZm7gEkanA7gKH6a09Eguz7flHw//GacPJLmkHA3f3N++MJmlxD1Fl+mB7B32EEpSCwztQ=="
|
||||||
},
|
},
|
||||||
"@octokit/plugin-paginate-rest": {
|
"@octokit/plugin-paginate-rest": {
|
||||||
"version": "2.13.3",
|
"version": "2.13.3",
|
||||||
@@ -512,24 +512,26 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@octokit/plugin-rest-endpoint-methods": {
|
"@octokit/plugin-rest-endpoint-methods": {
|
||||||
"version": "5.1.1",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.0.0.tgz",
|
||||||
"integrity": "sha512-u4zy0rVA8darm/AYsIeWkRalhQR99qPL1D/EXHejV2yaECMdHfxXiTXtba8NMBSajOJe8+C9g+EqMKSvysx0dg==",
|
"integrity": "sha512-Jc7CLNUueIshXT+HWt6T+M0sySPjF32mSFQAK7UfAg8qGeRI6OM1GSBxDLwbXjkqy2NVdnqCedJcP1nC785JYg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@octokit/types": "^6.14.1",
|
"@octokit/types": "^6.13.0",
|
||||||
"deprecation": "^2.3.1"
|
"deprecation": "^2.3.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@octokit/request": {
|
"@octokit/request": {
|
||||||
"version": "5.4.15",
|
"version": "5.4.14",
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.15.tgz",
|
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.14.tgz",
|
||||||
"integrity": "sha512-6UnZfZzLwNhdLRreOtTkT9n57ZwulCve8q3IT/Z477vThu6snfdkBuhxnChpOKNGxcQ71ow561Qoa6uqLdPtag==",
|
"integrity": "sha512-VkmtacOIQp9daSnBmDI92xNIeLuSRDOIuplp/CJomkvzt7M18NXgG044Cx/LFKLgjKt9T2tZR6AtJayba9GTSA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@octokit/endpoint": "^6.0.1",
|
"@octokit/endpoint": "^6.0.1",
|
||||||
"@octokit/request-error": "^2.0.0",
|
"@octokit/request-error": "^2.0.0",
|
||||||
"@octokit/types": "^6.7.1",
|
"@octokit/types": "^6.7.1",
|
||||||
|
"deprecation": "^2.0.0",
|
||||||
"is-plain-object": "^5.0.0",
|
"is-plain-object": "^5.0.0",
|
||||||
"node-fetch": "^2.6.1",
|
"node-fetch": "^2.6.1",
|
||||||
|
"once": "^1.4.0",
|
||||||
"universal-user-agent": "^6.0.0"
|
"universal-user-agent": "^6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -544,11 +546,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@octokit/types": {
|
"@octokit/types": {
|
||||||
"version": "6.14.2",
|
"version": "6.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.14.2.tgz",
|
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.13.0.tgz",
|
||||||
"integrity": "sha512-wiQtW9ZSy4OvgQ09iQOdyXYNN60GqjCL/UdMsepDr1Gr0QzpW6irIKbH3REuAHXAhxkEk9/F2a3Gcs1P6kW5jA==",
|
"integrity": "sha512-W2J9qlVIU11jMwKHUp5/rbVUeErqelCsO5vW5PKNb7wAXQVUz87Rc+imjlEvpvbH8yUb+KHmv8NEjVZdsdpyxA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@octokit/openapi-types": "^7.0.0"
|
"@octokit/openapi-types": "^6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@sinonjs/commons": {
|
"@sinonjs/commons": {
|
||||||
@@ -1018,9 +1020,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"before-after-hook": {
|
"before-after-hook": {
|
||||||
"version": "2.2.1",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.0.tgz",
|
||||||
"integrity": "sha512-/6FKxSTWoJdbsLDF8tdIjaRiFXiE6UHsEHE3OPI/cwPURCVi1ukP0gmLn7XWEiFk5TcwQjjY5PWsU+j+tgXgmw=="
|
"integrity": "sha512-jH6rKQIfroBbhEXVmI7XmXe3ix5S/PgJqpzdDPnR8JGLHWNYLsYZ6tK5iWOF/Ra3oqEX0NobXGlzbiylIzVphQ=="
|
||||||
},
|
},
|
||||||
"brace-expansion": {
|
"brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
@@ -4781,9 +4783,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"y18n": {
|
"y18n": {
|
||||||
"version": "4.0.1",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
|
||||||
"integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==",
|
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"yargs": {
|
"yargs": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@actions/github",
|
"name": "@actions/github",
|
||||||
"version": "5.0.0",
|
"version": "4.0.0",
|
||||||
"description": "Actions github lib",
|
"description": "Actions github lib",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"github",
|
"github",
|
||||||
@@ -39,9 +39,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/http-client": "^1.0.11",
|
"@actions/http-client": "^1.0.11",
|
||||||
"@octokit/core": "^3.4.0",
|
"@octokit/core": "^3.3.1",
|
||||||
"@octokit/plugin-paginate-rest": "^2.13.3",
|
"@octokit/plugin-paginate-rest": "^2.13.3",
|
||||||
"@octokit/plugin-rest-endpoint-methods": "^5.1.1"
|
"@octokit/plugin-rest-endpoint-methods": "^5.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"jest": "^25.1.0",
|
"jest": "^25.1.0",
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
# @actions/io Releases
|
# @actions/io Releases
|
||||||
|
|
||||||
### 1.1.0
|
|
||||||
|
|
||||||
- Add `findInPath` method to locate all matching executables in the system path
|
|
||||||
|
|
||||||
### 1.0.2
|
### 1.0.2
|
||||||
|
|
||||||
- [Add \"types\" to package.json](https://github.com/actions/toolkit/pull/221)
|
- [Add \"types\" to package.json](https://github.com/actions/toolkit/pull/221)
|
||||||
|
|
||||||
### 1.0.0
|
### 1.0.0
|
||||||
|
|
||||||
- Initial release
|
- Initial release
|
||||||
@@ -3,12 +3,9 @@ import {promises as fs} from 'fs'
|
|||||||
import * as os from 'os'
|
import * as os from 'os'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
import * as io from '../src/io'
|
import * as io from '../src/io'
|
||||||
|
import * as ioUtil from '../src/io-util'
|
||||||
|
|
||||||
describe('cp', () => {
|
describe('cp', () => {
|
||||||
beforeAll(async () => {
|
|
||||||
await io.rmRF(getTestTemp())
|
|
||||||
})
|
|
||||||
|
|
||||||
it('copies file with no flags', async () => {
|
it('copies file with no flags', async () => {
|
||||||
const root = path.join(getTestTemp(), 'cp_with_no_flags')
|
const root = path.join(getTestTemp(), 'cp_with_no_flags')
|
||||||
const sourceFile = path.join(root, 'cp_source')
|
const sourceFile = path.join(root, 'cp_source')
|
||||||
@@ -90,29 +87,6 @@ describe('cp', () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('copies directory into existing destination with -r without copying source directory', async () => {
|
|
||||||
const root: string = path.join(
|
|
||||||
getTestTemp(),
|
|
||||||
'cp_with_-r_existing_dest_no_source_dir'
|
|
||||||
)
|
|
||||||
const sourceFolder: string = path.join(root, 'cp_source')
|
|
||||||
const sourceFile: string = path.join(sourceFolder, 'cp_source_file')
|
|
||||||
|
|
||||||
const targetFolder: string = path.join(root, 'cp_target')
|
|
||||||
const targetFile: string = path.join(targetFolder, 'cp_source_file')
|
|
||||||
await io.mkdirP(sourceFolder)
|
|
||||||
await fs.writeFile(sourceFile, 'test file content', {encoding: 'utf8'})
|
|
||||||
await io.mkdirP(targetFolder)
|
|
||||||
await io.cp(sourceFolder, targetFolder, {
|
|
||||||
recursive: true,
|
|
||||||
copySourceDirectory: false
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(await fs.readFile(targetFile, {encoding: 'utf8'})).toBe(
|
|
||||||
'test file content'
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('copies directory into non-existing destination with -r', async () => {
|
it('copies directory into non-existing destination with -r', async () => {
|
||||||
const root: string = path.join(getTestTemp(), 'cp_with_-r_nonexistent_dest')
|
const root: string = path.join(getTestTemp(), 'cp_with_-r_nonexistent_dest')
|
||||||
const sourceFolder: string = path.join(root, 'cp_source')
|
const sourceFolder: string = path.join(root, 'cp_source')
|
||||||
@@ -192,10 +166,6 @@ describe('cp', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe('mv', () => {
|
describe('mv', () => {
|
||||||
beforeAll(async () => {
|
|
||||||
await io.rmRF(getTestTemp())
|
|
||||||
})
|
|
||||||
|
|
||||||
it('moves file with no flags', async () => {
|
it('moves file with no flags', async () => {
|
||||||
const root = path.join(getTestTemp(), ' mv_with_no_flags')
|
const root = path.join(getTestTemp(), ' mv_with_no_flags')
|
||||||
const sourceFile = path.join(root, ' mv_source')
|
const sourceFile = path.join(root, ' mv_source')
|
||||||
@@ -294,10 +264,6 @@ describe('mv', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe('rmRF', () => {
|
describe('rmRF', () => {
|
||||||
beforeAll(async () => {
|
|
||||||
await io.rmRF(getTestTemp())
|
|
||||||
})
|
|
||||||
|
|
||||||
it('removes single folder with rmRF', async () => {
|
it('removes single folder with rmRF', async () => {
|
||||||
const testPath = path.join(getTestTemp(), 'testFolder')
|
const testPath = path.join(getTestTemp(), 'testFolder')
|
||||||
|
|
||||||
@@ -847,13 +813,34 @@ describe('mkdirP', () => {
|
|||||||
(await fs.lstat(path.join(realDirPath, 'sub_dir'))).isDirectory()
|
(await fs.lstat(path.join(realDirPath, 'sub_dir'))).isDirectory()
|
||||||
).toBe(true)
|
).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('breaks if mkdirP loop out of control', async () => {
|
||||||
|
const testPath = path.join(
|
||||||
|
getTestTemp(),
|
||||||
|
'mkdirP_failsafe',
|
||||||
|
'1',
|
||||||
|
'2',
|
||||||
|
'3',
|
||||||
|
'4',
|
||||||
|
'5',
|
||||||
|
'6',
|
||||||
|
'7',
|
||||||
|
'8',
|
||||||
|
'9',
|
||||||
|
'10'
|
||||||
|
)
|
||||||
|
|
||||||
|
expect.assertions(1)
|
||||||
|
|
||||||
|
try {
|
||||||
|
await ioUtil.mkdirP(testPath, 10)
|
||||||
|
} catch (err) {
|
||||||
|
expect(err.code).toBe('ENOENT')
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('which', () => {
|
describe('which', () => {
|
||||||
beforeAll(async () => {
|
|
||||||
await io.rmRF(getTestTemp())
|
|
||||||
})
|
|
||||||
|
|
||||||
it('which() finds file name', async () => {
|
it('which() finds file name', async () => {
|
||||||
// create a executable file
|
// create a executable file
|
||||||
const testPath = path.join(getTestTemp(), 'which-finds-file-name')
|
const testPath = path.join(getTestTemp(), 'which-finds-file-name')
|
||||||
@@ -1386,53 +1373,6 @@ describe('which', () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('findInPath', () => {
|
|
||||||
beforeAll(async () => {
|
|
||||||
await io.rmRF(getTestTemp())
|
|
||||||
})
|
|
||||||
|
|
||||||
it('findInPath() not found', async () => {
|
|
||||||
expect(await io.findInPath('findInPath-test-no-such-file')).toEqual([])
|
|
||||||
})
|
|
||||||
|
|
||||||
it('findInPath() finds file names', async () => {
|
|
||||||
// create executable files
|
|
||||||
let fileName = 'FindInPath-Test-File'
|
|
||||||
if (process.platform === 'win32') {
|
|
||||||
fileName += '.exe'
|
|
||||||
}
|
|
||||||
|
|
||||||
const testPaths = ['1', '2', '3'].map(count =>
|
|
||||||
path.join(getTestTemp(), `findInPath-finds-file-names-${count}`)
|
|
||||||
)
|
|
||||||
for (const testPath of testPaths) {
|
|
||||||
await io.mkdirP(testPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
const filePaths = testPaths.map(testPath => path.join(testPath, fileName))
|
|
||||||
for (const filePath of filePaths) {
|
|
||||||
await fs.writeFile(filePath, '')
|
|
||||||
if (process.platform !== 'win32') {
|
|
||||||
chmod(filePath, '+x')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const originalPath = process.env['PATH']
|
|
||||||
try {
|
|
||||||
// update the PATH
|
|
||||||
for (const testPath of testPaths) {
|
|
||||||
process.env[
|
|
||||||
'PATH'
|
|
||||||
] = `${process.env['PATH']}${path.delimiter}${testPath}`
|
|
||||||
}
|
|
||||||
// exact file names
|
|
||||||
expect(await io.findInPath(fileName)).toEqual(filePaths)
|
|
||||||
} finally {
|
|
||||||
process.env['PATH'] = originalPath
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
async function findsExecutableWithScopedPermissions(
|
async function findsExecutableWithScopedPermissions(
|
||||||
chmodOptions: string
|
chmodOptions: string
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
|||||||
Generated
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "@actions/io",
|
"name": "@actions/io",
|
||||||
"version": "1.1.0",
|
"version": "1.0.2",
|
||||||
"lockfileVersion": 1
|
"lockfileVersion": 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@actions/io",
|
"name": "@actions/io",
|
||||||
"version": "1.1.0",
|
"version": "1.0.2",
|
||||||
"description": "Actions io lib",
|
"description": "Actions io lib",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"github",
|
"github",
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import {ok} from 'assert'
|
||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
|
|
||||||
@@ -58,6 +59,52 @@ export function isRooted(p: string): boolean {
|
|||||||
return p.startsWith('/')
|
return p.startsWith('/')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively create a directory at `fsPath`.
|
||||||
|
*
|
||||||
|
* This implementation is optimistic, meaning it attempts to create the full
|
||||||
|
* path first, and backs up the path stack from there.
|
||||||
|
*
|
||||||
|
* @param fsPath The path to create
|
||||||
|
* @param maxDepth The maximum recursion depth
|
||||||
|
* @param depth The current recursion depth
|
||||||
|
*/
|
||||||
|
export async function mkdirP(
|
||||||
|
fsPath: string,
|
||||||
|
maxDepth: number = 1000,
|
||||||
|
depth: number = 1
|
||||||
|
): Promise<void> {
|
||||||
|
ok(fsPath, 'a path argument must be provided')
|
||||||
|
|
||||||
|
fsPath = path.resolve(fsPath)
|
||||||
|
|
||||||
|
if (depth >= maxDepth) return mkdir(fsPath)
|
||||||
|
|
||||||
|
try {
|
||||||
|
await mkdir(fsPath)
|
||||||
|
return
|
||||||
|
} catch (err) {
|
||||||
|
switch (err.code) {
|
||||||
|
case 'ENOENT': {
|
||||||
|
await mkdirP(path.dirname(fsPath), maxDepth, depth + 1)
|
||||||
|
await mkdir(fsPath)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
let stats: fs.Stats
|
||||||
|
|
||||||
|
try {
|
||||||
|
stats = await stat(fsPath)
|
||||||
|
} catch (err2) {
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stats.isDirectory()) throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Best effort attempt to determine whether a file exists and is executable.
|
* Best effort attempt to determine whether a file exists and is executable.
|
||||||
* @param filePath file path to check
|
* @param filePath file path to check
|
||||||
|
|||||||
+52
-76
@@ -1,4 +1,3 @@
|
|||||||
import {ok} from 'assert'
|
|
||||||
import * as childProcess from 'child_process'
|
import * as childProcess from 'child_process'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
import {promisify} from 'util'
|
import {promisify} from 'util'
|
||||||
@@ -14,8 +13,6 @@ export interface CopyOptions {
|
|||||||
recursive?: boolean
|
recursive?: boolean
|
||||||
/** Optional. Whether to overwrite existing files in the destination. Defaults to true */
|
/** Optional. Whether to overwrite existing files in the destination. Defaults to true */
|
||||||
force?: boolean
|
force?: boolean
|
||||||
/** Optional. Whether to copy the source directory along with all the files. Only takes effect when recursive=true and copying a directory. Default is true*/
|
|
||||||
copySourceDirectory?: boolean
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,7 +36,7 @@ export async function cp(
|
|||||||
dest: string,
|
dest: string,
|
||||||
options: CopyOptions = {}
|
options: CopyOptions = {}
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const {force, recursive, copySourceDirectory} = readCopyOptions(options)
|
const {force, recursive} = readCopyOptions(options)
|
||||||
|
|
||||||
const destStat = (await ioUtil.exists(dest)) ? await ioUtil.stat(dest) : null
|
const destStat = (await ioUtil.exists(dest)) ? await ioUtil.stat(dest) : null
|
||||||
// Dest is an existing file, but not forcing
|
// Dest is an existing file, but not forcing
|
||||||
@@ -49,7 +46,7 @@ export async function cp(
|
|||||||
|
|
||||||
// If dest is an existing directory, should copy inside.
|
// If dest is an existing directory, should copy inside.
|
||||||
const newDest: string =
|
const newDest: string =
|
||||||
destStat && destStat.isDirectory() && copySourceDirectory
|
destStat && destStat.isDirectory()
|
||||||
? path.join(dest, path.basename(source))
|
? path.join(dest, path.basename(source))
|
||||||
: dest
|
: dest
|
||||||
|
|
||||||
@@ -164,8 +161,7 @@ export async function rmRF(inputPath: string): Promise<void> {
|
|||||||
* @returns Promise<void>
|
* @returns Promise<void>
|
||||||
*/
|
*/
|
||||||
export async function mkdirP(fsPath: string): Promise<void> {
|
export async function mkdirP(fsPath: string): Promise<void> {
|
||||||
ok(fsPath, 'a path argument must be provided')
|
await ioUtil.mkdirP(fsPath)
|
||||||
await ioUtil.mkdir(fsPath, {recursive: true})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -196,95 +192,75 @@ export async function which(tool: string, check?: boolean): Promise<string> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const matches: string[] = await findInPath(tool)
|
try {
|
||||||
|
// build the list of extensions to try
|
||||||
if (matches && matches.length > 0) {
|
const extensions: string[] = []
|
||||||
return matches[0]
|
if (ioUtil.IS_WINDOWS && process.env.PATHEXT) {
|
||||||
}
|
for (const extension of process.env.PATHEXT.split(path.delimiter)) {
|
||||||
|
if (extension) {
|
||||||
return ''
|
extensions.push(extension)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of all occurrences of the given tool on the system path.
|
|
||||||
*
|
|
||||||
* @returns Promise<string[]> the paths of the tool
|
|
||||||
*/
|
|
||||||
export async function findInPath(tool: string): Promise<string[]> {
|
|
||||||
if (!tool) {
|
|
||||||
throw new Error("parameter 'tool' is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
// build the list of extensions to try
|
|
||||||
const extensions: string[] = []
|
|
||||||
if (ioUtil.IS_WINDOWS && process.env['PATHEXT']) {
|
|
||||||
for (const extension of process.env['PATHEXT'].split(path.delimiter)) {
|
|
||||||
if (extension) {
|
|
||||||
extensions.push(extension)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// if it's rooted, return it if exists. otherwise return empty.
|
// if it's rooted, return it if exists. otherwise return empty.
|
||||||
if (ioUtil.isRooted(tool)) {
|
if (ioUtil.isRooted(tool)) {
|
||||||
const filePath: string = await ioUtil.tryGetExecutablePath(tool, extensions)
|
const filePath: string = await ioUtil.tryGetExecutablePath(
|
||||||
|
tool,
|
||||||
|
extensions
|
||||||
|
)
|
||||||
|
|
||||||
if (filePath) {
|
if (filePath) {
|
||||||
return [filePath]
|
return filePath
|
||||||
|
}
|
||||||
|
|
||||||
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
return []
|
// if any path separators, return empty
|
||||||
}
|
if (tool.includes('/') || (ioUtil.IS_WINDOWS && tool.includes('\\'))) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
// if any path separators, return empty
|
// build the list of directories
|
||||||
if (tool.includes(path.sep)) {
|
//
|
||||||
return []
|
// Note, technically "where" checks the current directory on Windows. From a toolkit perspective,
|
||||||
}
|
// it feels like we should not do this. Checking the current directory seems like more of a use
|
||||||
|
// case of a shell, and the which() function exposed by the toolkit should strive for consistency
|
||||||
|
// across platforms.
|
||||||
|
const directories: string[] = []
|
||||||
|
|
||||||
// build the list of directories
|
if (process.env.PATH) {
|
||||||
//
|
for (const p of process.env.PATH.split(path.delimiter)) {
|
||||||
// Note, technically "where" checks the current directory on Windows. From a toolkit perspective,
|
if (p) {
|
||||||
// it feels like we should not do this. Checking the current directory seems like more of a use
|
directories.push(p)
|
||||||
// case of a shell, and the which() function exposed by the toolkit should strive for consistency
|
}
|
||||||
// across platforms.
|
|
||||||
const directories: string[] = []
|
|
||||||
|
|
||||||
if (process.env.PATH) {
|
|
||||||
for (const p of process.env.PATH.split(path.delimiter)) {
|
|
||||||
if (p) {
|
|
||||||
directories.push(p)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// find all matches
|
// return the first match
|
||||||
const matches: string[] = []
|
for (const directory of directories) {
|
||||||
|
const filePath = await ioUtil.tryGetExecutablePath(
|
||||||
for (const directory of directories) {
|
directory + path.sep + tool,
|
||||||
const filePath = await ioUtil.tryGetExecutablePath(
|
extensions
|
||||||
path.join(directory, tool),
|
)
|
||||||
extensions
|
if (filePath) {
|
||||||
)
|
return filePath
|
||||||
if (filePath) {
|
}
|
||||||
matches.push(filePath)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return matches
|
return ''
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error(`which failed with message ${err.message}`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function readCopyOptions(options: CopyOptions): Required<CopyOptions> {
|
function readCopyOptions(options: CopyOptions): Required<CopyOptions> {
|
||||||
const force = options.force == null ? true : options.force
|
const force = options.force == null ? true : options.force
|
||||||
const recursive = Boolean(options.recursive)
|
const recursive = Boolean(options.recursive)
|
||||||
const copySourceDirectory =
|
return {force, recursive}
|
||||||
options.copySourceDirectory == null
|
|
||||||
? true
|
|
||||||
: Boolean(options.copySourceDirectory)
|
|
||||||
return {force, recursive, copySourceDirectory}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function cpDirRecursive(
|
async function cpDirRecursive(
|
||||||
|
|||||||
@@ -763,61 +763,6 @@ describe('@actions/tool-cache', function() {
|
|||||||
expect(err.toString()).toContain('404')
|
expect(err.toString()).toContain('404')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it('supports authorization headers', async function() {
|
|
||||||
nock('http://example.com', {
|
|
||||||
reqheaders: {
|
|
||||||
authorization: 'token abc123'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.get('/some-file-that-needs-authorization')
|
|
||||||
.reply(200, undefined)
|
|
||||||
|
|
||||||
await tc.downloadTool(
|
|
||||||
'http://example.com/some-file-that-needs-authorization',
|
|
||||||
undefined,
|
|
||||||
'token abc123'
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('supports custom headers', async function() {
|
|
||||||
nock('http://example.com', {
|
|
||||||
reqheaders: {
|
|
||||||
accept: 'application/octet-stream'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.get('/some-file-that-needs-headers')
|
|
||||||
.reply(200, undefined)
|
|
||||||
|
|
||||||
await tc.downloadTool(
|
|
||||||
'http://example.com/some-file-that-needs-headers',
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
{
|
|
||||||
accept: 'application/octet-stream'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('supports authorization and custom headers', async function() {
|
|
||||||
nock('http://example.com', {
|
|
||||||
reqheaders: {
|
|
||||||
accept: 'application/octet-stream',
|
|
||||||
authorization: 'token abc123'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.get('/some-file-that-needs-authorization-and-headers')
|
|
||||||
.reply(200, undefined)
|
|
||||||
|
|
||||||
await tc.downloadTool(
|
|
||||||
'http://example.com/some-file-that-needs-authorization-and-headers',
|
|
||||||
undefined,
|
|
||||||
'token abc123',
|
|
||||||
{
|
|
||||||
accept: 'application/octet-stream'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -32,14 +32,12 @@ const userAgent = 'actions/tool-cache'
|
|||||||
* @param url url of tool to download
|
* @param url url of tool to download
|
||||||
* @param dest path to download tool
|
* @param dest path to download tool
|
||||||
* @param auth authorization header
|
* @param auth authorization header
|
||||||
* @param headers other headers
|
|
||||||
* @returns path to downloaded tool
|
* @returns path to downloaded tool
|
||||||
*/
|
*/
|
||||||
export async function downloadTool(
|
export async function downloadTool(
|
||||||
url: string,
|
url: string,
|
||||||
dest?: string,
|
dest?: string,
|
||||||
auth?: string,
|
auth?: string
|
||||||
headers?: IHeaders
|
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
dest = dest || path.join(_getTempDirectory(), uuidV4())
|
dest = dest || path.join(_getTempDirectory(), uuidV4())
|
||||||
await io.mkdirP(path.dirname(dest))
|
await io.mkdirP(path.dirname(dest))
|
||||||
@@ -58,7 +56,7 @@ export async function downloadTool(
|
|||||||
const retryHelper = new RetryHelper(maxAttempts, minSeconds, maxSeconds)
|
const retryHelper = new RetryHelper(maxAttempts, minSeconds, maxSeconds)
|
||||||
return await retryHelper.execute(
|
return await retryHelper.execute(
|
||||||
async () => {
|
async () => {
|
||||||
return await downloadToolAttempt(url, dest || '', auth, headers)
|
return await downloadToolAttempt(url, dest || '', auth)
|
||||||
},
|
},
|
||||||
(err: Error) => {
|
(err: Error) => {
|
||||||
if (err instanceof HTTPError && err.httpStatusCode) {
|
if (err instanceof HTTPError && err.httpStatusCode) {
|
||||||
@@ -81,8 +79,7 @@ export async function downloadTool(
|
|||||||
async function downloadToolAttempt(
|
async function downloadToolAttempt(
|
||||||
url: string,
|
url: string,
|
||||||
dest: string,
|
dest: string,
|
||||||
auth?: string,
|
auth?: string
|
||||||
headers?: IHeaders
|
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
if (fs.existsSync(dest)) {
|
if (fs.existsSync(dest)) {
|
||||||
throw new Error(`Destination file path ${dest} already exists`)
|
throw new Error(`Destination file path ${dest} already exists`)
|
||||||
@@ -93,12 +90,12 @@ async function downloadToolAttempt(
|
|||||||
allowRetries: false
|
allowRetries: false
|
||||||
})
|
})
|
||||||
|
|
||||||
|
let headers: IHeaders | undefined
|
||||||
if (auth) {
|
if (auth) {
|
||||||
core.debug('set auth')
|
core.debug('set auth')
|
||||||
if (headers === undefined) {
|
headers = {
|
||||||
headers = {}
|
authorization: auth
|
||||||
}
|
}
|
||||||
headers.authorization = auth
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const response: httpm.HttpClientResponse = await http.get(url, headers)
|
const response: httpm.HttpClientResponse = await http.get(url, headers)
|
||||||
|
|||||||
+2
-1
@@ -5,7 +5,8 @@
|
|||||||
"strict": true,
|
"strict": true,
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"target": "es6",
|
"target": "es6",
|
||||||
"sourceMap": true
|
"sourceMap": true,
|
||||||
|
"lib": ["es6"]
|
||||||
},
|
},
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"node_modules",
|
"node_modules",
|
||||||
|
|||||||
Reference in New Issue
Block a user