Initial import
This commit is contained in:
commit
62b122fb5f
|
@ -0,0 +1,17 @@
|
||||||
|
name: "Close stale issues"
|
||||||
|
on:
|
||||||
|
push: {}
|
||||||
|
schedule:
|
||||||
|
- cron: 0 * * * *
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: bbq-beets/stale-bot@master
|
||||||
|
with:
|
||||||
|
stale_age_days: 0
|
||||||
|
wait_after_stale_days: 0
|
||||||
|
max_operations_per_run: 1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" # todo: secrets.github_token
|
|
@ -0,0 +1,2 @@
|
||||||
|
!node_modules/
|
||||||
|
__tests__/runner/*
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"printWidth": 80,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"useTabs": false,
|
||||||
|
"semi": true,
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "none",
|
||||||
|
"bracketSpacing": false,
|
||||||
|
"arrowParens": "avoid",
|
||||||
|
"parser": "typescript"
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2018 GitHub, Inc. and contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
|
@ -0,0 +1,30 @@
|
||||||
|
# Close Stale Issues
|
||||||
|
|
||||||
|
To use, spin up a workflow. The following inputs are available:
|
||||||
|
* stale_age_days: The number of days old an issue can be before marking it stale (default 60)
|
||||||
|
* wait_after_stale_days: The number of days to wait to close an issue after it being marked stale (default 7)
|
||||||
|
* max_operations_per_run:The maximum number of operations per run, used to control rate limiting (default 30)
|
||||||
|
* stale_label: The label to apply when an item is stale (default 'Stale')
|
||||||
|
* stale_message: The message to post on the issue when tagging it
|
||||||
|
|
||||||
|
You'll need to map `GITHUB_TOKEN` to a PAT token for the identity you want to use to modify the issues:
|
||||||
|
|
||||||
|
Example workflow:
|
||||||
|
```
|
||||||
|
name: "Close stale issues"
|
||||||
|
on:
|
||||||
|
push: {}
|
||||||
|
schedule:
|
||||||
|
- cron: 0 * * * *
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: bbq-beets/stale-bot@master
|
||||||
|
with:
|
||||||
|
stale_age_days: 60
|
||||||
|
wait_after_stale_days: 7
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||||
|
```
|
|
@ -0,0 +1,3 @@
|
||||||
|
describe('TODO - Add a test suite', () => {
|
||||||
|
it('TODO - Add a test', async () => {});
|
||||||
|
});
|
|
@ -0,0 +1,27 @@
|
||||||
|
name: 'Close Stale Issues'
|
||||||
|
description: 'Action to close stale issues'
|
||||||
|
author: 'GitHub'
|
||||||
|
inputs:
|
||||||
|
stale_age_days:
|
||||||
|
description: 'The number of days old an issue can be before marking it stale'
|
||||||
|
default: 60
|
||||||
|
wait_after_stale_days:
|
||||||
|
description: 'The number of days to wait to close an issue after it being marked stale'
|
||||||
|
default: 7
|
||||||
|
max_operations_per_run:
|
||||||
|
description: 'The maximum number of operations per run, used to control rate limiting'
|
||||||
|
default: 30
|
||||||
|
stale_label:
|
||||||
|
description: 'The label to apply when an item is stale'
|
||||||
|
default: 'Stale'
|
||||||
|
stale_message:
|
||||||
|
description: 'The message to post on the issue when tagging it'
|
||||||
|
default: >
|
||||||
|
Message goes here.
|
||||||
|
#This issue has not had any activity within the past ${{inputs.stale_age_days}} days. It will be
|
||||||
|
#closed in ${{wait_after_stale_days}} days if there is no more activity.
|
||||||
|
GITHUB_TOKEN:
|
||||||
|
description: 'The PAT for the identity to use to access to issues and to post messages'
|
||||||
|
runs:
|
||||||
|
using: 'node12'
|
||||||
|
main: 'lib/main.js'
|
|
@ -0,0 +1,22 @@
|
||||||
|
# Contributors
|
||||||
|
|
||||||
|
### Checkin
|
||||||
|
|
||||||
|
- Do checkin source (src)
|
||||||
|
- Do checkin build output (lib)
|
||||||
|
- Do checkin runtime node_modules
|
||||||
|
- Do not checkin devDependency node_modules (husky can help see below)
|
||||||
|
|
||||||
|
### devDependencies
|
||||||
|
|
||||||
|
In order to handle correctly checking in node_modules without devDependencies, we run [Husky](https://github.com/typicode/husky) before each commit.
|
||||||
|
This step ensures that formatting and checkin rules are followed and that devDependencies are excluded. To make sure Husky runs correctly, please use the following workflow:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install # installs all devDependencies including Husky
|
||||||
|
git add abc.ext # Add the files you've changed. This should include files in src, lib, and node_modules (see above)
|
||||||
|
git commit -m "Informative commit message" # Commit. This will run Husky
|
||||||
|
```
|
||||||
|
|
||||||
|
During the commit step, Husky will take care of formatting all files with [Prettier](https://github.com/prettier/prettier) as well as pruning out devDependencies using `npm prune --production`.
|
||||||
|
It will also make sure these changes are appropriately included in your commit (no further work is needed)
|
|
@ -0,0 +1,11 @@
|
||||||
|
module.exports = {
|
||||||
|
clearMocks: true,
|
||||||
|
moduleFileExtensions: ['js', 'ts'],
|
||||||
|
testEnvironment: 'node',
|
||||||
|
testMatch: ['**/*.test.ts'],
|
||||||
|
testRunner: 'jest-circus/runner',
|
||||||
|
transform: {
|
||||||
|
'^.+\\.ts$': 'ts-jest'
|
||||||
|
},
|
||||||
|
verbose: true
|
||||||
|
}
|
|
@ -0,0 +1,124 @@
|
||||||
|
"use strict";
|
||||||
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||||
|
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||||
|
result["default"] = mod;
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const core = __importStar(require("@actions/core"));
|
||||||
|
const github = __importStar(require("@actions/github"));
|
||||||
|
function run() {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
try {
|
||||||
|
const args = getAndValidateArgs();
|
||||||
|
const octokit = new github.GitHub(args.token);
|
||||||
|
const issues = yield octokit.issues.listForRepo({
|
||||||
|
owner: args.repo_owner,
|
||||||
|
repo: args.repo_name,
|
||||||
|
state: 'open'
|
||||||
|
});
|
||||||
|
let operationsLeft = args.max_operations_per_run - 1;
|
||||||
|
for (var issue of issues.data.values()) {
|
||||||
|
core.debug(`found issue: ${issue.title} last updated ${issue.updated_at}`);
|
||||||
|
if (isLabeledStale(issue, args.stale_label)) {
|
||||||
|
if (wasLastUpdatedBefore(issue, args.wait_after_stale_days)) {
|
||||||
|
operationsLeft -= yield closeIssue(octokit, issue, args);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (wasLastUpdatedBefore(issue, args.stale_age_days)) {
|
||||||
|
operationsLeft -= yield markStale(octokit, issue, args);
|
||||||
|
}
|
||||||
|
if (operationsLeft <= 0) {
|
||||||
|
core.warning(`performed ${args.max_operations_per_run} operations, exiting to avoid rate limit`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
core.error(error);
|
||||||
|
core.setFailed(error.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function isLabeledStale(issue, label) {
|
||||||
|
return issue.labels.filter(i => i.name === label).length > 0;
|
||||||
|
}
|
||||||
|
function wasLastUpdatedBefore(issue, num_days) {
|
||||||
|
const daysInMillis = (1000 * 60 * 60 * num_days);
|
||||||
|
const millisSinceLastUpdated = new Date().getTime() - new Date(issue.updated_at).getTime();
|
||||||
|
core.debug(`${daysInMillis}, ${millisSinceLastUpdated}`);
|
||||||
|
return millisSinceLastUpdated >= daysInMillis;
|
||||||
|
}
|
||||||
|
function markStale(octokit, issue, args) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
core.debug(`marking issue${issue.title} as stale`);
|
||||||
|
yield octokit.issues.createComment({
|
||||||
|
owner: args.repo_owner,
|
||||||
|
repo: args.repo_name,
|
||||||
|
issue_number: issue.number,
|
||||||
|
body: args.stale_message
|
||||||
|
});
|
||||||
|
yield octokit.issues.addLabels({
|
||||||
|
owner: args.repo_owner,
|
||||||
|
repo: args.repo_name,
|
||||||
|
issue_number: issue.number,
|
||||||
|
labels: [args.stale_label]
|
||||||
|
});
|
||||||
|
return 2; // operations performed
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function closeIssue(octokit, issue, args) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
core.debug(`closing issue ${issue.title} for being stale`);
|
||||||
|
yield octokit.issues.update({
|
||||||
|
owner: args.repo_owner,
|
||||||
|
repo: args.repo_name,
|
||||||
|
issue_number: issue.number,
|
||||||
|
state: "closed"
|
||||||
|
});
|
||||||
|
return 1; // operations performed
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function getAndValidateArgs() {
|
||||||
|
const args = {
|
||||||
|
token: process.env.GITHUB_TOKEN || '',
|
||||||
|
repo_owner: (process.env.GITHUB_REPOSITORY || '').split("/")[0],
|
||||||
|
repo_name: (process.env.GITHUB_REPOSITORY || '').split("/")[1],
|
||||||
|
stale_age_days: parseInt(core.getInput('stale_age_days')),
|
||||||
|
wait_after_stale_days: parseInt(core.getInput('wait_after_stale_days')),
|
||||||
|
max_operations_per_run: parseInt(core.getInput('max_operations_per_run')),
|
||||||
|
stale_label: core.getInput('stale_label'),
|
||||||
|
stale_message: core.getInput('stale_message')
|
||||||
|
};
|
||||||
|
if (!args.token) {
|
||||||
|
throw new Error('could not resolve token from GITHUB_TOKEN');
|
||||||
|
}
|
||||||
|
if (!args.repo_owner || !args.repo_name) {
|
||||||
|
throw new Error('could not resolve repo from GITHUB_REPOSITORY');
|
||||||
|
}
|
||||||
|
for (var stringInput of ["stale_label", "stale_message"]) {
|
||||||
|
if (!args[stringInput]) {
|
||||||
|
throw Error(`input ${stringInput} was empty`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var numberInput of ["stale_age_days", "wait_after_stale_days", "max_operations_per_run"]) {
|
||||||
|
if (isNaN(args[numberInput])) {
|
||||||
|
throw Error(`input ${numberInput} did not parse to a valid integer`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
run();
|
|
@ -0,0 +1,15 @@
|
||||||
|
#!/bin/sh
|
||||||
|
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||||
|
|
||||||
|
case `uname` in
|
||||||
|
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -x "$basedir/node" ]; then
|
||||||
|
"$basedir/node" "$basedir/../semver/bin/semver" "$@"
|
||||||
|
ret=$?
|
||||||
|
else
|
||||||
|
node "$basedir/../semver/bin/semver" "$@"
|
||||||
|
ret=$?
|
||||||
|
fi
|
||||||
|
exit $ret
|
|
@ -0,0 +1,7 @@
|
||||||
|
@IF EXIST "%~dp0\node.exe" (
|
||||||
|
"%~dp0\node.exe" "%~dp0\..\semver\bin\semver" %*
|
||||||
|
) ELSE (
|
||||||
|
@SETLOCAL
|
||||||
|
@SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||||
|
node "%~dp0\..\semver\bin\semver" %*
|
||||||
|
)
|
|
@ -0,0 +1,15 @@
|
||||||
|
#!/bin/sh
|
||||||
|
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||||
|
|
||||||
|
case `uname` in
|
||||||
|
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -x "$basedir/node" ]; then
|
||||||
|
"$basedir/node" "$basedir/../uuid/bin/uuid" "$@"
|
||||||
|
ret=$?
|
||||||
|
else
|
||||||
|
node "$basedir/../uuid/bin/uuid" "$@"
|
||||||
|
ret=$?
|
||||||
|
fi
|
||||||
|
exit $ret
|
|
@ -0,0 +1,7 @@
|
||||||
|
@IF EXIST "%~dp0\node.exe" (
|
||||||
|
"%~dp0\node.exe" "%~dp0\..\uuid\bin\uuid" %*
|
||||||
|
) ELSE (
|
||||||
|
@SETLOCAL
|
||||||
|
@SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||||
|
node "%~dp0\..\uuid\bin\uuid" %*
|
||||||
|
)
|
|
@ -0,0 +1,15 @@
|
||||||
|
#!/bin/sh
|
||||||
|
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||||
|
|
||||||
|
case `uname` in
|
||||||
|
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -x "$basedir/node" ]; then
|
||||||
|
"$basedir/node" "$basedir/../which/bin/which" "$@"
|
||||||
|
ret=$?
|
||||||
|
else
|
||||||
|
node "$basedir/../which/bin/which" "$@"
|
||||||
|
ret=$?
|
||||||
|
fi
|
||||||
|
exit $ret
|
|
@ -0,0 +1,7 @@
|
||||||
|
@IF EXIST "%~dp0\node.exe" (
|
||||||
|
"%~dp0\node.exe" "%~dp0\..\which\bin\which" %*
|
||||||
|
) ELSE (
|
||||||
|
@SETLOCAL
|
||||||
|
@SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||||
|
node "%~dp0\..\which\bin\which" %*
|
||||||
|
)
|
|
@ -0,0 +1,7 @@
|
||||||
|
# `@actions/core`
|
||||||
|
|
||||||
|
> Core functions for setting results, logging, registering secrets and exporting variables across actions
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
See [src/core.ts](src/core.ts).
|
|
@ -0,0 +1,16 @@
|
||||||
|
interface CommandProperties {
|
||||||
|
[key: string]: string;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Commands
|
||||||
|
*
|
||||||
|
* Command Format:
|
||||||
|
* ##[name key=value;key=value]message
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
* ##[warning]This is the user warning message
|
||||||
|
* ##[set-secret name=mypassword]definatelyNotAPassword!
|
||||||
|
*/
|
||||||
|
export declare function issueCommand(command: string, properties: CommandProperties, message: string): void;
|
||||||
|
export declare function issue(name: string, message: string): void;
|
||||||
|
export {};
|
|
@ -0,0 +1,66 @@
|
||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const os = require("os");
|
||||||
|
/**
|
||||||
|
* Commands
|
||||||
|
*
|
||||||
|
* Command Format:
|
||||||
|
* ##[name key=value;key=value]message
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
* ##[warning]This is the user warning message
|
||||||
|
* ##[set-secret name=mypassword]definatelyNotAPassword!
|
||||||
|
*/
|
||||||
|
function issueCommand(command, properties, message) {
|
||||||
|
const cmd = new Command(command, properties, message);
|
||||||
|
process.stdout.write(cmd.toString() + os.EOL);
|
||||||
|
}
|
||||||
|
exports.issueCommand = issueCommand;
|
||||||
|
function issue(name, message) {
|
||||||
|
issueCommand(name, {}, message);
|
||||||
|
}
|
||||||
|
exports.issue = issue;
|
||||||
|
const CMD_PREFIX = '##[';
|
||||||
|
class Command {
|
||||||
|
constructor(command, properties, message) {
|
||||||
|
if (!command) {
|
||||||
|
command = 'missing.command';
|
||||||
|
}
|
||||||
|
this.command = command;
|
||||||
|
this.properties = properties;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
toString() {
|
||||||
|
let cmdStr = CMD_PREFIX + this.command;
|
||||||
|
if (this.properties && Object.keys(this.properties).length > 0) {
|
||||||
|
cmdStr += ' ';
|
||||||
|
for (const key in this.properties) {
|
||||||
|
if (this.properties.hasOwnProperty(key)) {
|
||||||
|
const val = this.properties[key];
|
||||||
|
if (val) {
|
||||||
|
// safely append the val - avoid blowing up when attempting to
|
||||||
|
// call .replace() if message is not a string for some reason
|
||||||
|
cmdStr += `${key}=${escape(`${val || ''}`)};`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmdStr += ']';
|
||||||
|
// safely append the message - avoid blowing up when attempting to
|
||||||
|
// call .replace() if message is not a string for some reason
|
||||||
|
const message = `${this.message || ''}`;
|
||||||
|
cmdStr += escapeData(message);
|
||||||
|
return cmdStr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function escapeData(s) {
|
||||||
|
return s.replace(/\r/g, '%0D').replace(/\n/g, '%0A');
|
||||||
|
}
|
||||||
|
function escape(s) {
|
||||||
|
return s
|
||||||
|
.replace(/\r/g, '%0D')
|
||||||
|
.replace(/\n/g, '%0A')
|
||||||
|
.replace(/]/g, '%5D')
|
||||||
|
.replace(/;/g, '%3B');
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=command.js.map
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"command.js","sourceRoot":"","sources":["../src/command.ts"],"names":[],"mappings":";;AAAA,yBAAwB;AAQxB;;;;;;;;;GASG;AACH,SAAgB,YAAY,CAC1B,OAAe,EACf,UAA6B,EAC7B,OAAe;IAEf,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,CAAA;IACrD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAA;AAC/C,CAAC;AAPD,oCAOC;AAED,SAAgB,KAAK,CAAC,IAAY,EAAE,OAAe;IACjD,YAAY,CAAC,IAAI,EAAE,EAAE,EAAE,OAAO,CAAC,CAAA;AACjC,CAAC;AAFD,sBAEC;AAED,MAAM,UAAU,GAAG,KAAK,CAAA;AAExB,MAAM,OAAO;IAKX,YAAY,OAAe,EAAE,UAA6B,EAAE,OAAe;QACzE,IAAI,CAAC,OAAO,EAAE;YACZ,OAAO,GAAG,iBAAiB,CAAA;SAC5B;QAED,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QACtB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAC5B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;IACxB,CAAC;IAED,QAAQ;QACN,IAAI,MAAM,GAAG,UAAU,GAAG,IAAI,CAAC,OAAO,CAAA;QAEtC,IAAI,IAAI,CAAC,UAAU,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE;YAC9D,MAAM,IAAI,GAAG,CAAA;YACb,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,UAAU,EAAE;gBACjC,IAAI,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE;oBACvC,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;oBAChC,IAAI,GAAG,EAAE;wBACP,8DAA8D;wBAC9D,6DAA6D;wBAC7D,MAAM,IAAI,GAAG,GAAG,IAAI,MAAM,CAAC,GAAG,GAAG,IAAI,EAAE,EAAE,CAAC,GAAG,CAAA;qBAC9C;iBACF;aACF;SACF;QAED,MAAM,IAAI,GAAG,CAAA;QAEb,kEAAkE;QAClE,6DAA6D;QAC7D,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,OAAO,IAAI,EAAE,EAAE,CAAA;QACvC,MAAM,IAAI,UAAU,CAAC,OAAO,CAAC,CAAA;QAE7B,OAAO,MAAM,CAAA;IACf,CAAC;CACF;AAED,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;AACtD,CAAC;AAED,SAAS,MAAM,CAAC,CAAS;IACvB,OAAO,CAAC;SACL,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;SACrB,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC;SACpB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;AACzB,CAAC"}
|
|
@ -0,0 +1,81 @@
|
||||||
|
/**
|
||||||
|
* Interface for getInput options
|
||||||
|
*/
|
||||||
|
export interface InputOptions {
|
||||||
|
/** Optional. Whether the input is required. If required and not present, will throw. Defaults to false */
|
||||||
|
required?: boolean;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* The code to exit an action
|
||||||
|
*/
|
||||||
|
export declare enum ExitCode {
|
||||||
|
/**
|
||||||
|
* A code indicating that the action was successful
|
||||||
|
*/
|
||||||
|
Success = 0,
|
||||||
|
/**
|
||||||
|
* A code indicating that the action was a failure
|
||||||
|
*/
|
||||||
|
Failure = 1,
|
||||||
|
/**
|
||||||
|
* A code indicating that the action is complete, but neither succeeded nor failed
|
||||||
|
*/
|
||||||
|
Neutral = 78
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* sets env variable for this action and future actions in the job
|
||||||
|
* @param name the name of the variable to set
|
||||||
|
* @param val the value of the variable
|
||||||
|
*/
|
||||||
|
export declare function exportVariable(name: string, val: string): void;
|
||||||
|
/**
|
||||||
|
* exports the variable and registers a secret which will get masked from logs
|
||||||
|
* @param name the name of the variable to set
|
||||||
|
* @param val value of the secret
|
||||||
|
*/
|
||||||
|
export declare function exportSecret(name: string, val: string): void;
|
||||||
|
/**
|
||||||
|
* Prepends inputPath to the PATH (for this action and future actions)
|
||||||
|
* @param inputPath
|
||||||
|
*/
|
||||||
|
export declare function addPath(inputPath: string): void;
|
||||||
|
/**
|
||||||
|
* Gets the value of an input. The value is also trimmed.
|
||||||
|
*
|
||||||
|
* @param name name of the input to get
|
||||||
|
* @param options optional. See InputOptions.
|
||||||
|
* @returns string
|
||||||
|
*/
|
||||||
|
export declare function getInput(name: string, options?: InputOptions): string;
|
||||||
|
/**
|
||||||
|
* Sets the value of an output.
|
||||||
|
*
|
||||||
|
* @param name name of the output to set
|
||||||
|
* @param value value to store
|
||||||
|
*/
|
||||||
|
export declare function setOutput(name: string, value: string): void;
|
||||||
|
/**
|
||||||
|
* Sets the action status to neutral
|
||||||
|
*/
|
||||||
|
export declare function setNeutral(): void;
|
||||||
|
/**
|
||||||
|
* Sets the action status to failed.
|
||||||
|
* When the action exits it will be with an exit code of 1
|
||||||
|
* @param message add error issue message
|
||||||
|
*/
|
||||||
|
export declare function setFailed(message: string): void;
|
||||||
|
/**
|
||||||
|
* Writes debug message to user log
|
||||||
|
* @param message debug message
|
||||||
|
*/
|
||||||
|
export declare function debug(message: string): void;
|
||||||
|
/**
|
||||||
|
* Adds an error issue
|
||||||
|
* @param message error issue message
|
||||||
|
*/
|
||||||
|
export declare function error(message: string): void;
|
||||||
|
/**
|
||||||
|
* Adds an warning issue
|
||||||
|
* @param message warning issue message
|
||||||
|
*/
|
||||||
|
export declare function warning(message: string): void;
|
|
@ -0,0 +1,127 @@
|
||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const command_1 = require("./command");
|
||||||
|
const path = require("path");
|
||||||
|
/**
|
||||||
|
* The code to exit an action
|
||||||
|
*/
|
||||||
|
var ExitCode;
|
||||||
|
(function (ExitCode) {
|
||||||
|
/**
|
||||||
|
* A code indicating that the action was successful
|
||||||
|
*/
|
||||||
|
ExitCode[ExitCode["Success"] = 0] = "Success";
|
||||||
|
/**
|
||||||
|
* A code indicating that the action was a failure
|
||||||
|
*/
|
||||||
|
ExitCode[ExitCode["Failure"] = 1] = "Failure";
|
||||||
|
/**
|
||||||
|
* A code indicating that the action is complete, but neither succeeded nor failed
|
||||||
|
*/
|
||||||
|
ExitCode[ExitCode["Neutral"] = 78] = "Neutral";
|
||||||
|
})(ExitCode = exports.ExitCode || (exports.ExitCode = {}));
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
// Variables
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* sets env variable for this action and future actions in the job
|
||||||
|
* @param name the name of the variable to set
|
||||||
|
* @param val the value of the variable
|
||||||
|
*/
|
||||||
|
function exportVariable(name, val) {
|
||||||
|
process.env[name] = val;
|
||||||
|
command_1.issueCommand('set-env', { name }, val);
|
||||||
|
}
|
||||||
|
exports.exportVariable = exportVariable;
|
||||||
|
/**
|
||||||
|
* exports the variable and registers a secret which will get masked from logs
|
||||||
|
* @param name the name of the variable to set
|
||||||
|
* @param val value of the secret
|
||||||
|
*/
|
||||||
|
function exportSecret(name, val) {
|
||||||
|
exportVariable(name, val);
|
||||||
|
command_1.issueCommand('set-secret', {}, val);
|
||||||
|
}
|
||||||
|
exports.exportSecret = exportSecret;
|
||||||
|
/**
|
||||||
|
* Prepends inputPath to the PATH (for this action and future actions)
|
||||||
|
* @param inputPath
|
||||||
|
*/
|
||||||
|
function addPath(inputPath) {
|
||||||
|
command_1.issueCommand('add-path', {}, inputPath);
|
||||||
|
process.env['PATH'] = `${inputPath}${path.delimiter}${process.env['PATH']}`;
|
||||||
|
}
|
||||||
|
exports.addPath = addPath;
|
||||||
|
/**
|
||||||
|
* Gets the value of an input. The value is also trimmed.
|
||||||
|
*
|
||||||
|
* @param name name of the input to get
|
||||||
|
* @param options optional. See InputOptions.
|
||||||
|
* @returns string
|
||||||
|
*/
|
||||||
|
function getInput(name, options) {
|
||||||
|
const val = process.env[`INPUT_${name.replace(' ', '_').toUpperCase()}`] || '';
|
||||||
|
if (options && options.required && !val) {
|
||||||
|
throw new Error(`Input required and not supplied: ${name}`);
|
||||||
|
}
|
||||||
|
return val.trim();
|
||||||
|
}
|
||||||
|
exports.getInput = getInput;
|
||||||
|
/**
|
||||||
|
* Sets the value of an output.
|
||||||
|
*
|
||||||
|
* @param name name of the output to set
|
||||||
|
* @param value value to store
|
||||||
|
*/
|
||||||
|
function setOutput(name, value) {
|
||||||
|
command_1.issueCommand('set-output', { name }, value);
|
||||||
|
}
|
||||||
|
exports.setOutput = setOutput;
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
// Results
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Sets the action status to neutral
|
||||||
|
*/
|
||||||
|
function setNeutral() {
|
||||||
|
process.exitCode = ExitCode.Neutral;
|
||||||
|
}
|
||||||
|
exports.setNeutral = setNeutral;
|
||||||
|
/**
|
||||||
|
* Sets the action status to failed.
|
||||||
|
* When the action exits it will be with an exit code of 1
|
||||||
|
* @param message add error issue message
|
||||||
|
*/
|
||||||
|
function setFailed(message) {
|
||||||
|
process.exitCode = ExitCode.Failure;
|
||||||
|
error(message);
|
||||||
|
}
|
||||||
|
exports.setFailed = setFailed;
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
// Logging Commands
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Writes debug message to user log
|
||||||
|
* @param message debug message
|
||||||
|
*/
|
||||||
|
function debug(message) {
|
||||||
|
command_1.issueCommand('debug', {}, message);
|
||||||
|
}
|
||||||
|
exports.debug = debug;
|
||||||
|
/**
|
||||||
|
* Adds an error issue
|
||||||
|
* @param message error issue message
|
||||||
|
*/
|
||||||
|
function error(message) {
|
||||||
|
command_1.issue('error', message);
|
||||||
|
}
|
||||||
|
exports.error = error;
|
||||||
|
/**
|
||||||
|
* Adds an warning issue
|
||||||
|
* @param message warning issue message
|
||||||
|
*/
|
||||||
|
function warning(message) {
|
||||||
|
command_1.issue('warning', message);
|
||||||
|
}
|
||||||
|
exports.warning = warning;
|
||||||
|
//# sourceMappingURL=core.js.map
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"core.js","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":";;AAAA,uCAA6C;AAE7C,6BAA4B;AAU5B;;GAEG;AACH,IAAY,QAeX;AAfD,WAAY,QAAQ;IAClB;;OAEG;IACH,6CAAW,CAAA;IAEX;;OAEG;IACH,6CAAW,CAAA;IAEX;;OAEG;IACH,8CAAY,CAAA;AACd,CAAC,EAfW,QAAQ,GAAR,gBAAQ,KAAR,gBAAQ,QAenB;AAED,yEAAyE;AACzE,YAAY;AACZ,yEAAyE;AAEzE;;;;GAIG;AACH,SAAgB,cAAc,CAAC,IAAY,EAAE,GAAW;IACtD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,CAAA;IACvB,sBAAY,CAAC,SAAS,EAAE,EAAC,IAAI,EAAC,EAAE,GAAG,CAAC,CAAA;AACtC,CAAC;AAHD,wCAGC;AAED;;;;GAIG;AACH,SAAgB,YAAY,CAAC,IAAY,EAAE,GAAW;IACpD,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;IACzB,sBAAY,CAAC,YAAY,EAAE,EAAE,EAAE,GAAG,CAAC,CAAA;AACrC,CAAC;AAHD,oCAGC;AAED;;;GAGG;AACH,SAAgB,OAAO,CAAC,SAAiB;IACvC,sBAAY,CAAC,UAAU,EAAE,EAAE,EAAE,SAAS,CAAC,CAAA;IACvC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,GAAG,SAAS,GAAG,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAA;AAC7E,CAAC;AAHD,0BAGC;AAED;;;;;;GAMG;AACH,SAAgB,QAAQ,CAAC,IAAY,EAAE,OAAsB;IAC3D,MAAM,GAAG,GACP,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,IAAI,EAAE,CAAA;IACpE,IAAI,OAAO,IAAI,OAAO,CAAC,QAAQ,IAAI,CAAC,GAAG,EAAE;QACvC,MAAM,IAAI,KAAK,CAAC,oCAAoC,IAAI,EAAE,CAAC,CAAA;KAC5D;IAED,OAAO,GAAG,CAAC,IAAI,EAAE,CAAA;AACnB,CAAC;AARD,4BAQC;AAED;;;;;GAKG;AACH,SAAgB,SAAS,CAAC,IAAY,EAAE,KAAa;IACnD,sBAAY,CAAC,YAAY,EAAE,EAAC,IAAI,EAAC,EAAE,KAAK,CAAC,CAAA;AAC3C,CAAC;AAFD,8BAEC;AAED,yEAAyE;AACzE,UAAU;AACV,yEAAyE;AAEzE;;GAEG;AACH,SAAgB,UAAU;IACxB,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAA;AACrC,CAAC;AAFD,gCAEC;AAED;;;;GAIG;AACH,SAAgB,SAAS,CAAC,OAAe;IACvC,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAA;IACnC,KAAK,CAAC,OAAO,CAAC,CAAA;AAChB,CAAC;AAHD,8BAGC;AAED,yEAAyE;AACzE,mBAAmB;AACnB,yEAAyE;AAEzE;;;GAGG;AACH,SAAgB,KAAK,CAAC,OAAe;IACnC,sBAAY,CAAC,OAAO,EAAE,EAAE,EAAE,OAAO,CAAC,CAAA;AACpC,CAAC;AAFD,sBAEC;AAED;;;GAGG;AACH,SAAgB,KAAK,CAAC,OAAe;IACnC,eAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;AACzB,CAAC;AAFD,sBAEC;AAED;;;GAGG;AACH,SAAgB,OAAO,CAAC,OAAe;IACrC,eAAK,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;AAC3B,CAAC;AAFD,0BAEC"}
|
|
@ -0,0 +1,64 @@
|
||||||
|
{
|
||||||
|
"_from": "file:toolkit\\actions-core-0.0.0.tgz",
|
||||||
|
"_id": "@actions/core@0.0.0",
|
||||||
|
"_inBundle": false,
|
||||||
|
"_integrity": "sha512-P+mC79gXC2yvyU0+RDctxKUI1Q3tNruB+aSmFI47j2H0DylxtDEgycW9WXwt/zCY62lfwfvBoGKpuJRvFHDqpw==",
|
||||||
|
"_location": "/@actions/core",
|
||||||
|
"_phantomChildren": {},
|
||||||
|
"_requested": {
|
||||||
|
"type": "file",
|
||||||
|
"where": "Z:\\Dreamlifter\\stale-bot",
|
||||||
|
"raw": "@actions/core@file:toolkit/actions-core-0.0.0.tgz",
|
||||||
|
"name": "@actions/core",
|
||||||
|
"escapedName": "@actions%2fcore",
|
||||||
|
"scope": "@actions",
|
||||||
|
"rawSpec": "file:toolkit/actions-core-0.0.0.tgz",
|
||||||
|
"saveSpec": "file:toolkit\\actions-core-0.0.0.tgz",
|
||||||
|
"fetchSpec": "Z:\\Dreamlifter\\stale-bot\\toolkit\\actions-core-0.0.0.tgz"
|
||||||
|
},
|
||||||
|
"_requiredBy": [
|
||||||
|
"#USER",
|
||||||
|
"/",
|
||||||
|
"/@actions/tool-cache"
|
||||||
|
],
|
||||||
|
"_resolved": "Z:\\Dreamlifter\\stale-bot\\toolkit\\actions-core-0.0.0.tgz",
|
||||||
|
"_shasum": "3f3d82f209fd62dd9c01f180c963596f6c479f29",
|
||||||
|
"_spec": "@actions/core@file:toolkit/actions-core-0.0.0.tgz",
|
||||||
|
"_where": "Z:\\Dreamlifter\\stale-bot",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/actions/toolkit/issues"
|
||||||
|
},
|
||||||
|
"bundleDependencies": false,
|
||||||
|
"deprecated": false,
|
||||||
|
"description": "Actions core lib",
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^12.0.2"
|
||||||
|
},
|
||||||
|
"directories": {
|
||||||
|
"lib": "lib",
|
||||||
|
"test": "__tests__"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"lib"
|
||||||
|
],
|
||||||
|
"homepage": "https://github.com/actions/toolkit/tree/master/packages/core",
|
||||||
|
"keywords": [
|
||||||
|
"core",
|
||||||
|
"actions"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"main": "lib/core.js",
|
||||||
|
"name": "@actions/core",
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/actions/toolkit.git"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: run tests from root\" && exit 1",
|
||||||
|
"tsc": "tsc"
|
||||||
|
},
|
||||||
|
"version": "0.0.0"
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
# `@actions/exec`
|
||||||
|
|
||||||
|
> Functions necessary for running tools on the command line
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
See [src/exec.ts](src/exec.ts).
|
|
@ -0,0 +1,12 @@
|
||||||
|
import * as im from './interfaces';
|
||||||
|
/**
|
||||||
|
* Exec a command.
|
||||||
|
* Output will be streamed to the live console.
|
||||||
|
* Returns promise with return code
|
||||||
|
*
|
||||||
|
* @param commandLine command to execute (can include additional args). Must be correctly escaped.
|
||||||
|
* @param args optional arguments for tool. Escaping is handled by the lib.
|
||||||
|
* @param options optional exec options. See ExecOptions
|
||||||
|
* @returns Promise<number> exit code
|
||||||
|
*/
|
||||||
|
export declare function exec(commandLine: string, args?: string[], options?: im.ExecOptions): Promise<number>;
|
|
@ -0,0 +1,36 @@
|
||||||
|
"use strict";
|
||||||
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||||
|
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const tr = require("./toolrunner");
|
||||||
|
/**
|
||||||
|
* Exec a command.
|
||||||
|
* Output will be streamed to the live console.
|
||||||
|
* Returns promise with return code
|
||||||
|
*
|
||||||
|
* @param commandLine command to execute (can include additional args). Must be correctly escaped.
|
||||||
|
* @param args optional arguments for tool. Escaping is handled by the lib.
|
||||||
|
* @param options optional exec options. See ExecOptions
|
||||||
|
* @returns Promise<number> exit code
|
||||||
|
*/
|
||||||
|
function exec(commandLine, args, options) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const commandArgs = tr.argStringToArray(commandLine);
|
||||||
|
if (commandArgs.length === 0) {
|
||||||
|
throw new Error(`Parameter 'commandLine' cannot be null or empty.`);
|
||||||
|
}
|
||||||
|
// Path to tool to execute should be first arg
|
||||||
|
const toolPath = commandArgs[0];
|
||||||
|
args = commandArgs.slice(1).concat(args || []);
|
||||||
|
const runner = new tr.ToolRunner(toolPath, args, options);
|
||||||
|
return runner.exec();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.exec = exec;
|
||||||
|
//# sourceMappingURL=exec.js.map
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"exec.js","sourceRoot":"","sources":["../src/exec.ts"],"names":[],"mappings":";;;;;;;;;;AACA,mCAAkC;AAElC;;;;;;;;;GASG;AACH,SAAsB,IAAI,CACxB,WAAmB,EACnB,IAAe,EACf,OAAwB;;QAExB,MAAM,WAAW,GAAG,EAAE,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAA;QACpD,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE;YAC5B,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAA;SACpE;QACD,8CAA8C;QAC9C,MAAM,QAAQ,GAAG,WAAW,CAAC,CAAC,CAAC,CAAA;QAC/B,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAA;QAC9C,MAAM,MAAM,GAAkB,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;QACxE,OAAO,MAAM,CAAC,IAAI,EAAE,CAAA;IACtB,CAAC;CAAA;AAdD,oBAcC"}
|
|
@ -0,0 +1,35 @@
|
||||||
|
/// <reference types="node" />
|
||||||
|
import * as stream from 'stream';
|
||||||
|
/**
|
||||||
|
* Interface for exec options
|
||||||
|
*/
|
||||||
|
export interface ExecOptions {
|
||||||
|
/** optional working directory. defaults to current */
|
||||||
|
cwd?: string;
|
||||||
|
/** optional envvar dictionary. defaults to current process's env */
|
||||||
|
env?: {
|
||||||
|
[key: string]: string;
|
||||||
|
};
|
||||||
|
/** optional. defaults to false */
|
||||||
|
silent?: boolean;
|
||||||
|
/** optional out stream to use. Defaults to process.stdout */
|
||||||
|
outStream?: stream.Writable;
|
||||||
|
/** optional err stream to use. Defaults to process.stderr */
|
||||||
|
errStream?: stream.Writable;
|
||||||
|
/** optional. whether to skip quoting/escaping arguments if needed. defaults to false. */
|
||||||
|
windowsVerbatimArguments?: boolean;
|
||||||
|
/** optional. whether to fail if output to stderr. defaults to false */
|
||||||
|
failOnStdErr?: boolean;
|
||||||
|
/** optional. defaults to failing on non zero. ignore will not fail leaving it up to the caller */
|
||||||
|
ignoreReturnCode?: boolean;
|
||||||
|
/** optional. How long in ms to wait for STDIO streams to close after the exit event of the process before terminating. defaults to 10000 */
|
||||||
|
delay?: number;
|
||||||
|
/** optional. Listeners for output. Callback functions that will be called on these events */
|
||||||
|
listeners?: {
|
||||||
|
stdout?: (data: Buffer) => void;
|
||||||
|
stderr?: (data: Buffer) => void;
|
||||||
|
stdline?: (data: string) => void;
|
||||||
|
errline?: (data: string) => void;
|
||||||
|
debug?: (data: string) => void;
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
//# sourceMappingURL=interfaces.js.map
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":""}
|
|
@ -0,0 +1,37 @@
|
||||||
|
/// <reference types="node" />
|
||||||
|
import * as events from 'events';
|
||||||
|
import * as im from './interfaces';
|
||||||
|
export declare class ToolRunner extends events.EventEmitter {
|
||||||
|
constructor(toolPath: string, args?: string[], options?: im.ExecOptions);
|
||||||
|
private toolPath;
|
||||||
|
private args;
|
||||||
|
private options;
|
||||||
|
private _debug;
|
||||||
|
private _getCommandString;
|
||||||
|
private _processLineBuffer;
|
||||||
|
private _getSpawnFileName;
|
||||||
|
private _getSpawnArgs;
|
||||||
|
private _endsWith;
|
||||||
|
private _isCmdFile;
|
||||||
|
private _windowsQuoteCmdArg;
|
||||||
|
private _uvQuoteCmdArg;
|
||||||
|
private _cloneExecOptions;
|
||||||
|
private _getSpawnOptions;
|
||||||
|
/**
|
||||||
|
* Exec a tool.
|
||||||
|
* Output will be streamed to the live console.
|
||||||
|
* Returns promise with return code
|
||||||
|
*
|
||||||
|
* @param tool path to tool to exec
|
||||||
|
* @param options optional exec options. See ExecOptions
|
||||||
|
* @returns number
|
||||||
|
*/
|
||||||
|
exec(): Promise<number>;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Convert an arg string to an array of args. Handles escaping
|
||||||
|
*
|
||||||
|
* @param argString string of arguments
|
||||||
|
* @returns string[] array of arguments
|
||||||
|
*/
|
||||||
|
export declare function argStringToArray(argString: string): string[];
|
|
@ -0,0 +1,573 @@
|
||||||
|
"use strict";
|
||||||
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||||
|
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const os = require("os");
|
||||||
|
const events = require("events");
|
||||||
|
const child = require("child_process");
|
||||||
|
/* eslint-disable @typescript-eslint/unbound-method */
|
||||||
|
const IS_WINDOWS = process.platform === 'win32';
|
||||||
|
/*
|
||||||
|
* Class for running command line tools. Handles quoting and arg parsing in a platform agnostic way.
|
||||||
|
*/
|
||||||
|
class ToolRunner extends events.EventEmitter {
|
||||||
|
constructor(toolPath, args, options) {
|
||||||
|
super();
|
||||||
|
if (!toolPath) {
|
||||||
|
throw new Error("Parameter 'toolPath' cannot be null or empty.");
|
||||||
|
}
|
||||||
|
this.toolPath = toolPath;
|
||||||
|
this.args = args || [];
|
||||||
|
this.options = options || {};
|
||||||
|
}
|
||||||
|
_debug(message) {
|
||||||
|
if (this.options.listeners && this.options.listeners.debug) {
|
||||||
|
this.options.listeners.debug(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_getCommandString(options, noPrefix) {
|
||||||
|
const toolPath = this._getSpawnFileName();
|
||||||
|
const args = this._getSpawnArgs(options);
|
||||||
|
let cmd = noPrefix ? '' : '[command]'; // omit prefix when piped to a second tool
|
||||||
|
if (IS_WINDOWS) {
|
||||||
|
// Windows + cmd file
|
||||||
|
if (this._isCmdFile()) {
|
||||||
|
cmd += toolPath;
|
||||||
|
for (const a of args) {
|
||||||
|
cmd += ` ${a}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Windows + verbatim
|
||||||
|
else if (options.windowsVerbatimArguments) {
|
||||||
|
cmd += `"${toolPath}"`;
|
||||||
|
for (const a of args) {
|
||||||
|
cmd += ` ${a}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Windows (regular)
|
||||||
|
else {
|
||||||
|
cmd += this._windowsQuoteCmdArg(toolPath);
|
||||||
|
for (const a of args) {
|
||||||
|
cmd += ` ${this._windowsQuoteCmdArg(a)}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// OSX/Linux - this can likely be improved with some form of quoting.
|
||||||
|
// creating processes on Unix is fundamentally different than Windows.
|
||||||
|
// on Unix, execvp() takes an arg array.
|
||||||
|
cmd += toolPath;
|
||||||
|
for (const a of args) {
|
||||||
|
cmd += ` ${a}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
_processLineBuffer(data, strBuffer, onLine) {
|
||||||
|
try {
|
||||||
|
let s = strBuffer + data.toString();
|
||||||
|
let n = s.indexOf(os.EOL);
|
||||||
|
while (n > -1) {
|
||||||
|
const line = s.substring(0, n);
|
||||||
|
onLine(line);
|
||||||
|
// the rest of the string ...
|
||||||
|
s = s.substring(n + os.EOL.length);
|
||||||
|
n = s.indexOf(os.EOL);
|
||||||
|
}
|
||||||
|
strBuffer = s;
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
// streaming lines to console is best effort. Don't fail a build.
|
||||||
|
this._debug(`error processing line. Failed with error ${err}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_getSpawnFileName() {
|
||||||
|
if (IS_WINDOWS) {
|
||||||
|
if (this._isCmdFile()) {
|
||||||
|
return process.env['COMSPEC'] || 'cmd.exe';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.toolPath;
|
||||||
|
}
|
||||||
|
_getSpawnArgs(options) {
|
||||||
|
if (IS_WINDOWS) {
|
||||||
|
if (this._isCmdFile()) {
|
||||||
|
let argline = `/D /S /C "${this._windowsQuoteCmdArg(this.toolPath)}`;
|
||||||
|
for (const a of this.args) {
|
||||||
|
argline += ' ';
|
||||||
|
argline += options.windowsVerbatimArguments
|
||||||
|
? a
|
||||||
|
: this._windowsQuoteCmdArg(a);
|
||||||
|
}
|
||||||
|
argline += '"';
|
||||||
|
return [argline];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.args;
|
||||||
|
}
|
||||||
|
_endsWith(str, end) {
|
||||||
|
return str.endsWith(end);
|
||||||
|
}
|
||||||
|
_isCmdFile() {
|
||||||
|
const upperToolPath = this.toolPath.toUpperCase();
|
||||||
|
return (this._endsWith(upperToolPath, '.CMD') ||
|
||||||
|
this._endsWith(upperToolPath, '.BAT'));
|
||||||
|
}
|
||||||
|
_windowsQuoteCmdArg(arg) {
|
||||||
|
// for .exe, apply the normal quoting rules that libuv applies
|
||||||
|
if (!this._isCmdFile()) {
|
||||||
|
return this._uvQuoteCmdArg(arg);
|
||||||
|
}
|
||||||
|
// otherwise apply quoting rules specific to the cmd.exe command line parser.
|
||||||
|
// the libuv rules are generic and are not designed specifically for cmd.exe
|
||||||
|
// command line parser.
|
||||||
|
//
|
||||||
|
// for a detailed description of the cmd.exe command line parser, refer to
|
||||||
|
// http://stackoverflow.com/questions/4094699/how-does-the-windows-command-interpreter-cmd-exe-parse-scripts/7970912#7970912
|
||||||
|
// need quotes for empty arg
|
||||||
|
if (!arg) {
|
||||||
|
return '""';
|
||||||
|
}
|
||||||
|
// determine whether the arg needs to be quoted
|
||||||
|
const cmdSpecialChars = [
|
||||||
|
' ',
|
||||||
|
'\t',
|
||||||
|
'&',
|
||||||
|
'(',
|
||||||
|
')',
|
||||||
|
'[',
|
||||||
|
']',
|
||||||
|
'{',
|
||||||
|
'}',
|
||||||
|
'^',
|
||||||
|
'=',
|
||||||
|
';',
|
||||||
|
'!',
|
||||||
|
"'",
|
||||||
|
'+',
|
||||||
|
',',
|
||||||
|
'`',
|
||||||
|
'~',
|
||||||
|
'|',
|
||||||
|
'<',
|
||||||
|
'>',
|
||||||
|
'"'
|
||||||
|
];
|
||||||
|
let needsQuotes = false;
|
||||||
|
for (const char of arg) {
|
||||||
|
if (cmdSpecialChars.some(x => x === char)) {
|
||||||
|
needsQuotes = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// short-circuit if quotes not needed
|
||||||
|
if (!needsQuotes) {
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
// the following quoting rules are very similar to the rules that by libuv applies.
|
||||||
|
//
|
||||||
|
// 1) wrap the string in quotes
|
||||||
|
//
|
||||||
|
// 2) double-up quotes - i.e. " => ""
|
||||||
|
//
|
||||||
|
// this is different from the libuv quoting rules. libuv replaces " with \", which unfortunately
|
||||||
|
// doesn't work well with a cmd.exe command line.
|
||||||
|
//
|
||||||
|
// note, replacing " with "" also works well if the arg is passed to a downstream .NET console app.
|
||||||
|
// for example, the command line:
|
||||||
|
// foo.exe "myarg:""my val"""
|
||||||
|
// is parsed by a .NET console app into an arg array:
|
||||||
|
// [ "myarg:\"my val\"" ]
|
||||||
|
// which is the same end result when applying libuv quoting rules. although the actual
|
||||||
|
// command line from libuv quoting rules would look like:
|
||||||
|
// foo.exe "myarg:\"my val\""
|
||||||
|
//
|
||||||
|
// 3) double-up slashes that preceed a quote,
|
||||||
|
// e.g. hello \world => "hello \world"
|
||||||
|
// hello\"world => "hello\\""world"
|
||||||
|
// hello\\"world => "hello\\\\""world"
|
||||||
|
// hello world\ => "hello world\\"
|
||||||
|
//
|
||||||
|
// technically this is not required for a cmd.exe command line, or the batch argument parser.
|
||||||
|
// the reasons for including this as a .cmd quoting rule are:
|
||||||
|
//
|
||||||
|
// a) this is optimized for the scenario where the argument is passed from the .cmd file to an
|
||||||
|
// external program. many programs (e.g. .NET console apps) rely on the slash-doubling rule.
|
||||||
|
//
|
||||||
|
// b) it's what we've been doing previously (by deferring to node default behavior) and we
|
||||||
|
// haven't heard any complaints about that aspect.
|
||||||
|
//
|
||||||
|
// note, a weakness of the quoting rules chosen here, is that % is not escaped. in fact, % cannot be
|
||||||
|
// escaped when used on the command line directly - even though within a .cmd file % can be escaped
|
||||||
|
// by using %%.
|
||||||
|
//
|
||||||
|
// the saving grace is, on the command line, %var% is left as-is if var is not defined. this contrasts
|
||||||
|
// the line parsing rules within a .cmd file, where if var is not defined it is replaced with nothing.
|
||||||
|
//
|
||||||
|
// one option that was explored was replacing % with ^% - i.e. %var% => ^%var^%. this hack would
|
||||||
|
// often work, since it is unlikely that var^ would exist, and the ^ character is removed when the
|
||||||
|
// variable is used. the problem, however, is that ^ is not removed when %* is used to pass the args
|
||||||
|
// to an external program.
|
||||||
|
//
|
||||||
|
// an unexplored potential solution for the % escaping problem, is to create a wrapper .cmd file.
|
||||||
|
// % can be escaped within a .cmd file.
|
||||||
|
let reverse = '"';
|
||||||
|
let quoteHit = true;
|
||||||
|
for (let i = arg.length; i > 0; i--) {
|
||||||
|
// walk the string in reverse
|
||||||
|
reverse += arg[i - 1];
|
||||||
|
if (quoteHit && arg[i - 1] === '\\') {
|
||||||
|
reverse += '\\'; // double the slash
|
||||||
|
}
|
||||||
|
else if (arg[i - 1] === '"') {
|
||||||
|
quoteHit = true;
|
||||||
|
reverse += '"'; // double the quote
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
quoteHit = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reverse += '"';
|
||||||
|
return reverse
|
||||||
|
.split('')
|
||||||
|
.reverse()
|
||||||
|
.join('');
|
||||||
|
}
|
||||||
|
_uvQuoteCmdArg(arg) {
|
||||||
|
// Tool runner wraps child_process.spawn() and needs to apply the same quoting as
|
||||||
|
// Node in certain cases where the undocumented spawn option windowsVerbatimArguments
|
||||||
|
// is used.
|
||||||
|
//
|
||||||
|
// Since this function is a port of quote_cmd_arg from Node 4.x (technically, lib UV,
|
||||||
|
// see https://github.com/nodejs/node/blob/v4.x/deps/uv/src/win/process.c for details),
|
||||||
|
// pasting copyright notice from Node within this function:
|
||||||
|
//
|
||||||
|
// Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
if (!arg) {
|
||||||
|
// Need double quotation for empty argument
|
||||||
|
return '""';
|
||||||
|
}
|
||||||
|
if (!arg.includes(' ') && !arg.includes('\t') && !arg.includes('"')) {
|
||||||
|
// No quotation needed
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
if (!arg.includes('"') && !arg.includes('\\')) {
|
||||||
|
// No embedded double quotes or backslashes, so I can just wrap
|
||||||
|
// quote marks around the whole thing.
|
||||||
|
return `"${arg}"`;
|
||||||
|
}
|
||||||
|
// Expected input/output:
|
||||||
|
// input : hello"world
|
||||||
|
// output: "hello\"world"
|
||||||
|
// input : hello""world
|
||||||
|
// output: "hello\"\"world"
|
||||||
|
// input : hello\world
|
||||||
|
// output: hello\world
|
||||||
|
// input : hello\\world
|
||||||
|
// output: hello\\world
|
||||||
|
// input : hello\"world
|
||||||
|
// output: "hello\\\"world"
|
||||||
|
// input : hello\\"world
|
||||||
|
// output: "hello\\\\\"world"
|
||||||
|
// input : hello world\
|
||||||
|
// output: "hello world\\" - note the comment in libuv actually reads "hello world\"
|
||||||
|
// but it appears the comment is wrong, it should be "hello world\\"
|
||||||
|
let reverse = '"';
|
||||||
|
let quoteHit = true;
|
||||||
|
for (let i = arg.length; i > 0; i--) {
|
||||||
|
// walk the string in reverse
|
||||||
|
reverse += arg[i - 1];
|
||||||
|
if (quoteHit && arg[i - 1] === '\\') {
|
||||||
|
reverse += '\\';
|
||||||
|
}
|
||||||
|
else if (arg[i - 1] === '"') {
|
||||||
|
quoteHit = true;
|
||||||
|
reverse += '\\';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
quoteHit = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reverse += '"';
|
||||||
|
return reverse
|
||||||
|
.split('')
|
||||||
|
.reverse()
|
||||||
|
.join('');
|
||||||
|
}
|
||||||
|
_cloneExecOptions(options) {
|
||||||
|
options = options || {};
|
||||||
|
const result = {
|
||||||
|
cwd: options.cwd || process.cwd(),
|
||||||
|
env: options.env || process.env,
|
||||||
|
silent: options.silent || false,
|
||||||
|
windowsVerbatimArguments: options.windowsVerbatimArguments || false,
|
||||||
|
failOnStdErr: options.failOnStdErr || false,
|
||||||
|
ignoreReturnCode: options.ignoreReturnCode || false,
|
||||||
|
delay: options.delay || 10000
|
||||||
|
};
|
||||||
|
result.outStream = options.outStream || process.stdout;
|
||||||
|
result.errStream = options.errStream || process.stderr;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
_getSpawnOptions(options, toolPath) {
|
||||||
|
options = options || {};
|
||||||
|
const result = {};
|
||||||
|
result.cwd = options.cwd;
|
||||||
|
result.env = options.env;
|
||||||
|
result['windowsVerbatimArguments'] =
|
||||||
|
options.windowsVerbatimArguments || this._isCmdFile();
|
||||||
|
if (options.windowsVerbatimArguments) {
|
||||||
|
result.argv0 = `"${toolPath}"`;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Exec a tool.
|
||||||
|
* Output will be streamed to the live console.
|
||||||
|
* Returns promise with return code
|
||||||
|
*
|
||||||
|
* @param tool path to tool to exec
|
||||||
|
* @param options optional exec options. See ExecOptions
|
||||||
|
* @returns number
|
||||||
|
*/
|
||||||
|
exec() {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this._debug(`exec tool: ${this.toolPath}`);
|
||||||
|
this._debug('arguments:');
|
||||||
|
for (const arg of this.args) {
|
||||||
|
this._debug(` ${arg}`);
|
||||||
|
}
|
||||||
|
const optionsNonNull = this._cloneExecOptions(this.options);
|
||||||
|
if (!optionsNonNull.silent && optionsNonNull.outStream) {
|
||||||
|
optionsNonNull.outStream.write(this._getCommandString(optionsNonNull) + os.EOL);
|
||||||
|
}
|
||||||
|
const state = new ExecState(optionsNonNull, this.toolPath);
|
||||||
|
state.on('debug', (message) => {
|
||||||
|
this._debug(message);
|
||||||
|
});
|
||||||
|
const fileName = this._getSpawnFileName();
|
||||||
|
const cp = child.spawn(fileName, this._getSpawnArgs(optionsNonNull), this._getSpawnOptions(this.options, fileName));
|
||||||
|
const stdbuffer = '';
|
||||||
|
if (cp.stdout) {
|
||||||
|
cp.stdout.on('data', (data) => {
|
||||||
|
if (this.options.listeners && this.options.listeners.stdout) {
|
||||||
|
this.options.listeners.stdout(data);
|
||||||
|
}
|
||||||
|
if (!optionsNonNull.silent && optionsNonNull.outStream) {
|
||||||
|
optionsNonNull.outStream.write(data);
|
||||||
|
}
|
||||||
|
this._processLineBuffer(data, stdbuffer, (line) => {
|
||||||
|
if (this.options.listeners && this.options.listeners.stdline) {
|
||||||
|
this.options.listeners.stdline(line);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const errbuffer = '';
|
||||||
|
if (cp.stderr) {
|
||||||
|
cp.stderr.on('data', (data) => {
|
||||||
|
state.processStderr = true;
|
||||||
|
if (this.options.listeners && this.options.listeners.stderr) {
|
||||||
|
this.options.listeners.stderr(data);
|
||||||
|
}
|
||||||
|
if (!optionsNonNull.silent &&
|
||||||
|
optionsNonNull.errStream &&
|
||||||
|
optionsNonNull.outStream) {
|
||||||
|
const s = optionsNonNull.failOnStdErr
|
||||||
|
? optionsNonNull.errStream
|
||||||
|
: optionsNonNull.outStream;
|
||||||
|
s.write(data);
|
||||||
|
}
|
||||||
|
this._processLineBuffer(data, errbuffer, (line) => {
|
||||||
|
if (this.options.listeners && this.options.listeners.errline) {
|
||||||
|
this.options.listeners.errline(line);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
cp.on('error', (err) => {
|
||||||
|
state.processError = err.message;
|
||||||
|
state.processExited = true;
|
||||||
|
state.processClosed = true;
|
||||||
|
state.CheckComplete();
|
||||||
|
});
|
||||||
|
cp.on('exit', (code) => {
|
||||||
|
state.processExitCode = code;
|
||||||
|
state.processExited = true;
|
||||||
|
this._debug(`Exit code ${code} received from tool '${this.toolPath}'`);
|
||||||
|
state.CheckComplete();
|
||||||
|
});
|
||||||
|
cp.on('close', (code) => {
|
||||||
|
state.processExitCode = code;
|
||||||
|
state.processExited = true;
|
||||||
|
state.processClosed = true;
|
||||||
|
this._debug(`STDIO streams have closed for tool '${this.toolPath}'`);
|
||||||
|
state.CheckComplete();
|
||||||
|
});
|
||||||
|
state.on('done', (error, exitCode) => {
|
||||||
|
if (stdbuffer.length > 0) {
|
||||||
|
this.emit('stdline', stdbuffer);
|
||||||
|
}
|
||||||
|
if (errbuffer.length > 0) {
|
||||||
|
this.emit('errline', errbuffer);
|
||||||
|
}
|
||||||
|
cp.removeAllListeners();
|
||||||
|
if (error) {
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resolve(exitCode);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.ToolRunner = ToolRunner;
|
||||||
|
/**
|
||||||
|
* Convert an arg string to an array of args. Handles escaping
|
||||||
|
*
|
||||||
|
* @param argString string of arguments
|
||||||
|
* @returns string[] array of arguments
|
||||||
|
*/
|
||||||
|
function argStringToArray(argString) {
|
||||||
|
const args = [];
|
||||||
|
let inQuotes = false;
|
||||||
|
let escaped = false;
|
||||||
|
let arg = '';
|
||||||
|
function append(c) {
|
||||||
|
// we only escape double quotes.
|
||||||
|
if (escaped && c !== '"') {
|
||||||
|
arg += '\\';
|
||||||
|
}
|
||||||
|
arg += c;
|
||||||
|
escaped = false;
|
||||||
|
}
|
||||||
|
for (let i = 0; i < argString.length; i++) {
|
||||||
|
const c = argString.charAt(i);
|
||||||
|
if (c === '"') {
|
||||||
|
if (!escaped) {
|
||||||
|
inQuotes = !inQuotes;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
append(c);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c === '\\' && escaped) {
|
||||||
|
append(c);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c === '\\' && inQuotes) {
|
||||||
|
escaped = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c === ' ' && !inQuotes) {
|
||||||
|
if (arg.length > 0) {
|
||||||
|
args.push(arg);
|
||||||
|
arg = '';
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
append(c);
|
||||||
|
}
|
||||||
|
if (arg.length > 0) {
|
||||||
|
args.push(arg.trim());
|
||||||
|
}
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
exports.argStringToArray = argStringToArray;
|
||||||
|
class ExecState extends events.EventEmitter {
|
||||||
|
constructor(options, toolPath) {
|
||||||
|
super();
|
||||||
|
this.processClosed = false; // tracks whether the process has exited and stdio is closed
|
||||||
|
this.processError = '';
|
||||||
|
this.processExitCode = 0;
|
||||||
|
this.processExited = false; // tracks whether the process has exited
|
||||||
|
this.processStderr = false; // tracks whether stderr was written to
|
||||||
|
this.delay = 10000; // 10 seconds
|
||||||
|
this.done = false;
|
||||||
|
this.timeout = null;
|
||||||
|
if (!toolPath) {
|
||||||
|
throw new Error('toolPath must not be empty');
|
||||||
|
}
|
||||||
|
this.options = options;
|
||||||
|
this.toolPath = toolPath;
|
||||||
|
if (options.delay) {
|
||||||
|
this.delay = options.delay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CheckComplete() {
|
||||||
|
if (this.done) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.processClosed) {
|
||||||
|
this._setResult();
|
||||||
|
}
|
||||||
|
else if (this.processExited) {
|
||||||
|
this.timeout = setTimeout(ExecState.HandleTimeout, this.delay, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_debug(message) {
|
||||||
|
this.emit('debug', message);
|
||||||
|
}
|
||||||
|
_setResult() {
|
||||||
|
// determine whether there is an error
|
||||||
|
let error;
|
||||||
|
if (this.processExited) {
|
||||||
|
if (this.processError) {
|
||||||
|
error = new Error(`There was an error when attempting to execute the process '${this.toolPath}'. This may indicate the process failed to start. Error: ${this.processError}`);
|
||||||
|
}
|
||||||
|
else if (this.processExitCode !== 0 && !this.options.ignoreReturnCode) {
|
||||||
|
error = new Error(`The process '${this.toolPath}' failed with exit code ${this.processExitCode}`);
|
||||||
|
}
|
||||||
|
else if (this.processStderr && this.options.failOnStdErr) {
|
||||||
|
error = new Error(`The process '${this.toolPath}' failed because one or more lines were written to the STDERR stream`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// clear the timeout
|
||||||
|
if (this.timeout) {
|
||||||
|
clearTimeout(this.timeout);
|
||||||
|
this.timeout = null;
|
||||||
|
}
|
||||||
|
this.done = true;
|
||||||
|
this.emit('done', error, this.processExitCode);
|
||||||
|
}
|
||||||
|
static HandleTimeout(state) {
|
||||||
|
if (state.done) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!state.processClosed && state.processExited) {
|
||||||
|
const message = `The STDIO streams did not close within ${state.delay /
|
||||||
|
1000} seconds of the exit event from process '${state.toolPath}'. This may indicate a child process inherited the STDIO streams and has not yet exited.`;
|
||||||
|
state._debug(message);
|
||||||
|
}
|
||||||
|
state._setResult();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=toolrunner.js.map
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,63 @@
|
||||||
|
{
|
||||||
|
"_from": "file:toolkit\\actions-exec-0.0.0.tgz",
|
||||||
|
"_id": "@actions/exec@0.0.0",
|
||||||
|
"_inBundle": false,
|
||||||
|
"_integrity": "sha512-HHObusC4p1RElxIlrrN0sY/cweBYl+jKm3J/XWHPQZMipgJXB/dkVhUfl4KqH3Vim7oM2KjCGSfn+vTYrqVH3A==",
|
||||||
|
"_location": "/@actions/exec",
|
||||||
|
"_phantomChildren": {},
|
||||||
|
"_requested": {
|
||||||
|
"type": "file",
|
||||||
|
"where": "C:\\Users\\damccorm\\Documents\\node12-template",
|
||||||
|
"raw": "@actions/exec@file:toolkit/actions-exec-0.0.0.tgz",
|
||||||
|
"name": "@actions/exec",
|
||||||
|
"escapedName": "@actions%2fexec",
|
||||||
|
"scope": "@actions",
|
||||||
|
"rawSpec": "file:toolkit/actions-exec-0.0.0.tgz",
|
||||||
|
"saveSpec": "file:toolkit\\actions-exec-0.0.0.tgz",
|
||||||
|
"fetchSpec": "C:\\Users\\damccorm\\Documents\\node12-template\\toolkit\\actions-exec-0.0.0.tgz"
|
||||||
|
},
|
||||||
|
"_requiredBy": [
|
||||||
|
"/",
|
||||||
|
"/@actions/tool-cache"
|
||||||
|
],
|
||||||
|
"_resolved": "C:\\Users\\damccorm\\Documents\\node12-template\\toolkit\\actions-exec-0.0.0.tgz",
|
||||||
|
"_shasum": "341d868fe6c4123ded20db9c2106b7b8c16e1d73",
|
||||||
|
"_spec": "@actions/exec@file:toolkit/actions-exec-0.0.0.tgz",
|
||||||
|
"_where": "C:\\Users\\damccorm\\Documents\\node12-template",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/actions/toolkit/issues"
|
||||||
|
},
|
||||||
|
"bundleDependencies": false,
|
||||||
|
"deprecated": false,
|
||||||
|
"description": "Actions exec lib",
|
||||||
|
"devDependencies": {
|
||||||
|
"@actions/io": "^0.0.0"
|
||||||
|
},
|
||||||
|
"directories": {
|
||||||
|
"lib": "lib",
|
||||||
|
"test": "__tests__"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"lib"
|
||||||
|
],
|
||||||
|
"homepage": "https://github.com/actions/toolkit/tree/master/packages/exec",
|
||||||
|
"keywords": [
|
||||||
|
"exec",
|
||||||
|
"actions"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"main": "lib/exec.js",
|
||||||
|
"name": "@actions/exec",
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/actions/toolkit.git"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: run tests from root\" && exit 1",
|
||||||
|
"tsc": "tsc"
|
||||||
|
},
|
||||||
|
"version": "0.0.0"
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
# `@actions/github`
|
||||||
|
|
||||||
|
> A hydrated Octokit client.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Returns an [Octokit SDK] client. See https://octokit.github.io/rest.js for the API.
|
||||||
|
|
||||||
|
```
|
||||||
|
const github = require('@actions/github');
|
||||||
|
|
||||||
|
// This should be a token with access to your repository scoped in as a secret.
|
||||||
|
const myToken = process.env.GITHUB_TOKEN
|
||||||
|
|
||||||
|
const octokit = new github.GitHub(myToken)
|
||||||
|
|
||||||
|
const pulls = await octokit.pulls.get({
|
||||||
|
owner: 'octokit',
|
||||||
|
repo: 'rest.js',
|
||||||
|
pull_number: 123,
|
||||||
|
mediaType: {
|
||||||
|
format: 'diff'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(pulls)
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also make GraphQL requests:
|
||||||
|
|
||||||
|
```
|
||||||
|
const result = await octokit.graphql(query, variables)
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally, you can get the context of the current action:
|
||||||
|
|
||||||
|
```
|
||||||
|
const github = require('@actions/github');
|
||||||
|
|
||||||
|
const context = github.context
|
||||||
|
|
||||||
|
const newIssue = await octokit.issues.create({
|
||||||
|
...context.repo,
|
||||||
|
title: 'New issue!',
|
||||||
|
body: 'Hello Universe!'
|
||||||
|
})
|
||||||
|
```
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { WebhookPayload } from './interfaces';
|
||||||
|
export declare class Context {
|
||||||
|
/**
|
||||||
|
* Webhook payload object that triggered the workflow
|
||||||
|
*/
|
||||||
|
payload: WebhookPayload;
|
||||||
|
eventName: string;
|
||||||
|
sha: string;
|
||||||
|
ref: string;
|
||||||
|
workflow: string;
|
||||||
|
action: string;
|
||||||
|
actor: string;
|
||||||
|
/**
|
||||||
|
* Hydrate the context from the environment
|
||||||
|
*/
|
||||||
|
constructor();
|
||||||
|
readonly issue: {
|
||||||
|
owner: string;
|
||||||
|
repo: string;
|
||||||
|
number: number;
|
||||||
|
};
|
||||||
|
readonly repo: {
|
||||||
|
owner: string;
|
||||||
|
repo: string;
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
/* eslint-disable @typescript-eslint/no-require-imports */
|
||||||
|
class Context {
|
||||||
|
/**
|
||||||
|
* Hydrate the context from the environment
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
this.payload = process.env.GITHUB_EVENT_PATH
|
||||||
|
? require(process.env.GITHUB_EVENT_PATH)
|
||||||
|
: {};
|
||||||
|
this.eventName = process.env.GITHUB_EVENT_NAME;
|
||||||
|
this.sha = process.env.GITHUB_SHA;
|
||||||
|
this.ref = process.env.GITHUB_REF;
|
||||||
|
this.workflow = process.env.GITHUB_WORKFLOW;
|
||||||
|
this.action = process.env.GITHUB_ACTION;
|
||||||
|
this.actor = process.env.GITHUB_ACTOR;
|
||||||
|
}
|
||||||
|
get issue() {
|
||||||
|
const payload = this.payload;
|
||||||
|
return Object.assign({}, this.repo, { number: (payload.issue || payload.pullRequest || payload).number });
|
||||||
|
}
|
||||||
|
get repo() {
|
||||||
|
if (process.env.GITHUB_REPOSITORY) {
|
||||||
|
const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/');
|
||||||
|
return { owner, repo };
|
||||||
|
}
|
||||||
|
if (this.payload.repository) {
|
||||||
|
return {
|
||||||
|
owner: this.payload.repository.owner.login,
|
||||||
|
repo: this.payload.repository.name
|
||||||
|
};
|
||||||
|
}
|
||||||
|
throw new Error("context.repo requires a GITHUB_REPOSITORY environment variable like 'owner/repo'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.Context = Context;
|
||||||
|
//# sourceMappingURL=context.js.map
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":";;AAGA,0DAA0D;AAE1D,MAAa,OAAO;IAalB;;OAEG;IACH;QACE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB;YAC1C,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;YACxC,CAAC,CAAC,EAAE,CAAA;QACN,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,iBAA2B,CAAA;QACxD,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,UAAoB,CAAA;QAC3C,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,UAAoB,CAAA;QAC3C,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,eAAyB,CAAA;QACrD,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,aAAuB,CAAA;QACjD,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,YAAsB,CAAA;IACjD,CAAC;IAED,IAAI,KAAK;QACP,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAA;QAE5B,yBACK,IAAI,CAAC,IAAI,IACZ,MAAM,EAAE,CAAC,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,CAAC,MAAM,IACjE;IACH,CAAC;IAED,IAAI,IAAI;QACN,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE;YACjC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;YAC9D,OAAO,EAAC,KAAK,EAAE,IAAI,EAAC,CAAA;SACrB;QAED,IAAI,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE;YAC3B,OAAO;gBACL,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK;gBAC1C,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI;aACnC,CAAA;SACF;QAED,MAAM,IAAI,KAAK,CACb,kFAAkF,CACnF,CAAA;IACH,CAAC;CACF;AAtDD,0BAsDC"}
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { GraphQlQueryResponse, Variables } from '@octokit/graphql';
|
||||||
|
import Octokit from '@octokit/rest';
|
||||||
|
export declare class GitHub extends Octokit {
|
||||||
|
graphql: (query: string, variables?: Variables) => Promise<GraphQlQueryResponse>;
|
||||||
|
constructor(token: string);
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||||
|
result["default"] = mod;
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
// Originally pulled from https://github.com/JasonEtco/actions-toolkit/blob/master/src/github.ts
|
||||||
|
const graphql_1 = require("@octokit/graphql");
|
||||||
|
const rest_1 = __importDefault(require("@octokit/rest"));
|
||||||
|
const Context = __importStar(require("./context"));
|
||||||
|
// We need this in order to extend Octokit
|
||||||
|
rest_1.default.prototype = new rest_1.default();
|
||||||
|
module.exports.context = new Context.Context();
|
||||||
|
class GitHub extends rest_1.default {
|
||||||
|
constructor(token) {
|
||||||
|
super({ auth: `token ${token}` });
|
||||||
|
this.graphql = graphql_1.defaults({
|
||||||
|
headers: { authorization: `token ${token}` }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.GitHub = GitHub;
|
||||||
|
//# sourceMappingURL=github.js.map
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"github.js","sourceRoot":"","sources":["../src/github.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,gGAAgG;AAChG,8CAA0E;AAC1E,yDAAmC;AACnC,mDAAoC;AAEpC,0CAA0C;AAC1C,cAAO,CAAC,SAAS,GAAG,IAAI,cAAO,EAAE,CAAA;AAEjC,MAAM,CAAC,OAAO,CAAC,OAAO,GAAG,IAAI,OAAO,CAAC,OAAO,EAAE,CAAA;AAE9C,MAAa,MAAO,SAAQ,cAAO;IAMjC,YAAY,KAAa;QACvB,KAAK,CAAC,EAAC,IAAI,EAAE,SAAS,KAAK,EAAE,EAAC,CAAC,CAAA;QAC/B,IAAI,CAAC,OAAO,GAAG,kBAAQ,CAAC;YACtB,OAAO,EAAE,EAAC,aAAa,EAAE,SAAS,KAAK,EAAE,EAAC;SAC3C,CAAC,CAAA;IACJ,CAAC;CACF;AAZD,wBAYC"}
|
|
@ -0,0 +1,36 @@
|
||||||
|
export interface PayloadRepository {
|
||||||
|
[key: string]: any;
|
||||||
|
fullName?: string;
|
||||||
|
name: string;
|
||||||
|
owner: {
|
||||||
|
[key: string]: any;
|
||||||
|
login: string;
|
||||||
|
name?: string;
|
||||||
|
};
|
||||||
|
htmlUrl?: string;
|
||||||
|
}
|
||||||
|
export interface WebhookPayload {
|
||||||
|
[key: string]: any;
|
||||||
|
repository?: PayloadRepository;
|
||||||
|
issue?: {
|
||||||
|
[key: string]: any;
|
||||||
|
number: number;
|
||||||
|
html_url?: string;
|
||||||
|
body?: string;
|
||||||
|
};
|
||||||
|
pullRequest?: {
|
||||||
|
[key: string]: any;
|
||||||
|
number: number;
|
||||||
|
htmlUrl?: string;
|
||||||
|
body?: string;
|
||||||
|
};
|
||||||
|
sender?: {
|
||||||
|
[key: string]: any;
|
||||||
|
type: string;
|
||||||
|
};
|
||||||
|
action?: string;
|
||||||
|
installation?: {
|
||||||
|
id: number;
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
"use strict";
|
||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
//# sourceMappingURL=interfaces.js.map
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":";AAAA,uDAAuD"}
|
|
@ -0,0 +1,67 @@
|
||||||
|
{
|
||||||
|
"_from": "file:toolkit\\actions-github-0.0.0.tgz",
|
||||||
|
"_id": "@actions/github@0.0.0",
|
||||||
|
"_inBundle": false,
|
||||||
|
"_integrity": "sha512-K13pi9kbZqFnvhe8m6uqfz4kCnB4Ki6fzv4XBae1zDZfn2Si+Qx6j1pAfXSo7QI2+ZWAX/g0paFgcJsS6ZTWZA==",
|
||||||
|
"_location": "/@actions/github",
|
||||||
|
"_phantomChildren": {},
|
||||||
|
"_requested": {
|
||||||
|
"type": "file",
|
||||||
|
"where": "C:\\Users\\damccorm\\Documents\\node12-template",
|
||||||
|
"raw": "@actions/github@file:toolkit/actions-github-0.0.0.tgz",
|
||||||
|
"name": "@actions/github",
|
||||||
|
"escapedName": "@actions%2fgithub",
|
||||||
|
"scope": "@actions",
|
||||||
|
"rawSpec": "file:toolkit/actions-github-0.0.0.tgz",
|
||||||
|
"saveSpec": "file:toolkit\\actions-github-0.0.0.tgz",
|
||||||
|
"fetchSpec": "C:\\Users\\damccorm\\Documents\\node12-template\\toolkit\\actions-github-0.0.0.tgz"
|
||||||
|
},
|
||||||
|
"_requiredBy": [
|
||||||
|
"/"
|
||||||
|
],
|
||||||
|
"_resolved": "C:\\Users\\damccorm\\Documents\\node12-template\\toolkit\\actions-github-0.0.0.tgz",
|
||||||
|
"_shasum": "0764713c5b42ec9bbd9b4ca26b971dcdedadd820",
|
||||||
|
"_spec": "@actions/github@file:toolkit/actions-github-0.0.0.tgz",
|
||||||
|
"_where": "C:\\Users\\damccorm\\Documents\\node12-template",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/actions/toolkit/issues"
|
||||||
|
},
|
||||||
|
"bundleDependencies": false,
|
||||||
|
"dependencies": {
|
||||||
|
"@octokit/graphql": "^2.0.1",
|
||||||
|
"@octokit/rest": "^16.15.0"
|
||||||
|
},
|
||||||
|
"deprecated": false,
|
||||||
|
"description": "Actions github lib",
|
||||||
|
"devDependencies": {
|
||||||
|
"jest": "^24.7.1"
|
||||||
|
},
|
||||||
|
"directories": {
|
||||||
|
"lib": "lib",
|
||||||
|
"test": "__tests__"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"lib"
|
||||||
|
],
|
||||||
|
"homepage": "https://github.com/actions/toolkit/tree/master/packages/github",
|
||||||
|
"keywords": [
|
||||||
|
"github",
|
||||||
|
"actions"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"main": "lib/github.js",
|
||||||
|
"name": "@actions/github",
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/actions/toolkit.git"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"test": "jest",
|
||||||
|
"tsc": "tsc"
|
||||||
|
},
|
||||||
|
"version": "0.0.0"
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
# `@actions/io`
|
||||||
|
|
||||||
|
> Core functions for cli filesystem scenarios
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
/**
|
||||||
|
* Copies a file or folder.
|
||||||
|
*
|
||||||
|
* @param source source path
|
||||||
|
* @param dest destination path
|
||||||
|
* @param options optional. See CopyOptions.
|
||||||
|
*/
|
||||||
|
export function cp(source: string, dest: string, options?: CopyOptions): Promise<void>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a path recursively with force
|
||||||
|
*
|
||||||
|
* @param path path to remove
|
||||||
|
*/
|
||||||
|
export function rmRF(path: string): Promise<void>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make a directory. Creates the full path with folders in between
|
||||||
|
*
|
||||||
|
* @param p path to create
|
||||||
|
* @returns Promise<void>
|
||||||
|
*/
|
||||||
|
export function mkdirP(p: string): Promise<void>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves a path.
|
||||||
|
*
|
||||||
|
* @param source source path
|
||||||
|
* @param dest destination path
|
||||||
|
* @param options optional. See CopyOptions.
|
||||||
|
*/
|
||||||
|
export function mv(source: string, dest: string, options?: CopyOptions): Promise<void>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns path of a tool had the tool actually been invoked. Resolves via paths.
|
||||||
|
*
|
||||||
|
* @param tool name of the tool
|
||||||
|
* @param options optional. See WhichOptions.
|
||||||
|
* @returns Promise<string> path to tool
|
||||||
|
*/
|
||||||
|
export function which(tool: string, options?: WhichOptions): Promise<string>
|
||||||
|
```
|
|
@ -0,0 +1,29 @@
|
||||||
|
/// <reference types="node" />
|
||||||
|
import * as fs from 'fs';
|
||||||
|
export declare const chmod: typeof fs.promises.chmod, copyFile: typeof fs.promises.copyFile, lstat: typeof fs.promises.lstat, mkdir: typeof fs.promises.mkdir, readdir: typeof fs.promises.readdir, readlink: typeof fs.promises.readlink, rename: typeof fs.promises.rename, rmdir: typeof fs.promises.rmdir, stat: typeof fs.promises.stat, symlink: typeof fs.promises.symlink, unlink: typeof fs.promises.unlink;
|
||||||
|
export declare const IS_WINDOWS: boolean;
|
||||||
|
export declare function exists(fsPath: string): Promise<boolean>;
|
||||||
|
export declare function isDirectory(fsPath: string, useStat?: boolean): Promise<boolean>;
|
||||||
|
/**
|
||||||
|
* On OSX/Linux, true if path starts with '/'. On Windows, true for paths like:
|
||||||
|
* \, \hello, \\hello\share, C:, and C:\hello (and corresponding alternate separator cases).
|
||||||
|
*/
|
||||||
|
export declare function isRooted(p: string): boolean;
|
||||||
|
/**
|
||||||
|
* 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 declare function mkdirP(fsPath: string, maxDepth?: number, depth?: number): Promise<void>;
|
||||||
|
/**
|
||||||
|
* Best effort attempt to determine whether a file exists and is executable.
|
||||||
|
* @param filePath file path to check
|
||||||
|
* @param extensions additional file extensions to try
|
||||||
|
* @return if file exists and is executable, returns the file path. otherwise empty string.
|
||||||
|
*/
|
||||||
|
export declare function tryGetExecutablePath(filePath: string, extensions: string[]): Promise<string>;
|
|
@ -0,0 +1,194 @@
|
||||||
|
"use strict";
|
||||||
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||||
|
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
var _a;
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const assert_1 = require("assert");
|
||||||
|
const fs = require("fs");
|
||||||
|
const path = require("path");
|
||||||
|
_a = fs.promises, exports.chmod = _a.chmod, exports.copyFile = _a.copyFile, exports.lstat = _a.lstat, exports.mkdir = _a.mkdir, exports.readdir = _a.readdir, exports.readlink = _a.readlink, exports.rename = _a.rename, exports.rmdir = _a.rmdir, exports.stat = _a.stat, exports.symlink = _a.symlink, exports.unlink = _a.unlink;
|
||||||
|
exports.IS_WINDOWS = process.platform === 'win32';
|
||||||
|
function exists(fsPath) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
try {
|
||||||
|
yield exports.stat(fsPath);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
if (err.code === 'ENOENT') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.exists = exists;
|
||||||
|
function isDirectory(fsPath, useStat = false) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const stats = useStat ? yield exports.stat(fsPath) : yield exports.lstat(fsPath);
|
||||||
|
return stats.isDirectory();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.isDirectory = isDirectory;
|
||||||
|
/**
|
||||||
|
* On OSX/Linux, true if path starts with '/'. On Windows, true for paths like:
|
||||||
|
* \, \hello, \\hello\share, C:, and C:\hello (and corresponding alternate separator cases).
|
||||||
|
*/
|
||||||
|
function isRooted(p) {
|
||||||
|
p = normalizeSeparators(p);
|
||||||
|
if (!p) {
|
||||||
|
throw new Error('isRooted() parameter "p" cannot be empty');
|
||||||
|
}
|
||||||
|
if (exports.IS_WINDOWS) {
|
||||||
|
return (p.startsWith('\\') || /^[A-Z]:/i.test(p) // e.g. \ or \hello or \\hello
|
||||||
|
); // e.g. C: or C:\hello
|
||||||
|
}
|
||||||
|
return p.startsWith('/');
|
||||||
|
}
|
||||||
|
exports.isRooted = isRooted;
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
function mkdirP(fsPath, maxDepth = 1000, depth = 1) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
assert_1.ok(fsPath, 'a path argument must be provided');
|
||||||
|
fsPath = path.resolve(fsPath);
|
||||||
|
if (depth >= maxDepth)
|
||||||
|
return exports.mkdir(fsPath);
|
||||||
|
try {
|
||||||
|
yield exports.mkdir(fsPath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
switch (err.code) {
|
||||||
|
case 'ENOENT': {
|
||||||
|
yield mkdirP(path.dirname(fsPath), maxDepth, depth + 1);
|
||||||
|
yield exports.mkdir(fsPath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
let stats;
|
||||||
|
try {
|
||||||
|
stats = yield exports.stat(fsPath);
|
||||||
|
}
|
||||||
|
catch (err2) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
if (!stats.isDirectory())
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.mkdirP = mkdirP;
|
||||||
|
/**
|
||||||
|
* Best effort attempt to determine whether a file exists and is executable.
|
||||||
|
* @param filePath file path to check
|
||||||
|
* @param extensions additional file extensions to try
|
||||||
|
* @return if file exists and is executable, returns the file path. otherwise empty string.
|
||||||
|
*/
|
||||||
|
function tryGetExecutablePath(filePath, extensions) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
let stats = undefined;
|
||||||
|
try {
|
||||||
|
// test file exists
|
||||||
|
stats = yield exports.stat(filePath);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
if (err.code !== 'ENOENT') {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(`Unexpected error attempting to determine if executable file exists '${filePath}': ${err}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (stats && stats.isFile()) {
|
||||||
|
if (exports.IS_WINDOWS) {
|
||||||
|
// on Windows, test for valid extension
|
||||||
|
const upperExt = path.extname(filePath).toUpperCase();
|
||||||
|
if (extensions.some(validExt => validExt.toUpperCase() === upperExt)) {
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (isUnixExecutable(stats)) {
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// try each extension
|
||||||
|
const originalFilePath = filePath;
|
||||||
|
for (const extension of extensions) {
|
||||||
|
filePath = originalFilePath + extension;
|
||||||
|
stats = undefined;
|
||||||
|
try {
|
||||||
|
stats = yield exports.stat(filePath);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
if (err.code !== 'ENOENT') {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(`Unexpected error attempting to determine if executable file exists '${filePath}': ${err}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (stats && stats.isFile()) {
|
||||||
|
if (exports.IS_WINDOWS) {
|
||||||
|
// preserve the case of the actual file (since an extension was appended)
|
||||||
|
try {
|
||||||
|
const directory = path.dirname(filePath);
|
||||||
|
const upperName = path.basename(filePath).toUpperCase();
|
||||||
|
for (const actualName of yield exports.readdir(directory)) {
|
||||||
|
if (upperName === actualName.toUpperCase()) {
|
||||||
|
filePath = path.join(directory, actualName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(`Unexpected error attempting to determine the actual case of the file '${filePath}': ${err}`);
|
||||||
|
}
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (isUnixExecutable(stats)) {
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.tryGetExecutablePath = tryGetExecutablePath;
|
||||||
|
function normalizeSeparators(p) {
|
||||||
|
p = p || '';
|
||||||
|
if (exports.IS_WINDOWS) {
|
||||||
|
// convert slashes on Windows
|
||||||
|
p = p.replace(/\//g, '\\');
|
||||||
|
// remove redundant slashes
|
||||||
|
return p.replace(/\\\\+/g, '\\');
|
||||||
|
}
|
||||||
|
// remove redundant slashes
|
||||||
|
return p.replace(/\/\/+/g, '/');
|
||||||
|
}
|
||||||
|
// on Mac/Linux, test the execute bit
|
||||||
|
// R W X R W X R W X
|
||||||
|
// 256 128 64 32 16 8 4 2 1
|
||||||
|
function isUnixExecutable(stats) {
|
||||||
|
return ((stats.mode & 1) > 0 ||
|
||||||
|
((stats.mode & 8) > 0 && stats.gid === process.getgid()) ||
|
||||||
|
((stats.mode & 64) > 0 && stats.uid === process.getuid()));
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=io-util.js.map
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"io-util.js","sourceRoot":"","sources":["../src/io-util.ts"],"names":[],"mappings":";;;;;;;;;;;AAAA,mCAAyB;AACzB,yBAAwB;AACxB,6BAA4B;AAEf,gBAYE,qTAAA;AAEF,QAAA,UAAU,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAA;AAEtD,SAAsB,MAAM,CAAC,MAAc;;QACzC,IAAI;YACF,MAAM,YAAI,CAAC,MAAM,CAAC,CAAA;SACnB;QAAC,OAAO,GAAG,EAAE;YACZ,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE;gBACzB,OAAO,KAAK,CAAA;aACb;YAED,MAAM,GAAG,CAAA;SACV;QAED,OAAO,IAAI,CAAA;IACb,CAAC;CAAA;AAZD,wBAYC;AAED,SAAsB,WAAW,CAC/B,MAAc,EACd,UAAmB,KAAK;;QAExB,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,YAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,aAAK,CAAC,MAAM,CAAC,CAAA;QAChE,OAAO,KAAK,CAAC,WAAW,EAAE,CAAA;IAC5B,CAAC;CAAA;AAND,kCAMC;AAED;;;GAGG;AACH,SAAgB,QAAQ,CAAC,CAAS;IAChC,CAAC,GAAG,mBAAmB,CAAC,CAAC,CAAC,CAAA;IAC1B,IAAI,CAAC,CAAC,EAAE;QACN,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAA;KAC5D;IAED,IAAI,kBAAU,EAAE;QACd,OAAO,CACL,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,8BAA8B;SACxE,CAAA,CAAC,sBAAsB;KACzB;IAED,OAAO,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;AAC1B,CAAC;AAbD,4BAaC;AAED;;;;;;;;;GASG;AACH,SAAsB,MAAM,CAC1B,MAAc,EACd,WAAmB,IAAI,EACvB,QAAgB,CAAC;;QAEjB,WAAE,CAAC,MAAM,EAAE,kCAAkC,CAAC,CAAA;QAE9C,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;QAE7B,IAAI,KAAK,IAAI,QAAQ;YAAE,OAAO,aAAK,CAAC,MAAM,CAAC,CAAA;QAE3C,IAAI;YACF,MAAM,aAAK,CAAC,MAAM,CAAC,CAAA;YACnB,OAAM;SACP;QAAC,OAAO,GAAG,EAAE;YACZ,QAAQ,GAAG,CAAC,IAAI,EAAE;gBAChB,KAAK,QAAQ,CAAC,CAAC;oBACb,MAAM,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,KAAK,GAAG,CAAC,CAAC,CAAA;oBACvD,MAAM,aAAK,CAAC,MAAM,CAAC,CAAA;oBACnB,OAAM;iBACP;gBACD,OAAO,CAAC,CAAC;oBACP,IAAI,KAAe,CAAA;oBAEnB,IAAI;wBACF,KAAK,GAAG,MAAM,YAAI,CAAC,MAAM,CAAC,CAAA;qBAC3B;oBAAC,OAAO,IAAI,EAAE;wBACb,MAAM,GAAG,CAAA;qBACV;oBAED,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;wBAAE,MAAM,GAAG,CAAA;iBACpC;aACF;SACF;IACH,CAAC;CAAA;AAlCD,wBAkCC;AAED;;;;;GAKG;AACH,SAAsB,oBAAoB,CACxC,QAAgB,EAChB,UAAoB;;QAEpB,IAAI,KAAK,GAAyB,SAAS,CAAA;QAC3C,IAAI;YACF,mBAAmB;YACnB,KAAK,GAAG,MAAM,YAAI,CAAC,QAAQ,CAAC,CAAA;SAC7B;QAAC,OAAO,GAAG,EAAE;YACZ,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE;gBACzB,sCAAsC;gBACtC,OAAO,CAAC,GAAG,CACT,uEAAuE,QAAQ,MAAM,GAAG,EAAE,CAC3F,CAAA;aACF;SACF;QACD,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE;YAC3B,IAAI,kBAAU,EAAE;gBACd,uCAAuC;gBACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAA;gBACrD,IAAI,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,EAAE,KAAK,QAAQ,CAAC,EAAE;oBACpE,OAAO,QAAQ,CAAA;iBAChB;aACF;iBAAM;gBACL,IAAI,gBAAgB,CAAC,KAAK,CAAC,EAAE;oBAC3B,OAAO,QAAQ,CAAA;iBAChB;aACF;SACF;QAED,qBAAqB;QACrB,MAAM,gBAAgB,GAAG,QAAQ,CAAA;QACjC,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE;YAClC,QAAQ,GAAG,gBAAgB,GAAG,SAAS,CAAA;YAEvC,KAAK,GAAG,SAAS,CAAA;YACjB,IAAI;gBACF,KAAK,GAAG,MAAM,YAAI,CAAC,QAAQ,CAAC,CAAA;aAC7B;YAAC,OAAO,GAAG,EAAE;gBACZ,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE;oBACzB,sCAAsC;oBACtC,OAAO,CAAC,GAAG,CACT,uEAAuE,QAAQ,MAAM,GAAG,EAAE,CAC3F,CAAA;iBACF;aACF;YAED,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE;gBAC3B,IAAI,kBAAU,EAAE;oBACd,yEAAyE;oBACzE,IAAI;wBACF,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;wBACxC,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAA;wBACvD,KAAK,MAAM,UAAU,IAAI,MAAM,eAAO,CAAC,SAAS,CAAC,EAAE;4BACjD,IAAI,SAAS,KAAK,UAAU,CAAC,WAAW,EAAE,EAAE;gCAC1C,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAA;gCAC3C,MAAK;6BACN;yBACF;qBACF;oBAAC,OAAO,GAAG,EAAE;wBACZ,sCAAsC;wBACtC,OAAO,CAAC,GAAG,CACT,yEAAyE,QAAQ,MAAM,GAAG,EAAE,CAC7F,CAAA;qBACF;oBAED,OAAO,QAAQ,CAAA;iBAChB;qBAAM;oBACL,IAAI,gBAAgB,CAAC,KAAK,CAAC,EAAE;wBAC3B,OAAO,QAAQ,CAAA;qBAChB;iBACF;aACF;SACF;QAED,OAAO,EAAE,CAAA;IACX,CAAC;CAAA;AA5ED,oDA4EC;AAED,SAAS,mBAAmB,CAAC,CAAS;IACpC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAA;IACX,IAAI,kBAAU,EAAE;QACd,6BAA6B;QAC7B,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;QAE1B,2BAA2B;QAC3B,OAAO,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;KACjC;IAED,2BAA2B;IAC3B,OAAO,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;AACjC,CAAC;AAED,qCAAqC;AACrC,6BAA6B;AAC7B,6BAA6B;AAC7B,SAAS,gBAAgB,CAAC,KAAe;IACvC,OAAO,CACL,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC;QACpB,CAAC,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC;QACxD,CAAC,CAAC,KAAK,CAAC,IAAI,GAAG,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAC1D,CAAA;AACH,CAAC"}
|
|
@ -0,0 +1,56 @@
|
||||||
|
/**
|
||||||
|
* Interface for cp/mv options
|
||||||
|
*/
|
||||||
|
export interface CopyOptions {
|
||||||
|
/** Optional. Whether to recursively copy all subdirectories. Defaults to false */
|
||||||
|
recursive?: boolean;
|
||||||
|
/** Optional. Whether to overwrite existing files in the destination. Defaults to true */
|
||||||
|
force?: boolean;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Interface for cp/mv options
|
||||||
|
*/
|
||||||
|
export interface MoveOptions {
|
||||||
|
/** Optional. Whether to overwrite existing files in the destination. Defaults to true */
|
||||||
|
force?: boolean;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Copies a file or folder.
|
||||||
|
* Based off of shelljs - https://github.com/shelljs/shelljs/blob/9237f66c52e5daa40458f94f9565e18e8132f5a6/src/cp.js
|
||||||
|
*
|
||||||
|
* @param source source path
|
||||||
|
* @param dest destination path
|
||||||
|
* @param options optional. See CopyOptions.
|
||||||
|
*/
|
||||||
|
export declare function cp(source: string, dest: string, options?: CopyOptions): Promise<void>;
|
||||||
|
/**
|
||||||
|
* Moves a path.
|
||||||
|
*
|
||||||
|
* @param source source path
|
||||||
|
* @param dest destination path
|
||||||
|
* @param options optional. See MoveOptions.
|
||||||
|
*/
|
||||||
|
export declare function mv(source: string, dest: string, options?: MoveOptions): Promise<void>;
|
||||||
|
/**
|
||||||
|
* Remove a path recursively with force
|
||||||
|
*
|
||||||
|
* @param inputPath path to remove
|
||||||
|
*/
|
||||||
|
export declare function rmRF(inputPath: string): Promise<void>;
|
||||||
|
/**
|
||||||
|
* Make a directory. Creates the full path with folders in between
|
||||||
|
* Will throw if it fails
|
||||||
|
*
|
||||||
|
* @param fsPath path to create
|
||||||
|
* @returns Promise<void>
|
||||||
|
*/
|
||||||
|
export declare function mkdirP(fsPath: string): Promise<void>;
|
||||||
|
/**
|
||||||
|
* Returns path of a tool had the tool actually been invoked. Resolves via paths.
|
||||||
|
* If you check and the tool does not exist, it will throw.
|
||||||
|
*
|
||||||
|
* @param tool name of the tool
|
||||||
|
* @param check whether to check if tool exists
|
||||||
|
* @returns Promise<string> path to tool
|
||||||
|
*/
|
||||||
|
export declare function which(tool: string, check?: boolean): Promise<string>;
|
|
@ -0,0 +1,289 @@
|
||||||
|
"use strict";
|
||||||
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||||
|
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const childProcess = require("child_process");
|
||||||
|
const path = require("path");
|
||||||
|
const util_1 = require("util");
|
||||||
|
const ioUtil = require("./io-util");
|
||||||
|
const exec = util_1.promisify(childProcess.exec);
|
||||||
|
/**
|
||||||
|
* Copies a file or folder.
|
||||||
|
* Based off of shelljs - https://github.com/shelljs/shelljs/blob/9237f66c52e5daa40458f94f9565e18e8132f5a6/src/cp.js
|
||||||
|
*
|
||||||
|
* @param source source path
|
||||||
|
* @param dest destination path
|
||||||
|
* @param options optional. See CopyOptions.
|
||||||
|
*/
|
||||||
|
function cp(source, dest, options = {}) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const { force, recursive } = readCopyOptions(options);
|
||||||
|
const destStat = (yield ioUtil.exists(dest)) ? yield ioUtil.stat(dest) : null;
|
||||||
|
// Dest is an existing file, but not forcing
|
||||||
|
if (destStat && destStat.isFile() && !force) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// If dest is an existing directory, should copy inside.
|
||||||
|
const newDest = destStat && destStat.isDirectory()
|
||||||
|
? path.join(dest, path.basename(source))
|
||||||
|
: dest;
|
||||||
|
if (!(yield ioUtil.exists(source))) {
|
||||||
|
throw new Error(`no such file or directory: ${source}`);
|
||||||
|
}
|
||||||
|
const sourceStat = yield ioUtil.stat(source);
|
||||||
|
if (sourceStat.isDirectory()) {
|
||||||
|
if (!recursive) {
|
||||||
|
throw new Error(`Failed to copy. ${source} is a directory, but tried to copy without recursive flag.`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
yield cpDirRecursive(source, newDest, 0, force);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (path.relative(source, newDest) === '') {
|
||||||
|
// a file cannot be copied to itself
|
||||||
|
throw new Error(`'${newDest}' and '${source}' are the same file`);
|
||||||
|
}
|
||||||
|
yield copyFile(source, newDest, force);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.cp = cp;
|
||||||
|
/**
|
||||||
|
* Moves a path.
|
||||||
|
*
|
||||||
|
* @param source source path
|
||||||
|
* @param dest destination path
|
||||||
|
* @param options optional. See MoveOptions.
|
||||||
|
*/
|
||||||
|
function mv(source, dest, options = {}) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
if (yield ioUtil.exists(dest)) {
|
||||||
|
let destExists = true;
|
||||||
|
if (yield ioUtil.isDirectory(dest)) {
|
||||||
|
// If dest is directory copy src into dest
|
||||||
|
dest = path.join(dest, path.basename(source));
|
||||||
|
destExists = yield ioUtil.exists(dest);
|
||||||
|
}
|
||||||
|
if (destExists) {
|
||||||
|
if (options.force == null || options.force) {
|
||||||
|
yield rmRF(dest);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new Error('Destination already exists');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
yield mkdirP(path.dirname(dest));
|
||||||
|
yield ioUtil.rename(source, dest);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.mv = mv;
|
||||||
|
/**
|
||||||
|
* Remove a path recursively with force
|
||||||
|
*
|
||||||
|
* @param inputPath path to remove
|
||||||
|
*/
|
||||||
|
function rmRF(inputPath) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
if (ioUtil.IS_WINDOWS) {
|
||||||
|
// Node doesn't provide a delete operation, only an unlink function. This means that if the file is being used by another
|
||||||
|
// program (e.g. antivirus), it won't be deleted. To address this, we shell out the work to rd/del.
|
||||||
|
try {
|
||||||
|
if (yield ioUtil.isDirectory(inputPath, true)) {
|
||||||
|
yield exec(`rd /s /q "${inputPath}"`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
yield exec(`del /f /a "${inputPath}"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
// if you try to delete a file that doesn't exist, desired result is achieved
|
||||||
|
// other errors are valid
|
||||||
|
if (err.code !== 'ENOENT')
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
// Shelling out fails to remove a symlink folder with missing source, this unlink catches that
|
||||||
|
try {
|
||||||
|
yield ioUtil.unlink(inputPath);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
// if you try to delete a file that doesn't exist, desired result is achieved
|
||||||
|
// other errors are valid
|
||||||
|
if (err.code !== 'ENOENT')
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let isDir = false;
|
||||||
|
try {
|
||||||
|
isDir = yield ioUtil.isDirectory(inputPath);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
// if you try to delete a file that doesn't exist, desired result is achieved
|
||||||
|
// other errors are valid
|
||||||
|
if (err.code !== 'ENOENT')
|
||||||
|
throw err;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isDir) {
|
||||||
|
yield exec(`rm -rf "${inputPath}"`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
yield ioUtil.unlink(inputPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.rmRF = rmRF;
|
||||||
|
/**
|
||||||
|
* Make a directory. Creates the full path with folders in between
|
||||||
|
* Will throw if it fails
|
||||||
|
*
|
||||||
|
* @param fsPath path to create
|
||||||
|
* @returns Promise<void>
|
||||||
|
*/
|
||||||
|
function mkdirP(fsPath) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
yield ioUtil.mkdirP(fsPath);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.mkdirP = mkdirP;
|
||||||
|
/**
|
||||||
|
* Returns path of a tool had the tool actually been invoked. Resolves via paths.
|
||||||
|
* If you check and the tool does not exist, it will throw.
|
||||||
|
*
|
||||||
|
* @param tool name of the tool
|
||||||
|
* @param check whether to check if tool exists
|
||||||
|
* @returns Promise<string> path to tool
|
||||||
|
*/
|
||||||
|
function which(tool, check) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
if (!tool) {
|
||||||
|
throw new Error("parameter 'tool' is required");
|
||||||
|
}
|
||||||
|
// recursive when check=true
|
||||||
|
if (check) {
|
||||||
|
const result = yield which(tool, false);
|
||||||
|
if (!result) {
|
||||||
|
if (ioUtil.IS_WINDOWS) {
|
||||||
|
throw new Error(`Unable to locate executable file: ${tool}. Please verify either the file path exists or the file can be found within a directory specified by the PATH environment variable. Also verify the file has a valid extension for an executable file.`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new Error(`Unable to locate executable file: ${tool}. Please verify either the file path exists or the file can be found within a directory specified by the PATH environment variable. Also check the file mode to verify the file is executable.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// build the list of extensions to try
|
||||||
|
const extensions = [];
|
||||||
|
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 (ioUtil.isRooted(tool)) {
|
||||||
|
const filePath = yield ioUtil.tryGetExecutablePath(tool, extensions);
|
||||||
|
if (filePath) {
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
// if any path separators, return empty
|
||||||
|
if (tool.includes('/') || (ioUtil.IS_WINDOWS && tool.includes('\\'))) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
// build the list of directories
|
||||||
|
//
|
||||||
|
// Note, technically "where" checks the current directory on Windows. From a task lib 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 task lib should strive for consistency
|
||||||
|
// across platforms.
|
||||||
|
const directories = [];
|
||||||
|
if (process.env.PATH) {
|
||||||
|
for (const p of process.env.PATH.split(path.delimiter)) {
|
||||||
|
if (p) {
|
||||||
|
directories.push(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// return the first match
|
||||||
|
for (const directory of directories) {
|
||||||
|
const filePath = yield ioUtil.tryGetExecutablePath(directory + path.sep + tool, extensions);
|
||||||
|
if (filePath) {
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
throw new Error(`which failed with message ${err.message}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.which = which;
|
||||||
|
function readCopyOptions(options) {
|
||||||
|
const force = options.force == null ? true : options.force;
|
||||||
|
const recursive = Boolean(options.recursive);
|
||||||
|
return { force, recursive };
|
||||||
|
}
|
||||||
|
function cpDirRecursive(sourceDir, destDir, currentDepth, force) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
// Ensure there is not a run away recursive copy
|
||||||
|
if (currentDepth >= 255)
|
||||||
|
return;
|
||||||
|
currentDepth++;
|
||||||
|
yield mkdirP(destDir);
|
||||||
|
const files = yield ioUtil.readdir(sourceDir);
|
||||||
|
for (const fileName of files) {
|
||||||
|
const srcFile = `${sourceDir}/${fileName}`;
|
||||||
|
const destFile = `${destDir}/${fileName}`;
|
||||||
|
const srcFileStat = yield ioUtil.lstat(srcFile);
|
||||||
|
if (srcFileStat.isDirectory()) {
|
||||||
|
// Recurse
|
||||||
|
yield cpDirRecursive(srcFile, destFile, currentDepth, force);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
yield copyFile(srcFile, destFile, force);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Change the mode for the newly created directory
|
||||||
|
yield ioUtil.chmod(destDir, (yield ioUtil.stat(sourceDir)).mode);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Buffered file copy
|
||||||
|
function copyFile(srcFile, destFile, force) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
if ((yield ioUtil.lstat(srcFile)).isSymbolicLink()) {
|
||||||
|
// unlink/re-link it
|
||||||
|
try {
|
||||||
|
yield ioUtil.lstat(destFile);
|
||||||
|
yield ioUtil.unlink(destFile);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
// Try to override file permission
|
||||||
|
if (e.code === 'EPERM') {
|
||||||
|
yield ioUtil.chmod(destFile, '0666');
|
||||||
|
yield ioUtil.unlink(destFile);
|
||||||
|
}
|
||||||
|
// other errors = it doesn't exist, no work to do
|
||||||
|
}
|
||||||
|
// Copy over symlink
|
||||||
|
const symlinkFull = yield ioUtil.readlink(srcFile);
|
||||||
|
yield ioUtil.symlink(symlinkFull, destFile, ioUtil.IS_WINDOWS ? 'junction' : null);
|
||||||
|
}
|
||||||
|
else if (!(yield ioUtil.exists(destFile)) || force) {
|
||||||
|
yield ioUtil.copyFile(srcFile, destFile);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=io.js.map
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,60 @@
|
||||||
|
{
|
||||||
|
"_from": "file:toolkit\\actions-io-0.0.0.tgz",
|
||||||
|
"_id": "@actions/io@0.0.0",
|
||||||
|
"_inBundle": false,
|
||||||
|
"_integrity": "sha512-BZqiiacJkzERkYIMUQWrujLZWSFHEA6bD/LzR7QSDHpx32+PPk7NaUNmt8CG+y+OlYPc/ZZGaY3368K1ppfptA==",
|
||||||
|
"_location": "/@actions/io",
|
||||||
|
"_phantomChildren": {},
|
||||||
|
"_requested": {
|
||||||
|
"type": "file",
|
||||||
|
"where": "C:\\Users\\damccorm\\Documents\\node12-template",
|
||||||
|
"raw": "@actions/io@file:toolkit/actions-io-0.0.0.tgz",
|
||||||
|
"name": "@actions/io",
|
||||||
|
"escapedName": "@actions%2fio",
|
||||||
|
"scope": "@actions",
|
||||||
|
"rawSpec": "file:toolkit/actions-io-0.0.0.tgz",
|
||||||
|
"saveSpec": "file:toolkit\\actions-io-0.0.0.tgz",
|
||||||
|
"fetchSpec": "C:\\Users\\damccorm\\Documents\\node12-template\\toolkit\\actions-io-0.0.0.tgz"
|
||||||
|
},
|
||||||
|
"_requiredBy": [
|
||||||
|
"/",
|
||||||
|
"/@actions/tool-cache"
|
||||||
|
],
|
||||||
|
"_resolved": "C:\\Users\\damccorm\\Documents\\node12-template\\toolkit\\actions-io-0.0.0.tgz",
|
||||||
|
"_shasum": "64c85baec8d8ed889a5fb8e2ef794e36a692eeb8",
|
||||||
|
"_spec": "@actions/io@file:toolkit/actions-io-0.0.0.tgz",
|
||||||
|
"_where": "C:\\Users\\damccorm\\Documents\\node12-template",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/actions/toolkit/issues"
|
||||||
|
},
|
||||||
|
"bundleDependencies": false,
|
||||||
|
"deprecated": false,
|
||||||
|
"description": "Actions io lib",
|
||||||
|
"directories": {
|
||||||
|
"lib": "lib",
|
||||||
|
"test": "__tests__"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"lib"
|
||||||
|
],
|
||||||
|
"homepage": "https://github.com/actions/toolkit/tree/master/packages/io",
|
||||||
|
"keywords": [
|
||||||
|
"io",
|
||||||
|
"actions"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"main": "lib/io.js",
|
||||||
|
"name": "@actions/io",
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/actions/toolkit.git"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: run tests from root\" && exit 1",
|
||||||
|
"tsc": "tsc"
|
||||||
|
},
|
||||||
|
"version": "0.0.0"
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
# `@actions/tool-cache`
|
||||||
|
|
||||||
|
> Functions necessary for downloading and caching tools.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
See [src/tool-cache.ts](src/tool-cache.ts).
|
|
@ -0,0 +1,78 @@
|
||||||
|
export declare class HTTPError extends Error {
|
||||||
|
readonly httpStatusCode: number | undefined;
|
||||||
|
constructor(httpStatusCode: number | undefined);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Download a tool from an url and stream it into a file
|
||||||
|
*
|
||||||
|
* @param url url of tool to download
|
||||||
|
* @returns path to downloaded tool
|
||||||
|
*/
|
||||||
|
export declare function downloadTool(url: string): Promise<string>;
|
||||||
|
/**
|
||||||
|
* Extract a .7z file
|
||||||
|
*
|
||||||
|
* @param file path to the .7z file
|
||||||
|
* @param dest destination directory. Optional.
|
||||||
|
* @param _7zPath path to 7zr.exe. Optional, for long path support. Most .7z archives do not have this
|
||||||
|
* problem. If your .7z archive contains very long paths, you can pass the path to 7zr.exe which will
|
||||||
|
* gracefully handle long paths. By default 7zdec.exe is used because it is a very small program and is
|
||||||
|
* bundled with the tool lib. However it does not support long paths. 7zr.exe is the reduced command line
|
||||||
|
* interface, it is smaller than the full command line interface, and it does support long paths. At the
|
||||||
|
* time of this writing, it is freely available from the LZMA SDK that is available on the 7zip website.
|
||||||
|
* Be sure to check the current license agreement. If 7zr.exe is bundled with your action, then the path
|
||||||
|
* to 7zr.exe can be pass to this function.
|
||||||
|
* @returns path to the destination directory
|
||||||
|
*/
|
||||||
|
export declare function extract7z(file: string, dest?: string, _7zPath?: string): Promise<string>;
|
||||||
|
/**
|
||||||
|
* Extract a tar
|
||||||
|
*
|
||||||
|
* @param file path to the tar
|
||||||
|
* @param dest destination directory. Optional.
|
||||||
|
* @returns path to the destination directory
|
||||||
|
*/
|
||||||
|
export declare function extractTar(file: string, dest?: string): Promise<string>;
|
||||||
|
/**
|
||||||
|
* Extract a zip
|
||||||
|
*
|
||||||
|
* @param file path to the zip
|
||||||
|
* @param dest destination directory. Optional.
|
||||||
|
* @returns path to the destination directory
|
||||||
|
*/
|
||||||
|
export declare function extractZip(file: string, dest?: string): Promise<string>;
|
||||||
|
/**
|
||||||
|
* Caches a directory and installs it into the tool cacheDir
|
||||||
|
*
|
||||||
|
* @param sourceDir the directory to cache into tools
|
||||||
|
* @param tool tool name
|
||||||
|
* @param version version of the tool. semver format
|
||||||
|
* @param arch architecture of the tool. Optional. Defaults to machine architecture
|
||||||
|
*/
|
||||||
|
export declare function cacheDir(sourceDir: string, tool: string, version: string, arch?: string): Promise<string>;
|
||||||
|
/**
|
||||||
|
* Caches a downloaded file (GUID) and installs it
|
||||||
|
* into the tool cache with a given targetName
|
||||||
|
*
|
||||||
|
* @param sourceFile the file to cache into tools. Typically a result of downloadTool which is a guid.
|
||||||
|
* @param targetFile the name of the file name in the tools directory
|
||||||
|
* @param tool tool name
|
||||||
|
* @param version version of the tool. semver format
|
||||||
|
* @param arch architecture of the tool. Optional. Defaults to machine architecture
|
||||||
|
*/
|
||||||
|
export declare function cacheFile(sourceFile: string, targetFile: string, tool: string, version: string, arch?: string): Promise<string>;
|
||||||
|
/**
|
||||||
|
* Finds the path to a tool version in the local installed tool cache
|
||||||
|
*
|
||||||
|
* @param toolName name of the tool
|
||||||
|
* @param versionSpec version of the tool
|
||||||
|
* @param arch optional arch. defaults to arch of computer
|
||||||
|
*/
|
||||||
|
export declare function find(toolName: string, versionSpec: string, arch?: string): string;
|
||||||
|
/**
|
||||||
|
* Finds the paths to all versions of a tool that are installed in the local tool cache
|
||||||
|
*
|
||||||
|
* @param toolName name of the tool
|
||||||
|
* @param arch optional arch. defaults to arch of computer
|
||||||
|
*/
|
||||||
|
export declare function findAllVersions(toolName: string, arch?: string): string[];
|
|
@ -0,0 +1,436 @@
|
||||||
|
"use strict";
|
||||||
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||||
|
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const core = require("@actions/core");
|
||||||
|
const io = require("@actions/io");
|
||||||
|
const fs = require("fs");
|
||||||
|
const os = require("os");
|
||||||
|
const path = require("path");
|
||||||
|
const httpm = require("typed-rest-client/HttpClient");
|
||||||
|
const semver = require("semver");
|
||||||
|
const uuidV4 = require("uuid/v4");
|
||||||
|
const exec_1 = require("@actions/exec/lib/exec");
|
||||||
|
const assert_1 = require("assert");
|
||||||
|
class HTTPError extends Error {
|
||||||
|
constructor(httpStatusCode) {
|
||||||
|
super(`Unexpected HTTP response: ${httpStatusCode}`);
|
||||||
|
this.httpStatusCode = httpStatusCode;
|
||||||
|
Object.setPrototypeOf(this, new.target.prototype);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.HTTPError = HTTPError;
|
||||||
|
const IS_WINDOWS = process.platform === 'win32';
|
||||||
|
const userAgent = 'actions/tool-cache';
|
||||||
|
// On load grab temp directory and cache directory and remove them from env (currently don't want to expose this)
|
||||||
|
let tempDirectory = process.env['RUNNER_TEMPDIRECTORY'] || '';
|
||||||
|
let cacheRoot = process.env['RUNNER_TOOLSDIRECTORY'] || '';
|
||||||
|
// If directories not found, place them in common temp locations
|
||||||
|
if (!tempDirectory || !cacheRoot) {
|
||||||
|
let baseLocation;
|
||||||
|
if (IS_WINDOWS) {
|
||||||
|
// On windows use the USERPROFILE env variable
|
||||||
|
baseLocation = process.env['USERPROFILE'] || 'C:\\';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (process.platform === 'darwin') {
|
||||||
|
baseLocation = '/Users';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
baseLocation = '/home';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!tempDirectory) {
|
||||||
|
tempDirectory = path.join(baseLocation, 'actions', 'temp');
|
||||||
|
}
|
||||||
|
if (!cacheRoot) {
|
||||||
|
cacheRoot = path.join(baseLocation, 'actions', 'cache');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Download a tool from an url and stream it into a file
|
||||||
|
*
|
||||||
|
* @param url url of tool to download
|
||||||
|
* @returns path to downloaded tool
|
||||||
|
*/
|
||||||
|
function downloadTool(url) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
// Wrap in a promise so that we can resolve from within stream callbacks
|
||||||
|
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
||||||
|
try {
|
||||||
|
const http = new httpm.HttpClient(userAgent, [], {
|
||||||
|
allowRetries: true,
|
||||||
|
maxRetries: 3
|
||||||
|
});
|
||||||
|
const destPath = path.join(tempDirectory, uuidV4());
|
||||||
|
yield io.mkdirP(tempDirectory);
|
||||||
|
core.debug(`Downloading ${url}`);
|
||||||
|
core.debug(`Downloading ${destPath}`);
|
||||||
|
if (fs.existsSync(destPath)) {
|
||||||
|
throw new Error(`Destination file path ${destPath} already exists`);
|
||||||
|
}
|
||||||
|
const response = yield http.get(url);
|
||||||
|
if (response.message.statusCode !== 200) {
|
||||||
|
const err = new HTTPError(response.message.statusCode);
|
||||||
|
core.debug(`Failed to download from "${url}". Code(${response.message.statusCode}) Message(${response.message.statusMessage})`);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
const file = fs.createWriteStream(destPath);
|
||||||
|
file.on('open', () => __awaiter(this, void 0, void 0, function* () {
|
||||||
|
try {
|
||||||
|
const stream = response.message.pipe(file);
|
||||||
|
stream.on('close', () => {
|
||||||
|
core.debug('download complete');
|
||||||
|
resolve(destPath);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
core.debug(`Failed to download from "${url}". Code(${response.message.statusCode}) Message(${response.message.statusMessage})`);
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
file.on('error', err => {
|
||||||
|
file.end();
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.downloadTool = downloadTool;
|
||||||
|
/**
|
||||||
|
* Extract a .7z file
|
||||||
|
*
|
||||||
|
* @param file path to the .7z file
|
||||||
|
* @param dest destination directory. Optional.
|
||||||
|
* @param _7zPath path to 7zr.exe. Optional, for long path support. Most .7z archives do not have this
|
||||||
|
* problem. If your .7z archive contains very long paths, you can pass the path to 7zr.exe which will
|
||||||
|
* gracefully handle long paths. By default 7zdec.exe is used because it is a very small program and is
|
||||||
|
* bundled with the tool lib. However it does not support long paths. 7zr.exe is the reduced command line
|
||||||
|
* interface, it is smaller than the full command line interface, and it does support long paths. At the
|
||||||
|
* time of this writing, it is freely available from the LZMA SDK that is available on the 7zip website.
|
||||||
|
* Be sure to check the current license agreement. If 7zr.exe is bundled with your action, then the path
|
||||||
|
* to 7zr.exe can be pass to this function.
|
||||||
|
* @returns path to the destination directory
|
||||||
|
*/
|
||||||
|
function extract7z(file, dest, _7zPath) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
assert_1.ok(IS_WINDOWS, 'extract7z() not supported on current OS');
|
||||||
|
assert_1.ok(file, 'parameter "file" is required');
|
||||||
|
dest = dest || (yield _createExtractFolder(dest));
|
||||||
|
const originalCwd = process.cwd();
|
||||||
|
process.chdir(dest);
|
||||||
|
if (_7zPath) {
|
||||||
|
try {
|
||||||
|
const args = [
|
||||||
|
'x',
|
||||||
|
'-bb1',
|
||||||
|
'-bd',
|
||||||
|
'-sccUTF-8',
|
||||||
|
file
|
||||||
|
];
|
||||||
|
const options = {
|
||||||
|
silent: true
|
||||||
|
};
|
||||||
|
yield exec_1.exec(`"${_7zPath}"`, args, options);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
process.chdir(originalCwd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const escapedScript = path
|
||||||
|
.join(__dirname, '..', 'scripts', 'Invoke-7zdec.ps1')
|
||||||
|
.replace(/'/g, "''")
|
||||||
|
.replace(/"|\n|\r/g, ''); // double-up single quotes, remove double quotes and newlines
|
||||||
|
const escapedFile = file.replace(/'/g, "''").replace(/"|\n|\r/g, '');
|
||||||
|
const escapedTarget = dest.replace(/'/g, "''").replace(/"|\n|\r/g, '');
|
||||||
|
const command = `& '${escapedScript}' -Source '${escapedFile}' -Target '${escapedTarget}'`;
|
||||||
|
const args = [
|
||||||
|
'-NoLogo',
|
||||||
|
'-Sta',
|
||||||
|
'-NoProfile',
|
||||||
|
'-NonInteractive',
|
||||||
|
'-ExecutionPolicy',
|
||||||
|
'Unrestricted',
|
||||||
|
'-Command',
|
||||||
|
command
|
||||||
|
];
|
||||||
|
const options = {
|
||||||
|
silent: true
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const powershellPath = yield io.which('powershell', true);
|
||||||
|
yield exec_1.exec(`"${powershellPath}"`, args, options);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
process.chdir(originalCwd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dest;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.extract7z = extract7z;
|
||||||
|
/**
|
||||||
|
* Extract a tar
|
||||||
|
*
|
||||||
|
* @param file path to the tar
|
||||||
|
* @param dest destination directory. Optional.
|
||||||
|
* @returns path to the destination directory
|
||||||
|
*/
|
||||||
|
function extractTar(file, dest) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
if (!file) {
|
||||||
|
throw new Error("parameter 'file' is required");
|
||||||
|
}
|
||||||
|
dest = dest || (yield _createExtractFolder(dest));
|
||||||
|
const tarPath = yield io.which('tar', true);
|
||||||
|
yield exec_1.exec(`"${tarPath}"`, ['xzC', dest, '-f', file]);
|
||||||
|
return dest;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.extractTar = extractTar;
|
||||||
|
/**
|
||||||
|
* Extract a zip
|
||||||
|
*
|
||||||
|
* @param file path to the zip
|
||||||
|
* @param dest destination directory. Optional.
|
||||||
|
* @returns path to the destination directory
|
||||||
|
*/
|
||||||
|
function extractZip(file, dest) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
if (!file) {
|
||||||
|
throw new Error("parameter 'file' is required");
|
||||||
|
}
|
||||||
|
dest = dest || (yield _createExtractFolder(dest));
|
||||||
|
if (IS_WINDOWS) {
|
||||||
|
yield extractZipWin(file, dest);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
yield extractZipNix(file, dest);
|
||||||
|
}
|
||||||
|
return dest;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.extractZip = extractZip;
|
||||||
|
function extractZipWin(file, dest) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
// build the powershell command
|
||||||
|
const escapedFile = file.replace(/'/g, "''").replace(/"|\n|\r/g, ''); // double-up single quotes, remove double quotes and newlines
|
||||||
|
const escapedDest = dest.replace(/'/g, "''").replace(/"|\n|\r/g, '');
|
||||||
|
const command = `$ErrorActionPreference = 'Stop' ; try { Add-Type -AssemblyName System.IO.Compression.FileSystem } catch { } ; [System.IO.Compression.ZipFile]::ExtractToDirectory('${escapedFile}', '${escapedDest}')`;
|
||||||
|
// run powershell
|
||||||
|
const powershellPath = yield io.which('powershell');
|
||||||
|
const args = [
|
||||||
|
'-NoLogo',
|
||||||
|
'-Sta',
|
||||||
|
'-NoProfile',
|
||||||
|
'-NonInteractive',
|
||||||
|
'-ExecutionPolicy',
|
||||||
|
'Unrestricted',
|
||||||
|
'-Command',
|
||||||
|
command
|
||||||
|
];
|
||||||
|
yield exec_1.exec(`"${powershellPath}"`, args);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function extractZipNix(file, dest) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const unzipPath = path.join(__dirname, '..', 'scripts', 'externals', 'unzip');
|
||||||
|
yield exec_1.exec(`"${unzipPath}"`, [file], { cwd: dest });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Caches a directory and installs it into the tool cacheDir
|
||||||
|
*
|
||||||
|
* @param sourceDir the directory to cache into tools
|
||||||
|
* @param tool tool name
|
||||||
|
* @param version version of the tool. semver format
|
||||||
|
* @param arch architecture of the tool. Optional. Defaults to machine architecture
|
||||||
|
*/
|
||||||
|
function cacheDir(sourceDir, tool, version, arch) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
version = semver.clean(version) || version;
|
||||||
|
arch = arch || os.arch();
|
||||||
|
core.debug(`Caching tool ${tool} ${version} ${arch}`);
|
||||||
|
core.debug(`source dir: ${sourceDir}`);
|
||||||
|
if (!fs.statSync(sourceDir).isDirectory()) {
|
||||||
|
throw new Error('sourceDir is not a directory');
|
||||||
|
}
|
||||||
|
// Create the tool dir
|
||||||
|
const destPath = yield _createToolPath(tool, version, arch);
|
||||||
|
// copy each child item. do not move. move can fail on Windows
|
||||||
|
// due to anti-virus software having an open handle on a file.
|
||||||
|
for (const itemName of fs.readdirSync(sourceDir)) {
|
||||||
|
const s = path.join(sourceDir, itemName);
|
||||||
|
yield io.cp(s, destPath, { recursive: true });
|
||||||
|
}
|
||||||
|
// write .complete
|
||||||
|
_completeToolPath(tool, version, arch);
|
||||||
|
return destPath;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.cacheDir = cacheDir;
|
||||||
|
/**
|
||||||
|
* Caches a downloaded file (GUID) and installs it
|
||||||
|
* into the tool cache with a given targetName
|
||||||
|
*
|
||||||
|
* @param sourceFile the file to cache into tools. Typically a result of downloadTool which is a guid.
|
||||||
|
* @param targetFile the name of the file name in the tools directory
|
||||||
|
* @param tool tool name
|
||||||
|
* @param version version of the tool. semver format
|
||||||
|
* @param arch architecture of the tool. Optional. Defaults to machine architecture
|
||||||
|
*/
|
||||||
|
function cacheFile(sourceFile, targetFile, tool, version, arch) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
version = semver.clean(version) || version;
|
||||||
|
arch = arch || os.arch();
|
||||||
|
core.debug(`Caching tool ${tool} ${version} ${arch}`);
|
||||||
|
core.debug(`source file: ${sourceFile}`);
|
||||||
|
if (!fs.statSync(sourceFile).isFile()) {
|
||||||
|
throw new Error('sourceFile is not a file');
|
||||||
|
}
|
||||||
|
// create the tool dir
|
||||||
|
const destFolder = yield _createToolPath(tool, version, arch);
|
||||||
|
// copy instead of move. move can fail on Windows due to
|
||||||
|
// anti-virus software having an open handle on a file.
|
||||||
|
const destPath = path.join(destFolder, targetFile);
|
||||||
|
core.debug(`destination file ${destPath}`);
|
||||||
|
yield io.cp(sourceFile, destPath);
|
||||||
|
// write .complete
|
||||||
|
_completeToolPath(tool, version, arch);
|
||||||
|
return destFolder;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.cacheFile = cacheFile;
|
||||||
|
/**
|
||||||
|
* Finds the path to a tool version in the local installed tool cache
|
||||||
|
*
|
||||||
|
* @param toolName name of the tool
|
||||||
|
* @param versionSpec version of the tool
|
||||||
|
* @param arch optional arch. defaults to arch of computer
|
||||||
|
*/
|
||||||
|
function find(toolName, versionSpec, arch) {
|
||||||
|
if (!toolName) {
|
||||||
|
throw new Error('toolName parameter is required');
|
||||||
|
}
|
||||||
|
if (!versionSpec) {
|
||||||
|
throw new Error('versionSpec parameter is required');
|
||||||
|
}
|
||||||
|
arch = arch || os.arch();
|
||||||
|
// attempt to resolve an explicit version
|
||||||
|
if (!_isExplicitVersion(versionSpec)) {
|
||||||
|
const localVersions = findAllVersions(toolName, arch);
|
||||||
|
const match = _evaluateVersions(localVersions, versionSpec);
|
||||||
|
versionSpec = match;
|
||||||
|
}
|
||||||
|
// check for the explicit version in the cache
|
||||||
|
let toolPath = '';
|
||||||
|
if (versionSpec) {
|
||||||
|
versionSpec = semver.clean(versionSpec) || '';
|
||||||
|
const cachePath = path.join(cacheRoot, toolName, versionSpec, arch);
|
||||||
|
core.debug(`checking cache: ${cachePath}`);
|
||||||
|
if (fs.existsSync(cachePath) && fs.existsSync(`${cachePath}.complete`)) {
|
||||||
|
core.debug(`Found tool in cache ${toolName} ${versionSpec} ${arch}`);
|
||||||
|
toolPath = cachePath;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
core.debug('not found');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return toolPath;
|
||||||
|
}
|
||||||
|
exports.find = find;
|
||||||
|
/**
|
||||||
|
* Finds the paths to all versions of a tool that are installed in the local tool cache
|
||||||
|
*
|
||||||
|
* @param toolName name of the tool
|
||||||
|
* @param arch optional arch. defaults to arch of computer
|
||||||
|
*/
|
||||||
|
function findAllVersions(toolName, arch) {
|
||||||
|
const versions = [];
|
||||||
|
arch = arch || os.arch();
|
||||||
|
const toolPath = path.join(cacheRoot, toolName);
|
||||||
|
if (fs.existsSync(toolPath)) {
|
||||||
|
const children = fs.readdirSync(toolPath);
|
||||||
|
for (const child of children) {
|
||||||
|
if (_isExplicitVersion(child)) {
|
||||||
|
const fullPath = path.join(toolPath, child, arch || '');
|
||||||
|
if (fs.existsSync(fullPath) && fs.existsSync(`${fullPath}.complete`)) {
|
||||||
|
versions.push(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return versions;
|
||||||
|
}
|
||||||
|
exports.findAllVersions = findAllVersions;
|
||||||
|
function _createExtractFolder(dest) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
if (!dest) {
|
||||||
|
// create a temp dir
|
||||||
|
dest = path.join(tempDirectory, uuidV4());
|
||||||
|
}
|
||||||
|
yield io.mkdirP(dest);
|
||||||
|
return dest;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function _createToolPath(tool, version, arch) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const folderPath = path.join(cacheRoot, tool, semver.clean(version) || version, arch || '');
|
||||||
|
core.debug(`destination ${folderPath}`);
|
||||||
|
const markerPath = `${folderPath}.complete`;
|
||||||
|
yield io.rmRF(folderPath);
|
||||||
|
yield io.rmRF(markerPath);
|
||||||
|
yield io.mkdirP(folderPath);
|
||||||
|
return folderPath;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function _completeToolPath(tool, version, arch) {
|
||||||
|
const folderPath = path.join(cacheRoot, tool, semver.clean(version) || version, arch || '');
|
||||||
|
const markerPath = `${folderPath}.complete`;
|
||||||
|
fs.writeFileSync(markerPath, '');
|
||||||
|
core.debug('finished caching tool');
|
||||||
|
}
|
||||||
|
function _isExplicitVersion(versionSpec) {
|
||||||
|
const c = semver.clean(versionSpec) || '';
|
||||||
|
core.debug(`isExplicit: ${c}`);
|
||||||
|
const valid = semver.valid(c) != null;
|
||||||
|
core.debug(`explicit? ${valid}`);
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
function _evaluateVersions(versions, versionSpec) {
|
||||||
|
let version = '';
|
||||||
|
core.debug(`evaluating ${versions.length} versions`);
|
||||||
|
versions = versions.sort((a, b) => {
|
||||||
|
if (semver.gt(a, b)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
});
|
||||||
|
for (let i = versions.length - 1; i >= 0; i--) {
|
||||||
|
const potential = versions[i];
|
||||||
|
const satisfied = semver.satisfies(potential, versionSpec);
|
||||||
|
if (satisfied) {
|
||||||
|
version = potential;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (version) {
|
||||||
|
core.debug(`matched: ${version}`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
core.debug('match not found');
|
||||||
|
}
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=tool-cache.js.map
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,74 @@
|
||||||
|
{
|
||||||
|
"_from": "file:toolkit\\actions-tool-cache-0.0.0.tgz",
|
||||||
|
"_id": "@actions/tool-cache@0.0.0",
|
||||||
|
"_inBundle": false,
|
||||||
|
"_integrity": "sha512-NavDg5VFXDfbe9TpFuj+uOHacjg1bT3Wmo3DQuul3gsGRBEXyzhh2MWKnBZs/Zh7FE3prLmIqpbtymafNBFkIA==",
|
||||||
|
"_location": "/@actions/tool-cache",
|
||||||
|
"_phantomChildren": {},
|
||||||
|
"_requested": {
|
||||||
|
"type": "file",
|
||||||
|
"where": "C:\\Users\\damccorm\\Documents\\node12-template",
|
||||||
|
"raw": "@actions/tool-cache@file:toolkit/actions-tool-cache-0.0.0.tgz",
|
||||||
|
"name": "@actions/tool-cache",
|
||||||
|
"escapedName": "@actions%2ftool-cache",
|
||||||
|
"scope": "@actions",
|
||||||
|
"rawSpec": "file:toolkit/actions-tool-cache-0.0.0.tgz",
|
||||||
|
"saveSpec": "file:toolkit\\actions-tool-cache-0.0.0.tgz",
|
||||||
|
"fetchSpec": "C:\\Users\\damccorm\\Documents\\node12-template\\toolkit\\actions-tool-cache-0.0.0.tgz"
|
||||||
|
},
|
||||||
|
"_requiredBy": [
|
||||||
|
"/"
|
||||||
|
],
|
||||||
|
"_resolved": "C:\\Users\\damccorm\\Documents\\node12-template\\toolkit\\actions-tool-cache-0.0.0.tgz",
|
||||||
|
"_shasum": "fa216c10f724010a74602fd14881f25f5b008070",
|
||||||
|
"_spec": "@actions/tool-cache@file:toolkit/actions-tool-cache-0.0.0.tgz",
|
||||||
|
"_where": "C:\\Users\\damccorm\\Documents\\node12-template",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/actions/toolkit/issues"
|
||||||
|
},
|
||||||
|
"bundleDependencies": false,
|
||||||
|
"dependencies": {
|
||||||
|
"@actions/core": "^0.0.0",
|
||||||
|
"@actions/exec": "^0.0.0",
|
||||||
|
"@actions/io": "^0.0.0",
|
||||||
|
"semver": "^6.1.0",
|
||||||
|
"typed-rest-client": "^1.4.0",
|
||||||
|
"uuid": "^3.3.2"
|
||||||
|
},
|
||||||
|
"deprecated": false,
|
||||||
|
"description": "Actions tool-cache lib",
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/nock": "^10.0.3",
|
||||||
|
"@types/semver": "^6.0.0",
|
||||||
|
"@types/uuid": "^3.4.4",
|
||||||
|
"nock": "^10.0.6"
|
||||||
|
},
|
||||||
|
"directories": {
|
||||||
|
"lib": "lib",
|
||||||
|
"test": "__tests__"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"lib",
|
||||||
|
"scripts"
|
||||||
|
],
|
||||||
|
"homepage": "https://github.com/actions/toolkit/tree/master/packages/exec",
|
||||||
|
"keywords": [
|
||||||
|
"exec",
|
||||||
|
"actions"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"main": "lib/tool-cache.js",
|
||||||
|
"name": "@actions/tool-cache",
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/actions/toolkit.git"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: run tests from root\" && exit 1",
|
||||||
|
"tsc": "tsc"
|
||||||
|
},
|
||||||
|
"version": "0.0.0"
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[string]$Source,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[string]$Target)
|
||||||
|
|
||||||
|
# This script translates the output from 7zdec into UTF8. Node has limited
|
||||||
|
# built-in support for encodings.
|
||||||
|
#
|
||||||
|
# 7zdec uses the system default code page. The system default code page varies
|
||||||
|
# depending on the locale configuration. On an en-US box, the system default code
|
||||||
|
# page is Windows-1252.
|
||||||
|
#
|
||||||
|
# Note, on a typical en-US box, testing with the 'ç' character is a good way to
|
||||||
|
# determine whether data is passed correctly between processes. This is because
|
||||||
|
# the 'ç' character has a different code point across each of the common encodings
|
||||||
|
# on a typical en-US box, i.e.
|
||||||
|
# 1) the default console-output code page (IBM437)
|
||||||
|
# 2) the system default code page (i.e. CP_ACP) (Windows-1252)
|
||||||
|
# 3) UTF8
|
||||||
|
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
||||||
|
# Redefine the wrapper over STDOUT to use UTF8. Node expects UTF8 by default.
|
||||||
|
$stdout = [System.Console]::OpenStandardOutput()
|
||||||
|
$utf8 = New-Object System.Text.UTF8Encoding($false) # do not emit BOM
|
||||||
|
$writer = New-Object System.IO.StreamWriter($stdout, $utf8)
|
||||||
|
[System.Console]::SetOut($writer)
|
||||||
|
|
||||||
|
# All subsequent output must be written using [System.Console]::WriteLine(). In
|
||||||
|
# PowerShell 4, Write-Host and Out-Default do not consider the updated stream writer.
|
||||||
|
|
||||||
|
Set-Location -LiteralPath $Target
|
||||||
|
|
||||||
|
# Print the ##command.
|
||||||
|
$_7zdec = Join-Path -Path "$PSScriptRoot" -ChildPath "externals/7zdec.exe"
|
||||||
|
[System.Console]::WriteLine("##[command]$_7zdec x `"$Source`"")
|
||||||
|
|
||||||
|
# The $OutputEncoding variable instructs PowerShell how to interpret the output
|
||||||
|
# from the external command.
|
||||||
|
$OutputEncoding = [System.Text.Encoding]::Default
|
||||||
|
|
||||||
|
# Note, the output from 7zdec.exe needs to be iterated over. Otherwise PowerShell.exe
|
||||||
|
# will launch the external command in such a way that it inherits the streams.
|
||||||
|
& $_7zdec x $Source 2>&1 |
|
||||||
|
ForEach-Object {
|
||||||
|
if ($_ -is [System.Management.Automation.ErrorRecord]) {
|
||||||
|
[System.Console]::WriteLine($_.Exception.Message)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
[System.Console]::WriteLine($_)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[System.Console]::WriteLine("##[debug]7zdec.exe exit code '$LASTEXITCODE'")
|
||||||
|
[System.Console]::Out.Flush()
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
exit $LASTEXITCODE
|
||||||
|
}
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,21 @@
|
||||||
|
The MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2018 Octokit contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
|
@ -0,0 +1,421 @@
|
||||||
|
# endpoint.js
|
||||||
|
|
||||||
|
> Turns GitHub REST API endpoints into generic request options
|
||||||
|
|
||||||
|
[![@latest](https://img.shields.io/npm/v/@octokit/endpoint.svg)](https://www.npmjs.com/package/@octokit/endpoint)
|
||||||
|
[![Build Status](https://travis-ci.org/octokit/endpoint.js.svg?branch=master)](https://travis-ci.org/octokit/endpoint.js)
|
||||||
|
[![Greenkeeper](https://badges.greenkeeper.io/octokit/endpoint.js.svg)](https://greenkeeper.io/)
|
||||||
|
|
||||||
|
`@octokit/endpoint` combines [GitHub REST API routes](https://developer.github.com/v3/) with your parameters and turns them into generic request options that can be used in any request library.
|
||||||
|
|
||||||
|
<!-- update table of contents by running `npx markdown-toc README.md -i` -->
|
||||||
|
<!-- toc -->
|
||||||
|
|
||||||
|
- [Usage](#usage)
|
||||||
|
- [API](#api)
|
||||||
|
- [endpoint()](#endpoint)
|
||||||
|
- [endpoint.defaults()](#endpointdefaults)
|
||||||
|
- [endpoint.DEFAULTS](#endpointdefaults)
|
||||||
|
- [endpoint.merge()](#endpointmerge)
|
||||||
|
- [endpoint.parse()](#endpointparse)
|
||||||
|
- [Special cases](#special-cases)
|
||||||
|
- [The `data` parameter – set request body directly](#the-data-parameter-%E2%80%93-set-request-body-directly)
|
||||||
|
- [Set parameters for both the URL/query and the request body](#set-parameters-for-both-the-urlquery-and-the-request-body)
|
||||||
|
- [LICENSE](#license)
|
||||||
|
|
||||||
|
<!-- tocstop -->
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tbody valign=top align=left>
|
||||||
|
<tr><th>
|
||||||
|
Browsers
|
||||||
|
</th><td width=100%>
|
||||||
|
Load <code>@octokit/endpoint</code> directly from <a href="https://cdn.pika.dev">cdn.pika.dev</a>
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script type="module">
|
||||||
|
import { endpoint } from "https://cdn.pika.dev/@octokit/endpoint";
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
</td></tr>
|
||||||
|
<tr><th>
|
||||||
|
Node
|
||||||
|
</th><td>
|
||||||
|
|
||||||
|
Install with <code>npm install @octokit/endpoint</code>
|
||||||
|
|
||||||
|
```js
|
||||||
|
const { endpoint } = require("@octokit/endpoint");
|
||||||
|
// or: import { endpoint } from "@octokit/endpoint";
|
||||||
|
```
|
||||||
|
|
||||||
|
</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
Example for [List organization repositories](https://developer.github.com/v3/repos/#list-organization-repositories)
|
||||||
|
|
||||||
|
```js
|
||||||
|
const requestOptions = endpoint("GET /orgs/:org/repos", {
|
||||||
|
headers: {
|
||||||
|
authorization: "token 0000000000000000000000000000000000000001"
|
||||||
|
},
|
||||||
|
org: "octokit",
|
||||||
|
type: "private"
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
The resulting `requestOptions` looks as follows
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"url": "https://api.github.com/orgs/octokit/repos?type=private",
|
||||||
|
"headers": {
|
||||||
|
"accept": "application/vnd.github.v3+json",
|
||||||
|
"authorization": "token 0000000000000000000000000000000000000001",
|
||||||
|
"user-agent": "octokit/endpoint.js v1.2.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can pass `requestOptions` to commen request libraries
|
||||||
|
|
||||||
|
```js
|
||||||
|
const { url, ...options } = requestOptions;
|
||||||
|
// using with fetch (https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)
|
||||||
|
fetch(url, options);
|
||||||
|
// using with request (https://github.com/request/request)
|
||||||
|
request(requestOptions);
|
||||||
|
// using with got (https://github.com/sindresorhus/got)
|
||||||
|
got[options.method](url, options);
|
||||||
|
// using with axios
|
||||||
|
axios(requestOptions);
|
||||||
|
```
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
### `endpoint(route, options)` or `endpoint(options)`
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead align=left>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
name
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
type
|
||||||
|
</th>
|
||||||
|
<th width=100%>
|
||||||
|
description
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody align=left valign=top>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<code>route</code>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
String
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
If set, it has to be a string consisting of URL and the request method, e.g., <code>GET /orgs/:org</code>. If it’s set to a URL, only the method defaults to <code>GET</code>.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<code>options.method</code>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
String
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<strong>Required unless <code>route</code> is set.</strong> Any supported <a href="https://developer.github.com/v3/#http-verbs">http verb</a>. <em>Defaults to <code>GET</code></em>.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<code>options.url</code>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
String
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<strong>Required unless <code>route</code> is set.</strong> A path or full URL which may contain <code>:variable</code> or <code>{variable}</code> placeholders,
|
||||||
|
e.g., <code>/orgs/:org/repos</code>. The <code>url</code> is parsed using <a href="https://github.com/bramstein/url-template">url-template</a>.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<code>options.baseUrl</code>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
String
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<em>Defaults to <code>https://api.github.com</code></em>.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<code>options.headers</code>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
Object
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
Custom headers. Passed headers are merged with defaults:<br>
|
||||||
|
<em><code>headers['user-agent']</code> defaults to <code>octokit-endpoint.js/1.2.3</code> (where <code>1.2.3</code> is the released version)</em>.<br>
|
||||||
|
<em><code>headers['accept']</code> defaults to <code>application/vnd.github.v3+json</code></em>.<br>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<code>options.mediaType.format</code>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
String
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
Media type param, such as <code>raw</code>, <code>diff</code>, or <code>text+json</code>. See <a href="https://developer.github.com/v3/media/">Media Types</a>. Setting <code>options.mediaType.format</code> will amend the <code>headers.accept</code> value.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<code>options.mediaType.previews</code>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
Array of Strings
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
Name of previews, such as <code>mercy</code>, <code>symmetra</code>, or <code>scarlet-witch</code>. See <a href="https://developer.github.com/v3/previews/">API Previews</a>. If <code>options.mediaType.previews</code> was set as default, the new previews will be merged into the default ones. Setting <code>options.mediaType.previews</code> will amend the <code>headers.accept</code> value. <code>options.mediaType.previews</code> will be merged with an existing array set using <code>.defaults()</code>.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<code>options.data</code>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
Any
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
Set request body directly instead of setting it to JSON based on additional parameters. See <a href="#data-parameter">"The <code>data</code> parameter"</a> below.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<code>options.request</code>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
Object
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
Pass custom meta information for the request. The <code>request</code> object will be returned as is.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
All other options will be passed depending on the `method` and `url` options.
|
||||||
|
|
||||||
|
1. If the option key has a placeholder in the `url`, it will be used as the replacement. For example, if the passed options are `{url: '/orgs/:org/repos', org: 'foo'}` the returned `options.url` is `https://api.github.com/orgs/foo/repos`.
|
||||||
|
2. If the `method` is `GET` or `HEAD`, the option is passed as a query parameter.
|
||||||
|
3. Otherwise, the parameter is passed in the request body as a JSON key.
|
||||||
|
|
||||||
|
**Result**
|
||||||
|
|
||||||
|
`endpoint()` is a synchronous method and returns an object with the following keys:
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead align=left>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
key
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
type
|
||||||
|
</th>
|
||||||
|
<th width=100%>
|
||||||
|
description
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody align=left valign=top>
|
||||||
|
<tr>
|
||||||
|
<th><code>method</code></th>
|
||||||
|
<td>String</td>
|
||||||
|
<td>The http method. Always lowercase.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><code>url</code></th>
|
||||||
|
<td>String</td>
|
||||||
|
<td>The url with placeholders replaced with passed parameters.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><code>headers</code></th>
|
||||||
|
<td>Object</td>
|
||||||
|
<td>All header names are lowercased.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><code>body</code></th>
|
||||||
|
<td>Any</td>
|
||||||
|
<td>The request body if one is present. Only for <code>PATCH</code>, <code>POST</code>, <code>PUT</code>, <code>DELETE</code> requests.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><code>request</code></th>
|
||||||
|
<td>Object</td>
|
||||||
|
<td>Request meta option, it will be returned as it was passed into <code>endpoint()</code></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
### `endpoint.defaults()`
|
||||||
|
|
||||||
|
Override or set default options. Example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const request = require("request");
|
||||||
|
const myEndpoint = require("@octokit/endpoint").defaults({
|
||||||
|
baseUrl: "https://github-enterprise.acme-inc.com/api/v3",
|
||||||
|
headers: {
|
||||||
|
"user-agent": "myApp/1.2.3",
|
||||||
|
authorization: `token 0000000000000000000000000000000000000001`
|
||||||
|
},
|
||||||
|
org: "my-project",
|
||||||
|
per_page: 100
|
||||||
|
});
|
||||||
|
|
||||||
|
request(myEndpoint(`GET /orgs/:org/repos`));
|
||||||
|
```
|
||||||
|
|
||||||
|
You can call `.defaults()` again on the returned method, the defaults will cascade.
|
||||||
|
|
||||||
|
```js
|
||||||
|
const myProjectEndpoint = endpoint.defaults({
|
||||||
|
baseUrl: "https://github-enterprise.acme-inc.com/api/v3",
|
||||||
|
headers: {
|
||||||
|
"user-agent": "myApp/1.2.3"
|
||||||
|
},
|
||||||
|
org: "my-project"
|
||||||
|
});
|
||||||
|
const myProjectEndpointWithAuth = myProjectEndpoint.defaults({
|
||||||
|
headers: {
|
||||||
|
authorization: `token 0000000000000000000000000000000000000001`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
`myProjectEndpointWithAuth` now defaults the `baseUrl`, `headers['user-agent']`,
|
||||||
|
`org` and `headers['authorization']` on top of `headers['accept']` that is set
|
||||||
|
by the global default.
|
||||||
|
|
||||||
|
### `endpoint.DEFAULTS`
|
||||||
|
|
||||||
|
The current default options.
|
||||||
|
|
||||||
|
```js
|
||||||
|
endpoint.DEFAULTS.baseUrl; // https://api.github.com
|
||||||
|
const myEndpoint = endpoint.defaults({
|
||||||
|
baseUrl: "https://github-enterprise.acme-inc.com/api/v3"
|
||||||
|
});
|
||||||
|
myEndpoint.DEFAULTS.baseUrl; // https://github-enterprise.acme-inc.com/api/v3
|
||||||
|
```
|
||||||
|
|
||||||
|
### `endpoint.merge(route, options)` or `endpoint.merge(options)`
|
||||||
|
|
||||||
|
Get the defaulted endpoint options, but without parsing them into request options:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const myProjectEndpoint = endpoint.defaults({
|
||||||
|
baseUrl: "https://github-enterprise.acme-inc.com/api/v3",
|
||||||
|
headers: {
|
||||||
|
"user-agent": "myApp/1.2.3"
|
||||||
|
},
|
||||||
|
org: "my-project"
|
||||||
|
});
|
||||||
|
myProjectEndpoint.merge("GET /orgs/:org/repos", {
|
||||||
|
headers: {
|
||||||
|
authorization: `token 0000000000000000000000000000000000000001`
|
||||||
|
},
|
||||||
|
org: "my-secret-project",
|
||||||
|
type: "private"
|
||||||
|
});
|
||||||
|
|
||||||
|
// {
|
||||||
|
// baseUrl: 'https://github-enterprise.acme-inc.com/api/v3',
|
||||||
|
// method: 'GET',
|
||||||
|
// url: '/orgs/:org/repos',
|
||||||
|
// headers: {
|
||||||
|
// accept: 'application/vnd.github.v3+json',
|
||||||
|
// authorization: `token 0000000000000000000000000000000000000001`,
|
||||||
|
// 'user-agent': 'myApp/1.2.3'
|
||||||
|
// },
|
||||||
|
// org: 'my-secret-project',
|
||||||
|
// type: 'private'
|
||||||
|
// }
|
||||||
|
```
|
||||||
|
|
||||||
|
### `endpoint.parse()`
|
||||||
|
|
||||||
|
Stateless method to turn endpoint options into request options. Calling
|
||||||
|
`endpoint(options)` is the same as calling `endpoint.parse(endpoint.merge(options))`.
|
||||||
|
|
||||||
|
## Special cases
|
||||||
|
|
||||||
|
<a name="data-parameter"></a>
|
||||||
|
|
||||||
|
### The `data` parameter – set request body directly
|
||||||
|
|
||||||
|
Some endpoints such as [Render a Markdown document in raw mode](https://developer.github.com/v3/markdown/#render-a-markdown-document-in-raw-mode) don’t have parameters that are sent as request body keys, instead, the request body needs to be set directly. In these cases, set the `data` parameter.
|
||||||
|
|
||||||
|
```js
|
||||||
|
const options = endpoint("POST /markdown/raw", {
|
||||||
|
data: "Hello world github/linguist#1 **cool**, and #1!",
|
||||||
|
headers: {
|
||||||
|
accept: "text/html;charset=utf-8",
|
||||||
|
"content-type": "text/plain"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// options is
|
||||||
|
// {
|
||||||
|
// method: 'post',
|
||||||
|
// url: 'https://api.github.com/markdown/raw',
|
||||||
|
// headers: {
|
||||||
|
// accept: 'text/html;charset=utf-8',
|
||||||
|
// 'content-type': 'text/plain',
|
||||||
|
// 'user-agent': userAgent
|
||||||
|
// },
|
||||||
|
// body: 'Hello world github/linguist#1 **cool**, and #1!'
|
||||||
|
// }
|
||||||
|
```
|
||||||
|
|
||||||
|
### Set parameters for both the URL/query and the request body
|
||||||
|
|
||||||
|
There are API endpoints that accept both query parameters as well as a body. In that case, you need to add the query parameters as templates to `options.url`, as defined in the [RFC 6570 URI Template specification](https://tools.ietf.org/html/rfc6570).
|
||||||
|
|
||||||
|
Example
|
||||||
|
|
||||||
|
```js
|
||||||
|
endpoint(
|
||||||
|
"POST https://uploads.github.com/repos/octocat/Hello-World/releases/1/assets{?name,label}",
|
||||||
|
{
|
||||||
|
name: "example.zip",
|
||||||
|
label: "short description",
|
||||||
|
headers: {
|
||||||
|
"content-type": "text/plain",
|
||||||
|
"content-length": 14,
|
||||||
|
authorization: `token 0000000000000000000000000000000000000001`
|
||||||
|
},
|
||||||
|
data: "Hello, world!"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
## LICENSE
|
||||||
|
|
||||||
|
[MIT](LICENSE)
|
|
@ -0,0 +1,197 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
|
|
||||||
|
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
|
||||||
|
|
||||||
|
var deepmerge = _interopDefault(require('deepmerge'));
|
||||||
|
var isPlainObject = _interopDefault(require('is-plain-object'));
|
||||||
|
var urlTemplate = _interopDefault(require('url-template'));
|
||||||
|
var getUserAgent = _interopDefault(require('universal-user-agent'));
|
||||||
|
|
||||||
|
function lowercaseKeys(object) {
|
||||||
|
if (!object) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.keys(object).reduce((newObj, key) => {
|
||||||
|
newObj[key.toLowerCase()] = object[key];
|
||||||
|
return newObj;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
function merge(defaults, route, options) {
|
||||||
|
if (typeof route === "string") {
|
||||||
|
let [method, url] = route.split(" ");
|
||||||
|
options = Object.assign(url ? {
|
||||||
|
method,
|
||||||
|
url
|
||||||
|
} : {
|
||||||
|
url: method
|
||||||
|
}, options);
|
||||||
|
} else {
|
||||||
|
options = route || {};
|
||||||
|
} // lowercase header names before merging with defaults to avoid duplicates
|
||||||
|
|
||||||
|
|
||||||
|
options.headers = lowercaseKeys(options.headers);
|
||||||
|
const mergedOptions = deepmerge.all([defaults, options].filter(Boolean), {
|
||||||
|
isMergeableObject: isPlainObject
|
||||||
|
}); // mediaType.previews arrays are merged, instead of overwritten
|
||||||
|
|
||||||
|
if (defaults && defaults.mediaType.previews.length) {
|
||||||
|
mergedOptions.mediaType.previews = defaults.mediaType.previews.filter(preview => !mergedOptions.mediaType.previews.includes(preview)).concat(mergedOptions.mediaType.previews);
|
||||||
|
}
|
||||||
|
|
||||||
|
mergedOptions.mediaType.previews = mergedOptions.mediaType.previews.map(preview => preview.replace(/-preview/, ""));
|
||||||
|
return mergedOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addQueryParameters(url, parameters) {
|
||||||
|
const separator = /\?/.test(url) ? "&" : "?";
|
||||||
|
const names = Object.keys(parameters);
|
||||||
|
|
||||||
|
if (names.length === 0) {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
return url + separator + names.map(name => {
|
||||||
|
if (name === "q") {
|
||||||
|
return "q=" + parameters.q.split("+").map(encodeURIComponent).join("+");
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${name}=${encodeURIComponent(parameters[name])}`;
|
||||||
|
}).join("&");
|
||||||
|
}
|
||||||
|
|
||||||
|
const urlVariableRegex = /\{[^}]+\}/g;
|
||||||
|
|
||||||
|
function removeNonChars(variableName) {
|
||||||
|
return variableName.replace(/^\W+|\W+$/g, "").split(/,/);
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractUrlVariableNames(url) {
|
||||||
|
const matches = url.match(urlVariableRegex);
|
||||||
|
|
||||||
|
if (!matches) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return matches.map(removeNonChars).reduce((a, b) => a.concat(b), []);
|
||||||
|
}
|
||||||
|
|
||||||
|
function omit(object, keysToOmit) {
|
||||||
|
return Object.keys(object).filter(option => !keysToOmit.includes(option)).reduce((obj, key) => {
|
||||||
|
obj[key] = object[key];
|
||||||
|
return obj;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
function parse(options) {
|
||||||
|
// https://fetch.spec.whatwg.org/#methods
|
||||||
|
let method = options.method.toUpperCase(); // replace :varname with {varname} to make it RFC 6570 compatible
|
||||||
|
|
||||||
|
let url = options.url.replace(/:([a-z]\w+)/g, "{+$1}");
|
||||||
|
let headers = Object.assign({}, options.headers);
|
||||||
|
let body;
|
||||||
|
let parameters = omit(options, ["method", "baseUrl", "url", "headers", "request", "mediaType"]); // extract variable names from URL to calculate remaining variables later
|
||||||
|
|
||||||
|
const urlVariableNames = extractUrlVariableNames(url);
|
||||||
|
url = urlTemplate.parse(url).expand(parameters);
|
||||||
|
|
||||||
|
if (!/^http/.test(url)) {
|
||||||
|
url = options.baseUrl + url;
|
||||||
|
}
|
||||||
|
|
||||||
|
const omittedParameters = Object.keys(options).filter(option => urlVariableNames.includes(option)).concat("baseUrl");
|
||||||
|
const remainingParameters = omit(parameters, omittedParameters);
|
||||||
|
const isBinaryRequset = /application\/octet-stream/i.test(headers.accept);
|
||||||
|
|
||||||
|
if (!isBinaryRequset) {
|
||||||
|
if (options.mediaType.format) {
|
||||||
|
// e.g. application/vnd.github.v3+json => application/vnd.github.v3.raw
|
||||||
|
headers.accept = headers.accept.split(/,/).map(preview => preview.replace(/application\/vnd(\.\w+)(\.v3)?(\.\w+)?(\+json)?$/, `application/vnd$1$2.${options.mediaType.format}`)).join(",");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.mediaType.previews.length) {
|
||||||
|
const previewsFromAcceptHeader = headers.accept.match(/[\w-]+(?=-preview)/g) || [];
|
||||||
|
headers.accept = previewsFromAcceptHeader.concat(options.mediaType.previews).map(preview => {
|
||||||
|
const format = options.mediaType.format ? `.${options.mediaType.format}` : "+json";
|
||||||
|
return `application/vnd.github.${preview}-preview${format}`;
|
||||||
|
}).join(",");
|
||||||
|
}
|
||||||
|
} // for GET/HEAD requests, set URL query parameters from remaining parameters
|
||||||
|
// for PATCH/POST/PUT/DELETE requests, set request body from remaining parameters
|
||||||
|
|
||||||
|
|
||||||
|
if (["GET", "HEAD"].includes(method)) {
|
||||||
|
url = addQueryParameters(url, remainingParameters);
|
||||||
|
} else {
|
||||||
|
if ("data" in remainingParameters) {
|
||||||
|
body = remainingParameters.data;
|
||||||
|
} else {
|
||||||
|
if (Object.keys(remainingParameters).length) {
|
||||||
|
body = remainingParameters;
|
||||||
|
} else {
|
||||||
|
headers["content-length"] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // default content-type for JSON if body is set
|
||||||
|
|
||||||
|
|
||||||
|
if (!headers["content-type"] && typeof body !== "undefined") {
|
||||||
|
headers["content-type"] = "application/json; charset=utf-8";
|
||||||
|
} // GitHub expects 'content-length: 0' header for PUT/PATCH requests without body.
|
||||||
|
// fetch does not allow to set `content-length` header, but we can set body to an empty string
|
||||||
|
|
||||||
|
|
||||||
|
if (["PATCH", "PUT"].includes(method) && typeof body === "undefined") {
|
||||||
|
body = "";
|
||||||
|
} // Only return body/request keys if present
|
||||||
|
|
||||||
|
|
||||||
|
return Object.assign({
|
||||||
|
method,
|
||||||
|
url,
|
||||||
|
headers
|
||||||
|
}, typeof body !== "undefined" ? {
|
||||||
|
body
|
||||||
|
} : null, options.request ? {
|
||||||
|
request: options.request
|
||||||
|
} : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
function endpointWithDefaults(defaults, route, options) {
|
||||||
|
return parse(merge(defaults, route, options));
|
||||||
|
}
|
||||||
|
|
||||||
|
function withDefaults(oldDefaults, newDefaults) {
|
||||||
|
const DEFAULTS = merge(oldDefaults, newDefaults);
|
||||||
|
const endpoint = endpointWithDefaults.bind(null, DEFAULTS);
|
||||||
|
return Object.assign(endpoint, {
|
||||||
|
DEFAULTS,
|
||||||
|
defaults: withDefaults.bind(null, DEFAULTS),
|
||||||
|
merge: merge.bind(null, DEFAULTS),
|
||||||
|
parse
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const VERSION = "0.0.0-development";
|
||||||
|
|
||||||
|
const userAgent = `octokit-endpoint.js/${VERSION} ${getUserAgent()}`;
|
||||||
|
const DEFAULTS = {
|
||||||
|
method: "GET",
|
||||||
|
baseUrl: "https://api.github.com",
|
||||||
|
headers: {
|
||||||
|
accept: "application/vnd.github.v3+json",
|
||||||
|
"user-agent": userAgent
|
||||||
|
},
|
||||||
|
mediaType: {
|
||||||
|
format: "",
|
||||||
|
previews: []
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const endpoint = withDefaults(null, DEFAULTS);
|
||||||
|
|
||||||
|
exports.endpoint = endpoint;
|
|
@ -0,0 +1,15 @@
|
||||||
|
import getUserAgent from "universal-user-agent";
|
||||||
|
import { VERSION } from "./version";
|
||||||
|
const userAgent = `octokit-endpoint.js/${VERSION} ${getUserAgent()}`;
|
||||||
|
export const DEFAULTS = {
|
||||||
|
method: "GET",
|
||||||
|
baseUrl: "https://api.github.com",
|
||||||
|
headers: {
|
||||||
|
accept: "application/vnd.github.v3+json",
|
||||||
|
"user-agent": userAgent
|
||||||
|
},
|
||||||
|
mediaType: {
|
||||||
|
format: "",
|
||||||
|
previews: []
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { merge } from "./merge";
|
||||||
|
import { parse } from "./parse";
|
||||||
|
export function endpointWithDefaults(defaults, route, options) {
|
||||||
|
return parse(merge(defaults, route, options));
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
import { withDefaults } from "./with-defaults";
|
||||||
|
import { DEFAULTS } from "./defaults";
|
||||||
|
export const endpoint = withDefaults(null, DEFAULTS);
|
|
@ -0,0 +1,25 @@
|
||||||
|
import deepmerge from "deepmerge";
|
||||||
|
import isPlainObject from "is-plain-object";
|
||||||
|
import { lowercaseKeys } from "./util/lowercase-keys";
|
||||||
|
export function merge(defaults, route, options) {
|
||||||
|
if (typeof route === "string") {
|
||||||
|
let [method, url] = route.split(" ");
|
||||||
|
options = Object.assign(url ? { method, url } : { url: method }, options);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
options = route || {};
|
||||||
|
}
|
||||||
|
// lowercase header names before merging with defaults to avoid duplicates
|
||||||
|
options.headers = lowercaseKeys(options.headers);
|
||||||
|
const mergedOptions = deepmerge.all([defaults, options].filter(Boolean), {
|
||||||
|
isMergeableObject: isPlainObject
|
||||||
|
});
|
||||||
|
// mediaType.previews arrays are merged, instead of overwritten
|
||||||
|
if (defaults && defaults.mediaType.previews.length) {
|
||||||
|
mergedOptions.mediaType.previews = defaults.mediaType.previews
|
||||||
|
.filter(preview => !mergedOptions.mediaType.previews.includes(preview))
|
||||||
|
.concat(mergedOptions.mediaType.previews);
|
||||||
|
}
|
||||||
|
mergedOptions.mediaType.previews = mergedOptions.mediaType.previews.map((preview) => preview.replace(/-preview/, ""));
|
||||||
|
return mergedOptions;
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
import urlTemplate from "url-template";
|
||||||
|
import { addQueryParameters } from "./util/add-query-parameters";
|
||||||
|
import { extractUrlVariableNames } from "./util/extract-url-variable-names";
|
||||||
|
import { omit } from "./util/omit";
|
||||||
|
export function parse(options) {
|
||||||
|
// https://fetch.spec.whatwg.org/#methods
|
||||||
|
let method = options.method.toUpperCase();
|
||||||
|
// replace :varname with {varname} to make it RFC 6570 compatible
|
||||||
|
let url = options.url.replace(/:([a-z]\w+)/g, "{+$1}");
|
||||||
|
let headers = Object.assign({}, options.headers);
|
||||||
|
let body;
|
||||||
|
let parameters = omit(options, [
|
||||||
|
"method",
|
||||||
|
"baseUrl",
|
||||||
|
"url",
|
||||||
|
"headers",
|
||||||
|
"request",
|
||||||
|
"mediaType"
|
||||||
|
]);
|
||||||
|
// extract variable names from URL to calculate remaining variables later
|
||||||
|
const urlVariableNames = extractUrlVariableNames(url);
|
||||||
|
url = urlTemplate.parse(url).expand(parameters);
|
||||||
|
if (!/^http/.test(url)) {
|
||||||
|
url = options.baseUrl + url;
|
||||||
|
}
|
||||||
|
const omittedParameters = Object.keys(options)
|
||||||
|
.filter(option => urlVariableNames.includes(option))
|
||||||
|
.concat("baseUrl");
|
||||||
|
const remainingParameters = omit(parameters, omittedParameters);
|
||||||
|
const isBinaryRequset = /application\/octet-stream/i.test(headers.accept);
|
||||||
|
if (!isBinaryRequset) {
|
||||||
|
if (options.mediaType.format) {
|
||||||
|
// e.g. application/vnd.github.v3+json => application/vnd.github.v3.raw
|
||||||
|
headers.accept = headers.accept
|
||||||
|
.split(/,/)
|
||||||
|
.map(preview => preview.replace(/application\/vnd(\.\w+)(\.v3)?(\.\w+)?(\+json)?$/, `application/vnd$1$2.${options.mediaType.format}`))
|
||||||
|
.join(",");
|
||||||
|
}
|
||||||
|
if (options.mediaType.previews.length) {
|
||||||
|
const previewsFromAcceptHeader = headers.accept.match(/[\w-]+(?=-preview)/g) || [];
|
||||||
|
headers.accept = previewsFromAcceptHeader
|
||||||
|
.concat(options.mediaType.previews)
|
||||||
|
.map(preview => {
|
||||||
|
const format = options.mediaType.format
|
||||||
|
? `.${options.mediaType.format}`
|
||||||
|
: "+json";
|
||||||
|
return `application/vnd.github.${preview}-preview${format}`;
|
||||||
|
})
|
||||||
|
.join(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// for GET/HEAD requests, set URL query parameters from remaining parameters
|
||||||
|
// for PATCH/POST/PUT/DELETE requests, set request body from remaining parameters
|
||||||
|
if (["GET", "HEAD"].includes(method)) {
|
||||||
|
url = addQueryParameters(url, remainingParameters);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ("data" in remainingParameters) {
|
||||||
|
body = remainingParameters.data;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (Object.keys(remainingParameters).length) {
|
||||||
|
body = remainingParameters;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
headers["content-length"] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// default content-type for JSON if body is set
|
||||||
|
if (!headers["content-type"] && typeof body !== "undefined") {
|
||||||
|
headers["content-type"] = "application/json; charset=utf-8";
|
||||||
|
}
|
||||||
|
// GitHub expects 'content-length: 0' header for PUT/PATCH requests without body.
|
||||||
|
// fetch does not allow to set `content-length` header, but we can set body to an empty string
|
||||||
|
if (["PATCH", "PUT"].includes(method) && typeof body === "undefined") {
|
||||||
|
body = "";
|
||||||
|
}
|
||||||
|
// Only return body/request keys if present
|
||||||
|
return Object.assign({ method, url, headers }, typeof body !== "undefined" ? { body } : null, options.request ? { request: options.request } : null);
|
||||||
|
}
|
21
node_modules/@octokit/endpoint/dist-src/util/add-query-parameters.js
generated
vendored
Normal file
21
node_modules/@octokit/endpoint/dist-src/util/add-query-parameters.js
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
export function addQueryParameters(url, parameters) {
|
||||||
|
const separator = /\?/.test(url) ? "&" : "?";
|
||||||
|
const names = Object.keys(parameters);
|
||||||
|
if (names.length === 0) {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
return (url +
|
||||||
|
separator +
|
||||||
|
names
|
||||||
|
.map(name => {
|
||||||
|
if (name === "q") {
|
||||||
|
return ("q=" +
|
||||||
|
parameters
|
||||||
|
.q.split("+")
|
||||||
|
.map(encodeURIComponent)
|
||||||
|
.join("+"));
|
||||||
|
}
|
||||||
|
return `${name}=${encodeURIComponent(parameters[name])}`;
|
||||||
|
})
|
||||||
|
.join("&"));
|
||||||
|
}
|
11
node_modules/@octokit/endpoint/dist-src/util/extract-url-variable-names.js
generated
vendored
Normal file
11
node_modules/@octokit/endpoint/dist-src/util/extract-url-variable-names.js
generated
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
const urlVariableRegex = /\{[^}]+\}/g;
|
||||||
|
function removeNonChars(variableName) {
|
||||||
|
return variableName.replace(/^\W+|\W+$/g, "").split(/,/);
|
||||||
|
}
|
||||||
|
export function extractUrlVariableNames(url) {
|
||||||
|
const matches = url.match(urlVariableRegex);
|
||||||
|
if (!matches) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return matches.map(removeNonChars).reduce((a, b) => a.concat(b), []);
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
export function lowercaseKeys(object) {
|
||||||
|
if (!object) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return Object.keys(object).reduce((newObj, key) => {
|
||||||
|
newObj[key.toLowerCase()] = object[key];
|
||||||
|
return newObj;
|
||||||
|
}, {});
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
export function omit(object, keysToOmit) {
|
||||||
|
return Object.keys(object)
|
||||||
|
.filter(option => !keysToOmit.includes(option))
|
||||||
|
.reduce((obj, key) => {
|
||||||
|
obj[key] = object[key];
|
||||||
|
return obj;
|
||||||
|
}, {});
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
export const VERSION = "0.0.0-development";
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { endpointWithDefaults } from "./endpoint-with-defaults";
|
||||||
|
import { merge } from "./merge";
|
||||||
|
import { parse } from "./parse";
|
||||||
|
export function withDefaults(oldDefaults, newDefaults) {
|
||||||
|
const DEFAULTS = merge(oldDefaults, newDefaults);
|
||||||
|
const endpoint = endpointWithDefaults.bind(null, DEFAULTS);
|
||||||
|
return Object.assign(endpoint, {
|
||||||
|
DEFAULTS,
|
||||||
|
defaults: withDefaults.bind(null, DEFAULTS),
|
||||||
|
merge: merge.bind(null, DEFAULTS),
|
||||||
|
parse
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
import { Defaults } from "./types";
|
||||||
|
export declare const DEFAULTS: Defaults;
|
2
node_modules/@octokit/endpoint/dist-types/endpoint-with-defaults.d.ts
generated
vendored
Normal file
2
node_modules/@octokit/endpoint/dist-types/endpoint-with-defaults.d.ts
generated
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
import { Defaults, Endpoint, RequestOptions, Route, Parameters } from "./types";
|
||||||
|
export declare function endpointWithDefaults(defaults: Defaults, route: Route | Endpoint, options?: Parameters): RequestOptions;
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1 @@
|
||||||
|
export declare const endpoint: import("./types").endpoint;
|
|
@ -0,0 +1,2 @@
|
||||||
|
import { Defaults, Route, Parameters } from "./types";
|
||||||
|
export declare function merge(defaults: Defaults | null, route?: Route | Parameters, options?: Parameters): Defaults;
|
|
@ -0,0 +1,2 @@
|
||||||
|
import { Defaults, RequestOptions } from "./types";
|
||||||
|
export declare function parse(options: Defaults): RequestOptions;
|
|
@ -0,0 +1,150 @@
|
||||||
|
import { Routes as KnownRoutes } from "./generated/routes";
|
||||||
|
export interface endpoint {
|
||||||
|
/**
|
||||||
|
* Transforms a GitHub REST API endpoint into generic request options
|
||||||
|
*
|
||||||
|
* @param {object} endpoint Must set `method` and `url`. Plus URL, query or body parameters, as well as `headers`, `mediaType.{format|previews}`, `request`, or `baseUrl`.
|
||||||
|
*/
|
||||||
|
(options: Endpoint): RequestOptions;
|
||||||
|
/**
|
||||||
|
* Transforms a GitHub REST API endpoint into generic request options
|
||||||
|
*
|
||||||
|
* @param {string} route Request method + URL. Example: `'GET /orgs/:org'`
|
||||||
|
* @param {object} [parameters] URL, query or body parameters, as well as `headers`, `mediaType.{format|previews}`, `request`, or `baseUrl`.
|
||||||
|
*/
|
||||||
|
<R extends Route>(route: keyof KnownRoutes | R, options?: R extends keyof KnownRoutes ? KnownRoutes[R][0] & Parameters : Parameters): R extends keyof KnownRoutes ? KnownRoutes[R][1] : RequestOptions;
|
||||||
|
/**
|
||||||
|
* Object with current default route and parameters
|
||||||
|
*/
|
||||||
|
DEFAULTS: Defaults;
|
||||||
|
/**
|
||||||
|
* Returns a new `endpoint` with updated route and parameters
|
||||||
|
*/
|
||||||
|
defaults: (newDefaults: Parameters) => endpoint;
|
||||||
|
merge: {
|
||||||
|
/**
|
||||||
|
* Merges current endpoint defaults with passed route and parameters,
|
||||||
|
* without transforming them into request options.
|
||||||
|
*
|
||||||
|
* @param {string} route Request method + URL. Example: `'GET /orgs/:org'`
|
||||||
|
* @param {object} [parameters] URL, query or body parameters, as well as `headers`, `mediaType.{format|previews}`, `request`, or `baseUrl`.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
(route: Route, parameters?: Parameters): Defaults;
|
||||||
|
/**
|
||||||
|
* Merges current endpoint defaults with passed route and parameters,
|
||||||
|
* without transforming them into request options.
|
||||||
|
*
|
||||||
|
* @param {object} endpoint Must set `method` and `url`. Plus URL, query or body parameters, as well as `headers`, `mediaType.{format|previews}`, `request`, or `baseUrl`.
|
||||||
|
*/
|
||||||
|
(options: Parameters): Defaults;
|
||||||
|
/**
|
||||||
|
* Returns current default options.
|
||||||
|
*
|
||||||
|
* @deprecated use endpoint.DEFAULTS instead
|
||||||
|
*/
|
||||||
|
(): Defaults;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Stateless method to turn endpoint options into request options.
|
||||||
|
* Calling `endpoint(options)` is the same as calling `endpoint.parse(endpoint.merge(options))`.
|
||||||
|
*
|
||||||
|
* @param {object} options `method`, `url`. Plus URL, query or body parameters, as well as `headers`, `mediaType.{format|previews}`, `request`, or `baseUrl`.
|
||||||
|
*/
|
||||||
|
parse: (options: Defaults) => RequestOptions;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Request method + URL. Example: `'GET /orgs/:org'`
|
||||||
|
*/
|
||||||
|
export declare type Route = string;
|
||||||
|
/**
|
||||||
|
* Relative or absolute URL. Examples: `'/orgs/:org'`, `https://example.com/foo/bar`
|
||||||
|
*/
|
||||||
|
export declare type Url = string;
|
||||||
|
/**
|
||||||
|
* Request method
|
||||||
|
*/
|
||||||
|
export declare type Method = "DELETE" | "GET" | "HEAD" | "PATCH" | "POST" | "PUT";
|
||||||
|
/**
|
||||||
|
* Endpoint parameters
|
||||||
|
*/
|
||||||
|
export declare type Parameters = {
|
||||||
|
/**
|
||||||
|
* Base URL to be used when a relative URL is passed, such as `/orgs/:org`.
|
||||||
|
* If `baseUrl` is `https://enterprise.acme-inc.com/api/v3`, then the resulting
|
||||||
|
* `RequestOptions.url` will be `https://enterprise.acme-inc.com/api/v3/orgs/:org`.
|
||||||
|
*/
|
||||||
|
baseUrl?: string;
|
||||||
|
/**
|
||||||
|
* HTTP headers. Use lowercase keys.
|
||||||
|
*/
|
||||||
|
headers?: Headers;
|
||||||
|
/**
|
||||||
|
* Media type options, see {@link https://developer.github.com/v3/media/|GitHub Developer Guide}
|
||||||
|
*/
|
||||||
|
mediaType?: {
|
||||||
|
/**
|
||||||
|
* `json` by default. Can be `raw`, `text`, `html`, `full`, `diff`, `patch`, `sha`, `base64`. Depending on endpoint
|
||||||
|
*/
|
||||||
|
format?: string;
|
||||||
|
/**
|
||||||
|
* Custom media type names of {@link https://developer.github.com/v3/media/|API Previews} without the `-preview` suffix.
|
||||||
|
* Example for single preview: `['squirrel-girl']`.
|
||||||
|
* Example for multiple previews: `['squirrel-girl', 'mister-fantastic']`.
|
||||||
|
*/
|
||||||
|
previews?: string[];
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Pass custom meta information for the request. The `request` object will be returned as is.
|
||||||
|
*/
|
||||||
|
request?: EndpointRequestOptions;
|
||||||
|
/**
|
||||||
|
* Any additional parameter will be passed as follows
|
||||||
|
* 1. URL parameter if `':parameter'` or `{parameter}` is part of `url`
|
||||||
|
* 2. Query parameter if `method` is `'GET'` or `'HEAD'`
|
||||||
|
* 3. Request body if `parameter` is `'data'`
|
||||||
|
* 4. JSON in the request body in the form of `body[parameter]` unless `parameter` key is `'data'`
|
||||||
|
*/
|
||||||
|
[parameter: string]: any;
|
||||||
|
};
|
||||||
|
export declare type Endpoint = Parameters & {
|
||||||
|
method: Method;
|
||||||
|
url: Url;
|
||||||
|
};
|
||||||
|
export declare type Defaults = Parameters & {
|
||||||
|
method: Method;
|
||||||
|
baseUrl: string;
|
||||||
|
headers: Headers & {
|
||||||
|
accept: string;
|
||||||
|
"user-agent": string;
|
||||||
|
};
|
||||||
|
mediaType: {
|
||||||
|
format: string;
|
||||||
|
previews: string[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
export declare type RequestOptions = {
|
||||||
|
method: Method;
|
||||||
|
url: Url;
|
||||||
|
headers: Headers;
|
||||||
|
body?: any;
|
||||||
|
request?: EndpointRequestOptions;
|
||||||
|
};
|
||||||
|
export declare type Headers = {
|
||||||
|
/**
|
||||||
|
* Avoid setting `accept`, use `mediaFormat.{format|previews}` instead.
|
||||||
|
*/
|
||||||
|
accept?: string;
|
||||||
|
/**
|
||||||
|
* Use `authorization` to send authenticated request, remember `token ` / `bearer ` prefixes. Example: `token 1234567890abcdef1234567890abcdef12345678`
|
||||||
|
*/
|
||||||
|
authorization?: string;
|
||||||
|
/**
|
||||||
|
* `user-agent` is set do a default and can be overwritten as needed.
|
||||||
|
*/
|
||||||
|
"user-agent"?: string;
|
||||||
|
[header: string]: string | number | undefined;
|
||||||
|
};
|
||||||
|
export declare type EndpointRequestOptions = {
|
||||||
|
[option: string]: any;
|
||||||
|
};
|
4
node_modules/@octokit/endpoint/dist-types/util/add-query-parameters.d.ts
generated
vendored
Normal file
4
node_modules/@octokit/endpoint/dist-types/util/add-query-parameters.d.ts
generated
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
export declare function addQueryParameters(url: string, parameters: {
|
||||||
|
[x: string]: string | undefined;
|
||||||
|
q?: string;
|
||||||
|
}): string;
|
1
node_modules/@octokit/endpoint/dist-types/util/extract-url-variable-names.d.ts
generated
vendored
Normal file
1
node_modules/@octokit/endpoint/dist-types/util/extract-url-variable-names.d.ts
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export declare function extractUrlVariableNames(url: string): string[];
|
|
@ -0,0 +1,3 @@
|
||||||
|
export declare function lowercaseKeys(object?: {
|
||||||
|
[key: string]: any;
|
||||||
|
}): {};
|
|
@ -0,0 +1,5 @@
|
||||||
|
export declare function omit(object: {
|
||||||
|
[key: string]: any;
|
||||||
|
}, keysToOmit: string[]): {
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
|
@ -0,0 +1 @@
|
||||||
|
export declare const VERSION = "0.0.0-development";
|
|
@ -0,0 +1,2 @@
|
||||||
|
import { Defaults, endpoint, Parameters } from "./types";
|
||||||
|
export declare function withDefaults(oldDefaults: Defaults | null, newDefaults: Parameters): endpoint;
|
|
@ -0,0 +1,233 @@
|
||||||
|
import deepmerge from 'deepmerge';
|
||||||
|
import isPlainObject from 'is-plain-object';
|
||||||
|
import urlTemplate from 'url-template';
|
||||||
|
import getUserAgent from 'universal-user-agent';
|
||||||
|
|
||||||
|
function _slicedToArray(arr, i) {
|
||||||
|
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest();
|
||||||
|
}
|
||||||
|
|
||||||
|
function _arrayWithHoles(arr) {
|
||||||
|
if (Array.isArray(arr)) return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _iterableToArrayLimit(arr, i) {
|
||||||
|
var _arr = [];
|
||||||
|
var _n = true;
|
||||||
|
var _d = false;
|
||||||
|
var _e = undefined;
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
|
||||||
|
_arr.push(_s.value);
|
||||||
|
|
||||||
|
if (i && _arr.length === i) break;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
_d = true;
|
||||||
|
_e = err;
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (!_n && _i["return"] != null) _i["return"]();
|
||||||
|
} finally {
|
||||||
|
if (_d) throw _e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _nonIterableRest() {
|
||||||
|
throw new TypeError("Invalid attempt to destructure non-iterable instance");
|
||||||
|
}
|
||||||
|
|
||||||
|
function lowercaseKeys(object) {
|
||||||
|
if (!object) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.keys(object).reduce((newObj, key) => {
|
||||||
|
newObj[key.toLowerCase()] = object[key];
|
||||||
|
return newObj;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
function merge(defaults, route, options) {
|
||||||
|
if (typeof route === "string") {
|
||||||
|
let _route$split = route.split(" "),
|
||||||
|
_route$split2 = _slicedToArray(_route$split, 2),
|
||||||
|
method = _route$split2[0],
|
||||||
|
url = _route$split2[1];
|
||||||
|
|
||||||
|
options = Object.assign(url ? {
|
||||||
|
method,
|
||||||
|
url
|
||||||
|
} : {
|
||||||
|
url: method
|
||||||
|
}, options);
|
||||||
|
} else {
|
||||||
|
options = route || {};
|
||||||
|
} // lowercase header names before merging with defaults to avoid duplicates
|
||||||
|
|
||||||
|
|
||||||
|
options.headers = lowercaseKeys(options.headers);
|
||||||
|
const mergedOptions = deepmerge.all([defaults, options].filter(Boolean), {
|
||||||
|
isMergeableObject: isPlainObject
|
||||||
|
}); // mediaType.previews arrays are merged, instead of overwritten
|
||||||
|
|
||||||
|
if (defaults && defaults.mediaType.previews.length) {
|
||||||
|
mergedOptions.mediaType.previews = defaults.mediaType.previews.filter(preview => !mergedOptions.mediaType.previews.includes(preview)).concat(mergedOptions.mediaType.previews);
|
||||||
|
}
|
||||||
|
|
||||||
|
mergedOptions.mediaType.previews = mergedOptions.mediaType.previews.map(preview => preview.replace(/-preview/, ""));
|
||||||
|
return mergedOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addQueryParameters(url, parameters) {
|
||||||
|
const separator = /\?/.test(url) ? "&" : "?";
|
||||||
|
const names = Object.keys(parameters);
|
||||||
|
|
||||||
|
if (names.length === 0) {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
return url + separator + names.map(name => {
|
||||||
|
if (name === "q") {
|
||||||
|
return "q=" + parameters.q.split("+").map(encodeURIComponent).join("+");
|
||||||
|
}
|
||||||
|
|
||||||
|
return "".concat(name, "=").concat(encodeURIComponent(parameters[name]));
|
||||||
|
}).join("&");
|
||||||
|
}
|
||||||
|
|
||||||
|
const urlVariableRegex = /\{[^}]+\}/g;
|
||||||
|
|
||||||
|
function removeNonChars(variableName) {
|
||||||
|
return variableName.replace(/^\W+|\W+$/g, "").split(/,/);
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractUrlVariableNames(url) {
|
||||||
|
const matches = url.match(urlVariableRegex);
|
||||||
|
|
||||||
|
if (!matches) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return matches.map(removeNonChars).reduce((a, b) => a.concat(b), []);
|
||||||
|
}
|
||||||
|
|
||||||
|
function omit(object, keysToOmit) {
|
||||||
|
return Object.keys(object).filter(option => !keysToOmit.includes(option)).reduce((obj, key) => {
|
||||||
|
obj[key] = object[key];
|
||||||
|
return obj;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
function parse(options) {
|
||||||
|
// https://fetch.spec.whatwg.org/#methods
|
||||||
|
let method = options.method.toUpperCase(); // replace :varname with {varname} to make it RFC 6570 compatible
|
||||||
|
|
||||||
|
let url = options.url.replace(/:([a-z]\w+)/g, "{+$1}");
|
||||||
|
let headers = Object.assign({}, options.headers);
|
||||||
|
let body;
|
||||||
|
let parameters = omit(options, ["method", "baseUrl", "url", "headers", "request", "mediaType"]); // extract variable names from URL to calculate remaining variables later
|
||||||
|
|
||||||
|
const urlVariableNames = extractUrlVariableNames(url);
|
||||||
|
url = urlTemplate.parse(url).expand(parameters);
|
||||||
|
|
||||||
|
if (!/^http/.test(url)) {
|
||||||
|
url = options.baseUrl + url;
|
||||||
|
}
|
||||||
|
|
||||||
|
const omittedParameters = Object.keys(options).filter(option => urlVariableNames.includes(option)).concat("baseUrl");
|
||||||
|
const remainingParameters = omit(parameters, omittedParameters);
|
||||||
|
const isBinaryRequset = /application\/octet-stream/i.test(headers.accept);
|
||||||
|
|
||||||
|
if (!isBinaryRequset) {
|
||||||
|
if (options.mediaType.format) {
|
||||||
|
// e.g. application/vnd.github.v3+json => application/vnd.github.v3.raw
|
||||||
|
headers.accept = headers.accept.split(/,/).map(preview => preview.replace(/application\/vnd(\.\w+)(\.v3)?(\.\w+)?(\+json)?$/, "application/vnd$1$2.".concat(options.mediaType.format))).join(",");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.mediaType.previews.length) {
|
||||||
|
const previewsFromAcceptHeader = headers.accept.match(/[\w-]+(?=-preview)/g) || [];
|
||||||
|
headers.accept = previewsFromAcceptHeader.concat(options.mediaType.previews).map(preview => {
|
||||||
|
const format = options.mediaType.format ? ".".concat(options.mediaType.format) : "+json";
|
||||||
|
return "application/vnd.github.".concat(preview, "-preview").concat(format);
|
||||||
|
}).join(",");
|
||||||
|
}
|
||||||
|
} // for GET/HEAD requests, set URL query parameters from remaining parameters
|
||||||
|
// for PATCH/POST/PUT/DELETE requests, set request body from remaining parameters
|
||||||
|
|
||||||
|
|
||||||
|
if (["GET", "HEAD"].includes(method)) {
|
||||||
|
url = addQueryParameters(url, remainingParameters);
|
||||||
|
} else {
|
||||||
|
if ("data" in remainingParameters) {
|
||||||
|
body = remainingParameters.data;
|
||||||
|
} else {
|
||||||
|
if (Object.keys(remainingParameters).length) {
|
||||||
|
body = remainingParameters;
|
||||||
|
} else {
|
||||||
|
headers["content-length"] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // default content-type for JSON if body is set
|
||||||
|
|
||||||
|
|
||||||
|
if (!headers["content-type"] && typeof body !== "undefined") {
|
||||||
|
headers["content-type"] = "application/json; charset=utf-8";
|
||||||
|
} // GitHub expects 'content-length: 0' header for PUT/PATCH requests without body.
|
||||||
|
// fetch does not allow to set `content-length` header, but we can set body to an empty string
|
||||||
|
|
||||||
|
|
||||||
|
if (["PATCH", "PUT"].includes(method) && typeof body === "undefined") {
|
||||||
|
body = "";
|
||||||
|
} // Only return body/request keys if present
|
||||||
|
|
||||||
|
|
||||||
|
return Object.assign({
|
||||||
|
method,
|
||||||
|
url,
|
||||||
|
headers
|
||||||
|
}, typeof body !== "undefined" ? {
|
||||||
|
body
|
||||||
|
} : null, options.request ? {
|
||||||
|
request: options.request
|
||||||
|
} : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
function endpointWithDefaults(defaults, route, options) {
|
||||||
|
return parse(merge(defaults, route, options));
|
||||||
|
}
|
||||||
|
|
||||||
|
function withDefaults(oldDefaults, newDefaults) {
|
||||||
|
const DEFAULTS = merge(oldDefaults, newDefaults);
|
||||||
|
const endpoint = endpointWithDefaults.bind(null, DEFAULTS);
|
||||||
|
return Object.assign(endpoint, {
|
||||||
|
DEFAULTS,
|
||||||
|
defaults: withDefaults.bind(null, DEFAULTS),
|
||||||
|
merge: merge.bind(null, DEFAULTS),
|
||||||
|
parse
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const VERSION = "0.0.0-development";
|
||||||
|
|
||||||
|
const userAgent = "octokit-endpoint.js/".concat(VERSION, " ").concat(getUserAgent());
|
||||||
|
const DEFAULTS = {
|
||||||
|
method: "GET",
|
||||||
|
baseUrl: "https://api.github.com",
|
||||||
|
headers: {
|
||||||
|
accept: "application/vnd.github.v3+json",
|
||||||
|
"user-agent": userAgent
|
||||||
|
},
|
||||||
|
mediaType: {
|
||||||
|
format: "",
|
||||||
|
previews: []
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const endpoint = withDefaults(null, DEFAULTS);
|
||||||
|
|
||||||
|
export { endpoint };
|
21
node_modules/@octokit/endpoint/node_modules/is-plain-object/LICENSE
generated
vendored
Normal file
21
node_modules/@octokit/endpoint/node_modules/is-plain-object/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014-2017, Jon Schlinkert.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
119
node_modules/@octokit/endpoint/node_modules/is-plain-object/README.md
generated
vendored
Normal file
119
node_modules/@octokit/endpoint/node_modules/is-plain-object/README.md
generated
vendored
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
# is-plain-object [![NPM version](https://img.shields.io/npm/v/is-plain-object.svg?style=flat)](https://www.npmjs.com/package/is-plain-object) [![NPM monthly downloads](https://img.shields.io/npm/dm/is-plain-object.svg?style=flat)](https://npmjs.org/package/is-plain-object) [![NPM total downloads](https://img.shields.io/npm/dt/is-plain-object.svg?style=flat)](https://npmjs.org/package/is-plain-object) [![Linux Build Status](https://img.shields.io/travis/jonschlinkert/is-plain-object.svg?style=flat&label=Travis)](https://travis-ci.org/jonschlinkert/is-plain-object)
|
||||||
|
|
||||||
|
> Returns true if an object was created by the `Object` constructor.
|
||||||
|
|
||||||
|
Please consider following this project's author, [Jon Schlinkert](https://github.com/jonschlinkert), and consider starring the project to show your :heart: and support.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
Install with [npm](https://www.npmjs.com/):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ npm install --save is-plain-object
|
||||||
|
```
|
||||||
|
|
||||||
|
Use [isobject](https://github.com/jonschlinkert/isobject) if you only want to check if the value is an object and not an array or null.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
import isPlainObject from 'is-plain-object';
|
||||||
|
```
|
||||||
|
|
||||||
|
**true** when created by the `Object` constructor.
|
||||||
|
|
||||||
|
```js
|
||||||
|
isPlainObject(Object.create({}));
|
||||||
|
//=> true
|
||||||
|
isPlainObject(Object.create(Object.prototype));
|
||||||
|
//=> true
|
||||||
|
isPlainObject({foo: 'bar'});
|
||||||
|
//=> true
|
||||||
|
isPlainObject({});
|
||||||
|
//=> true
|
||||||
|
```
|
||||||
|
|
||||||
|
**false** when not created by the `Object` constructor.
|
||||||
|
|
||||||
|
```js
|
||||||
|
isPlainObject(1);
|
||||||
|
//=> false
|
||||||
|
isPlainObject(['foo', 'bar']);
|
||||||
|
//=> false
|
||||||
|
isPlainObject([]);
|
||||||
|
//=> false
|
||||||
|
isPlainObject(new Foo);
|
||||||
|
//=> false
|
||||||
|
isPlainObject(null);
|
||||||
|
//=> false
|
||||||
|
isPlainObject(Object.create(null));
|
||||||
|
//=> false
|
||||||
|
```
|
||||||
|
|
||||||
|
## About
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><strong>Contributing</strong></summary>
|
||||||
|
|
||||||
|
Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new).
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><strong>Running Tests</strong></summary>
|
||||||
|
|
||||||
|
Running and reviewing unit tests is a great way to get familiarized with a library and its API. You can install dependencies and run tests with the following command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ npm install && npm test
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><strong>Building docs</strong></summary>
|
||||||
|
|
||||||
|
_(This project's readme.md is generated by [verb](https://github.com/verbose/verb-generate-readme), please don't edit the readme directly. Any changes to the readme must be made in the [.verb.md](.verb.md) readme template.)_
|
||||||
|
|
||||||
|
To generate the readme, run the following command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ npm install -g verbose/verb#dev verb-generate-readme && verb
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
### Related projects
|
||||||
|
|
||||||
|
You might also be interested in these projects:
|
||||||
|
|
||||||
|
* [is-number](https://www.npmjs.com/package/is-number): Returns true if a number or string value is a finite number. Useful for regex… [more](https://github.com/jonschlinkert/is-number) | [homepage](https://github.com/jonschlinkert/is-number "Returns true if a number or string value is a finite number. Useful for regex matches, parsing, user input, etc.")
|
||||||
|
* [isobject](https://www.npmjs.com/package/isobject): Returns true if the value is an object and not an array or null. | [homepage](https://github.com/jonschlinkert/isobject "Returns true if the value is an object and not an array or null.")
|
||||||
|
* [kind-of](https://www.npmjs.com/package/kind-of): Get the native type of a value. | [homepage](https://github.com/jonschlinkert/kind-of "Get the native type of a value.")
|
||||||
|
|
||||||
|
### Contributors
|
||||||
|
|
||||||
|
| **Commits** | **Contributor** |
|
||||||
|
| --- | --- |
|
||||||
|
| 19 | [jonschlinkert](https://github.com/jonschlinkert) |
|
||||||
|
| 6 | [TrySound](https://github.com/TrySound) |
|
||||||
|
| 6 | [stevenvachon](https://github.com/stevenvachon) |
|
||||||
|
| 3 | [onokumus](https://github.com/onokumus) |
|
||||||
|
| 1 | [wtgtybhertgeghgtwtg](https://github.com/wtgtybhertgeghgtwtg) |
|
||||||
|
|
||||||
|
### Author
|
||||||
|
|
||||||
|
**Jon Schlinkert**
|
||||||
|
|
||||||
|
* [GitHub Profile](https://github.com/jonschlinkert)
|
||||||
|
* [Twitter Profile](https://twitter.com/jonschlinkert)
|
||||||
|
* [LinkedIn Profile](https://linkedin.com/in/jonschlinkert)
|
||||||
|
|
||||||
|
### License
|
||||||
|
|
||||||
|
Copyright © 2019, [Jon Schlinkert](https://github.com/jonschlinkert).
|
||||||
|
Released under the [MIT License](LICENSE).
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.8.0, on April 28, 2019._
|
48
node_modules/@octokit/endpoint/node_modules/is-plain-object/index.cjs.js
generated
vendored
Normal file
48
node_modules/@octokit/endpoint/node_modules/is-plain-object/index.cjs.js
generated
vendored
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* isobject <https://github.com/jonschlinkert/isobject>
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014-2017, Jon Schlinkert.
|
||||||
|
* Released under the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function isObject(val) {
|
||||||
|
return val != null && typeof val === 'object' && Array.isArray(val) === false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* is-plain-object <https://github.com/jonschlinkert/is-plain-object>
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014-2017, Jon Schlinkert.
|
||||||
|
* Released under the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function isObjectObject(o) {
|
||||||
|
return isObject(o) === true
|
||||||
|
&& Object.prototype.toString.call(o) === '[object Object]';
|
||||||
|
}
|
||||||
|
|
||||||
|
function isPlainObject(o) {
|
||||||
|
var ctor,prot;
|
||||||
|
|
||||||
|
if (isObjectObject(o) === false) return false;
|
||||||
|
|
||||||
|
// If has modified constructor
|
||||||
|
ctor = o.constructor;
|
||||||
|
if (typeof ctor !== 'function') return false;
|
||||||
|
|
||||||
|
// If has modified prototype
|
||||||
|
prot = ctor.prototype;
|
||||||
|
if (isObjectObject(prot) === false) return false;
|
||||||
|
|
||||||
|
// If constructor does not have an Object-specific method
|
||||||
|
if (prot.hasOwnProperty('isPrototypeOf') === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Most likely a plain Object
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = isPlainObject;
|
3
node_modules/@octokit/endpoint/node_modules/is-plain-object/index.d.ts
generated
vendored
Normal file
3
node_modules/@octokit/endpoint/node_modules/is-plain-object/index.d.ts
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
declare function isPlainObject(o: any): boolean;
|
||||||
|
|
||||||
|
export default isPlainObject;
|
35
node_modules/@octokit/endpoint/node_modules/is-plain-object/index.js
generated
vendored
Normal file
35
node_modules/@octokit/endpoint/node_modules/is-plain-object/index.js
generated
vendored
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*!
|
||||||
|
* is-plain-object <https://github.com/jonschlinkert/is-plain-object>
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014-2017, Jon Schlinkert.
|
||||||
|
* Released under the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import isObject from 'isobject';
|
||||||
|
|
||||||
|
function isObjectObject(o) {
|
||||||
|
return isObject(o) === true
|
||||||
|
&& Object.prototype.toString.call(o) === '[object Object]';
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function isPlainObject(o) {
|
||||||
|
var ctor,prot;
|
||||||
|
|
||||||
|
if (isObjectObject(o) === false) return false;
|
||||||
|
|
||||||
|
// If has modified constructor
|
||||||
|
ctor = o.constructor;
|
||||||
|
if (typeof ctor !== 'function') return false;
|
||||||
|
|
||||||
|
// If has modified prototype
|
||||||
|
prot = ctor.prototype;
|
||||||
|
if (isObjectObject(prot) === false) return false;
|
||||||
|
|
||||||
|
// If constructor does not have an Object-specific method
|
||||||
|
if (prot.hasOwnProperty('isPrototypeOf') === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Most likely a plain Object
|
||||||
|
return true;
|
||||||
|
};
|
124
node_modules/@octokit/endpoint/node_modules/is-plain-object/package.json
generated
vendored
Normal file
124
node_modules/@octokit/endpoint/node_modules/is-plain-object/package.json
generated
vendored
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
{
|
||||||
|
"_from": "is-plain-object@^3.0.0",
|
||||||
|
"_id": "is-plain-object@3.0.0",
|
||||||
|
"_inBundle": false,
|
||||||
|
"_integrity": "sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg==",
|
||||||
|
"_location": "/@octokit/endpoint/is-plain-object",
|
||||||
|
"_phantomChildren": {},
|
||||||
|
"_requested": {
|
||||||
|
"type": "range",
|
||||||
|
"registry": true,
|
||||||
|
"raw": "is-plain-object@^3.0.0",
|
||||||
|
"name": "is-plain-object",
|
||||||
|
"escapedName": "is-plain-object",
|
||||||
|
"rawSpec": "^3.0.0",
|
||||||
|
"saveSpec": null,
|
||||||
|
"fetchSpec": "^3.0.0"
|
||||||
|
},
|
||||||
|
"_requiredBy": [
|
||||||
|
"/@octokit/endpoint"
|
||||||
|
],
|
||||||
|
"_resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.0.tgz",
|
||||||
|
"_shasum": "47bfc5da1b5d50d64110806c199359482e75a928",
|
||||||
|
"_spec": "is-plain-object@^3.0.0",
|
||||||
|
"_where": "C:\\Users\\damccorm\\Documents\\node12-template\\node_modules\\@octokit\\endpoint",
|
||||||
|
"author": {
|
||||||
|
"name": "Jon Schlinkert",
|
||||||
|
"url": "https://github.com/jonschlinkert"
|
||||||
|
},
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/jonschlinkert/is-plain-object/issues"
|
||||||
|
},
|
||||||
|
"bundleDependencies": false,
|
||||||
|
"contributors": [
|
||||||
|
{
|
||||||
|
"name": "Jon Schlinkert",
|
||||||
|
"url": "http://twitter.com/jonschlinkert"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Osman Nuri Okumuş",
|
||||||
|
"url": "http://onokumus.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Steven Vachon",
|
||||||
|
"url": "https://svachon.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/wtgtybhertgeghgtwtg"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"isobject": "^4.0.0"
|
||||||
|
},
|
||||||
|
"deprecated": false,
|
||||||
|
"description": "Returns true if an object was created by the `Object` constructor.",
|
||||||
|
"devDependencies": {
|
||||||
|
"chai": "^4.2.0",
|
||||||
|
"esm": "^3.2.22",
|
||||||
|
"gulp-format-md": "^1.0.0",
|
||||||
|
"mocha": "^6.1.4",
|
||||||
|
"mocha-headless-chrome": "^2.0.2",
|
||||||
|
"rollup": "^1.10.1",
|
||||||
|
"rollup-plugin-node-resolve": "^4.2.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"index.d.ts",
|
||||||
|
"index.js",
|
||||||
|
"index.cjs.js"
|
||||||
|
],
|
||||||
|
"homepage": "https://github.com/jonschlinkert/is-plain-object",
|
||||||
|
"keywords": [
|
||||||
|
"check",
|
||||||
|
"is",
|
||||||
|
"is-object",
|
||||||
|
"isobject",
|
||||||
|
"javascript",
|
||||||
|
"kind",
|
||||||
|
"kind-of",
|
||||||
|
"object",
|
||||||
|
"plain",
|
||||||
|
"type",
|
||||||
|
"typeof",
|
||||||
|
"value"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"main": "index.cjs.js",
|
||||||
|
"module": "index.js",
|
||||||
|
"name": "is-plain-object",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/jonschlinkert/is-plain-object.git"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "rollup -c",
|
||||||
|
"prepare": "rollup -c",
|
||||||
|
"test": "npm run test_node && npm run build && npm run test_browser",
|
||||||
|
"test_browser": "mocha-headless-chrome --args=disable-web-security -f test/browser.html",
|
||||||
|
"test_node": "mocha -r esm"
|
||||||
|
},
|
||||||
|
"types": "index.d.ts",
|
||||||
|
"verb": {
|
||||||
|
"toc": false,
|
||||||
|
"layout": "default",
|
||||||
|
"tasks": [
|
||||||
|
"readme"
|
||||||
|
],
|
||||||
|
"plugins": [
|
||||||
|
"gulp-format-md"
|
||||||
|
],
|
||||||
|
"related": {
|
||||||
|
"list": [
|
||||||
|
"is-number",
|
||||||
|
"isobject",
|
||||||
|
"kind-of"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"reflinks": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"version": "3.0.0"
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014-2017, Jon Schlinkert.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
|
@ -0,0 +1,127 @@
|
||||||
|
# isobject [![NPM version](https://img.shields.io/npm/v/isobject.svg?style=flat)](https://www.npmjs.com/package/isobject) [![NPM monthly downloads](https://img.shields.io/npm/dm/isobject.svg?style=flat)](https://npmjs.org/package/isobject) [![NPM total downloads](https://img.shields.io/npm/dt/isobject.svg?style=flat)](https://npmjs.org/package/isobject) [![Linux Build Status](https://img.shields.io/travis/jonschlinkert/isobject.svg?style=flat&label=Travis)](https://travis-ci.org/jonschlinkert/isobject)
|
||||||
|
|
||||||
|
> Returns true if the value is an object and not an array or null.
|
||||||
|
|
||||||
|
Please consider following this project's author, [Jon Schlinkert](https://github.com/jonschlinkert), and consider starring the project to show your :heart: and support.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
Install with [npm](https://www.npmjs.com/):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ npm install --save isobject
|
||||||
|
```
|
||||||
|
|
||||||
|
Use [is-plain-object](https://github.com/jonschlinkert/is-plain-object) if you want only objects that are created by the `Object` constructor.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
Install with [npm](https://www.npmjs.com/):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ npm install isobject
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
import isObject from 'isobject';
|
||||||
|
```
|
||||||
|
|
||||||
|
**True**
|
||||||
|
|
||||||
|
All of the following return `true`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
isObject({});
|
||||||
|
isObject(Object.create({}));
|
||||||
|
isObject(Object.create(Object.prototype));
|
||||||
|
isObject(Object.create(null));
|
||||||
|
isObject({});
|
||||||
|
isObject(new Foo);
|
||||||
|
isObject(/foo/);
|
||||||
|
```
|
||||||
|
|
||||||
|
**False**
|
||||||
|
|
||||||
|
All of the following return `false`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
isObject();
|
||||||
|
isObject(function () {});
|
||||||
|
isObject(1);
|
||||||
|
isObject([]);
|
||||||
|
isObject(undefined);
|
||||||
|
isObject(null);
|
||||||
|
```
|
||||||
|
|
||||||
|
## About
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><strong>Contributing</strong></summary>
|
||||||
|
|
||||||
|
Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new).
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><strong>Running Tests</strong></summary>
|
||||||
|
|
||||||
|
Running and reviewing unit tests is a great way to get familiarized with a library and its API. You can install dependencies and run tests with the following command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ npm install && npm test
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><strong>Building docs</strong></summary>
|
||||||
|
|
||||||
|
_(This project's readme.md is generated by [verb](https://github.com/verbose/verb-generate-readme), please don't edit the readme directly. Any changes to the readme must be made in the [.verb.md](.verb.md) readme template.)_
|
||||||
|
|
||||||
|
To generate the readme, run the following command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ npm install -g verbose/verb#dev verb-generate-readme && verb
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
### Related projects
|
||||||
|
|
||||||
|
You might also be interested in these projects:
|
||||||
|
|
||||||
|
* [extend-shallow](https://www.npmjs.com/package/extend-shallow): Extend an object with the properties of additional objects. node.js/javascript util. | [homepage](https://github.com/jonschlinkert/extend-shallow "Extend an object with the properties of additional objects. node.js/javascript util.")
|
||||||
|
* [is-plain-object](https://www.npmjs.com/package/is-plain-object): Returns true if an object was created by the `Object` constructor. | [homepage](https://github.com/jonschlinkert/is-plain-object "Returns true if an object was created by the `Object` constructor.")
|
||||||
|
* [kind-of](https://www.npmjs.com/package/kind-of): Get the native type of a value. | [homepage](https://github.com/jonschlinkert/kind-of "Get the native type of a value.")
|
||||||
|
* [merge-deep](https://www.npmjs.com/package/merge-deep): Recursively merge values in a javascript object. | [homepage](https://github.com/jonschlinkert/merge-deep "Recursively merge values in a javascript object.")
|
||||||
|
|
||||||
|
### Contributors
|
||||||
|
|
||||||
|
| **Commits** | **Contributor** |
|
||||||
|
| --- | --- |
|
||||||
|
| 30 | [jonschlinkert](https://github.com/jonschlinkert) |
|
||||||
|
| 8 | [doowb](https://github.com/doowb) |
|
||||||
|
| 7 | [TrySound](https://github.com/TrySound) |
|
||||||
|
| 3 | [onokumus](https://github.com/onokumus) |
|
||||||
|
| 1 | [LeSuisse](https://github.com/LeSuisse) |
|
||||||
|
| 1 | [tmcw](https://github.com/tmcw) |
|
||||||
|
| 1 | [ZhouHansen](https://github.com/ZhouHansen) |
|
||||||
|
|
||||||
|
### Author
|
||||||
|
|
||||||
|
**Jon Schlinkert**
|
||||||
|
|
||||||
|
* [GitHub Profile](https://github.com/jonschlinkert)
|
||||||
|
* [Twitter Profile](https://twitter.com/jonschlinkert)
|
||||||
|
* [LinkedIn Profile](https://linkedin.com/in/jonschlinkert)
|
||||||
|
|
||||||
|
### License
|
||||||
|
|
||||||
|
Copyright © 2019, [Jon Schlinkert](https://github.com/jonschlinkert).
|
||||||
|
Released under the [MIT License](LICENSE).
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.8.0, on April 28, 2019._
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue