Skip to content

Commit 7801ea8

Browse files
committed
refactor: upgrade command links to upgrade-helper
The upgrade helper has a high failure rate. Linking the user to the upgrade helper is the best way to deprecate this feature.
1 parent 6e9a441 commit 7801ea8

File tree

12 files changed

+115
-1290
lines changed

12 files changed

+115
-1290
lines changed

packages/cli-doctor/src/commands/__tests__/info.test.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@ import info from '../info';
22
import {logger} from '@react-native-community/cli-tools';
33
import loadConfig from '@react-native-community/cli-config';
44

5-
jest.mock('@react-native-community/cli-config');
5+
jest.mock('@react-native-community/cli-config', () => ({
6+
__esModule: true,
7+
default: () => ({
8+
project: {},
9+
root: '.',
10+
}),
11+
}));
612

713
beforeEach(() => {
814
jest.resetAllMocks();

packages/cli-tools/src/releaseChecker/getLatestRelease.ts

Lines changed: 61 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,38 @@ import {fetch} from '../fetch';
44
import logger from '../logger';
55

66
export type Release = {
7-
version: string;
7+
// The current stable release
8+
stable: string;
9+
// The current candidate release. These are only populated if the latest release is a candidate release.
10+
candidate?: string;
811
changelogUrl: string;
912
diffUrl: string;
1013
};
1114

15+
interface DiffPurge {
16+
name: string;
17+
zipball_url: string;
18+
tarball_url: string;
19+
commit: {
20+
sha: string;
21+
url: string;
22+
};
23+
node_id: string;
24+
}
25+
26+
function isDiffPurgeEntry(data: any): data is DiffPurge {
27+
return (
28+
[
29+
data.name,
30+
data.zipball_url,
31+
data.tarball_url,
32+
data.commit?.sha,
33+
data.commit?.url,
34+
data.node_id,
35+
].indexOf(false) === -1
36+
);
37+
}
38+
1239
/**
1340
* Checks via GitHub API if there is a newer stable React Native release and,
1441
* if it exists, returns the release data.
@@ -49,17 +76,15 @@ export default async function getLatestRelease(
4976

5077
logger.debug('Checking for newer releases on GitHub');
5178
const eTag = cacheManager.get(name, 'eTag');
52-
const latestVersion = await getLatestRnDiffPurgeVersion(name, eTag);
53-
logger.debug(`Latest release: ${latestVersion}`);
79+
const {stable, candidate} = await getLatestRnDiffPurgeVersion(name, eTag);
80+
logger.debug(`Latest release: ${stable} (${candidate})`);
5481

55-
if (
56-
semver.compare(latestVersion, currentVersion) === 1 &&
57-
!semver.prerelease(latestVersion)
58-
) {
82+
if (semver.compare(stable, currentVersion) >= 0) {
5983
return {
60-
version: latestVersion,
61-
changelogUrl: buildChangelogUrl(latestVersion),
62-
diffUrl: buildDiffUrl(currentVersion),
84+
stable,
85+
candidate,
86+
changelogUrl: buildChangelogUrl(stable),
87+
diffUrl: buildDiffUrl(stable),
6388
};
6489
}
6590
} catch (e) {
@@ -79,13 +104,18 @@ function buildDiffUrl(version: string) {
79104
return `https://react-native-community.github.io/upgrade-helper/?from=${version}`;
80105
}
81106

107+
type LatestVersions = {
108+
candidate?: string;
109+
stable: string;
110+
};
111+
82112
/**
83113
* Returns the most recent React Native version available to upgrade to.
84114
*/
85115
async function getLatestRnDiffPurgeVersion(
86116
name: string,
87117
eTag?: string,
88-
): Promise<string> {
118+
): Promise<LatestVersions> {
89119
const options = {
90120
// https://developer.github.com/v3/#user-agent-required
91121
headers: {'User-Agent': 'React-Native-CLI'} as Headers,
@@ -100,32 +130,38 @@ async function getLatestRnDiffPurgeVersion(
100130
options,
101131
);
102132

133+
const result: LatestVersions = {stable: '0.0.0'};
134+
103135
// Remote is newer.
104136
if (status === 200) {
105-
const body: Array<any> = data;
106-
const latestVersion = body[0].name.substring(8);
137+
const body: DiffPurge[] = data.filter(isDiffPurgeEntry);
107138
const eTagHeader = headers.get('eTag');
108139

109-
// Update cache only if newer release is stable.
110-
if (!semver.prerelease(latestVersion) && eTagHeader) {
111-
logger.debug(`Saving ${eTagHeader} to cache`);
112-
cacheManager.set(name, 'eTag', eTagHeader);
113-
cacheManager.set(name, 'latestVersion', latestVersion);
140+
for (let {name: version} of body) {
141+
if (!result.candidate && version.includes('-rc')) {
142+
result.candidate = version.substring(8);
143+
continue;
144+
}
145+
if (!version.includes('-rc')) {
146+
result.stable = version.substring(8);
147+
if (eTagHeader) {
148+
logger.debug(`Saving ${eTagHeader} to cache`);
149+
cacheManager.set(name, 'eTag', eTagHeader);
150+
cacheManager.set(name, 'latestVersion', result.stable);
151+
}
152+
return result;
153+
}
114154
}
115-
116-
return latestVersion;
155+
return result;
117156
}
118157

119158
// Cache is still valid.
120159
if (status === 304) {
121-
const latestVersion = cacheManager.get(name, 'latestVersion');
122-
if (latestVersion) {
123-
return latestVersion;
124-
}
160+
result.stable = cacheManager.get(name, 'latestVersion') ?? result.stable;
125161
}
126162

127163
// Should be returned only if something went wrong.
128-
return '0.0.0';
164+
return result;
129165
}
130166

131167
type Headers = {

packages/cli-tools/src/releaseChecker/index.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,21 @@ const getReactNativeVersion = (projectRoot: string): string | undefined =>
1717
* Logs out a message if the user's version is behind a stable version of React Native
1818
*/
1919
export async function logIfUpdateAvailable(projectRoot: string): Promise<void> {
20-
const hasUpdate = await latest(projectRoot);
21-
if (hasUpdate) {
22-
printNewRelease(hasUpdate.name, hasUpdate.upgrade, hasUpdate.current);
20+
const versions = await latest(projectRoot);
21+
if (!versions?.upgrade) {
22+
return;
23+
}
24+
if (semver.gt(versions.upgrade.stable, versions.current)) {
25+
printNewRelease(versions.name, versions.upgrade, versions.current);
2326
}
2427
}
2528

2629
type Update = {
27-
upgrade: Release;
30+
// Only populated if an upgrade is available
31+
upgrade?: Release;
32+
// The project's package's current version
2833
current: string;
34+
// The project's package's name
2935
name: string;
3036
};
3137

@@ -39,13 +45,13 @@ export async function latest(projectRoot: string): Promise<Update | undefined> {
3945
return;
4046
}
4147
const {name} = require(path.join(projectRoot, 'package.json'));
42-
const latestRelease = await getLatestRelease(name, currentVersion);
48+
const upgrade = await getLatestRelease(name, currentVersion);
4349

44-
if (latestRelease) {
50+
if (upgrade) {
4551
return {
4652
name,
4753
current: currentVersion,
48-
upgrade: latestRelease,
54+
upgrade,
4955
};
5056
}
5157
} catch (e) {
@@ -57,7 +63,7 @@ export async function latest(projectRoot: string): Promise<Update | undefined> {
5763
);
5864
logger.debug(e as any);
5965
}
60-
return undefined;
66+
return;
6167
}
6268

6369
/**

packages/cli-tools/src/releaseChecker/printNewRelease.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export default function printNewRelease(
1515
currentVersion: string,
1616
) {
1717
logger.info(
18-
`React Native v${latestRelease.version} is now available (your project is running on v${currentVersion}).`,
18+
`React Native v${latestRelease.stable} is now available (your project is running on v${currentVersion}).`,
1919
);
2020
logger.info(`Changelog: ${chalk.dim.underline(latestRelease.changelogUrl)}`);
2121
logger.info(`Diff: ${chalk.dim.underline(latestRelease.diffUrl)}`);

packages/cli/src/commands/upgrade/__mocks__/@react-native-community/cli-config.ts

Lines changed: 0 additions & 17 deletions
This file was deleted.

packages/cli/src/commands/upgrade/__tests__/__snapshots__/upgrade-tv.test.ts.snap

Lines changed: 0 additions & 167 deletions
This file was deleted.

0 commit comments

Comments
 (0)