mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
Adding firefox to test suite (#17195)
* Created general driver to accept an argument select the driver to run. * Added environment variable for driver, changed package.json to use custim leadfoot, and made changes to browserdriver to use any driver. * Made changes per PR. * Fixed all nits.
This commit is contained in:
parent
dc0ce9e2b9
commit
a31ec148f4
13 changed files with 213 additions and 106 deletions
|
@ -242,6 +242,7 @@
|
|||
"event-stream": "3.3.2",
|
||||
"expect.js": "0.3.1",
|
||||
"faker": "1.1.0",
|
||||
"geckodriver": "1.10.0",
|
||||
"getopts": "2.0.0",
|
||||
"grunt": "1.0.1",
|
||||
"grunt-aws-s3": "0.14.5",
|
||||
|
@ -269,7 +270,7 @@
|
|||
"karma-junit-reporter": "1.2.0",
|
||||
"karma-mocha": "1.3.0",
|
||||
"karma-safari-launcher": "1.0.0",
|
||||
"leadfoot": "1.7.1",
|
||||
"leadfoot": "silne30/leadfoot#validation_for_response_in_ff58",
|
||||
"license-checker": "^16.0.0",
|
||||
"load-grunt-config": "0.19.2",
|
||||
"makelogs": "^4.0.4",
|
||||
|
|
|
@ -94,6 +94,11 @@ export const schema = Joi.object().keys({
|
|||
url: Joi.string().uri({ scheme: /https?/ }).default('http://localhost:9515')
|
||||
}).default(),
|
||||
|
||||
firefoxdriver: Joi.object().keys({
|
||||
url: Joi.string().uri({ scheme: /https?/ }).default('http://localhost:2828')
|
||||
}).default(),
|
||||
|
||||
|
||||
// definition of apps that work with `common.navigateToApp()`
|
||||
apps: Joi.object().pattern(
|
||||
ID_PATTERN,
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
import { EventEmitter } from 'events';
|
||||
|
||||
import { createLocalChromedriverApi } from './chromedriver_local_api';
|
||||
import { createRemoteChromedriverApi } from './chromedriver_remote_api';
|
||||
import { createLocalBrowserDriverApi } from './browser_driver_local_api';
|
||||
import { createRemoteBrowserDriverApi } from './browser_driver_remote_api';
|
||||
import { ping } from './ping';
|
||||
|
||||
const noop = () => {};
|
||||
|
||||
/**
|
||||
* Api for interacting with a local or remote instance of Chromedriver
|
||||
* Api for interacting with a local or remote instance of a browser
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
export class ChromedriverApi extends EventEmitter {
|
||||
static async factory(log, url) {
|
||||
export class BrowserDriverApi extends EventEmitter {
|
||||
static async factory(log, url, browserType) {
|
||||
return (await ping(url))
|
||||
? createRemoteChromedriverApi(log, url)
|
||||
: createLocalChromedriverApi(log, url);
|
||||
? createRemoteBrowserDriverApi(log, url)
|
||||
: createLocalBrowserDriverApi(log, url, browserType);
|
||||
}
|
||||
|
||||
constructor(options = {}) {
|
||||
|
@ -25,19 +25,22 @@ export class ChromedriverApi extends EventEmitter {
|
|||
url,
|
||||
start = noop,
|
||||
stop = noop,
|
||||
requiredCapabilities,
|
||||
} = options;
|
||||
|
||||
if (!url) {
|
||||
throw new TypeError('url is a required parameter');
|
||||
}
|
||||
|
||||
this._requiredCapabilities = requiredCapabilities;
|
||||
this._url = url;
|
||||
this._state = undefined;
|
||||
this._callCustomStart = () => start(this);
|
||||
this._callCustomStop = () => stop(this);
|
||||
this._beforeStopFns = [];
|
||||
}
|
||||
|
||||
getRequiredCapabilities() {
|
||||
return this._requiredCapabilities;
|
||||
}
|
||||
getUrl() {
|
||||
return this._url;
|
||||
}
|
||||
|
@ -52,7 +55,7 @@ export class ChromedriverApi extends EventEmitter {
|
|||
|
||||
async start() {
|
||||
if (this._state !== undefined) {
|
||||
throw new Error('Chromedriver can only be started once');
|
||||
throw new Error('Driver can only be started once');
|
||||
}
|
||||
|
||||
this._state = 'started';
|
||||
|
@ -61,7 +64,7 @@ export class ChromedriverApi extends EventEmitter {
|
|||
|
||||
async stop() {
|
||||
if (this._state !== 'started') {
|
||||
throw new Error('Chromedriver can only be stopped after being started');
|
||||
throw new Error('Driver can only be stopped after being started');
|
||||
}
|
||||
|
||||
this._state = 'stopped';
|
|
@ -0,0 +1,75 @@
|
|||
import { spawn } from 'child_process';
|
||||
import { parse as parseUrl } from 'url';
|
||||
|
||||
import treeKill from 'tree-kill';
|
||||
import { delay, fromNode as fcb } from 'bluebird';
|
||||
import { path as CHROMEDRIVER_EXEC } from 'chromedriver';
|
||||
import { path as FIREFOXDRIVER_EXEC } from 'geckodriver';
|
||||
|
||||
import { ping } from './ping';
|
||||
import { BrowserDriverApi } from './browser_driver_api';
|
||||
const START_TIMEOUT = 15000;
|
||||
const PING_INTERVAL = 500;
|
||||
|
||||
export function createLocalBrowserDriverApi(log, url, browser) {
|
||||
let runningDriver = null;
|
||||
const driverName = browser + 'driver';
|
||||
switch (browser) {
|
||||
case 'firefox':
|
||||
runningDriver = FIREFOXDRIVER_EXEC;
|
||||
break;
|
||||
default:
|
||||
runningDriver = CHROMEDRIVER_EXEC;
|
||||
}
|
||||
let proc = null;
|
||||
|
||||
return new BrowserDriverApi({
|
||||
url,
|
||||
requiredCapabilities: Object.create({ browserType: browser }),
|
||||
|
||||
async start(api) {
|
||||
const { port } = parseUrl(url);
|
||||
log.debug('Starting local ' + driverName + ' at port %d', port);
|
||||
|
||||
proc = spawn(runningDriver, [`--port=${port}`], {
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
});
|
||||
|
||||
proc.stdout.on('data', chunk => {
|
||||
log.debug('[' + driverName + ':stdout]', chunk.toString('utf8').trim());
|
||||
});
|
||||
proc.stderr.on('data', chunk => {
|
||||
log.debug('[' + driverName + ':stderr]', chunk.toString('utf8').trim());
|
||||
});
|
||||
|
||||
proc.on('exit', (code) => {
|
||||
if (!api.isStopped() || code > 0) {
|
||||
api.emit('error', new Error(driverName + ` exited with code ${code}`));
|
||||
}
|
||||
});
|
||||
|
||||
const pingsStartedAt = Date.now();
|
||||
while (true) {
|
||||
log.debug('[' + driverName + ':ping] attempting to reach at %j', url);
|
||||
if (await ping(url)) {
|
||||
log.debug('[' + driverName + ':ping] success');
|
||||
break;
|
||||
} else {
|
||||
log.debug('[' + driverName + ':ping] failure');
|
||||
}
|
||||
|
||||
if ((Date.now() - pingsStartedAt) < START_TIMEOUT) {
|
||||
log.debug('[' + driverName + ':ping] waiting for %d before next ping', PING_INTERVAL);
|
||||
await delay(PING_INTERVAL);
|
||||
continue;
|
||||
}
|
||||
|
||||
throw new Error(driverName + ` did not start within the ${START_TIMEOUT}ms timeout`);
|
||||
}
|
||||
},
|
||||
|
||||
async stop() {
|
||||
await fcb(cb => treeKill(proc.pid, undefined, cb));
|
||||
}
|
||||
});
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
import { BrowserDriverApi } from './browser_driver_api';
|
||||
|
||||
export function createRemoteBrowserDriverApi(log, url) {
|
||||
return new BrowserDriverApi({
|
||||
url,
|
||||
|
||||
start() {
|
||||
log.info(`Reusing instance at %j`, url);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export { BrowserDriverApi } from './browser_driver_api';
|
|
@ -1,64 +0,0 @@
|
|||
import { spawn } from 'child_process';
|
||||
import { parse as parseUrl } from 'url';
|
||||
|
||||
import treeKill from 'tree-kill';
|
||||
import { delay, fromNode as fcb } from 'bluebird';
|
||||
import { path as CHROMEDRIVER_EXEC } from 'chromedriver';
|
||||
|
||||
import { ping } from './ping';
|
||||
import { ChromedriverApi } from './chromedriver_api';
|
||||
const START_TIMEOUT = 15000;
|
||||
const PING_INTERVAL = 500;
|
||||
|
||||
export function createLocalChromedriverApi(log, url) {
|
||||
let proc = null;
|
||||
|
||||
return new ChromedriverApi({
|
||||
url,
|
||||
|
||||
async start(api) {
|
||||
const { port } = parseUrl(url);
|
||||
log.info('Starting local chromedriver at port %d', port);
|
||||
|
||||
proc = spawn(CHROMEDRIVER_EXEC, [`--port=${port}`], {
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
});
|
||||
|
||||
proc.stdout.on('data', chunk => {
|
||||
log.debug('[chromedriver:stdout]', chunk.toString('utf8').trim());
|
||||
});
|
||||
proc.stderr.on('data', chunk => {
|
||||
log.debug('[chromedriver:stderr]', chunk.toString('utf8').trim());
|
||||
});
|
||||
|
||||
proc.on('exit', (code) => {
|
||||
if (!api.isStopped() || code > 0) {
|
||||
api.emit('error', new Error(`Chromedriver exited with code ${code}`));
|
||||
}
|
||||
});
|
||||
|
||||
const pingsStartedAt = Date.now();
|
||||
while (true) {
|
||||
log.debug('[chromedriver:ping] attempting to reach chromedriver at %j', url);
|
||||
if (await ping(url)) {
|
||||
log.debug('[chromedriver:ping] success');
|
||||
break;
|
||||
} else {
|
||||
log.debug('[chromedriver:ping] failure');
|
||||
}
|
||||
|
||||
if ((Date.now() - pingsStartedAt) < START_TIMEOUT) {
|
||||
log.debug('[chromedriver:ping] waiting for %d before next ping', PING_INTERVAL);
|
||||
await delay(PING_INTERVAL);
|
||||
continue;
|
||||
}
|
||||
|
||||
throw new Error(`Chromedriver did not start within the ${START_TIMEOUT}ms timeout`);
|
||||
}
|
||||
},
|
||||
|
||||
async stop() {
|
||||
await fcb(cb => treeKill(proc.pid, undefined, cb));
|
||||
}
|
||||
});
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
import { ChromedriverApi } from './chromedriver_api';
|
||||
|
||||
export function createRemoteChromedriverApi(log, url) {
|
||||
return new ChromedriverApi({
|
||||
url,
|
||||
|
||||
start() {
|
||||
log.info(`Reusing instance at %j`, url);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
export { ChromedriverApi } from './chromedriver_api';
|
|
@ -8,15 +8,14 @@ const SECOND = 1000;
|
|||
const MINUTE = 60 * SECOND;
|
||||
|
||||
let attemptCounter = 0;
|
||||
async function attemptToCreateCommand(log, server, chromedriverApi) {
|
||||
async function attemptToCreateCommand(log, server, driverApi) {
|
||||
const attemptId = ++attemptCounter;
|
||||
|
||||
log.debug('[leadfoot:command] Creating session');
|
||||
const session = await server.createSession({ browserName: 'chrome' });
|
||||
const session = await server.createSession({}, driverApi.getRequiredCapabilities());
|
||||
if (attemptId !== attemptCounter) return; // abort
|
||||
|
||||
log.debug('[leadfoot:command] Registerying session for teardown');
|
||||
chromedriverApi.beforeStop(async () => session.quit());
|
||||
driverApi.beforeStop(async () => session.quit());
|
||||
if (attemptId !== attemptCounter) return; // abort
|
||||
|
||||
log.debug('[leadfoot:command] Completing session capabilities');
|
||||
|
@ -29,7 +28,7 @@ async function attemptToCreateCommand(log, server, chromedriverApi) {
|
|||
return { command: new Command(session) };
|
||||
}
|
||||
|
||||
export async function initLeadfootCommand({ log, chromedriverApi }) {
|
||||
export async function initLeadfootCommand({ log, browserDriverApi }) {
|
||||
return await Promise.race([
|
||||
(async () => {
|
||||
await delay(2 * MINUTE);
|
||||
|
@ -41,7 +40,7 @@ export async function initLeadfootCommand({ log, chromedriverApi }) {
|
|||
// backend (chromedriver in this case). it helps with session management
|
||||
// and all communication to the remote browser go through it, so we shim
|
||||
// some of it's methods to enable very verbose logging.
|
||||
const server = initVerboseRemoteLogging(log, new Server(chromedriverApi.getUrl()));
|
||||
const server = initVerboseRemoteLogging(log, new Server(browserDriverApi.getUrl()));
|
||||
|
||||
// by default, calling server.createSession() automatically fixes the webdriver
|
||||
// "capabilities" hash so that leadfoot knows the hoops it has to jump through
|
||||
|
@ -59,7 +58,7 @@ export async function initLeadfootCommand({ log, chromedriverApi }) {
|
|||
while (true) {
|
||||
const command = await Promise.race([
|
||||
delay(30 * SECOND),
|
||||
attemptToCreateCommand(log, server, chromedriverApi)
|
||||
attemptToCreateCommand(log, server, browserDriverApi)
|
||||
]);
|
||||
|
||||
if (!command) {
|
||||
|
|
|
@ -1,18 +1,24 @@
|
|||
import { initLeadfootCommand } from './leadfoot_command';
|
||||
import { createRemoteInterceptors } from './interceptors';
|
||||
import { ChromedriverApi } from './chromedriver_api';
|
||||
import { BrowserDriverApi } from './browser_driver_api';
|
||||
|
||||
export async function RemoteProvider({ getService }) {
|
||||
const lifecycle = getService('lifecycle');
|
||||
const config = getService('config');
|
||||
const log = getService('log');
|
||||
const possibleBrowsers = ['chrome', 'firefox'];
|
||||
const browserType = process.env.TEST_BROWSER_TYPE || 'chrome';
|
||||
|
||||
const chromedriverApi = await ChromedriverApi.factory(log, config.get('chromedriver.url'));
|
||||
lifecycle.on('cleanup', async () => await chromedriverApi.stop());
|
||||
if (!possibleBrowsers.includes(browserType)) {
|
||||
throw new Error(`Unexpected TEST_BROWSER_TYPE "${browserType}". Valid options are ` + possibleBrowsers.join(','));
|
||||
}
|
||||
|
||||
await chromedriverApi.start();
|
||||
const browserDriverApi = await BrowserDriverApi.factory(log, config.get(browserType + 'driver.url'), browserType);
|
||||
lifecycle.on('cleanup', async () => await browserDriverApi.stop());
|
||||
|
||||
const { command } = await initLeadfootCommand({ log, chromedriverApi });
|
||||
await browserDriverApi.start();
|
||||
|
||||
const { command } = await initLeadfootCommand({ log, browserDriverApi: browserDriverApi });
|
||||
const interceptors = createRemoteInterceptors(command);
|
||||
|
||||
log.info('Remote initialized');
|
||||
|
|
92
yarn.lock
92
yarn.lock
|
@ -246,6 +246,10 @@ address@^1.0.1:
|
|||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/address/-/address-1.0.3.tgz#b5f50631f8d6cec8bd20c963963afb55e06cbce9"
|
||||
|
||||
adm-zip@0.4.7:
|
||||
version "0.4.7"
|
||||
resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.7.tgz#8606c2cbf1c426ce8c8ec00174447fd49b6eafc1"
|
||||
|
||||
after@0.8.2:
|
||||
version "0.8.2"
|
||||
resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
|
||||
|
@ -1460,6 +1464,10 @@ bluebird@2.9.34:
|
|||
version "2.9.34"
|
||||
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.9.34.tgz#2f7b4ec80216328a9fddebdf69c8d4942feff7d8"
|
||||
|
||||
bluebird@3.4.6:
|
||||
version "3.4.6"
|
||||
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.6.tgz#01da8d821d87813d158967e743d5fe6c62cf8c0f"
|
||||
|
||||
bluebird@3.5.1, bluebird@^3.3.0:
|
||||
version "3.5.1"
|
||||
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9"
|
||||
|
@ -2025,6 +2033,10 @@ chokidar@^1.4.1, chokidar@^1.6.0, chokidar@^1.7.0:
|
|||
optionalDependencies:
|
||||
fsevents "^1.0.0"
|
||||
|
||||
chownr@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181"
|
||||
|
||||
chromedriver@2.33.2:
|
||||
version "2.33.2"
|
||||
resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-2.33.2.tgz#8fc779d54b6e45bef55d264a1eceed52427a9b49"
|
||||
|
@ -2493,7 +2505,7 @@ create-ecdh@^4.0.0:
|
|||
bn.js "^4.1.0"
|
||||
elliptic "^6.0.0"
|
||||
|
||||
create-error-class@^3.0.0:
|
||||
create-error-class@^3.0.0, create-error-class@^3.0.1:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6"
|
||||
dependencies:
|
||||
|
@ -3277,6 +3289,12 @@ dtrace-provider@~0.6:
|
|||
dependencies:
|
||||
nan "^2.0.8"
|
||||
|
||||
duplexer2@^0.1.4:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1"
|
||||
dependencies:
|
||||
readable-stream "^2.0.2"
|
||||
|
||||
duplexer3@^0.1.4:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
|
||||
|
@ -4516,6 +4534,15 @@ gauge@~2.7.3:
|
|||
strip-ansi "^3.0.1"
|
||||
wide-align "^1.1.0"
|
||||
|
||||
geckodriver@1.10.0:
|
||||
version "1.10.0"
|
||||
resolved "https://registry.yarnpkg.com/geckodriver/-/geckodriver-1.10.0.tgz#73e2f785666521d0d3a9ddc9fd5a0a5e3bf47845"
|
||||
dependencies:
|
||||
adm-zip "0.4.7"
|
||||
bluebird "3.4.6"
|
||||
got "5.6.0"
|
||||
tar "4.0.2"
|
||||
|
||||
generate-function@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74"
|
||||
|
@ -4753,6 +4780,27 @@ good-squeeze@2.1.0:
|
|||
hoek "2.x.x"
|
||||
json-stringify-safe "5.0.x"
|
||||
|
||||
got@5.6.0:
|
||||
version "5.6.0"
|
||||
resolved "https://registry.yarnpkg.com/got/-/got-5.6.0.tgz#bb1d7ee163b78082bbc8eb836f3f395004ea6fbf"
|
||||
dependencies:
|
||||
create-error-class "^3.0.1"
|
||||
duplexer2 "^0.1.4"
|
||||
is-plain-obj "^1.0.0"
|
||||
is-redirect "^1.0.0"
|
||||
is-retry-allowed "^1.0.0"
|
||||
is-stream "^1.0.0"
|
||||
lowercase-keys "^1.0.0"
|
||||
node-status-codes "^1.0.0"
|
||||
object-assign "^4.0.1"
|
||||
parse-json "^2.1.0"
|
||||
pinkie-promise "^2.0.0"
|
||||
read-all-stream "^3.0.0"
|
||||
readable-stream "^2.0.5"
|
||||
timed-out "^2.0.0"
|
||||
unzip-response "^1.0.0"
|
||||
url-parse-lax "^1.0.0"
|
||||
|
||||
got@^3.2.0:
|
||||
version "3.3.1"
|
||||
resolved "https://registry.yarnpkg.com/got/-/got-3.3.1.tgz#e5d0ed4af55fc3eef4d56007769d98192bcb2eca"
|
||||
|
@ -6818,9 +6866,9 @@ lcid@^1.0.0:
|
|||
dependencies:
|
||||
invert-kv "^1.0.0"
|
||||
|
||||
leadfoot@1.7.1:
|
||||
version "1.7.1"
|
||||
resolved "https://registry.yarnpkg.com/leadfoot/-/leadfoot-1.7.1.tgz#7dae9961f01c9bec862b621ccece0826c8c64599"
|
||||
leadfoot@silne30/leadfoot#validation_for_response_in_ff58:
|
||||
version "1.7.4"
|
||||
resolved "https://codeload.github.com/silne30/leadfoot/tar.gz/460c8ed67c08177adc9c79243ff045880f4cad09"
|
||||
dependencies:
|
||||
dojo "2.0.0-alpha.7"
|
||||
jszip "2.5.0"
|
||||
|
@ -7580,6 +7628,18 @@ minimost@^1.0.0:
|
|||
camelcase-keys "^4.0.0"
|
||||
minimist "^1.2.0"
|
||||
|
||||
minipass@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.2.1.tgz#5ada97538b1027b4cf7213432428578cb564011f"
|
||||
dependencies:
|
||||
yallist "^3.0.0"
|
||||
|
||||
minizlib@^1.0.4:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb"
|
||||
dependencies:
|
||||
minipass "^2.2.1"
|
||||
|
||||
mkdirp@0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12"
|
||||
|
@ -7838,6 +7898,10 @@ node-pre-gyp@^0.6.39:
|
|||
tar "^2.2.1"
|
||||
tar-pack "^3.4.0"
|
||||
|
||||
node-status-codes@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/node-status-codes/-/node-status-codes-1.0.0.tgz#5ae5541d024645d32a58fcddc9ceecea7ae3ac2f"
|
||||
|
||||
node-uuid@~1.4.0:
|
||||
version "1.4.8"
|
||||
resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907"
|
||||
|
@ -8238,7 +8302,7 @@ parse-headers@^2.0.0:
|
|||
for-each "^0.3.2"
|
||||
trim "0.0.1"
|
||||
|
||||
parse-json@^2.2.0:
|
||||
parse-json@^2.1.0, parse-json@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
|
||||
dependencies:
|
||||
|
@ -10598,6 +10662,16 @@ tar@2.2.0:
|
|||
fstream "^1.0.2"
|
||||
inherits "2"
|
||||
|
||||
tar@4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/tar/-/tar-4.0.2.tgz#e8e22bf3eec330e5c616d415a698395e294e8fad"
|
||||
dependencies:
|
||||
chownr "^1.0.1"
|
||||
minipass "^2.2.1"
|
||||
minizlib "^1.0.4"
|
||||
mkdirp "^0.5.0"
|
||||
yallist "^3.0.2"
|
||||
|
||||
tar@^2.2.1, "tar@~2.2.1 ":
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1"
|
||||
|
@ -11038,6 +11112,10 @@ unpipe@1.0.0, unpipe@~1.0.0:
|
|||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
|
||||
|
||||
unzip-response@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-1.0.2.tgz#b984f0877fc0a89c2c773cc1ef7b5b232b5b06fe"
|
||||
|
||||
unzip-response@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97"
|
||||
|
@ -11822,6 +11900,10 @@ yallist@^2.0.0, yallist@^2.1.2:
|
|||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
|
||||
|
||||
yallist@^3.0.0, yallist@^3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9"
|
||||
|
||||
yargs-parser@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue