Add more CLI tests

This commit is contained in:
Chocobozzz 2019-06-13 11:09:38 +02:00
parent 4913295f9d
commit 1a12f66d63
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
16 changed files with 401 additions and 181 deletions

View File

@ -102,7 +102,6 @@
"body-parser": "^1.12.4", "body-parser": "^1.12.4",
"bull": "^3.4.2", "bull": "^3.4.2",
"bytes": "^3.0.0", "bytes": "^3.0.0",
"cli-table": "^0.3.1",
"commander": "^2.13.0", "commander": "^2.13.0",
"config": "^3.0.0", "config": "^3.0.0",
"cookie-parser": "^1.4.3", "cookie-parser": "^1.4.3",
@ -130,7 +129,6 @@
"memoizee": "^0.4.14", "memoizee": "^0.4.14",
"morgan": "^1.5.3", "morgan": "^1.5.3",
"multer": "^1.1.0", "multer": "^1.1.0",
"netrc-parser": "^3.1.6",
"nodemailer": "^6.0.0", "nodemailer": "^6.0.0",
"parse-torrent": "^6.0.0", "parse-torrent": "^6.0.0",
"password-generator": "^2.0.2", "password-generator": "^2.0.2",

View File

@ -13,7 +13,7 @@ recreateDB () {
} }
removeFiles () { removeFiles () {
rm -rf "./test$1" "./config/local-test.json" "./config/local-test-$1.json" rm -rf "./test$1" "./config/local-test.json" "./config/local-test-$1.json" ~/.config/PeerTube/CLI-$1
} }
dropRedis () { dropRedis () {

View File

@ -12,5 +12,4 @@ rm -rf ./dist/server/tools/
) )
npm run tsc -- --build ./server/tools/tsconfig.json npm run tsc -- --build ./server/tools/tsconfig.json
cp -r "./server/tools/node_modules" "./dist/server/tools"
mv "./server/tools/node_modules" "./dist/server/tools"

View File

