Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions jest/setupUnitTests.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
jest.mock('@react-native-community/cli-tools', () => {
return {
...jest.requireActual('@react-native-community/cli-tools'),
fetch: jest.fn(),
logger: {
success: jest.fn(),
info: jest.fn(),
Expand Down
3 changes: 0 additions & 3 deletions packages/cli/src/commands/init/__tests__/templateName.test.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
// @flow
import {processTemplateName} from '../templateName';
import {fetch} from '../../../tools/fetch';

jest.mock('../../../tools/fetch', () => ({fetch: jest.fn()}));

const RN_NPM_PACKAGE = 'react-native';
const ABS_RN_PATH = '/path/to/react-native';
Expand Down
2 changes: 0 additions & 2 deletions packages/cli/src/commands/init/templateName.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
// @flow
import path from 'path';
import {URL} from 'url';
import {fetch} from '../../tools/fetch';

const FILE_PROTOCOL = /file:/;
const HTTP_PROTOCOL = /https?:/;
const TARBALL = /\.tgz$/;
const VERSION_POSTFIX = /(.*)(-\d+\.\d+\.\d+)/;
const VERSIONED_PACKAGE = /(@?.+)(@)(.+)/;
Expand Down
23 changes: 12 additions & 11 deletions packages/cli/src/commands/upgrade/__tests__/upgrade.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import fs from 'fs';
import snapshotDiff from 'snapshot-diff';
import stripAnsi from 'strip-ansi';
import upgrade from '../upgrade';
import {fetch} from '../../../tools/fetch';
import logger from '../../../tools/logger';
import {fetch, logger} from '@react-native-community/cli-tools';
import loadConfig from '../../../tools/config';
import merge from '../../../tools/merge';

Expand Down Expand Up @@ -43,11 +42,9 @@ jest.mock('../../../tools/packageManager', () => ({
mockPushLog('$ yarn add', ...args);
},
}));
jest.mock('../../../tools/fetch', () => ({
fetch: jest.fn(() => Promise.resolve('patch')),
}));
jest.mock('@react-native-community/cli-tools', () => ({
...jest.requireActual('@react-native-community/cli-tools'),
fetch: jest.fn(),
logger: {
info: jest.fn((...args) => mockPushLog('info', args)),
error: jest.fn((...args) => mockPushLog('error', args)),
Expand All @@ -58,6 +55,10 @@ jest.mock('@react-native-community/cli-tools', () => ({
},
}));

const mockFetch = (value = '', status = 200) => {
(fetch: any).mockImplementation(() => Promise.resolve({data: value, status}));
};

const mockExecaDefault = (command, args) => {
mockPushLog('$', 'execa', command, args);
if (command === 'npm' && args[3] === '--json') {
Expand Down Expand Up @@ -121,7 +122,7 @@ test('uses latest version of react-native when none passed', async () => {
}, 60000);

test('applies patch in current working directory when nested', async () => {
(fetch: any).mockImplementation(() => Promise.resolve(samplePatch));
mockFetch(samplePatch, 200);
(execa: any).mockImplementation(mockExecaNested);
const config = {...ctx, root: '/project/root/NestedApp'};
await upgrade.func([newVersion], config, opts);
Expand Down Expand Up @@ -162,7 +163,7 @@ test('warns when dependency upgrade version is in semver range', async () => {
}, 60000);

test('fetches empty patch and installs deps', async () => {
(fetch: any).mockImplementation(() => Promise.resolve(''));
mockFetch();
await upgrade.func([newVersion], ctx, opts);
expect(flushOutput()).toMatchInlineSnapshot(`
"info Fetching diff between v0.57.8 and v0.58.4...
Expand All @@ -178,7 +179,7 @@ test('fetches empty patch and installs deps', async () => {
}, 60000);

test('fetches regular patch, adds remote, applies patch, installs deps, removes remote,', async () => {
(fetch: any).mockImplementation(() => Promise.resolve(samplePatch));
mockFetch(samplePatch, 200);
await upgrade.func(
[newVersion],
merge(ctx, {
Expand Down Expand Up @@ -217,7 +218,7 @@ test('fetches regular patch, adds remote, applies patch, installs deps, removes
);
}, 60000);
test('fetches regular patch, adds remote, applies patch, installs deps, removes remote when updated from nested directory', async () => {
(fetch: any).mockImplementation(() => Promise.resolve(samplePatch));
mockFetch(samplePatch, 200);
(execa: any).mockImplementation(mockExecaNested);
const config = {...ctx, root: '/project/root/NestedApp'};
await upgrade.func([newVersion], config, opts);
Expand All @@ -242,7 +243,7 @@ test('fetches regular patch, adds remote, applies patch, installs deps, removes
`);
}, 60000);
test('cleans up if patching fails,', async () => {
(fetch: any).mockImplementation(() => Promise.resolve(samplePatch));
mockFetch(samplePatch, 200);
(execa: any).mockImplementation((command, args) => {
mockPushLog('$', 'execa', command, args);
if (command === 'npm' && args[3] === '--json') {
Expand Down Expand Up @@ -296,7 +297,7 @@ test('cleans up if patching fails,', async () => {
`);
}, 60000);
test('works with --name-ios and --name-android', async () => {
(fetch: any).mockImplementation(() => Promise.resolve(samplePatch));
mockFetch(samplePatch, 200);
await upgrade.func(
[newVersion],
merge(ctx, {
Expand Down
10 changes: 7 additions & 3 deletions packages/cli/src/commands/upgrade/upgrade.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ import chalk from 'chalk';
import semver from 'semver';
import execa from 'execa';
import type {ConfigT} from 'types';
import {logger, CLIError} from '@react-native-community/cli-tools';
import {logger, CLIError, fetch} from '@react-native-community/cli-tools';
import * as PackageManager from '../../tools/packageManager';
import {fetch} from '../../tools/fetch';
import legacyUpgrade from './legacyUpgrade';

type FlagsT = {
Expand Down Expand Up @@ -46,8 +45,13 @@ const getPatch = async (currentVersion, newVersion, config) => {
logger.info(`Fetching diff between v${currentVersion} and v${newVersion}...`);

try {
patch = await fetch(`${rawDiffUrl}/${currentVersion}..${newVersion}.diff`);
const {data} = await fetch(
`${rawDiffUrl}/${currentVersion}..${newVersion}.diff`,
);

patch = data;
} catch (error) {
logger.error(error.message);
logger.error(
`Failed to fetch diff for react-native@${newVersion}. Maybe it's not released yet?`,
);
Expand Down
17 changes: 0 additions & 17 deletions packages/cli/src/tools/fetch.js

This file was deleted.

47 changes: 13 additions & 34 deletions packages/cli/src/tools/releaseChecker/getLatestRelease.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
/**
* @flow
*/
import https from 'https';
import semver from 'semver';
import logger from '../logger';
import cacheManager from './releaseCacheManager';
import {fetch} from '@react-native-community/cli-tools';

export type Release = {
version: string,
Expand Down Expand Up @@ -71,8 +71,6 @@ function buildChangelogUrl(version: string) {
*/
async function getLatestRnDiffPurgeVersion(name: string, eTag: ?string) {
const options = {
hostname: 'api.github.com',
path: '/repos/react-native-community/rn-diff-purge/tags',
// https://developer.github.com/v3/#user-agent-required
headers: ({'User-Agent': 'React-Native-CLI'}: Headers),
};
Expand All @@ -81,24 +79,30 @@ async function getLatestRnDiffPurgeVersion(name: string, eTag: ?string) {
options.headers['If-None-Match'] = eTag;
}

const response = await httpsGet(options);
const {data, status, headers} = await fetch(
'https://api.github.com/repos/react-native-community/rn-diff-purge/tags',
options,
);

// Remote is newer.
if (response.statusCode === 200) {
const latestVersion = JSON.parse(response.body)[0].name.substring(8);
if (status === 200) {
const body: Array<any> = data;
const latestVersion = body[0].name.substring(8);

// Update cache only if newer release is stable.
if (!semver.prerelease(latestVersion)) {
logger.debug(`Saving ${response.eTag} to cache`);
cacheManager.set(name, 'eTag', response.eTag);
const eTagHeader = headers.get('eTag');

logger.debug(`Saving ${eTagHeader} to cache`);
cacheManager.set(name, 'eTag', eTagHeader);
cacheManager.set(name, 'latestVersion', latestVersion);
}

return latestVersion;
}

// Cache is still valid.
if (response.statusCode === 304) {
if (status === 304) {
const latestVersion = cacheManager.get(name, 'latestVersion');
if (latestVersion) {
return latestVersion;
Expand All @@ -113,28 +117,3 @@ type Headers = {
'User-Agent': mixed,
[header: string]: mixed,
};

function httpsGet(options) {
return new Promise((resolve, reject) => {
https
.get(options, result => {
let body = '';

result.setEncoding('utf8');
result.on('data', data => {
body += data;
});

result.on('end', () => {
resolve({
body,
eTag: result.headers.etag,
statusCode: result.statusCode,
});
});

result.on('error', error => reject(error));
})
.on('error', error => reject(error));
});
}
37 changes: 37 additions & 0 deletions packages/tools/src/fetch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import nodeFetch, {
RequestInit as FetchOptions,
Response,
Request,
Headers,
} from 'node-fetch';
import {CLIError} from './errors';

async function unwrapFetchResult(response: Response) {
const data = await response.text();

try {
return JSON.parse(data);
} catch (e) {
return data;
}
}

export default async function fetch(
url: string | Request,
options?: FetchOptions,
): Promise<{status: number, data: any, headers: Headers}> {
const result = await nodeFetch(url, options);
const data = await unwrapFetchResult(result);

if (result.status >= 400) {
throw new CLIError(
`Fetch request failed with status ${result.status}: ${data}.`,
);
}

return {
status: result.status,
headers: result.headers,
data,
};
}
1 change: 1 addition & 0 deletions packages/tools/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ export {default as logger} from './logger';
export {default as groupFilesByType} from './groupFilesByType';
export {default as isPackagerRunning} from './isPackagerRunning';
export {default as getDefaultUserTerminal} from './getDefaultUserTerminal';
export {default as fetch} from './fetch';

export * from './errors';
7 changes: 3 additions & 4 deletions packages/tools/src/isPackagerRunning.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*
*/

import fetch from 'node-fetch';
import fetch from './fetch';

/**
* Indicates whether or not the packager is running. It returns a promise that
Expand All @@ -19,10 +19,9 @@ async function isPackagerRunning(
packagerPort: string = process.env.RCT_METRO_PORT || '8081',
): Promise<'running' | 'not_running' | 'unrecognized'> {
try {
const result = await fetch(`http://localhost:${packagerPort}/status`);
const body = await result.text();
const {data} = await fetch(`http://localhost:${packagerPort}/status`);

return body === 'packager-status:running' ? 'running' : 'unrecognized';
return data === 'packager-status:running' ? 'running' : 'unrecognized';
} catch (_error) {
return 'not_running';
}
Expand Down