react-native-update-cli 1.38.2 → 1.39.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/bundle.js CHANGED
@@ -134,6 +134,8 @@ async function runReactNativeBundleCommand(bundleName, development, entryFile, o
134
134
  });
135
135
  }
136
136
  }
137
+ const bundleParams = await (0, _utils.checkPlugins)();
138
+ const isSentry = bundleParams.sentry;
137
139
  const bundleCommand = usingExpo ? 'export:embed' : platform === 'harmony' ? 'bundle-harmony' : 'bundle';
138
140
  if (platform === 'harmony') {
139
141
  Array.prototype.push.apply(reactNativeBundleArgs, [
@@ -207,7 +209,7 @@ async function runReactNativeBundleCommand(bundleName, development, entryFile, o
207
209
  await copyHarmonyBundle(outputFolder);
208
210
  }
209
211
  if (hermesEnabled) {
210
- await compileHermesByteCode(bundleName, outputFolder, sourcemapOutput);
212
+ await compileHermesByteCode(bundleName, outputFolder, sourcemapOutput, !isSentry);
211
213
  }
212
214
  resolve(null);
213
215
  }
@@ -258,7 +260,7 @@ async function checkGradleConfig() {
258
260
  crunchPngs
259
261
  };
260
262
  }
261
- async function compileHermesByteCode(bundleName, outputFolder, sourcemapOutput) {
263
+ async function compileHermesByteCode(bundleName, outputFolder, sourcemapOutput, shouldCleanSourcemap) {
262
264
  console.log('Hermes enabled, now compiling to hermes bytecode:\n');
263
265
  // >= rn 0.69
264
266
  const rnDir = _nodepath.default.dirname(require.resolve('react-native', {
@@ -303,8 +305,79 @@ async function compileHermesByteCode(bundleName, outputFolder, sourcemapOutput)
303
305
  stdio: 'ignore'
304
306
  });
305
307
  }
308
+ if (shouldCleanSourcemap) {
309
+ _fsextra.removeSync(_nodepath.default.join(outputFolder, `${bundleName}.txt.map`));
310
+ }
311
+ }
312
+ async function copyDebugidForSentry(bundleName, outputFolder, sourcemapOutput) {
313
+ if (sourcemapOutput) {
314
+ let copyDebugidPath;
315
+ try {
316
+ copyDebugidPath = require.resolve('@sentry/react-native/scripts/copy-debugid.js', {
317
+ paths: [
318
+ process.cwd()
319
+ ]
320
+ });
321
+ } catch (error) {
322
+ console.error('无法找到 Sentry copy-debugid.js 脚本文件,请确保已正确安装 @sentry/react-native');
323
+ return;
324
+ }
325
+ if (!_fsextra.existsSync(copyDebugidPath)) {
326
+ return;
327
+ }
328
+ console.log('Copying debugid');
329
+ (0, _nodechild_process.spawnSync)('node', [
330
+ copyDebugidPath,
331
+ _nodepath.default.join(outputFolder, `${bundleName}.txt.map`),
332
+ _nodepath.default.join(outputFolder, `${bundleName}.map`)
333
+ ], {
334
+ stdio: 'ignore'
335
+ });
336
+ }
306
337
  _fsextra.removeSync(_nodepath.default.join(outputFolder, `${bundleName}.txt.map`));
307
338
  }
339
+ async function uploadSourcemapForSentry(bundleName, outputFolder, sourcemapOutput, version) {
340
+ if (sourcemapOutput) {
341
+ let sentryCliPath;
342
+ try {
343
+ sentryCliPath = require.resolve('@sentry/cli/bin/sentry-cli', {
344
+ paths: [
345
+ process.cwd()
346
+ ]
347
+ });
348
+ } catch (error) {
349
+ console.error('无法找到 Sentry CLI 工具,请确保已正确安装 @sentry/cli');
350
+ return;
351
+ }
352
+ if (!_fsextra.existsSync(sentryCliPath)) {
353
+ return;
354
+ }
355
+ (0, _nodechild_process.spawnSync)('node', [
356
+ sentryCliPath,
357
+ 'releases',
358
+ 'set-commits',
359
+ version,
360
+ '--auto'
361
+ ], {
362
+ stdio: 'inherit'
363
+ });
364
+ console.log(`Sentry release created for version: ${version}`);
365
+ console.log('Uploading sourcemap');
366
+ (0, _nodechild_process.spawnSync)('node', [
367
+ sentryCliPath,
368
+ 'releases',
369
+ 'files',
370
+ version,
371
+ 'upload-sourcemaps',
372
+ '--strip-prefix',
373
+ _nodepath.default.join(process.cwd(), outputFolder),
374
+ _nodepath.default.join(outputFolder, bundleName),
375
+ _nodepath.default.join(outputFolder, `${bundleName}.map`)
376
+ ], {
377
+ stdio: 'inherit'
378
+ });
379
+ }
380
+ }
308
381
  async function pack(dir, output) {
309
382
  console.log('Packing');
310
383
  _fsextra.ensureDirSync(_nodepath.default.dirname(output));
@@ -316,7 +389,7 @@ async function pack(dir, output) {
316
389
  }
317
390
  const childs = _fsextra.readdirSync(root);
318
391
  for (const name of childs){
319
- if (name === '.' || name === '..' || name === 'index.bundlejs.map') {
392
+ if (name === '.' || name === '..' || name === 'index.bundlejs.map' || name === 'index.bundlejs.txt.map') {
320
393
  continue;
321
394
  }
322
395
  const fullPath = _nodepath.default.join(root, name);
@@ -632,6 +705,9 @@ const commands = {
632
705
  ...options,
633
706
  platform
634
707
  });
708
+ const bundleParams = await (0, _utils.checkPlugins)();
709
+ const sourcemapPlugin = bundleParams.sourcemap;
710
+ const isSentry = bundleParams.sentry;
635
711
  const sourcemapOutput = _nodepath.default.join(intermediaDir, `${bundleName}.map`);
636
712
  const realOutput = output.replace(/\$\{time\}/g, `${Date.now()}`);
637
713
  if (!platform) {
@@ -639,11 +715,11 @@ const commands = {
639
715
  }
640
716
  const { version, major, minor } = (0, _utils.getRNVersion)();
641
717
  console.log(`Bundling with react-native: ${version}`);
642
- await runReactNativeBundleCommand(bundleName, dev, entryFile, intermediaDir, platform, sourcemap ? sourcemapOutput : '');
718
+ await runReactNativeBundleCommand(bundleName, dev, entryFile, intermediaDir, platform, sourcemap || sourcemapPlugin ? sourcemapOutput : '');
643
719
  await pack(_nodepath.default.resolve(intermediaDir), realOutput);
644
720
  const v = await (0, _utils.question)('是否现在上传此热更包?(Y/N)');
645
721
  if (v.toLowerCase() === 'y') {
646
- await this.publish({
722
+ const versionName = await this.publish({
647
723
  args: [
648
724
  realOutput
649
725
  ],
@@ -651,6 +727,10 @@ const commands = {
651
727
  platform
652
728
  }
653
729
  });
730
+ if (isSentry) {
731
+ await copyDebugidForSentry(bundleName, intermediaDir, sourcemapOutput);
732
+ await uploadSourcemapForSentry(bundleName, intermediaDir, sourcemapOutput, versionName);
733
+ }
654
734
  }
655
735
  },
656
736
  async diff ({ args, options }) {
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "checkPlugins", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return checkPlugins;
9
+ }
10
+ });
11
+ const _pluginconfig = require("./plugin-config");
12
+ async function checkPlugins() {
13
+ const params = {
14
+ sentry: false,
15
+ sourcemap: false
16
+ };
17
+ for (const plugin of _pluginconfig.plugins){
18
+ try {
19
+ const isEnabled = await plugin.detect();
20
+ if (isEnabled && plugin.bundleParams) {
21
+ Object.assign(params, plugin.bundleParams);
22
+ console.log(`检测到 ${plugin.name} 插件,应用相应打包配置`);
23
+ }
24
+ } catch (err) {
25
+ console.warn(`检测 ${plugin.name} 插件时出错:`, err);
26
+ }
27
+ }
28
+ return params;
29
+ }
@@ -9,6 +9,9 @@ function _export(target, all) {
9
9
  });
10
10
  }
11
11
  _export(exports, {
12
+ checkPlugins: function() {
13
+ return _checkplugin.checkPlugins;
14
+ },
12
15
  getApkInfo: function() {
13
16
  return getApkInfo;
14
17
  },
@@ -45,6 +48,7 @@ const _appinfoparser = /*#__PURE__*/ _interop_require_default(require("./app-inf
45
48
  const _satisfies = /*#__PURE__*/ _interop_require_default(require("semver/functions/satisfies"));
46
49
  const _chalk = /*#__PURE__*/ _interop_require_default(require("chalk"));
47
50
  const _latestversion = /*#__PURE__*/ _interop_require_default(require("@badisi/latest-version"));
51
+ const _checkplugin = require("./check-plugin");
48
52
  const _read = require("read");
49
53
  function _interop_require_default(obj) {
50
54
  return obj && obj.__esModule ? obj : {
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "plugins", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return plugins;
9
+ }
10
+ });
11
+ const _fsextra = /*#__PURE__*/ _interop_require_default(require("fs-extra"));
12
+ function _interop_require_default(obj) {
13
+ return obj && obj.__esModule ? obj : {
14
+ default: obj
15
+ };
16
+ }
17
+ const plugins = [
18
+ {
19
+ name: 'sentry',
20
+ bundleParams: {
21
+ sentry: true,
22
+ sourcemap: true
23
+ },
24
+ detect: async ()=>{
25
+ try {
26
+ await _fsextra.default.access('ios/sentry.properties');
27
+ return true;
28
+ } catch (e) {
29
+ try {
30
+ await _fsextra.default.access('android/sentry.properties');
31
+ return true;
32
+ } catch (e) {
33
+ return false;
34
+ }
35
+ }
36
+ }
37
+ }
38
+ ];
package/lib/versions.js CHANGED
@@ -86,8 +86,9 @@ const commands = {
86
86
  const platform = (0, _app.checkPlatform)(options.platform || await (0, _utils.question)('平台(ios/android/harmony):'));
87
87
  const { appId } = await (0, _app.getSelectedApp)(platform);
88
88
  const { hash } = await (0, _api.uploadFile)(fn);
89
+ const versionName = name || await (0, _utils.question)('输入版本名称: ') || '(未命名)';
89
90
  const { id } = await (0, _api.post)(`/app/${appId}/version/create`, {
90
- name: name || await (0, _utils.question)('输入版本名称: ') || '(未命名)',
91
+ name: versionName,
91
92
  hash,
92
93
  description: description || await (0, _utils.question)('输入版本描述:'),
93
94
  metaInfo: metaInfo || await (0, _utils.question)('输入自定义的 meta info:')
@@ -105,6 +106,7 @@ const commands = {
105
106
  }
106
107
  });
107
108
  }
109
+ return versionName;
108
110
  },
109
111
  versions: async ({ options })=>{
110
112
  const platform = (0, _app.checkPlatform)(options.platform || await (0, _utils.question)('平台(ios/android/harmony):'));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-update-cli",
3
- "version": "1.38.2",
3
+ "version": "1.39.1",
4
4
  "description": "Command tools for javaScript updater with `pushy` service for react native apps.",
5
5
  "main": "index.js",
6
6
  "bin": {
package/src/bundle.js CHANGED
@@ -3,7 +3,7 @@ import { getRNVersion, translateOptions } from './utils';
3
3
  import * as fs from 'fs-extra';
4
4
  import { ZipFile } from 'yazl';
5
5
  import { open as openZipFile } from 'yauzl';
6
- import { question, printVersionCommand } from './utils';
6
+ import { question, checkPlugins } from './utils';
7
7
  import { checkPlatform } from './app';
8
8
  import { spawn, spawnSync } from 'node:child_process';
9
9
  import semverSatisfies from 'semver/functions/satisfies';
@@ -86,6 +86,8 @@ async function runReactNativeBundleCommand(
86
86
  });
87
87
  }
88
88
  }
89
+ const bundleParams = await checkPlugins();
90
+ const isSentry = bundleParams.sentry;
89
91
  const bundleCommand = usingExpo
90
92
  ? 'export:embed'
91
93
  : platform === 'harmony'
@@ -190,6 +192,7 @@ async function runReactNativeBundleCommand(
190
192
  bundleName,
191
193
  outputFolder,
192
194
  sourcemapOutput,
195
+ !isSentry,
193
196
  );
194
197
  }
195
198
  resolve(null);
@@ -253,6 +256,7 @@ async function compileHermesByteCode(
253
256
  bundleName,
254
257
  outputFolder,
255
258
  sourcemapOutput,
259
+ shouldCleanSourcemap,
256
260
  ) {
257
261
  console.log('Hermes enabled, now compiling to hermes bytecode:\n');
258
262
  // >= rn 0.69
@@ -309,9 +313,98 @@ async function compileHermesByteCode(
309
313
  },
310
314
  );
311
315
  }
316
+ if (shouldCleanSourcemap) {
317
+ fs.removeSync(path.join(outputFolder, `${bundleName}.txt.map`));
318
+ }
319
+ }
320
+
321
+ async function copyDebugidForSentry(bundleName, outputFolder, sourcemapOutput) {
322
+ if (sourcemapOutput) {
323
+ let copyDebugidPath;
324
+ try {
325
+ copyDebugidPath = require.resolve(
326
+ '@sentry/react-native/scripts/copy-debugid.js',
327
+ {
328
+ paths: [process.cwd()],
329
+ },
330
+ );
331
+ } catch (error) {
332
+ console.error(
333
+ '无法找到 Sentry copy-debugid.js 脚本文件,请确保已正确安装 @sentry/react-native',
334
+ );
335
+ return;
336
+ }
337
+
338
+ if (!fs.existsSync(copyDebugidPath)) {
339
+ return;
340
+ }
341
+ console.log('Copying debugid');
342
+ spawnSync(
343
+ 'node',
344
+ [
345
+ copyDebugidPath,
346
+ path.join(outputFolder, `${bundleName}.txt.map`),
347
+ path.join(outputFolder, `${bundleName}.map`),
348
+ ],
349
+ {
350
+ stdio: 'ignore',
351
+ },
352
+ );
353
+ }
312
354
  fs.removeSync(path.join(outputFolder, `${bundleName}.txt.map`));
313
355
  }
