diff --git a/.circleci/config.yml b/.circleci/config.yml index 02f79c2c0..bc60f04b0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -110,6 +110,14 @@ jobs: - run: name: Test End-to-End command: yarn run test:e2e + test_e2e_cli: + <<: *defaults + executor: node_latest + steps: + - restore_repo + - run: + name: Test End-to-End ClI + command: yarn run test:e2e:cli coverage: <<: *defaults @@ -149,7 +157,15 @@ workflows: - test_node_lts_10 - test_node_lts_12 <<: *ignore_non_dev_branches + - test_e2e_cli: + requires: + - prepare + - test_node_latest + - test_node_lts_10 + - test_node_lts_12 + <<: *ignore_non_dev_branches - coverage: requires: - test_e2e + - test_e2e_cli <<: *ignore_non_dev_branches diff --git a/.eslintrc b/.eslintrc index a7443349a..881e7792c 100644 --- a/.eslintrc +++ b/.eslintrc @@ -3,10 +3,10 @@ "@verdaccio" ], "rules": { - "@typescript-eslint/no-var-requires": ["warn"], + "@typescript-eslint/no-var-requires": 0, "@typescript-eslint/ban-ts-ignore": 0, - "@typescript-eslint/no-inferrable-types": ["warn"], - "@typescript-eslint/no-empty-function": ["warn"], + "@typescript-eslint/no-inferrable-types": 0, + "@typescript-eslint/no-empty-function": 0, "@typescript-eslint/no-this-alias": ["warn"], "@typescript-eslint/no-use-before-define": 0, "@typescript-eslint/array-type": ["warn"], diff --git a/package.json b/package.json index c223372c8..0a5123ea9 100644 --- a/package.json +++ b/package.json @@ -78,6 +78,7 @@ "cross-env": "6.0.3", "detect-secrets": "1.0.5", "eslint": "5.16.0", + "fs-extra": "8.1.0", "get-stdin": "7.0.0", "husky": "2.7.0", "in-publish": "2.0.0", @@ -92,6 +93,7 @@ "standard-version": "7.0.0", "supertest": "4.0.2", "typescript": "3.7.1-rc", + "verdaccio": "latest", "verdaccio-auth-memory": "8.3.0", "verdaccio-memory": "8.2.0" }, @@ -116,8 +118,9 @@ "test:clean": "npx jest --clearCache", "test:unit": "cross-env NODE_ENV=test BABEL_ENV=test TZ=UTC FORCE_COLOR=1 jest --config ./jest.config.js --maxWorkers 2 --passWithNoTests", "test:functional": "cross-env NODE_ENV=test jest --config ./test/jest.config.functional.js --testPathPattern ./test/functional/index* --passWithNoTests", + "test:e2e:cli": "cross-env NODE_ENV=test jest --config ./test/e2e-cli/jest.config.e2e.cli.js --passWithNoTests", "test:e2e": "cross-env BABEL_ENV=test jest --config ./test/jest.config.e2e.js", - "test:all": "npm run test && npm run test:functional && npm run test:e2e", + "test:all": "npm run test && npm run test:functional && npm run test:e2e & npm run test:e2e:pkg", "pre:ci": "npm run lint", "coverage:publish": "codecov", "lint": "npm run type-check && npm run lint:ts && npm run lint:lockfile", diff --git a/test/.eslintrc b/test/.eslintrc index d462ff13f..b2c8bc5d2 100644 --- a/test/.eslintrc +++ b/test/.eslintrc @@ -24,6 +24,7 @@ } ], "no-useless-escape": 0, - "@typescript-eslint/explicit-function-return-type": 0 + "@typescript-eslint/explicit-function-return-type": 0, + "@typescript-eslint/no-empty-function": 0 } } diff --git a/test/e2e-cli/.eslintrc b/test/e2e-cli/.eslintrc new file mode 100644 index 000000000..cbfb89d2f --- /dev/null +++ b/test/e2e-cli/.eslintrc @@ -0,0 +1,6 @@ +{ + "rules": { + "@typescript-eslint/no-var-requires": 0, + "@typescript-eslint/explicit-member-accessibility": 0 + } +} diff --git a/test/e2e-cli/config/_bootstrap_verdaccio.yaml b/test/e2e-cli/config/_bootstrap_verdaccio.yaml new file mode 100644 index 000000000..50fe65d73 --- /dev/null +++ b/test/e2e-cli/config/_bootstrap_verdaccio.yaml @@ -0,0 +1,37 @@ +storage: ./storage + +#store: +# memory: +# limit: 1000 + +auth: + htpasswd: + file: ./htpasswd + max_users: -1 + +web: + enable: true + title: verdaccio-e2e-pkg + +uplinks: + npmjs: + url: https://registry.npmjs.org/ + +logs: + - { type: stdout, format: pretty, level: warn } + +packages: + '@*/*': + access: $all + publish: $anonymous + unpublish: $authenticated + proxy: npmjs + 'verdaccio': + access: $all + publish: $anonymous + '**': + access: $all + publish: $anonymous + unpublish: $authenticated + proxy: npmjs +_debug: true diff --git a/test/e2e-cli/config/default.yaml b/test/e2e-cli/config/default.yaml new file mode 100644 index 000000000..e107aea83 --- /dev/null +++ b/test/e2e-cli/config/default.yaml @@ -0,0 +1,35 @@ +storage: ./storage + +#store: +# memory: +# limit: 1000 + +auth: + htpasswd: + file: ./htpasswd + max_users: -1 + +web: + enable: true + title: verdaccio-default + +uplinks: + local: + url: http://localhost:4873 + +logs: + - { type: stdout, format: pretty, level: warn } + +packages: + '@*/*': + access: $all + publish: $anonymous + unpublish: $authenticated + proxy: local + '**': + access: $all + publish: $all + unpublish: $authenticated + proxy: local + +_debug: true diff --git a/test/e2e-cli/env_babel.js b/test/e2e-cli/env_babel.js new file mode 100644 index 000000000..eddce9aa3 --- /dev/null +++ b/test/e2e-cli/env_babel.js @@ -0,0 +1,4 @@ +require('@babel/register')({ + extensions: [".ts", ".js"] +}); +module.exports = require('./setup/test_environment'); diff --git a/test/e2e-cli/env_setup.js b/test/e2e-cli/env_setup.js new file mode 100644 index 000000000..222f7183e --- /dev/null +++ b/test/e2e-cli/env_setup.js @@ -0,0 +1,4 @@ +require('@babel/register')({ + extensions: [".ts", ".js"] +}); +module.exports = require('./setup/setup'); diff --git a/test/e2e-cli/env_teardown.js b/test/e2e-cli/env_teardown.js new file mode 100644 index 000000000..75165a7c7 --- /dev/null +++ b/test/e2e-cli/env_teardown.js @@ -0,0 +1,4 @@ +require('@babel/register')({ + extensions: [".ts", ".js"] +}); +module.exports = require('./setup/teardown'); diff --git a/test/e2e-cli/jest.config.e2e.cli.js b/test/e2e-cli/jest.config.e2e.cli.js new file mode 100644 index 000000000..5cec14386 --- /dev/null +++ b/test/e2e-cli/jest.config.e2e.cli.js @@ -0,0 +1,12 @@ +const { defaults } = require('jest-config'); + +module.exports = { + name: 'verdaccio-e2e-cli-jest', + verbose: true, + collectCoverage: false, + moduleFileExtensions: [...defaults.moduleFileExtensions, 'ts'], + testEnvironment: './env_babel.js', + globalSetup: './env_setup.js', + globalTeardown: './env_teardown.js', + testRegex: '(/test/e2e.*\\.spec)\\.ts' +}; diff --git a/test/e2e-cli/projects/basic/.npmignore b/test/e2e-cli/projects/basic/.npmignore new file mode 100644 index 000000000..e69de29bb diff --git a/test/e2e-cli/projects/basic/README.md b/test/e2e-cli/projects/basic/README.md new file mode 100644 index 000000000..80c7d1601 --- /dev/null +++ b/test/e2e-cli/projects/basic/README.md @@ -0,0 +1,3 @@ +# Simple project + +This is a normal readme diff --git a/test/e2e-cli/projects/basic/index.js b/test/e2e-cli/projects/basic/index.js new file mode 100644 index 000000000..474a5966c --- /dev/null +++ b/test/e2e-cli/projects/basic/index.js @@ -0,0 +1,6 @@ +module.exports = function() { + const message = "this is a basic project"; + console.log(message); + + return message; +}; diff --git a/test/e2e-cli/projects/basic/package.json b/test/e2e-cli/projects/basic/package.json new file mode 100644 index 000000000..59afd2e21 --- /dev/null +++ b/test/e2e-cli/projects/basic/package.json @@ -0,0 +1,18 @@ +{ + "name": "basic-verdaccio", + "version": "1.0.0", + "description": "this is a basic project", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [ + "verdaccio", + "sample" + ], + "dependencies": { + "verdaccio": "latest" + }, + "author": "Juan Picado ", + "license": "MIT" +} diff --git a/test/e2e-cli/projects/scoped_basic/.npmignore b/test/e2e-cli/projects/scoped_basic/.npmignore new file mode 100644 index 000000000..e69de29bb diff --git a/test/e2e-cli/projects/scoped_basic/README.md b/test/e2e-cli/projects/scoped_basic/README.md new file mode 100644 index 000000000..80c7d1601 --- /dev/null +++ b/test/e2e-cli/projects/scoped_basic/README.md @@ -0,0 +1,3 @@ +# Simple project + +This is a normal readme diff --git a/test/e2e-cli/projects/scoped_basic/index.js b/test/e2e-cli/projects/scoped_basic/index.js new file mode 100644 index 000000000..76e3f217a --- /dev/null +++ b/test/e2e-cli/projects/scoped_basic/index.js @@ -0,0 +1,6 @@ +module.exports = function() { + const message = "this is a scoped basic project"; + console.log(message); + + return message; +}; diff --git a/test/e2e-cli/projects/scoped_basic/package.json b/test/e2e-cli/projects/scoped_basic/package.json new file mode 100644 index 000000000..bfa5b01de --- /dev/null +++ b/test/e2e-cli/projects/scoped_basic/package.json @@ -0,0 +1,15 @@ +{ + "name": "@e2e-verdaccio/basic", + "version": "1.0.0", + "description": "this is a scoped basic project", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": ["verdaccio", "sample", "scoped"], + "dependencies": { + "verdaccio": "latest" + }, + "author": "Juan Picado ", + "license": "MIT" +} diff --git a/test/e2e-cli/setup/setup.ts b/test/e2e-cli/setup/setup.ts new file mode 100644 index 000000000..27ac7b771 --- /dev/null +++ b/test/e2e-cli/setup/setup.ts @@ -0,0 +1,30 @@ +import fs from "fs"; +import path from "path"; +import os from "os"; +import {yellow} from "kleur"; +import {spawn} from "child_process"; +import { npm } from '../utils/process'; +import * as __global from '../utils/global.js'; + +module.exports = async () => { + const tempRoot = fs.mkdtempSync(path.join(fs.realpathSync(os.tmpdir()), 'verdaccio-cli-e2e-')); + __global.addItem('dir-root', tempRoot); + console.log(yellow(`Add temp root folder: ${tempRoot}`)); + fs.copyFileSync( + path.join(__dirname, '../config/_bootstrap_verdaccio.yaml'), + path.join(tempRoot, 'verdaccio.yaml'), + ); + // @ts-ignore + global.__namespace = __global; + console.log(`current directory: ${process.cwd()}`); + // @ts-ignore + global.registryProcess = spawn( + 'node', + [require.resolve('verdaccio/bin/verdaccio'), '-c', './verdaccio.yaml'], + // @ts-ignore + { cwd: tempRoot, silence: true }, + ); + + // publish current build version on local registry + await npm('publish', '--registry' ,'http://localhost:4873'); +} diff --git a/test/e2e-cli/setup/teardown.ts b/test/e2e-cli/setup/teardown.ts new file mode 100644 index 000000000..346c5c595 --- /dev/null +++ b/test/e2e-cli/setup/teardown.ts @@ -0,0 +1,4 @@ +module.exports = async function() { + // @ts-ignore + global.registryProcess.kill(); +}; diff --git a/test/e2e-cli/setup/test_environment.ts b/test/e2e-cli/setup/test_environment.ts new file mode 100644 index 000000000..4ad640234 --- /dev/null +++ b/test/e2e-cli/setup/test_environment.ts @@ -0,0 +1,28 @@ +const fs = require('fs'); +import os from 'os'; +import path from 'path'; +import NodeEnvironment from 'jest-environment-node'; +const __global = require('../utils/global'); +// import { npm } from '../utils/process'; + + +class E2ECliTestEnvironment extends NodeEnvironment { + constructor(config) { + super(config) + } + + async setup() { + const tempRoot = fs.mkdtempSync(path.join(fs.realpathSync(os.tmpdir()), 'verdaccio-suite-test-')); + __global.addItem('dir-root', tempRoot); + this.global.__namespace = __global; + console.log(`current directory: ${process.cwd()}`); + } + + async teardown() {} + + runScript(script) { + return super.runScript(script); + } +} + +export default E2ECliTestEnvironment; diff --git a/test/e2e-cli/test/__partials/npm_commands.ts b/test/e2e-cli/test/__partials/npm_commands.ts new file mode 100644 index 000000000..9f5515ce4 --- /dev/null +++ b/test/e2e-cli/test/__partials/npm_commands.ts @@ -0,0 +1,5 @@ +import { silentNpm } from '../../utils/process'; + +export function installVerdaccio(verdaccioInstall) { + return silentNpm('install', '--prefix', verdaccioInstall, 'verdaccio', '--registry' ,'http://localhost:4873', '--no-package-lock'); +} diff --git a/test/e2e-cli/test/core/info.spec.ts b/test/e2e-cli/test/core/info.spec.ts new file mode 100644 index 000000000..d5fa8047a --- /dev/null +++ b/test/e2e-cli/test/core/info.spec.ts @@ -0,0 +1,29 @@ +import path from 'path'; +import {runVerdaccio} from '../../utils/process'; +import {installVerdaccio} from "../__partials/npm_commands"; + +describe('verdaccio info', ()=> { + jest.setTimeout(90000); + // @ts-ignore + const tempRootFolder = global.__namespace.getItem('dir-root'); + const verdaccioInstall = path.join(tempRootFolder, 'verdaccio-root-info'); + let registryProcess; + + beforeAll(async () => { + await installVerdaccio(verdaccioInstall); + }); + + + test('should run verdaccio info command', async () => { + const pathVerdaccioModule = require.resolve('verdaccio/bin/verdaccio', { + paths: [verdaccioInstall] + }); + const hasMatch = await runVerdaccio(pathVerdaccioModule, verdaccioInstall, ['--info'], /Environment/); + + expect(hasMatch.ok).toBeTruthy(); + }); + + afterAll(() => { + registryProcess.kill(); + }); +}); diff --git a/test/e2e-cli/test/core/listen.spec.ts b/test/e2e-cli/test/core/listen.spec.ts new file mode 100644 index 000000000..df92f546a --- /dev/null +++ b/test/e2e-cli/test/core/listen.spec.ts @@ -0,0 +1,41 @@ +import path from 'path'; +import fs from "fs"; +import {installVerdaccio} from "../__partials/npm_commands"; +import {spawnRegistry} from "../../utils/registry"; +import {callRegistry} from "../../utils/web"; + +describe('npm install', ()=> { + jest.setTimeout(90000); + const port = '9012'; + + // @ts-ignore + const tempRootFolder = global.__namespace.getItem('dir-root'); + const verdaccioInstall = path.join(tempRootFolder, 'verdaccio-root-install'); + let registryProcess; + const configPath = path.join(tempRootFolder, 'verdaccio.yaml'); + + beforeAll(async () => { + await installVerdaccio(verdaccioInstall); + fs.copyFileSync(path.join(__dirname, '../../config/default.yaml'), configPath); + }); + + test('should match the listing port and load metadata', async () => { + const pathVerdaccioModule = require.resolve('verdaccio/bin/verdaccio', { + paths: [verdaccioInstall] + }); + + registryProcess = await spawnRegistry(pathVerdaccioModule, + ['-c', configPath, '-l', port], + { cwd: verdaccioInstall, silent: true } + ); + + const body = await callRegistry(`http://localhost:${port}/verdaccio`); + const parsedBody = JSON.parse(body); + + expect(parsedBody.name).toEqual('verdaccio'); + }); + + afterAll(async () => { + registryProcess.kill(); + }); +}); diff --git a/test/e2e-cli/test/install/install.spec.ts b/test/e2e-cli/test/install/install.spec.ts new file mode 100644 index 000000000..72da34c68 --- /dev/null +++ b/test/e2e-cli/test/install/install.spec.ts @@ -0,0 +1,54 @@ +import path from 'path'; +import fs from "fs"; +import * as __global from "../../utils/global"; +import {spawnRegistry} from "../../utils/registry"; +import {execAndWaitForOutputToMatch} from '../../utils/process'; +import {installVerdaccio} from "../__partials/npm_commands"; +import {expectFileToExist} from "../../utils/expect"; + +describe('npm install', ()=> { + jest.setTimeout(90000); + const port = '9011'; + + // @ts-ignore + const tempRootFolder = global.__namespace.getItem('dir-root'); + const verdaccioInstall = path.join(tempRootFolder, 'verdaccio-root-install'); + let registryProcess; + + beforeAll(async () => { + await installVerdaccio(verdaccioInstall); + + const configPath = path.join(tempRootFolder, 'verdaccio.yaml'); + fs.copyFileSync(path.join(__dirname, '../../config/default.yaml'), configPath); + // @ts-ignore + global.__namespace = __global; + const pathVerdaccioModule = require.resolve('verdaccio/bin/verdaccio', { + paths: [verdaccioInstall] + }); + registryProcess = await spawnRegistry(pathVerdaccioModule, + ['-c', configPath, '-l', port], + { cwd: verdaccioInstall, silent: true } + ); + }); + + test('should match on npm info verdaccio', async () => { + // FIXME: not the best match, looking for a better way to match the terminal output + const output = await execAndWaitForOutputToMatch('npm', ['info', 'verdaccio', '--registry'], /A lightweight private npm proxy registry/); + + expect(output.ok).toBeTruthy(); + }); + + test('should install jquery', async () => { + const testCwd = path.join(tempRootFolder, '_jquery_'); + await execAndWaitForOutputToMatch('npm', ['install', '--prefix', testCwd, 'jquery', '--registry' ,`http://localhost:${port}`], /''/, { + cwd: verdaccioInstall + }); + + const exist = await expectFileToExist(path.join(testCwd, 'node_modules', 'jquery', 'package.json')); + expect(exist).toBeTruthy(); + }); + + afterAll(async () => { + registryProcess.kill(); + }); +}); diff --git a/test/e2e-cli/utils/expect.ts b/test/e2e-cli/utils/expect.ts new file mode 100644 index 000000000..e768caaba --- /dev/null +++ b/test/e2e-cli/utils/expect.ts @@ -0,0 +1,13 @@ +import * as fs from 'fs-extra'; + +export function expectFileToExist(fileName: string) { + return new Promise((resolve, reject) => { + fs.exists(fileName, (exist) => { + if (exist) { + resolve(exist); + } else { + reject(new Error(`File ${fileName} was expected to exist but not found...`)); + } + }); + }); +} diff --git a/test/e2e-cli/utils/global.js b/test/e2e-cli/utils/global.js new file mode 100644 index 000000000..fe593662c --- /dev/null +++ b/test/e2e-cli/utils/global.js @@ -0,0 +1,14 @@ +const namespace = Object.create(null); + +exports.addItem = function(name, value) { + namespace[name] = value; +} + +exports.getItem = function(name) { + console.log("get-item", name, namespace); + if (!(name in namespace)) { + throw new Error("The item ".concat(name, " does exist in the namespace")); + } + + return namespace[name]; +} diff --git a/test/e2e-cli/utils/process.ts b/test/e2e-cli/utils/process.ts new file mode 100644 index 000000000..6b50fce94 --- /dev/null +++ b/test/e2e-cli/utils/process.ts @@ -0,0 +1,97 @@ +import * as child_process from 'child_process'; +import {SpawnOptions} from "child_process"; + +export async function _exec(options, cmd, args) { + let stdout = ''; + let stderr = ''; + const flags = []; + const cwd = process.cwd(); + const env = options.env; + console.log(`Running \`${cmd} ${args.map(x => `"${x}"`).join(' ')}\`${flags}...`); + console.log(`CWD: ${cwd}`); + console.log(`ENV: ${JSON.stringify(env)}`); + const spawnOptions = { + cwd, + ...env ? { env } : {}, + }; + + if (process.platform.startsWith('win')) { + args.unshift('/c', cmd); + cmd = 'cmd.exe'; + spawnOptions['stdio'] = 'pipe'; + } + + + const childProcess = child_process.spawn(cmd, args, spawnOptions); + childProcess.stdout.on('data', (data) => { + stdout += data.toString('utf-8'); + if (options.silent) { + return; + } + + data.toString('utf-8') + .split(/[\n\r]+/) + .filter(line => line !== '') + .forEach(line => console.log(' ' + line)); + }); + + childProcess.stderr.on('data', (data) => { + stderr += data.toString('utf-8'); + if (options.silent) { + return; + } + + data.toString('utf-8') + .split(/[\n\r]+/) + .filter(line => line !== '') + .forEach(line => console.error((' ' + line))); + }); + + const err = new Error(`Running "${cmd} ${args.join(' ')}" returned error code `); + return new Promise((resolve, reject) => { + childProcess.on('exit', (error) => { + if (!error) { + resolve({ stdout, stderr }); + } else { + err.message += `${error}...\n\nSTDOUT:\n${stdout}\n\nSTDERR:\n${stderr}\n`; + reject(err); + } + }); + + if (options.waitForMatch) { + const match = options.waitForMatch; + childProcess.stdout.on('data', (data) => { + // console.log("-->data==>", data.toString(), data.toString().match(match)); + if (data.toString().match(match)) { + resolve({ok: true, stdout, stderr }); + } + }); + childProcess.stderr.on('data', (data) => { + if (data.toString().match(match)) { + resolve({ stdout, stderr }); + } + }); + } + }); +} + +export function execAndWaitForOutputToMatch( + cmd: string, + args: string[], + match: RegExp, + spawnOptions: SpawnOptions = {}): any { + return _exec({ waitForMatch: match, ...spawnOptions, silence: true }, cmd, args); +} + + +export function npm(...args) { + return _exec({}, 'npm', args); +} + +export function runVerdaccio(cmd, installation, args, match: RegExp): any { + return _exec({ cwd: installation, silent: true, waitForMatch: match }, cmd, args); +} + +export function silentNpm(...args) { + return _exec({silent: true}, 'npm', args); +} diff --git a/test/e2e-cli/utils/registry.ts b/test/e2e-cli/utils/registry.ts new file mode 100644 index 000000000..6595ce546 --- /dev/null +++ b/test/e2e-cli/utils/registry.ts @@ -0,0 +1,26 @@ +import {fork} from "child_process"; + +export function prepareEnvironment(rootFolder: string, folderName: string) { + +} + +export function spawnRegistry( + verdaccioPath: string, + args: string[], + childOptions) { + return new Promise((resolve, reject) => { + let _childOptions = {silent: true, ...childOptions}; + + const childFork = fork(verdaccioPath, args, _childOptions); + + childFork.on('message', (msg) => { + if ('verdaccio_started' in msg) { + resolve(childFork); + } + }); + + childFork.on('error', (err) => reject([err])); + childFork.on('disconnect', (err) => reject([err])); + childFork.on('exit', (err) => reject([err])); + }); +} diff --git a/test/e2e-cli/utils/utils.ts b/test/e2e-cli/utils/utils.ts new file mode 100644 index 000000000..6cc37b111 --- /dev/null +++ b/test/e2e-cli/utils/utils.ts @@ -0,0 +1,9 @@ +import path from "path"; +import fs from "fs"; + +export function copyConfigFile(rootFolder, configTemplate): string { + const configPath = path.join(rootFolder, 'verdaccio.yaml'); + fs.copyFileSync(path.join(__dirname, configTemplate), configPath); + + return configPath; +} diff --git a/test/e2e-cli/utils/web.ts b/test/e2e-cli/utils/web.ts new file mode 100644 index 000000000..e6d89f73a --- /dev/null +++ b/test/e2e-cli/utils/web.ts @@ -0,0 +1,23 @@ +import {IncomingMessage} from 'http'; +import request from 'request'; + + +export function callRegistry(url: string): Promise { + return new Promise((resolve, reject) => { + let options = { + url: url, + headers: { 'Accept': 'application/json' }, + }; + // @ts-ignore + request(options, (error: any, response: IncomingMessage, body: string) => { + if (error) { + reject(error); + // @ts-ignore + } else if (response.statusCode >= 400) { + reject(new Error(`Requesting "${url}" returned status code ${response.statusCode}.`)); + } else { + resolve(body); + } + }); + }); +} diff --git a/yarn.lock b/yarn.lock index adfd65069..8d16ca870 100644 Binary files a/yarn.lock and b/yarn.lock differ