@ -134,6 +134,10 @@ function isProdInstance () {
return process.env.NODE_ENV === 'production' return process.env.NODE_ENV === 'production'
} }
function getAppNumber () {
return process.env.NODE_APP_INSTANCE
}
function root () { function root () {
// We are in /helpers/utils.js // We are in /helpers/utils.js
const paths = [ __dirname, '..', '..' ] const paths = [ __dirname, '..', '..' ]
@ -256,6 +260,7 @@ const execPromise = promisify1<string, string>(exec)
export { export {
isTestInstance, isTestInstance,
isProdInstance, isProdInstance,
getAppNumber,
objectConverter, objectConverter,
root, root,

View File

@ -1,28 +1,44 @@
/* tslint:disable:no-unused-expression */
import 'mocha' import 'mocha'
import { expect } from 'chai'
import { import {
expect addVideoChannel,
} from 'chai' buildAbsoluteFixturePath,
import { cleanupTests,
createUser, createUser,
execCLI, execCLI,
flushTests,
getEnvCli,
killallServers,
flushAndRunServer, flushAndRunServer,
getEnvCli,
getMyUserInformation,
getVideosList,
ServerInfo, ServerInfo,
setAccessTokensToServers, cleanupTests setAccessTokensToServers,
userLogin, waitJobs
} from '../../../shared/extra-utils' } from '../../../shared/extra-utils'
import { User, Video } from '../../../shared'
import { getYoutubeVideoUrl } from '../../../shared/extra-utils/videos/video-imports'
describe('Test CLI wrapper', function () { describe('Test CLI wrapper', function () {
let server: ServerInfo let server: ServerInfo
let channelId: number
const cmd = 'node ./dist/server/tools/peertube.js' const cmd = 'node ./dist/server/tools/peertube.js'
before(async function () { before(async function () {
this.timeout(30000) this.timeout(30000)
server = await flushAndRunServer(1) server = await flushAndRunServer(1)
await setAccessTokensToServers([ server ]) await setAccessTokensToServers([ server ])
await createUser({ url: server.url, accessToken: server.accessToken, username: 'user_1', password: 'super password' }) await createUser({ url: server.url, accessToken: server.accessToken, username: 'user_1', password: 'super_password' })
const userAccessToken = await userLogin(server, { username: 'user_1', password: 'super_password' })
{
const res = await addVideoChannel(server.url, userAccessToken, { name: 'user_channel', displayName: 'User channel' })
channelId = res.body.videoChannel.id
}
}) })
it('Should display no selected instance', async function () { it('Should display no selected instance', async function () {
@ -31,21 +47,95 @@ describe('Test CLI wrapper', function () {
const env = getEnvCli(server) const env = getEnvCli(server)
const stdout = await execCLI(`${env} ${cmd} --help`) const stdout = await execCLI(`${env} ${cmd} --help`)
expect(stdout).to.contain('selected') expect(stdout).to.contain('no instance selected')
}) })
it('Should remember the authentifying material of the user', async function () { it('Should add a user', async function () {
this.timeout(60000) this.timeout(60000)
const env = getEnvCli(server) const env = getEnvCli(server)
await execCLI(`${env} ` + cmd + ` auth add --url ${server.url} -U user_1 -p "super password"`) await execCLI(`${env} ${cmd} auth add -u ${server.url} -U user_1 -p super_password`)
})
it('Should default to this user', async function () {
this.timeout(60000)
const env = getEnvCli(server)
const stdout = await execCLI(`${env} ${cmd} --help`)
expect(stdout).to.contain(`instance ${server.url} selected`)
})
it('Should remember the user', async function () {
this.timeout(60000)
const env = getEnvCli(server)
const stdout = await execCLI(`${env} ${cmd} auth list`)
expect(stdout).to.contain(server.url)
})
it('Should upload a video', async function () {
this.timeout(60000)
const env = getEnvCli(server)
const fixture = buildAbsoluteFixturePath('60fps_720p_small.mp4')
const params = `-f ${fixture} --video-name 'test upload' --channel-id ${channelId}`
await execCLI(`${env} ${cmd} upload ${params}`)
})
it('Should have the video uploaded', async function () {
const res = await getVideosList(server.url)
expect(res.body.total).to.equal(1)
const videos: Video[] = res.body.data
expect(videos[0].name).to.equal('test upload')
expect(videos[0].channel.name).to.equal('user_channel')
})
it('Should import a video', async function () {
this.timeout(60000)
const env = getEnvCli(server)
const params = `--target-url ${getYoutubeVideoUrl()} --channel-id ${channelId}`
await execCLI(`${env} ${cmd} import ${params}`)
})
it('Should have imported the video', async function () {
this.timeout(60000)
await waitJobs([ server ])
const res = await getVideosList(server.url)
expect(res.body.total).to.equal(2)
const videos: Video[] = res.body.data
const video = videos.find(v => v.name === 'small video - youtube')
expect(video).to.not.be.undefined
expect(video.channel.name).to.equal('user_channel')
})
it('Should remove the auth user', async function () {
const env = getEnvCli(server)
await execCLI(`${env} ${cmd} auth del ${server.url}`)
const stdout = await execCLI(`${env} ${cmd} --help`)
expect(stdout).to.contain('no instance selected')
}) })
after(async function () { after(async function () {
this.timeout(10000) this.timeout(10000)
await execCLI(cmd + ` auth del ${server.url}`)
await cleanupTests([ server ]) await cleanupTests([ server ])
}) })
}) })

View File

@ -1,5 +1,12 @@
const config = require('application-config')('PeerTube/CLI') import { Netrc } from 'netrc-parser'
const netrc = require('netrc-parser').default import { isTestInstance, getAppNumber } from '../helpers/core-utils'
import { join } from 'path'
import { root } from '../../shared/extra-utils'
let configName = 'PeerTube/CLI'
if (isTestInstance()) configName += `-${getAppNumber()}`
const config = require('application-config')(configName)
const version = require('../../../package.json').version const version = require('../../../package.json').version
@ -12,7 +19,7 @@ function getSettings () {
return new Promise<Settings>((res, rej) => { return new Promise<Settings>((res, rej) => {
const defaultSettings = { const defaultSettings = {
remotes: [], remotes: [],
default: 0 default: -1
} }
config.read((err, data) => { config.read((err, data) => {
@ -24,6 +31,12 @@ function getSettings () {
} }
async function getNetrc () { async function getNetrc () {
const Netrc = require('netrc-parser').Netrc
const netrc = isTestInstance()
? new Netrc(join(root(), 'test' + getAppNumber(), 'netrc'))
: new Netrc()
await netrc.load() await netrc.load()
return netrc return netrc
@ -31,7 +44,7 @@ async function getNetrc () {
function writeSettings (settings) { function writeSettings (settings) {
return new Promise((res, rej) => { return new Promise((res, rej) => {
config.write(settings, function (err) { config.write(settings, err => {
if (err) return rej(err) if (err) return rej(err)
return res() return res()
@ -39,9 +52,19 @@ function writeSettings (settings) {
}) })
} }
function getRemoteObjectOrDie (program: any, settings: Settings) { function deleteSettings () {
return new Promise((res, rej) => {
config.trash((err) => {
if (err) return rej(err)
return res()
})
})
}
function getRemoteObjectOrDie (program: any, settings: Settings, netrc: Netrc) {
if (!program['url'] || !program['username'] || !program['password']) { if (!program['url'] || !program['username'] || !program['password']) {
// No remote and we don't have program parameters: throw // No remote and we don't have program parameters: quit
if (settings.remotes.length === 0 || Object.keys(netrc.machines).length === 0) { if (settings.remotes.length === 0 || Object.keys(netrc.machines).length === 0) {
if (!program[ 'url' ]) console.error('--url field is required.') if (!program[ 'url' ]) console.error('--url field is required.')
if (!program[ 'username' ]) console.error('--username field is required.') if (!program[ 'username' ]) console.error('--username field is required.')
@ -54,15 +77,12 @@ function getRemoteObjectOrDie (program: any, settings: Settings) {
let username: string = program['username'] let username: string = program['username']
let password: string = program['password'] let password: string = program['password']
if (!url) { if (!url && settings.default !== -1) url = settings.remotes[settings.default]
url = settings.default !== -1
? settings.remotes[settings.default]
: settings.remotes[0]
}
const machine = netrc.machines[url] const machine = netrc.machines[url]
if (!username) username = machine.login
if (!password) password = machine.password if (!username && machine) username = machine.login
if (!password && machine) password = machine.password
return { url, username, password } return { url, username, password }
} }
@ -82,5 +102,6 @@ export {
getSettings, getSettings,
getNetrc, getNetrc,
getRemoteObjectOrDie, getRemoteObjectOrDie,
writeSettings writeSettings,
deleteSettings
} }

View File

@ -4,6 +4,8 @@
"private": true, "private": true,
"dependencies": { "dependencies": {
"application-config": "^1.0.1", "application-config": "^1.0.1",
"cli-table": "^0.3.1",
"netrc-parser": "^3.1.6",
"webtorrent-hybrid": "^2.1.0" "webtorrent-hybrid": "^2.1.0"
}, },
"summon": { "summon": {

View File

@ -9,7 +9,11 @@ const Table = require('cli-table')
async function delInstance (url: string) { async function delInstance (url: string) {
const [ settings, netrc ] = await Promise.all([ getSettings(), getNetrc() ]) const [ settings, netrc ] = await Promise.all([ getSettings(), getNetrc() ])
settings.remotes.splice(settings.remotes.indexOf(url)) const index = settings.remotes.indexOf(url)
settings.remotes.splice(index)
if (settings.default === index) settings.default = -1
await writeSettings(settings) await writeSettings(settings)
delete netrc.machines[url] delete netrc.machines[url]
@ -17,12 +21,17 @@ async function delInstance (url: string) {
await netrc.save() await netrc.save()
} }
async function setInstance (url: string, username: string, password: string) { async function setInstance (url: string, username: string, password: string, isDefault: boolean) {
const [ settings, netrc ] = await Promise.all([ getSettings(), getNetrc() ]) const [ settings, netrc ] = await Promise.all([ getSettings(), getNetrc() ])
if (settings.remotes.indexOf(url) === -1) { if (settings.remotes.indexOf(url) === -1) {
settings.remotes.push(url) settings.remotes.push(url)
} }
if (isDefault || settings.remotes.length === 1) {
settings.default = settings.remotes.length - 1
}
await writeSettings(settings) await writeSettings(settings)
netrc.machines[url] = { login: username, password } netrc.machines[url] = { login: username, password }
@ -66,7 +75,7 @@ program
} }
} }
}, async (_, result) => { }, async (_, result) => {
await setInstance(result.url, result.username, result.password) await setInstance(result.url, result.username, result.password, program['default'])
process.exit(0) process.exit(0)
}) })

View File

@ -1,12 +1,5 @@
import * as program from 'commander' import * as program from 'commander'
import { getClient, Server, serverLogin } from '../../shared/extra-utils'
import {
getClient,
serverLogin,
Server,
Client,
User
} from '../../shared/extra-utils'
program program
.option('-u, --url <url>', 'Server url') .option('-u, --url <url>', 'Server url')
@ -22,6 +15,7 @@ if (
if (!program['url']) console.error('--url field is required.') if (!program['url']) console.error('--url field is required.')
if (!program['username']) console.error('--username field is required.') if (!program['username']) console.error('--username field is required.')
if (!program['password']) console.error('--password field is required.') if (!program['password']) console.error('--password field is required.')
process.exit(-1) process.exit(-1)
} }
@ -32,11 +26,11 @@ getClient(program.url)
user: { user: {
username: program['username'], username: program['username'],
password: program['password'] password: program['password']
} as User, },
client: { client: {
id: res.body.client_id as string, id: res.body.client_id,
secret: res.body.client_secret as string secret: res.body.client_secret
} as Client }
} as Server } as Server
return serverLogin(server) return serverLogin(server)

View File

@ -14,8 +14,10 @@ import { sha256 } from '../helpers/core-utils'
import { buildOriginallyPublishedAt, safeGetYoutubeDL } from '../helpers/youtube-dl' import { buildOriginallyPublishedAt, safeGetYoutubeDL } from '../helpers/youtube-dl'
import { getNetrc, getRemoteObjectOrDie, getSettings } from './cli' import { getNetrc, getRemoteObjectOrDie, getSettings } from './cli'
let accessToken: string type UserInfo = {
let client: { id: string, secret: string } username: string
password: string
}
const processOptions = { const processOptions = {
cwd: __dirname, cwd: __dirname,
@ -28,13 +30,14 @@ program
.option('-U, --username <username>', 'Username') .option('-U, --username <username>', 'Username')
.option('-p, --password <token>', 'Password') .option('-p, --password <token>', 'Password')
.option('-t, --target-url <targetUrl>', 'Video target URL') .option('-t, --target-url <targetUrl>', 'Video target URL')
.option('-C, --channel-id <channel_id>', 'Channel ID')
.option('-l, --language <languageCode>', 'Language ISO 639 code (fr or en...)') .option('-l, --language <languageCode>', 'Language ISO 639 code (fr or en...)')
.option('-v, --verbose', 'Verbose mode') .option('-v, --verbose', 'Verbose mode')
.parse(process.argv) .parse(process.argv)
Promise.all([ getSettings(), getNetrc() ]) Promise.all([ getSettings(), getNetrc() ])
.then(([ settings, netrc ]) => { .then(([ settings, netrc ]) => {
const { url, username, password } = getRemoteObjectOrDie(program, settings) const { url, username, password } = getRemoteObjectOrDie(program, settings, netrc)
if (!program[ 'targetUrl' ]) { if (!program[ 'targetUrl' ]) {
console.error('--targetUrl field is required.') console.error('--targetUrl field is required.')
@ -45,56 +48,20 @@ Promise.all([ getSettings(), getNetrc() ])
removeEndSlashes(url) removeEndSlashes(url)
removeEndSlashes(program[ 'targetUrl' ]) removeEndSlashes(program[ 'targetUrl' ])
const user = { const user = { username, password }
username: username,
password: password
}
run(user, url) run(url, user)
.catch(err => { .catch(err => {
console.error(err) console.error(err)
process.exit(-1) process.exit(-1)
}) })
}) })
async function promptPassword () { async function run (url: string, user: UserInfo) {
return new Promise((res, rej) => {
prompt.start()
const schema = {
properties: {
password: {
hidden: true,
required: true
}
}
}
prompt.get(schema, function (err, result) {
if (err) {
return rej(err)
}
return res(result.password)
})
})
}
async function run (user, url: string) {
if (!user.password) { if (!user.password) {
user.password = await promptPassword() user.password = await promptPassword()
} }
const res = await getClient(url)
client = {
id: res.body.client_id,
secret: res.body.client_secret
}
try {
const res = await login(program[ 'url' ], client, user)
accessToken = res.body.access_token
} catch (err) {
throw new Error('Cannot authenticate. Please check your username/password.')
}
const youtubeDL = await safeGetYoutubeDL() const youtubeDL = await safeGetYoutubeDL()
const options = [ '-j', '--flat-playlist', '--playlist-reverse' ] const options = [ '-j', '--flat-playlist', '--playlist-reverse' ]
@ -115,7 +82,12 @@ async function run (user, url: string) {
console.log('Will download and upload %d videos.\n', infoArray.length) console.log('Will download and upload %d videos.\n', infoArray.length)
for (const info of infoArray) { for (const info of infoArray) {
await processVideo(info, program[ 'language' ], processOptions.cwd, url, user) await processVideo({
cwd: processOptions.cwd,
url,
user,
youtubeInfo: info
})
} }
console.log('Video/s for user %s imported: %s', program[ 'username' ], program[ 'targetUrl' ]) console.log('Video/s for user %s imported: %s', program[ 'username' ], program[ 'targetUrl' ])
@ -123,11 +95,18 @@ async function run (user, url: string) {
}) })
} }
function processVideo (info: any, languageCode: string, cwd: string, url: string, user) { function processVideo (parameters: {
return new Promise(async res => { cwd: string,
if (program[ 'verbose' ]) console.log('Fetching object.', info) url: string,
user: { username: string, password: string },
youtubeInfo: any
}) {
const { youtubeInfo, cwd, url, user } = parameters
const videoInfo = await fetchObject(info) return new Promise(async res => {
if (program[ 'verbose' ]) console.log('Fetching object.', youtubeInfo)
const videoInfo = await fetchObject(youtubeInfo)
if (program[ 'verbose' ]) console.log('Fetched object.', videoInfo) if (program[ 'verbose' ]) console.log('Fetched object.', videoInfo)
const result = await searchVideoWithSort(url, videoInfo.title, '-match') const result = await searchVideoWithSort(url, videoInfo.title, '-match')
@ -153,7 +132,13 @@ function processVideo (info: any, languageCode: string, cwd: string, url: string
} }
console.log(output.join('\n')) console.log(output.join('\n'))
await uploadVideoOnPeerTube(normalizeObject(videoInfo), path, cwd, url, user, languageCode) await uploadVideoOnPeerTube({
cwd,
url,
user,
videoInfo: normalizeObject(videoInfo),
videoPath: path
})
return res() return res()
}) })
} catch (err) { } catch (err) {
@ -163,7 +148,15 @@ function processVideo (info: any, languageCode: string, cwd: string, url: string
}) })
} }
async function uploadVideoOnPeerTube (videoInfo: any, videoPath: string, cwd: string, url: string, user, language?: string) { async function uploadVideoOnPeerTube (parameters: {
videoInfo: any,
videoPath: string,
cwd: string,
url: string,
user: { username: string; password: string }
}) {
const { videoInfo, videoPath, cwd, url, user } = parameters
const category = await getCategory(videoInfo.categories, url) const category = await getCategory(videoInfo.categories, url)
const licence = getLicence(videoInfo.license) const licence = getLicence(videoInfo.license)
let tags = [] let tags = []
@ -194,7 +187,7 @@ async function uploadVideoOnPeerTube (videoInfo: any, videoPath: string, cwd: st
}), }),
category, category,
licence, licence,
language, language: program[ 'language' ],
nsfw: isNSFW(videoInfo), nsfw: isNSFW(videoInfo),
waitTranscoding: true, waitTranscoding: true,
commentsEnabled: true, commentsEnabled: true,
@ -209,15 +202,21 @@ async function uploadVideoOnPeerTube (videoInfo: any, videoPath: string, cwd: st
originallyPublishedAt: originallyPublishedAt ? originallyPublishedAt.toISOString() : null originallyPublishedAt: originallyPublishedAt ? originallyPublishedAt.toISOString() : null
} }
if (program[ 'channelId' ]) {
Object.assign(videoAttributes, { channelId: program['channelId'] })
}
console.log('\nUploading on PeerTube video "%s".', videoAttributes.name) console.log('\nUploading on PeerTube video "%s".', videoAttributes.name)
let accessToken = await getAccessTokenOrDie(url, user)
try { try {
await uploadVideo(url, accessToken, videoAttributes) await uploadVideo(url, accessToken, videoAttributes)
} catch (err) { } catch (err) {
if (err.message.indexOf('401') !== -1) { if (err.message.indexOf('401') !== -1) {
console.log('Got 401 Unauthorized, token may have expired, renewing token and retry.') console.log('Got 401 Unauthorized, token may have expired, renewing token and retry.')
const res = await login(url, client, user) accessToken = await getAccessTokenOrDie(url, user)
accessToken = res.body.access_token
await uploadVideo(url, accessToken, videoAttributes) await uploadVideo(url, accessToken, videoAttributes)
} else { } else {
@ -232,6 +231,8 @@ async function uploadVideoOnPeerTube (videoInfo: any, videoPath: string, cwd: st
console.log('Uploaded video "%s"!\n', videoAttributes.name) console.log('Uploaded video "%s"!\n', videoAttributes.name)
} }
/* ---------------------------------------------------------- */
async function getCategory (categories: string[], url: string) { async function getCategory (categories: string[], url: string) {
if (!categories) return undefined if (!categories) return undefined
@ -250,8 +251,6 @@ async function getCategory (categories: string[], url: string) {
return undefined return undefined
} }
/* ---------------------------------------------------------- */
function getLicence (licence: string) { function getLicence (licence: string) {
if (!licence) return undefined if (!licence) return undefined
@ -305,9 +304,7 @@ function buildUrl (info: any) {
} }
function isNSFW (info: any) { function isNSFW (info: any) {
if (info.age_limit && info.age_limit >= 16) return true return info.age_limit && info.age_limit >= 16
return false
} }
function removeEndSlashes (url: string) { function removeEndSlashes (url: string) {
@ -315,3 +312,39 @@ function removeEndSlashes (url: string) {
url.slice(0, -1) url.slice(0, -1)
} }
} }
async function promptPassword () {
return new Promise<string>((res, rej) => {
prompt.start()
const schema = {
properties: {
password: {
hidden: true,
required: true
}
}
}
prompt.get(schema, function (err, result) {
if (err) {
return rej(err)
}
return res(result.password)
})
})
}
async function getAccessTokenOrDie (url: string, user: UserInfo) {
const resClient = await getClient(url)
const client = {
id: resClient.body.client_id,
secret: resClient.body.client_secret
}
try {
const res = await login(url, client, user)
return res.body.access_token
} catch (err) {
console.error('Cannot authenticate. Please check your username/password.')
process.exit(-1)
}
}

View File

@ -69,8 +69,7 @@ const start = async () => {
} }
start().then((data) => { start()
// do nothing .catch((err) => {
}).catch((err) => {
console.error(err) console.error(err)
}) })

View File

@ -4,7 +4,7 @@ import { isAbsolute } from 'path'
import { getClient, login } from '../../shared/extra-utils' import { getClient, login } from '../../shared/extra-utils'
import { uploadVideo } from '../../shared/extra-utils/' import { uploadVideo } from '../../shared/extra-utils/'
import { VideoPrivacy } from '../../shared/models/videos' import { VideoPrivacy } from '../../shared/models/videos'
import { getRemoteObjectOrDie, getSettings } from './cli' import { getNetrc, getRemoteObjectOrDie, getSettings } from './cli'
program program
.name('upload') .name('upload')
@ -26,9 +26,9 @@ program
.option('-f, --file <file>', 'Video absolute file path') .option('-f, --file <file>', 'Video absolute file path')
.parse(process.argv) .parse(process.argv)
getSettings() Promise.all([ getSettings(), getNetrc() ])
.then(settings => { .then(([ settings, netrc ]) => {
const { url, username, password } = getRemoteObjectOrDie(program, settings) const { url, username, password } = getRemoteObjectOrDie(program, settings, netrc)
if (!program[ 'videoName' ] || !program[ 'file' ] || !program[ 'channelId' ]) { if (!program[ 'videoName' ] || !program[ 'file' ] || !program[ 'channelId' ]) {
if (!program[ 'videoName' ]) console.error('--video-name is required.') if (!program[ 'videoName' ]) console.error('--video-name is required.')
@ -50,7 +50,7 @@ getSettings()
}) })
async function run (url: string, username: string, password: string) { async function run (url: string, username: string, password: string) {
const resClient = await getClient(program[ 'url' ]) const resClient = await getClient(url)
const client = { const client = {
id: resClient.body.client_id, id: resClient.body.client_id,
secret: resClient.body.client_secret secret: resClient.body.client_secret

View File

@ -63,9 +63,10 @@ if (!process.argv.slice(2).length) {
getSettings() getSettings()
.then(settings => { .then(settings => {
const state = (settings.default === undefined || settings.default === -1) ? const state = (settings.default === undefined || settings.default === -1)
'no instance selected, commands will require explicit arguments' : ? 'no instance selected, commands will require explicit arguments'
('instance ' + settings.remotes[settings.default] + ' selected') : 'instance ' + settings.remotes[settings.default] + ' selected'
program program
.on('--help', function () { .on('--help', function () {
console.log() console.log()

View File

@ -293,6 +293,13 @@ chunk-store-stream@^3.0.1:
block-stream2 "^1.0.0" block-stream2 "^1.0.0"
readable-stream "^2.0.5" readable-stream "^2.0.5"
cli-table@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23"
integrity sha1-9TsFJmqLGguTSz0IIebi3FkUriM=
dependencies:
colors "1.0.3"
cliui@^3.2.0: cliui@^3.2.0:
version "3.2.0" version "3.2.0"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
@ -317,6 +324,11 @@ code-point-at@^1.0.0:
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
colors@1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b"
integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=
colour@latest: colour@latest:
version "0.7.1" version "0.7.1"
resolved "https://registry.yarnpkg.com/colour/-/colour-0.7.1.tgz#9cb169917ec5d12c0736d3e8685746df1cadf778" resolved "https://registry.yarnpkg.com/colour/-/colour-0.7.1.tgz#9cb169917ec5d12c0736d3e8685746df1cadf778"
@ -373,6 +385,17 @@ create-torrent@^3.23.1, create-torrent@^3.33.0:
run-parallel "^1.0.0" run-parallel "^1.0.0"
simple-sha1 "^2.0.0" simple-sha1 "^2.0.0"
cross-spawn@^6.0.0:
version "6.0.5"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
dependencies:
nice-try "^1.0.4"
path-key "^2.0.1"
semver "^5.5.0"
shebang-command "^1.2.0"
which "^1.2.9"
debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0: debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0:
version "2.6.9" version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
@ -493,6 +516,19 @@ error-ex@^1.2.0:
dependencies: dependencies:
is-arrayish "^0.2.1" is-arrayish "^0.2.1"
execa@^0.10.0:
version "0.10.0"
resolved "https://registry.yarnpkg.com/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50"
integrity sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==
dependencies:
cross-spawn "^6.0.0"
get-stream "^3.0.0"
is-stream "^1.1.0"
npm-run-path "^2.0.0"
p-finally "^1.0.0"
signal-exit "^3.0.0"
strip-eof "^1.0.0"
executable@^4.0.0: executable@^4.0.0:
version "4.1.1" version "4.1.1"
resolved "https://registry.yarnpkg.com/executable/-/executable-4.1.1.tgz#41532bff361d3e57af4d763b70582db18f5d133c" resolved "https://registry.yarnpkg.com/executable/-/executable-4.1.1.tgz#41532bff361d3e57af4d763b70582db18f5d133c"
@ -576,6 +612,11 @@ get-stdin@^6.0.0:
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b"
integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==
get-stream@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=
glob@^7.1.3: glob@^7.1.3:
version "7.1.4" version "7.1.4"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255"
@ -694,6 +735,11 @@ is-fullwidth-code-point@^2.0.0:
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
is-stream@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
is-typedarray@^1.0.0: is-typedarray@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
@ -963,6 +1009,14 @@ netmask@^1.0.6:
resolved "https://registry.yarnpkg.com/netmask/-/netmask-1.0.6.tgz#20297e89d86f6f6400f250d9f4f6b4c1945fcd35" resolved "https://registry.yarnpkg.com/netmask/-/netmask-1.0.6.tgz#20297e89d86f6f6400f250d9f4f6b4c1945fcd35"
integrity sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU= integrity sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU=
netrc-parser@^3.1.6:
version "3.1.6"
resolved "https://registry.yarnpkg.com/netrc-parser/-/netrc-parser-3.1.6.tgz#7243c9ec850b8e805b9bdc7eae7b1450d4a96e72"
integrity sha512-lY+fmkqSwntAAjfP63jB4z5p5WbuZwyMCD3pInT7dpHU/Gc6Vv90SAC6A0aNiqaRGHiuZFBtiwu+pu8W/Eyotw==
dependencies:
debug "^3.1.0"
execa "^0.10.0"
network-address@^1.0.0, network-address@^1.1.0: network-address@^1.0.0, network-address@^1.1.0:
version "1.1.2" version "1.1.2"
resolved "https://registry.yarnpkg.com/network-address/-/network-address-1.1.2.tgz#4aa7bfd43f03f0b81c9702b13d6a858ddb326f3e" resolved "https://registry.yarnpkg.com/network-address/-/network-address-1.1.2.tgz#4aa7bfd43f03f0b81c9702b13d6a858ddb326f3e"
@ -973,6 +1027,11 @@ next-event@^1.0.0:
resolved "https://registry.yarnpkg.com/next-event/-/next-event-1.0.0.tgz#e7778acde2e55802e0ad1879c39cf6f75eda61d8" resolved "https://registry.yarnpkg.com/next-event/-/next-event-1.0.0.tgz#e7778acde2e55802e0ad1879c39cf6f75eda61d8"
integrity sha1-53eKzeLlWALgrRh5w5z2917aYdg= integrity sha1-53eKzeLlWALgrRh5w5z2917aYdg=
nice-try@^1.0.4:
version "1.0.5"
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
node-cmake@2.3.2: node-cmake@2.3.2:
version "2.3.2" version "2.3.2"
resolved "https://registry.yarnpkg.com/node-cmake/-/node-cmake-2.3.2.tgz#e0fbc54b11405b07705e4d6d41865ae95ad289d0" resolved "https://registry.yarnpkg.com/node-cmake/-/node-cmake-2.3.2.tgz#e0fbc54b11405b07705e4d6d41865ae95ad289d0"
@ -1049,6 +1108,13 @@ npm-packlist@^1.1.6:
ignore-walk "^3.0.1" ignore-walk "^3.0.1"
npm-bundled "^1.0.1" npm-bundled "^1.0.1"
npm-run-path@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=
dependencies:
path-key "^2.0.0"
npmlog@^4.0.2: npmlog@^4.0.2:
version "4.1.2" version "4.1.2"
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
@ -1111,6 +1177,11 @@ osenv@^0.1.4:
os-homedir "^1.0.0" os-homedir "^1.0.0"
os-tmpdir "^1.0.0" os-tmpdir "^1.0.0"
p-finally@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
package-json-versionify@^1.0.2: package-json-versionify@^1.0.2:
version "1.0.4" version "1.0.4"
resolved "https://registry.yarnpkg.com/package-json-versionify/-/package-json-versionify-1.0.4.tgz#5860587a944873a6b7e6d26e8e51ffb22315bf17" resolved "https://registry.yarnpkg.com/package-json-versionify/-/package-json-versionify-1.0.4.tgz#5860587a944873a6b7e6d26e8e51ffb22315bf17"
@ -1155,6 +1226,11 @@ path-is-absolute@^1.0.0:
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
path-key@^2.0.0, path-key@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
path-parse@^1.0.6: path-parse@^1.0.6:
version "1.0.6" version "1.0.6"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
@ -1400,7 +1476,7 @@ sax@>=0.6.0, sax@^1.2.4:
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
"semver@2 || 3 || 4 || 5", semver@^5.3.0: "semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5.0:
version "5.7.0" version "5.7.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b"
integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==
@ -1415,6 +1491,18 @@ set-blocking@^2.0.0, set-blocking@~2.0.0:
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
shebang-command@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=
dependencies:
shebang-regex "^1.0.0"
shebang-regex@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
signal-exit@^3.0.0: signal-exit@^3.0.0:
version "3.0.2" version "3.0.2"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
@ -1591,6 +1679,11 @@ strip-bom@^2.0.0:
dependencies: dependencies:
is-utf8 "^0.2.0" is-utf8 "^0.2.0"
strip-eof@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
strip-json-comments@~2.0.1: strip-json-comments@~2.0.1:
version "2.0.1" version "2.0.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
@ -1855,7 +1948,7 @@ which-module@^1.0.0:
resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8= integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=
which@^1.2.14: which@^1.2.14, which@^1.2.9:
version "1.3.1" version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==

View File

@ -1,7 +1,7 @@
/* tslint:disable:no-unused-expression */ /* tslint:disable:no-unused-expression */
import * as chai from 'chai' import * as chai from 'chai'
import { isAbsolute, join } from 'path' import { basename, isAbsolute, join, resolve } from 'path'
import * as request from 'supertest' import * as request from 'supertest'
import * as WebTorrent from 'webtorrent' import * as WebTorrent from 'webtorrent'
import { pathExists, readFile } from 'fs-extra' import { pathExists, readFile } from 'fs-extra'
@ -34,7 +34,11 @@ function webtorrentAdd (torrent: string, refreshWebTorrent = false) {
function root () { function root () {
// We are in /miscs // We are in /miscs
return join(__dirname, '..', '..', '..') let root = join(__dirname, '..', '..', '..')
if (basename(root) === 'dist') root = resolve(root, '..')
return root
} }
async function testImage (url: string, imageName: string, imagePath: string, extension = '.jpg') { async function testImage (url: string, imageName: string, imagePath: string, extension = '.jpg') {

View File

@ -1372,13 +1372,6 @@ cli-cursor@^2.0.0, cli-cursor@^2.1.0:
dependencies: dependencies:
restore-cursor "^2.0.0" restore-cursor "^2.0.0"
cli-table@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23"
integrity sha1-9TsFJmqLGguTSz0IIebi3FkUriM=
dependencies:
colors "1.0.3"
cli-truncate@^0.2.1: cli-truncate@^0.2.1:
version "0.2.1" version "0.2.1"
resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-0.2.1.tgz#9f15cfbb0705005369216c626ac7d05ab90dd574" resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-0.2.1.tgz#9f15cfbb0705005369216c626ac7d05ab90dd574"
@ -1505,7 +1498,7 @@ colornames@^1.1.1:
resolved "https://registry.yarnpkg.com/colornames/-/colornames-1.1.1.tgz#f8889030685c7c4ff9e2a559f5077eb76a816f96" resolved "https://registry.yarnpkg.com/colornames/-/colornames-1.1.1.tgz#f8889030685c7c4ff9e2a559f5077eb76a816f96"
integrity sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y= integrity sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=
colors@1.0.3, colors@1.0.x: colors@1.0.x:
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b"
integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs= integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=
@ -2435,19 +2428,6 @@ event-emitter@^0.3.5, event-emitter@~0.3.5:
d "1" d "1"
es5-ext "~0.10.14" es5-ext "~0.10.14"
execa@^0.10.0:
version "0.10.0"
resolved "https://registry.yarnpkg.com/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50"
integrity sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==
dependencies:
cross-spawn "^6.0.0"
get-stream "^3.0.0"
is-stream "^1.1.0"
npm-run-path "^2.0.0"
p-finally "^1.0.0"
signal-exit "^3.0.0"
strip-eof "^1.0.0"
execa@^0.7.0: execa@^0.7.0:
version "0.7.0" version "0.7.0"
resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777"
@ -4845,14 +4825,6 @@ netmask@^1.0.6:
resolved "https://registry.yarnpkg.com/netmask/-/netmask-1.0.6.tgz#20297e89d86f6f6400f250d9f4f6b4c1945fcd35" resolved "https://registry.yarnpkg.com/netmask/-/netmask-1.0.6.tgz#20297e89d86f6f6400f250d9f4f6b4c1945fcd35"
integrity sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU= integrity sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU=
netrc-parser@^3.1.6:
version "3.1.6"
resolved "https://registry.yarnpkg.com/netrc-parser/-/netrc-parser-3.1.6.tgz#7243c9ec850b8e805b9bdc7eae7b1450d4a96e72"
integrity sha512-lY+fmkqSwntAAjfP63jB4z5p5WbuZwyMCD3pInT7dpHU/Gc6Vv90SAC6A0aNiqaRGHiuZFBtiwu+pu8W/Eyotw==
dependencies:
debug "^3.1.0"
execa "^0.10.0"
next-event@^1.0.0: next-event@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/next-event/-/next-event-1.0.0.tgz#e7778acde2e55802e0ad1879c39cf6f75eda61d8" resolved "https://registry.yarnpkg.com/next-event/-/next-event-1.0.0.tgz#e7778acde2e55802e0ad1879c39cf6f75eda61d8"