diff --git a/cli/package.json b/cli/package.json index ea354b12f0..251048b61b 100644 --- a/cli/package.json +++ b/cli/package.json @@ -36,9 +36,9 @@ "semver": "^5.5.0", "table": "^4.0.2", "through": "^2.3.8", - "unzipper": "^0.8.11", "which": "^1.3.0", - "yargs": "^4.2.0" + "yargs": "^4.2.0", + "yauzl-promise": "^2.1.2" }, "devDependencies": { "babel-cli": "^6.26.0", diff --git a/cli/src/commands/runTests.js b/cli/src/commands/runTests.js index 4af1cf3df3..53f49c8ec3 100644 --- a/cli/src/commands/runTests.js +++ b/cli/src/commands/runTests.js @@ -1,16 +1,14 @@ // @flow -import {child_process, fs, os, path} from '../lib/node.js'; +import {fs, path} from '../lib/node.js'; import {copyFile, recursiveRmdir} from '../lib/fileUtils.js'; -import {gitHubClient} from '../lib/github.js'; import {getLibDefs, parseRepoDirItem} from '../lib/libDefs.js'; import isInFlowTypedRepo from '../lib/isInFlowTypedRepo'; import {toSemverString as flowVerToSemverString} from '../lib/flowVersion'; import {getDiff} from '../lib/git'; +import {getFlowBinaries, type Flow} from '../lib/binaries'; -import got from 'got'; import * as semver from 'semver'; -import * as unzip from 'unzipper'; import typeof Yargs from 'yargs'; import type {FlowVersion} from '../lib/flowVersion.js'; @@ -21,24 +19,10 @@ export type Args = { numberOfFlowVersions?: number, }; -// Used to decide which binary to fetch for each version of Flow -const BIN_PLATFORM = (_ => { - switch (os.type()) { - case 'Linux': - return 'linux64'; - case 'Darwin': - return 'osx'; - case 'Windows_NT': - return 'win64'; - - default: - throw new Error('Unsupported os.type()! ' + os.type()); - } -})(); const PKG_ROOT_DIR = path.join(__dirname, '..', '..'); const TEST_DIR = path.join(PKG_ROOT_DIR, '.test-dir'); const BIN_DIR = path.join(PKG_ROOT_DIR, '.flow-bins-cache'); -const P = Promise; +const NUMBER_OF_FLOW_VERSIONS = 15; type TestGroup = { id: string, @@ -86,203 +70,6 @@ async function getTestGroups( }); } -/** - * Memoized function that queries the GitHub releases for Flow, downloads the - * zip for each version, extracts the zip, and moves the binary to - * TEST_BIN/flow-vXXX for use later when running tests. - */ -let _flowBinVersionPromise = null; -async function getOrderedFlowBinVersions( - numberOfReleases: number = 15, -): Promise> { - if (_flowBinVersionPromise !== null) { - return _flowBinVersionPromise; - } - return (_flowBinVersionPromise = (async function() { - console.log('Fetching all Flow binaries...'); - const IS_WINDOWS = os.type() === 'Windows_NT'; - const GH_CLIENT = gitHubClient(); - // We only test against the latest numberOfReleases Versions - const QUERY_PAGE_SIZE = numberOfReleases; - const OS_ARCH_FILTER_RE = new RegExp(`flow-${BIN_PLATFORM}`); - - let page = 0; - const apiPayload = await GH_CLIENT.repos.getReleases({ - owner: 'facebook', - repo: 'flow', - page: page++, - per_page: QUERY_PAGE_SIZE, - }); - - const flowBins = apiPayload.data - .filter(rel => { - // Temporary fix for https://github.com/facebook/flow/issues/5922 - if (rel.tag_name === 'v0.67.0') { - console.log( - '==========================================================================================', - ); - console.log( - 'We are tempoarily skipping v0.67.0 due to https://github.com/facebook/flow/issues/5922', - ); - console.log( - '==========================================================================================', - ); - return false; - } - - // We only test against versions since 0.15.0 because it has proper - // [ignore] fixes (which are necessary to run tests) - // Because Windows was only supported starting with version 0.30.0, we also skip version prior to that when running on windows. - if (semver.lt(rel.tag_name, IS_WINDOWS ? '0.30.0' : '0.15.0')) { - return false; - } - - // Because flow 0.57 was broken before 0.57.3 on the Windows platform, we also skip those versions when running on windows. - if ( - IS_WINDOWS && - (semver.eq(rel.tag_name, '0.57.0') || - semver.eq(rel.tag_name, '0.57.1') || - semver.eq(rel.tag_name, '0.57.2')) - ) { - return false; - } - return true; - }) - .map(rel => { - // Find the binary zip in the list of assets - const binZip = rel.assets - .filter(({name}) => { - return OS_ARCH_FILTER_RE.test(name) && !/-latest.zip$/.test(name); - }) - .map(asset => asset.browser_download_url); - - if (binZip.length !== 1) { - throw new Error( - 'Unexpected number of ' + - BIN_PLATFORM + - ' assets for flow-' + - rel.tag_name + - '! ' + - JSON.stringify(binZip), - ); - } else { - const version = - rel.tag_name[0] === 'v' ? rel.tag_name : 'v' + rel.tag_name; - return {version, binURL: binZip[0]}; - } - }) - .sort((a, b) => { - return semver.lt(a.version, b.version) ? -1 : 1; - }); - - await P.all( - flowBins.map(async ({version, binURL}) => { - const zipPath = path.join(BIN_DIR, 'flow-' + version + '.zip'); - const binPath = path.join( - BIN_DIR, - 'flow-' + version + (IS_WINDOWS ? '.exe' : ''), - ); - - if (await fs.exists(binPath)) { - return; - } - - // Download the zip file - await new Promise((res, rej) => { - console.log(' Fetching flow-%s...', version); - got - .stream(binURL, { - headers: { - 'User-Agent': - 'flow-typed Test Runner ' + - '(github.com/flowtype/flow-typed)', - }, - }) - .on('error', err => rej(err)) - .pipe( - fs.createWriteStream(zipPath).on('close', () => { - console.log(' flow-%s finished downloading.', version); - res(); - }), - ); - }); - - // Extract the flow binary - const flowBinDirPath = path.join(BIN_DIR, 'TMP-flow-' + version); - await fs.mkdir(flowBinDirPath); - console.log(' Extracting flow-%s...', version); - await new Promise((res, rej) => { - const unzipExtractor = unzip.Extract({path: flowBinDirPath}); - unzipExtractor.on('error', function(err) { - rej(err); - }); - unzipExtractor.on('close', function() { - res(); - }); - fs.createReadStream(zipPath).pipe(unzipExtractor); - }); - if (IS_WINDOWS) { - await fs.rename( - path.join(flowBinDirPath, 'flow', 'flow.exe'), - path.join(BIN_DIR, 'flow-' + version + '.exe'), - ); - } else { - await fs.rename( - path.join(flowBinDirPath, 'flow', 'flow'), - path.join(BIN_DIR, 'flow-' + version), - ); - - await child_process.execP( - ['chmod', '755', path.join(BIN_DIR, 'flow-' + version)].join(' '), - ); - } - - console.log(' Removing flow-%s artifacts...', version); - await P.all([recursiveRmdir(flowBinDirPath), fs.unlink(zipPath)]); - console.log(' flow-%s complete!', version); - }), - ); - - console.log('Finished fetching Flow binaries.\n'); - - return flowBins.map(bin => bin.version); - })()); -} - -const flowNameRegex = /^flow-v[0-9]+.[0-9]+.[0-9]+(\.exe)?$/; -/** - * flow filename should be `flow-vx.x.x` - * @param {string} name - */ -function checkFlowFilename(name) { - return flowNameRegex.test(name); -} - -/** - * Return the sorted list of cached flow binaries that have previously been retrieved from github - * and cached in the `.flow-bins-cache` directory. This function is usually called when a failure - * has occurred when attempting to refresh the flow releases from github, i.e. offline or over - * API limit. - */ -async function getCachedFlowBinVersions( - numberOfReleases: number = 15, -): Promise> { - // read the files with name `flow-vx.x.x` from the bin dir and remove the leading `flow-v` prefix - const versions: any[] = (await fs.readdir(path.join(BIN_DIR))) - .filter(checkFlowFilename) - .map(dir => dir.slice(6)); - - // sort the versions that we have inplace - versions.sort((a, b) => { - return semver.lt(a, b) ? -1 : 1; - }); - - versions.splice(0, versions.length - numberOfReleases); - - // return the versions with a leading 'v' to satisfy the expected return value - return versions.map(version => `v${version}`); -} - async function writeFlowConfig( repoDirPath, testDirPath, @@ -309,52 +96,25 @@ async function writeFlowConfig( await fs.writeFile(destFlowConfigPath, flowConfigData); } -function testTypeDefinition(flowVer, testDirPath) { - return new Promise(res => { - const child = child_process.exec( - [ - path.join(BIN_DIR, 'flow-' + flowVer), - 'check', - '--strip-root', - '--all', - testDirPath, - ].join(' '), - ); - - let stdErrOut = ''; - child.stdout.on('data', data => (stdErrOut += data)); - child.stderr.on('data', data => (stdErrOut += data)); - - child.on('error', execError => { - res({stdErrOut, errCode: null, execError}); - }); - - child.on('close', errCode => { - res({stdErrOut, errCode, execError: null}); - }); - }); -} - -async function runFlowTypeDefTests(flowVersionsToRun, groupId, testDirPath) { - const errors = []; - while (flowVersionsToRun.length > 0) { +async function runFlowTypeDefTests(flowsToRun, groupId, testDirPath) { + const errors: Array = []; + while (flowsToRun.length > 0) { // Run tests in batches to avoid saturation - const testBatch = flowVersionsToRun - .slice(0, Math.min(flowVersionsToRun.length, 5)) - .map(group => (flowVersionsToRun.shift(), group)); + const testBatch = flowsToRun + .slice(0, Math.min(flowsToRun.length, 5)) + .map(group => (flowsToRun.shift(), group)); - await P.all( - testBatch.map(async flowVer => { - const testRunId = groupId + ' (flow-' + flowVer + ')'; + await Promise.all( + testBatch.map(async flow => { + const testRunId = groupId + ' (flow-' + flow.version + ')'; console.log('Testing %s...', testRunId); - const {stdErrOut, errCode, execError} = await testTypeDefinition( - flowVer, + const {stdErrOut, errCode, execError} = await flow.runTests( testDirPath, ); - if (execError !== null) { + if (execError) { errors.push( testRunId + ': Error executing Flow process: ' + execError.stack, ); @@ -378,80 +138,63 @@ async function runFlowTypeDefTests(flowVersionsToRun, groupId, testDirPath) { async function testLowestCapableFlowVersion( lowerVersions, testDirPath, - lowestFlowVersionRan, + lowestFlowRan, ) { let lowerFlowVersionsToRun = lowerVersions; - let lowestCapableFlowVersion = lowestFlowVersionRan; + let lowestCapableFlow = lowestFlowRan; while (lowerFlowVersionsToRun.length > 0) { const lowerTestBatch = lowerFlowVersionsToRun .slice(0, Math.min(lowerFlowVersionsToRun.length, 5)) .map(group => (lowerFlowVersionsToRun.shift(), group)); - await P.all( - lowerTestBatch.map(async flowVer => { - const {stdErrOut, execError} = await testTypeDefinition( - flowVer, - testDirPath, - ); + await Promise.all( + lowerTestBatch.map(async flow => { + const {stdErrOut, execError} = await flow.runTests(testDirPath); if (execError !== null || !stdErrOut.endsWith('Found 0 errors\n')) { lowerFlowVersionsToRun = []; } else { - lowestCapableFlowVersion = semver.lt( - lowestCapableFlowVersion, - flowVer, - ) - ? lowestCapableFlowVersion - : flowVer; + lowestCapableFlow = semver.lt(lowestCapableFlow.version, flow.version) + ? lowestCapableFlow + : flow; } }), ); } - return lowestCapableFlowVersion; + return lowestCapableFlow; } async function findLowestCapableFlowVersion( repoDirPath, - orderedFlowVersions, - lowestFlowVersionRan, + flows, + lowestFlowRan, testDirPath, libDefPath, ) { - let lowerFlowVersionsToRun = orderedFlowVersions.filter(flowVer => { - return semver.lt(flowVer, lowestFlowVersionRan); + let lowerFlowsToRun = flows.filter(flow => { + return semver.lt(flow.version, lowestFlowRan.version); }); - lowerFlowVersionsToRun.reverse(); - const lowerLowVersions = lowerFlowVersionsToRun.filter(flowVer => - semver.lt(flowVer, '0.53.0'), + lowerFlowsToRun.reverse(); + const lowerLowFlow = lowerFlowsToRun.filter(flow => + semver.lt(flow.version, '0.53.0'), ); - const higherLowVersions = lowerFlowVersionsToRun.filter(flowVer => - semver.gte(flowVer, '0.53.0'), + const higherLowFlows = lowerFlowsToRun.filter(flow => + semver.gte(flow.version, '0.53.0'), ); await writeFlowConfig(repoDirPath, testDirPath, libDefPath, true); - const lowestOfHigherVersions = await testLowestCapableFlowVersion( - higherLowVersions, + const lowestOfHigherFlow = await testLowestCapableFlowVersion( + higherLowFlows, testDirPath, - lowestFlowVersionRan, + lowestFlowRan, ); await writeFlowConfig(repoDirPath, testDirPath, libDefPath, false); return await testLowestCapableFlowVersion( - lowerLowVersions, + lowerLowFlow, testDirPath, - lowestOfHigherVersions, + lowestOfHigherFlow, ); } -/** - * Remove all files except flow instances - */ -async function removeTrashFromBinDir() { - (await fs.readdir(path.join(BIN_DIR))) - .filter(name => !checkFlowFilename(name)) - .forEach(async el => { - await fs.unlink(path.resolve(BIN_DIR, el)); - }); -} - /** * Given a TestGroup structure determine all versions of Flow that match the * FlowVersion specification and, for each, run `flow check` on the test @@ -460,7 +203,7 @@ async function removeTrashFromBinDir() { async function runTestGroup( repoDirPath: string, testGroup: TestGroup, - orderedFlowVersions: Array, + flowBins: Array, ): Promise> { const errors = []; // Some older versions of Flow choke on ">"/"<"/"=" @@ -491,8 +234,8 @@ async function runTestGroup( path.basename(testGroup.libDefPath), ); const copiedFileNames = new Set(); - await P.all([ - P.all( + await Promise.all([ + Promise.all( testGroup.testFilePaths.map(async (filePath, idx) => { // Because there could be multiple test files with the same basename, // we disambiguate each one with a locally-unique index. @@ -515,21 +258,20 @@ async function runTestGroup( // For each compatible version of Flow, run `flow check` and verify there // are no errors. const testGrpFlowSemVerRange = flowVerToSemverString(testGroup.flowVersion); - const flowVersionsToRun = orderedFlowVersions.filter(flowVer => { - return semver.satisfies(flowVer, testGrpFlowSemVerRange); + const flowsToRun = flowBins.filter(flow => { + return semver.satisfies(flow.version, testGrpFlowSemVerRange); }); - // Windows hasn't flow < 30.0 but we have tests for flow < 30.0. We need skip it. Example: redux_v3 - if (!flowVersionsToRun.length) { + if (!flowsToRun.length) { return []; } - let lowestFlowVersionRan = flowVersionsToRun[0]; + let lowestFlowRan = flowsToRun[0]; - const lowerVersions = flowVersionsToRun.filter(flowVer => - semver.lt(flowVer, '0.53.0'), + const lowerVersions = flowsToRun.filter(flow => + semver.lt(flow.version, '0.53.0'), ); - const higherVersions = flowVersionsToRun.filter(flowVer => - semver.gte(flowVer, '0.53.0'), + const higherVersions = flowsToRun.filter(flow => + semver.gte(flow.version, '0.53.0'), ); await writeFlowConfig( @@ -552,19 +294,19 @@ async function runTestGroup( ); errors.push(...higherVersionErrors, ...lowerVersionErrors); - const lowestCapableFlowVersion = await findLowestCapableFlowVersion( + const lowestCapableFlow = await findLowestCapableFlowVersion( repoDirPath, - orderedFlowVersions, - lowestFlowVersionRan, + flowBins, + lowestFlowRan, testDirPath, testGroup.libDefPath, ); - if (lowestCapableFlowVersion !== lowestFlowVersionRan) { - console.log(`Tests for ${ - testGroup.id - } ran successfully on flow ${lowestCapableFlowVersion}. - Consider setting ${lowestCapableFlowVersion} as the lower bound!`); + if (lowestCapableFlow.version !== lowestFlowRan.version) { + console.log(`Tests for ${testGroup.id} ran successfully on flow ${ + lowestCapableFlow.version + }. + Consider setting ${lowestCapableFlow.version} as the lower bound!`); } return errors; @@ -579,7 +321,7 @@ async function runTests( repoDirPath: string, testPatterns: Array, onlyChanged?: boolean, - numberOfFlowVersions?: number, + flowBins: Array, ): Promise>> { const testPatternRes = testPatterns.map(patt => new RegExp(patt, 'g')); const testGroups = (await getTestGroups(repoDirPath, onlyChanged)).filter( @@ -609,23 +351,11 @@ async function runTests( const results = new Map(); while (testGroups.length > 0) { const testGroup = testGroups.shift(); - //Prepare bin folder to collect flow instances - await removeTrashFromBinDir(); - let orderedFlowVersions; - try { - orderedFlowVersions = await getOrderedFlowBinVersions( - numberOfFlowVersions, - ); - } catch (e) { - orderedFlowVersions = await getCachedFlowBinVersions( - numberOfFlowVersions, - ); - } const testGroupErrors = await runTestGroup( repoDirPath, testGroup, - orderedFlowVersions, + flowBins, ); if (testGroupErrors.length > 0) { const errors = results.get(testGroup.id) || []; @@ -676,7 +406,8 @@ export async function run(argv: Args): Promise { } const testPatterns = argv._.slice(1); const onlyChanged = Boolean(argv.onlyChanged); - const numberOfFlowVersions = Number(argv.numberOfFlowVersions) || 15; + const numberOfFlowVersions = + Number(argv.numberOfFlowVersions) || NUMBER_OF_FLOW_VERSIONS; const cwd = process.cwd(); const basePath = argv.path ? String(argv.path) : cwd; @@ -699,11 +430,12 @@ export async function run(argv: Args): Promise { ); } + const flowBins = await getFlowBinaries(BIN_DIR, numberOfFlowVersions); const results = await runTests( repoDirPath, testPatterns, onlyChanged, - numberOfFlowVersions, + flowBins, ); console.log(' '); Array.from(results).forEach(([testGroupName, errors]) => { diff --git a/cli/src/lib/binaries.js b/cli/src/lib/binaries.js new file mode 100644 index 0000000000..33770b9021 --- /dev/null +++ b/cli/src/lib/binaries.js @@ -0,0 +1,214 @@ +// @flow +import {getGitHubClient} from './github'; +import {child_process} from './node'; +import os from 'os'; +import got from 'got'; +import semver from 'semver'; +import fs from 'fs-extra'; +import yauzl from 'yauzl-promise'; +import path from 'path'; + +const githubClient = getGitHubClient(); + +function getOsType() { + switch (os.type()) { + case 'Linux': + return 'linux64'; + case 'Darwin': + return 'osx'; + case 'Windows_NT': + return 'win64'; + + default: + throw new Error('Unsupported os.type()! ' + os.type()); + } +} + +const isWindows = os.type() === 'Windows_NT'; +export class Flow { + binPath: string; + version: string; + + constructor(binPath: string) { + this.binPath = binPath; + // linux/macos flow bins has no ext + this.version = isWindows + ? path.parse(binPath).name + : path.parse(binPath).base; + } + + runTests( + testDirPath: string, + ): Promise<{ + stdErrOut: string, + errCode: ?number, + execError: ?Error, + }> { + return new Promise(res => { + const child = child_process.exec( + `${this.binPath} check --strip-root --all ${testDirPath}`, + ); + + let stdErrOut = ''; + child.stdout.on('data', data => (stdErrOut += data)); + child.stderr.on('data', data => (stdErrOut += data)); + + child.on('error', execError => { + res({stdErrOut, errCode: null, execError}); + }); + + child.on('close', errCode => { + res({stdErrOut, errCode, execError: null}); + }); + }); + } +} + +function createBinFilename(binRoot, filename) { + return isWindows + ? path.resolve(binRoot, `${filename}.exe`) + : path.resolve(binRoot, filename); +} + +function saveFileFromStream(stream, filepath) { + return new Promise(res => { + stream.pipe( + fs.createWriteStream(filepath).on('close', () => { + res(); + }), + ); + }); +} + +async function extractZip(buffer, filepath, flowname) { + console.log(`Start unzipping '${flowname}' file`); + const zipFile = await yauzl.fromBuffer(buffer); + let entry = null; + while ((entry = await zipFile.readEntry())) { + if (entry.fileName.startsWith('flow/flow')) { + break; + } + } + if (!entry) { + throw new Error('flow binary not found in zip file'); + } + const readStream = await zipFile.openReadStream(entry); + await saveFileFromStream(readStream, filepath); + await zipFile.close(); + console.log(`'${flowname}' unzipped to cache`); +} + +async function downloadBin(url, filepath, flowname) { + console.log(`start '${flowname}' downloading`); + const response = await got(url, {encoding: null}); + console.log(`'${flowname}' downloaded`); + await extractZip(response.body, filepath, flowname); + if (!isWindows) { + await child_process.execP(`chmod 755 ${filepath}`); + } + return new Flow(filepath); +} + +const osType = getOsType(); +function createFileName(version) { + return `flow-${osType}-${version}.zip`; +} + +function getBinUrl(assets, version) { + const filename = createFileName(version); + for (const asset of assets) { + if (asset.name === filename) { + return asset.browser_download_url; + } + } +} + +function filterActualVersions(releases, count, binRoot) { + function getKey(version) { + const major = semver.major(version); + const minor = semver.minor(version); + return `${major}.${minor}`; + } + + return releases.reduce((res, release) => { + if (res.length === count) { + return res; + } + const key = getKey(release.tag_name); + return res.length && res[res.length - 1].key === key + ? res + : res.concat({ + key: key, + version: release.tag_name, + filename: createBinFilename(binRoot, release.tag_name), + binUrl: getBinUrl(release.assets, release.tag_name), + }); + }, []); +} + +async function getActualVersions(count, binRoot) { + console.log('fetch data from github'); + const dataFromGithub = await githubClient.repos.getReleases({ + owner: 'facebook', + repo: 'flow', + page: 0, + per_page: 100, + }); + console.log('data fetched'); + return filterActualVersions(dataFromGithub.data, count, binRoot); +} + +async function getCached(cacheLocation) { + console.log(`get data from cache`); + const files: Array = await fs.readdir(cacheLocation); + return files.map(file => new Flow(path.resolve(cacheLocation, file))); +} + +async function removeFile(binPath, filename) { + try { + await fs.unlink(binPath); + console.log(`${filename} removed from cache`); + } catch (_) { + console.error(`remove '${filename}' failed`); + } +} + +function removeOutdatedVersionsFromCache(flows) { + return Promise.all(flows.map(f => removeFile(f.binPath, f.version))); +} + +function downloadActualVersionsToCache(versions) { + return Promise.all( + versions.map(v => downloadBin(v.binUrl, v.filename, v.version)), + ); +} + +let memoizedFlowBinaries = null; +export async function getFlowBinaries(binRoot: string, count: number) { + if (memoizedFlowBinaries) { + return memoizedFlowBinaries; + } + await fs.mkdirp(binRoot); + + const [cached, actualVersions] = await Promise.all([ + getCached(binRoot), + getActualVersions(count, binRoot), + ]); + + const nonCachedVersions = actualVersions.filter(v => + cached.every(c => c.version !== v.version), + ); + const outdatedVersions = cached.filter(c => + actualVersions.every(v => v.version !== c.version), + ); + + await Promise.all([ + removeOutdatedVersionsFromCache(outdatedVersions), + downloadActualVersionsToCache(nonCachedVersions), + ]); + + memoizedFlowBinaries = nonCachedVersions.length + ? await getCached(binRoot) + : cached; + return memoizedFlowBinaries; +} diff --git a/cli/src/lib/github.js b/cli/src/lib/github.js index a646001374..372420a2e9 100644 --- a/cli/src/lib/github.js +++ b/cli/src/lib/github.js @@ -2,12 +2,36 @@ import Octokit from '@octokit/rest'; -const CLIENT = new Octokit(); +type GetReleasesArgs = { + owner: string, + repo: string, + page: number, + per_page: number, +}; + +type Releases = { + data: $ReadOnlyArray<{ + tag_name: string, + assets: $ReadOnlyArray<{ + name: string, + browser_download_url: string, + }>, + }>, +}; + +type GitHubClient = { + repos: { + getReleases(args: GetReleasesArgs): Promise, + }, + authenticate(args: Object): void, +}; + +const CLIENT: GitHubClient = new Octokit(); if (process.env.GH_TOK) { CLIENT.authenticate({type: 'oauth', token: process.env.GH_TOK}); } -export function gitHubClient(): Object { +export function getGitHubClient() { return CLIENT; } diff --git a/cli/yarn.lock b/cli/yarn.lock index a0eae2704a..6a6899c4de 100644 --- a/cli/yarn.lock +++ b/cli/yarn.lock @@ -1009,31 +1009,16 @@ before-after-hook@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-1.1.0.tgz#83165e15a59460d13702cb8febd6a1807896db5a" -big-integer@^1.6.17: - version "1.6.26" - resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.26.tgz#3af1672fa62daf2d5ecafacf6e5aa0d25e02c1c8" - binary-extensions@^1.0.0: version "1.8.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.8.0.tgz#48ec8d16df4377eae5fa5884682480af4d95c774" -binary@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/binary/-/binary-0.3.0.tgz#9f60553bc5ce8c3386f3b553cff47462adecaa79" - dependencies: - buffers "~0.1.1" - chainsaw "~0.1.0" - block-stream@*: version "0.0.9" resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" dependencies: inherits "~2.0.0" -bluebird@~3.4.1: - version "3.4.7" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" - boom@2.x.x: version "2.10.1" resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" @@ -1094,18 +1079,14 @@ btoa-lite@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337" -buffer-indexof-polyfill@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.1.tgz#a9fb806ce8145d5428510ce72f278bb363a638bf" +buffer-crc32@~0.2.3: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" buffer-shims@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" -buffers@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb" - builtin-modules@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" @@ -1151,12 +1132,6 @@ center-align@^0.1.1: align-text "^0.1.3" lazy-cache "^1.0.3" -chainsaw@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/chainsaw/-/chainsaw-0.1.0.tgz#5eab50b28afe58074d0d58291388828b5e5fbc98" - dependencies: - traverse ">=0.3.0 <0.4" - chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" @@ -1481,12 +1456,6 @@ domexception@^1.0.0: dependencies: webidl-conversions "^4.0.2" -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" @@ -1652,6 +1621,10 @@ esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" +events-intercept@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/events-intercept/-/events-intercept-2.0.0.tgz#adbf38681c5a4b2011c41ee41f61a34cba448897" + exec-sh@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.0.tgz#14f75de3f20d286ef933099b2ce50a90359cef10" @@ -1745,6 +1718,12 @@ fb-watchman@^2.0.0: dependencies: bser "^2.0.0" +fd-slicer@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" + dependencies: + pend "~1.2.0" + figures@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" @@ -2937,10 +2916,6 @@ levn@^0.3.0, levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" -listenercount@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/listenercount/-/listenercount-1.0.1.tgz#84c8a72ab59c4725321480c975e6508342e70937" - load-json-file@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" @@ -3406,6 +3381,10 @@ path-type@^1.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + performance-now@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" @@ -3569,7 +3548,7 @@ readable-stream@^2.0.1, readable-stream@^2.1.4, readable-stream@^2.2.2: string_decoder "~1.0.3" util-deprecate "~1.0.1" -readable-stream@~2.1.4, readable-stream@~2.1.5: +readable-stream@~2.1.4: version "2.1.5" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.1.5.tgz#66fa8b720e1438b364681f2ad1a63c618448c9d0" dependencies: @@ -3878,10 +3857,6 @@ set-immediate-shim@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" -setimmediate@~1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -4233,10 +4208,6 @@ tr46@^1.0.0: dependencies: punycode "^2.1.0" -"traverse@>=0.3.0 <0.4": - version "0.3.9" - resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9" - trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" @@ -4294,20 +4265,6 @@ universalify@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.0.tgz#9eb1c4651debcc670cc94f1a75762332bb967778" -unzipper@^0.8.11: - version "0.8.11" - resolved "https://registry.yarnpkg.com/unzipper/-/unzipper-0.8.11.tgz#894383dc6b4bdab944e446f665a82d40d167fbd4" - dependencies: - big-integer "^1.6.17" - binary "~0.3.0" - bluebird "~3.4.1" - buffer-indexof-polyfill "~1.0.0" - duplexer2 "~0.1.4" - fstream "~1.0.10" - listenercount "~1.0.1" - readable-stream "~2.1.5" - setimmediate "~1.0.4" - url-parse-lax@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" @@ -4559,3 +4516,23 @@ yargs@~3.10.0: cliui "^2.1.0" decamelize "^1.0.0" window-size "0.1.0" + +yauzl-clone@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/yauzl-clone/-/yauzl-clone-1.0.3.tgz#155ff4a64a2f3b888c22346c1e54a05fb922d98a" + dependencies: + events-intercept "^2.0.0" + +yauzl-promise@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yauzl-promise/-/yauzl-promise-2.1.2.tgz#fb65e1e87720ebc04d4dddc83887c580bd2c2192" + dependencies: + yauzl "^2.9.1" + yauzl-clone "^1.0.2" + +yauzl@^2.9.1: + version "2.9.1" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.9.1.tgz#a81981ea70a57946133883f029c5821a89359a7f" + dependencies: + buffer-crc32 "~0.2.3" + fd-slicer "~1.0.1"