314
356
 
357
+ async function uploadSourcemapForSentry(
358
+ bundleName,
359
+ outputFolder,
360
+ sourcemapOutput,
361
+ version,
362
+ ) {
363
+ if (sourcemapOutput) {
364
+ let sentryCliPath;
365
+ try {
366
+ sentryCliPath = require.resolve('@sentry/cli/bin/sentry-cli', {
367
+ paths: [process.cwd()],
368
+ });
369
+ } catch (error) {
370
+ console.error('无法找到 Sentry CLI 工具,请确保已正确安装 @sentry/cli');
371
+ return;
372
+ }
373
+
374
+ if (!fs.existsSync(sentryCliPath)) {
375
+ return;
376
+ }
377
+
378
+ spawnSync(
379
+ 'node',
380
+ [sentryCliPath, 'releases', 'set-commits', version, '--auto'],
381
+ {
382
+ stdio: 'inherit',
383
+ },
384
+ );
385
+ console.log(`Sentry release created for version: ${version}`);
386
+
387
+ console.log('Uploading sourcemap');
388
+ spawnSync(
389
+ 'node',
390
+ [
391
+ sentryCliPath,
392
+ 'releases',
393
+ 'files',
394
+ version,
395
+ 'upload-sourcemaps',
396
+ '--strip-prefix',
397
+ path.join(process.cwd(), outputFolder),
398
+ path.join(outputFolder, bundleName),
399
+ path.join(outputFolder, `${bundleName}.map`),
400
+ ],
401
+ {
402
+ stdio: 'inherit',
403
+ },
404
+ );
405
+ }
406
+ }
407
+
315
408
  async function pack(dir, output) {
316
409
  console.log('Packing');
317
410
  fs.ensureDirSync(path.dirname(output));
@@ -324,7 +417,7 @@ async function pack(dir, output) {
324
417
  }
325
418
  const childs = fs.readdirSync(root);
326
419
  for (const name of childs) {
327
- if (name === '.' || name === '..' || name === 'index.bundlejs.map') {
420
+ if (name === '.' || name === '..' || name === 'index.bundlejs.map' || name === 'index.bundlejs.txt.map') {
328
421
  continue;
329
422
  }
330
423
  const fullPath = path.join(root, name);
@@ -724,6 +817,10 @@ export const commands = {
724
817
  platform,
725
818
  });
726
819
 
820
+ const bundleParams = await checkPlugins();
821
+ const sourcemapPlugin = bundleParams.sourcemap;
822
+ const isSentry = bundleParams.sentry;
823
+
727
824
  const sourcemapOutput = path.join(intermediaDir, `${bundleName}.map`);
728
825
 
729
826
  const realOutput = output.replace(/\$\{time\}/g, `${Date.now()}`);
@@ -742,19 +839,28 @@ export const commands = {
742
839
  entryFile,
743
840
  intermediaDir,
744
841
  platform,
745
- sourcemap ? sourcemapOutput : '',
842
+ sourcemap || sourcemapPlugin ? sourcemapOutput : '',
746
843
  );
747
844
 
748
845
  await pack(path.resolve(intermediaDir), realOutput);
749
846
 
750
847
  const v = await question('是否现在上传此热更包?(Y/N)');
751
848
  if (v.toLowerCase() === 'y') {
752
- await this.publish({
849
+ const versionName = await this.publish({
753
850
  args: [realOutput],
754
851
  options: {
755
852
  platform,
756
853
  },
757
854
  });
855
+ if (isSentry) {
856
+ await copyDebugidForSentry(bundleName, intermediaDir, sourcemapOutput);
857
+ await uploadSourcemapForSentry(
858
+ bundleName,
859
+ intermediaDir,
860
+ sourcemapOutput,
861
+ versionName,
862
+ );
863
+ }
758
864
  }
759
865
  },
760
866
 
@@ -0,0 +1,28 @@
1
+ import { plugins } from './plugin-config';
2
+
3
+ interface BundleParams {
4
+ sentry: boolean;
5
+ sourcemap: boolean;
6
+ [key: string]: any;
7
+ }
8
+
9
+ export async function checkPlugins(): Promise<BundleParams> {
10
+ const params: BundleParams = {
11
+ sentry: false,
12
+ sourcemap: false,
13
+ };
14
+
15
+ for (const plugin of plugins) {
16
+ try {
17
+ const isEnabled = await plugin.detect();
18
+ if (isEnabled && plugin.bundleParams) {
19
+ Object.assign(params, plugin.bundleParams);
20
+ console.log(`检测到 ${plugin.name} 插件,应用相应打包配置`);
21
+ }
22
+ } catch (err) {
23
+ console.warn(`检测 ${plugin.name} 插件时出错:`, err);
24
+ }
25
+ }
26
+
27
+ return params;
28
+ }
@@ -6,6 +6,7 @@ import AppInfoParser from './app-info-parser';
6
6
  import semverSatisfies from 'semver/functions/satisfies';
7
7
  import chalk from 'chalk';
8
8
  import latestVersion from '@badisi/latest-version';
9
+ import { checkPlugins } from './check-plugin';
9
10
 
10
11
  import { read } from 'read';
11
12
 
@@ -225,3 +226,5 @@ export async function printVersionCommand() {
225
226
  }
226
227
 
227
228
  export const pricingPageUrl = 'https://pushy.reactnative.cn/pricing.html';
229
+
230
+ export { checkPlugins };
@@ -0,0 +1,32 @@
1
+ import fs from 'fs-extra';
2
+
3
+ interface PluginConfig {
4
+ name: string;
5
+ bundleParams?: {
6
+ [key: string]: any;
7
+ };
8
+ detect: () => Promise<boolean>;
9
+ }
10
+
11
+ export const plugins: PluginConfig[] = [
12
+ {
13
+ name: 'sentry',
14
+ bundleParams: {
15
+ sentry: true,
16
+ sourcemap: true,
17
+ },
18
+ detect: async () => {
19
+ try {
20
+ await fs.access('ios/sentry.properties');
21
+ return true;
22
+ } catch {
23
+ try {
24
+ await fs.access('android/sentry.properties');
25
+ return true;
26
+ } catch {
27
+ return false;
28
+ }
29
+ }
30
+ }
31
+ }
32
+ ];
package/src/versions.js CHANGED
@@ -97,8 +97,9 @@ export const commands = {
97
97
 
98
98
  const { hash } = await uploadFile(fn);
99
99
 
100
+ const versionName = name || (await question('输入版本名称: ')) || '(未命名)';
100
101
  const { id } = await post(`/app/${appId}/version/create`, {
101
- name: name || (await question('输入版本名称: ')) || '(未命名)',
102
+ name: versionName,
102
103
  hash,
103
104
  description: description || (await question('输入版本描述:')),
104
105
  metaInfo: metaInfo || (await question('输入自定义的 meta info:')),
@@ -111,6 +112,7 @@ export const commands = {
111
112
  if (v.toLowerCase() === 'y') {
112
113
  await this.update({ args: [], options: { versionId: id, platform } });
113
114
  }
115
+ return versionName;
114
116
  },
115
117
  versions: async ({ options }) => {
116
118
  const platform = checkPlatform(