Skip to content

Commit 9fb2cc3

Browse files
author
Murat Mehmet
committed
feat: check for update before each run
fix #137
1 parent 97ff859 commit 9fb2cc3

File tree

5 files changed

+295
-0
lines changed

5 files changed

+295
-0
lines changed

integrate-lock.json

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
{
2+
"lockfileVersion": 1,
3+
"packages": {
4+
"@clack/prompts": {
5+
"version": "^0.10.0",
6+
"integrated": false
7+
},
8+
"@ryansonshine/commitizen": {
9+
"version": "^4.2.8",
10+
"integrated": false
11+
},
12+
"@ryansonshine/cz-conventional-changelog": {
13+
"version": "^3.3.4",
14+
"integrated": false
15+
},
16+
"@types/jest": {
17+
"version": "^29.5.14",
18+
"integrated": false
19+
},
20+
"@types/lodash.get": {
21+
"version": "^4.4.9",
22+
"integrated": false
23+
},
24+
"@types/lodash.mergewith": {
25+
"version": "^4.6.9",
26+
"integrated": false
27+
},
28+
"@types/lodash.set": {
29+
"version": "^4.3.9",
30+
"integrated": false
31+
},
32+
"@types/node": {
33+
"version": "^22.13.4",
34+
"integrated": false
35+
},
36+
"@types/prettier": {
37+
"version": "^3.0.0",
38+
"integrated": false
39+
},
40+
"@types/semver": {
41+
"version": "^7.5.8",
42+
"integrated": false
43+
},
44+
"@types/xml2js": {
45+
"version": "^0.4.14",
46+
"integrated": false
47+
},
48+
"@typescript-eslint/eslint-plugin": {
49+
"version": "^8.24.1",
50+
"integrated": false
51+
},
52+
"@typescript-eslint/parser": {
53+
"version": "^8.24.1",
54+
"integrated": false
55+
},
56+
"ajv": {
57+
"version": "^8.17.1",
58+
"integrated": false
59+
},
60+
"chalk": {
61+
"version": "^5.4.1",
62+
"integrated": false
63+
},
64+
"commander": {
65+
"version": "^13.1.0",
66+
"integrated": false
67+
},
68+
"conventional-changelog-conventionalcommits": {
69+
"version": "^8.0.0",
70+
"integrated": false
71+
},
72+
"cpy-cli": {
73+
"version": "^5.0.0",
74+
"integrated": false
75+
},
76+
"eslint": {
77+
"version": "^8.57.0",
78+
"integrated": false
79+
},
80+
"eslint-config-prettier": {
81+
"version": "^10.0.1",
82+
"integrated": false
83+
},
84+
"eslint-plugin-node": {
85+
"version": "^11.1.0",
86+
"integrated": false
87+
},
88+
"eslint-plugin-prettier": {
89+
"version": "^5.2.3",
90+
"integrated": false
91+
},
92+
"execa": {
93+
"version": "^9",
94+
"integrated": false
95+
},
96+
"glob": {
97+
"version": "^11.0.1",
98+
"integrated": false
99+
},
100+
"husky": {
101+
"version": "^9.1.7",
102+
"integrated": false
103+
},
104+
"isomorphic-fetch": {
105+
"version": "^3.0.0",
106+
"integrated": false
107+
},
108+
"jest": {
109+
"version": "^29.7.0",
110+
"integrated": false
111+
},
112+
"lint-staged": {
113+
"version": "^15.4.3",
114+
"integrated": false
115+
},
116+
"lodash.get": {
117+
"version": "^4.4.2",
118+
"integrated": false
119+
},
120+
"lodash.mergewith": {
121+
"version": "^4.6.2",
122+
"integrated": false
123+
},
124+
"lodash.set": {
125+
"version": "^4.3.2",
126+
"integrated": false
127+
},
128+
"picocolors": {
129+
"version": "^1.1.1",
130+
"integrated": false
131+
},
132+
"prettier": {
133+
"version": "^3.5.1",
134+
"integrated": false
135+
},
136+
"prettier-2": {
137+
"version": "npm:prettier@^2",
138+
"integrated": false
139+
},
140+
"semantic-release": {
141+
"version": "^24.2.3",
142+
"integrated": false
143+
},
144+
"semver": {
145+
"version": "^7.7.1",
146+
"integrated": false
147+
},
148+
"simple-plist": {
149+
"version": "^1.3.1",
150+
"integrated": false
151+
},
152+
"ts-jest": {
153+
"version": "^29.2.5",
154+
"integrated": false
155+
},
156+
"ts-node": {
157+
"version": "^10.9.2",
158+
"integrated": false
159+
},
160+
"typescript": {
161+
"version": "^5.7.3",
162+
"integrated": false
163+
},
164+
"typescript-json-schema": {
165+
"version": "^0.65.1",
166+
"integrated": false
167+
},
168+
"xcode": {
169+
"version": "^3.0.1",
170+
"integrated": false
171+
},
172+
"xml2js": {
173+
"version": "^0.6.2",
174+
"integrated": false
175+
},
176+
"yaml": {
177+
"version": "^2.7.0",
178+
"integrated": false
179+
}
180+
}
181+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { checkForUpdate } from '../../../utils/checkForUpdate';
2+
import { logWarning } from '../../../prompter';
3+
import { runCommand } from '../../../utils/runCommand';
4+
5+
// Mock dependencies
6+
jest.mock('../../../prompter');
7+
jest.mock('../../../utils/runCommand');
8+
jest.mock('../../../../package.json', () => ({
9+
version: '1.0.0',
10+
name: 'react-native-integrate',
11+
}));
12+
13+
describe('checkForUpdate', () => {
14+
beforeEach(() => {
15+
jest.clearAllMocks();
16+
});
17+
18+
it('should show warning when newer version is available', async () => {
19+
// Mock runCommand to return a newer version
20+
(runCommand as jest.Mock).mockResolvedValue({
21+
output: '1.1.0',
22+
exitCode: 0,
23+
});
24+
25+
await checkForUpdate();
26+
27+
expect(runCommand).toHaveBeenCalledWith(
28+
'npm view react-native-integrate version',
29+
{ silent: true }
30+
);
31+
expect(logWarning).toHaveBeenCalledWith(
32+
expect.stringContaining('new version')
33+
);
34+
});
35+
36+
it('should not show warning when current version is latest', async () => {
37+
// Mock runCommand to return same version
38+
(runCommand as jest.Mock).mockResolvedValue({
39+
output: '1.0.0',
40+
exitCode: 0,
41+
});
42+
43+
await checkForUpdate();
44+
45+
expect(runCommand).toHaveBeenCalledWith(
46+
'npm view react-native-integrate version',
47+
{ silent: true }
48+
);
49+
expect(logWarning).not.toHaveBeenCalled();
50+
});
51+
52+
it('should not show warning when npm command fails', async () => {
53+
// Mock runCommand to throw error
54+
(runCommand as jest.Mock).mockRejectedValue(new Error('npm error'));
55+
56+
await checkForUpdate();
57+
58+
expect(runCommand).toHaveBeenCalledWith(
59+
'npm view react-native-integrate version',
60+
{ silent: true }
61+
);
62+
expect(logWarning).not.toHaveBeenCalled();
63+
});
64+
65+
it('should not check for updates when version is not defined in package.json', async () => {
66+
// Mock package.json without version
67+
jest.resetModules();
68+
jest.mock('../../../../package.json', () => ({
69+
name: 'react-native-integrate',
70+
}));
71+
72+
await checkForUpdate();
73+
74+
expect(runCommand).not.toHaveBeenCalled();
75+
expect(logWarning).not.toHaveBeenCalled();
76+
});
77+
});

src/integrate.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { AnalyzedPackages, LockProjectData } from './types/integrator.types';
1414
import { IntegrationConfig, PackageWithConfig } from './types/mod.types';
1515
import { analyzePackages } from './utils/analyzePackages';
1616
import { checkCondition } from './utils/checkCondition';
17+
import { checkForUpdate } from './utils/checkForUpdate';
1718
import { getErrMessage } from './utils/getErrMessage';
1819
import {
1920
getIntegrateConfig,
@@ -30,6 +31,7 @@ import { updateIntegrationStatus } from './utils/updateIntegrationStatus';
3031
import { getText, transformTextInObject, variables } from './variables';
3132

3233
export async function integrate(packageName?: string): Promise<void> {
34+
await checkForUpdate();
3335
startSpinner('analyzing packages');
3436
const analyzedPackages = analyzePackages(packageName);
3537
const { deletedPackages, installedPackages, integratedPackages } =

src/upgrade.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { LockProjectData } from './types/integrator.types';
1717
import { IntegrationConfig, PackageWithConfig } from './types/mod.types';
1818
import { analyzePackages } from './utils/analyzePackages';
1919
import { checkCondition } from './utils/checkCondition';
20+
import { checkForUpdate } from './utils/checkForUpdate';
2021
import { getErrMessage } from './utils/getErrMessage';
2122
import { getPackageConfig } from './utils/getPackageConfig';
2223
import { getProjectPath } from './utils/getProjectPath';
@@ -36,6 +37,7 @@ import { validateOldProjectPath } from './utils/upgrade/validateOldProjectPath';
3637
import { getText, transformTextInObject, variables } from './variables';
3738

3839
export async function upgrade(): Promise<void> {
40+
await checkForUpdate();
3941
let stage = 1;
4042
const isManual = options.get().manual;
4143
if (!isManual) {

src/utils/checkForUpdate.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import color from 'picocolors';
2+
import semver from 'semver/preload';
3+
import { logWarning } from '../prompter';
4+
import { PackageJsonType } from '../types/mod.types';
5+
import { runCommand } from './runCommand';
6+
7+
export async function checkForUpdate(): Promise<void> {
8+
try {
9+
const {
10+
version: currentVersion,
11+
name,
12+
// eslint-disable-next-line @typescript-eslint/no-require-imports
13+
}: PackageJsonType = require('../../package.json');
14+
15+
if (!currentVersion) return;
16+
17+
let { output: latestVersion } = await runCommand(
18+
`npm view ${name} version`,
19+
{ silent: true }
20+
);
21+
latestVersion = latestVersion.trim();
22+
23+
if (semver.gt(latestVersion, currentVersion)) {
24+
logWarning(
25+
'A new version is available! ' +
26+
`Current: ${color.gray(currentVersion)} | Latest: ${color.green(latestVersion)}\n` +
27+
`${color.yellow('Run')} ${color.blue(`npm install -g ${name}@latest`)} to update.`
28+
);
29+
}
30+
} catch (_error) {
31+
/* empty */
32+
}
33+
}

0 commit comments

Comments
 (0)