Skip to content

Commit 0b08c77

Browse files
authored
Support sentry (#8)
* add logic to support sentry * udpate * change reference path * support git commits and version info * udate * add try catch for require.resolve * update upload sourcemap workflow
1 parent b24b27d commit 0b08c77

File tree

5 files changed

+182
-4
lines changed

5 files changed

+182
-4
lines changed

src/bundle.js

Lines changed: 112 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { getRNVersion, translateOptions } from './utils';
33
import * as fs from 'fs-extra';
44
import { ZipFile } from 'yazl';
55
import { open as openZipFile } from 'yauzl';
6-
import { question, printVersionCommand } from './utils';
6+
import { question, checkPlugins } from './utils';
77
import { checkPlatform } from './app';
88
import { spawn, spawnSync } from 'node:child_process';
99
import semverSatisfies from 'semver/functions/satisfies';
@@ -86,6 +86,9 @@ async function runReactNativeBundleCommand(
8686
});
8787
}
8888
}
89+
const bundleParams = await checkPlugins();
90+
const minifyOption = bundleParams.minify;
91+
const isSentry = bundleParams.sentry;
8992
const bundleCommand = usingExpo
9093
? 'export:embed'
9194
: platform === 'harmony'
@@ -123,6 +126,8 @@ async function runReactNativeBundleCommand(
123126
'--platform',
124127
platform,
125128
'--reset-cache',
129+
'--minify',
130+
minifyOption,
126131
]);
127132

128133
if (sourcemapOutput) {
@@ -190,6 +195,7 @@ async function runReactNativeBundleCommand(
190195
bundleName,
191196
outputFolder,
192197
sourcemapOutput,
198+
!isSentry,
193199
);
194200
}
195201
resolve(null);
@@ -253,6 +259,7 @@ async function compileHermesByteCode(
253259
bundleName,
254260
outputFolder,
255261
sourcemapOutput,
262+
shouldCleanSourcemap,
256263
) {
257264
console.log('Hermes enabled, now compiling to hermes bytecode:\n');
258265
// >= rn 0.69
@@ -309,9 +316,98 @@ async function compileHermesByteCode(
309316
},
310317
);
311318
}
319+
if (shouldCleanSourcemap) {
320+
fs.removeSync(path.join(outputFolder, `${bundleName}.txt.map`));
321+
}
322+
}
323+
324+
async function copyDebugidForSentry(bundleName, outputFolder, sourcemapOutput) {
325+
if (sourcemapOutput) {
326+
let copyDebugidPath;
327+
try {
328+
copyDebugidPath = require.resolve(
329+
'@sentry/react-native/scripts/copy-debugid.js',
330+
{
331+
paths: [process.cwd()],
332+
},
333+
);
334+
} catch (error) {
335+
console.error(
336+
'无法找到 Sentry copy-debugid.js 脚本文件,请确保已正确安装 @sentry/react-native',
337+
);
338+
return;
339+
}
340+
341+
if (!fs.existsSync(copyDebugidPath)) {
342+
return;
343+
}
344+
console.log('Copying debugid');
345+
spawnSync(
346+
'node',
347+
[
348+
copyDebugidPath,
349+
path.join(outputFolder, `${bundleName}.txt.map`),
350+
path.join(outputFolder, `${bundleName}.map`),
351+
],
352+
{
353+
stdio: 'ignore',
354+
},
355+
);
356+
}
312357
fs.removeSync(path.join(outputFolder, `${bundleName}.txt.map`));
313358
}
314359

360+
async function uploadSourcemapForSentry(
361+
bundleName,
362+
outputFolder,
363+
sourcemapOutput,
364+
version,
365+
) {
366+
if (sourcemapOutput) {
367+
let sentryCliPath;
368+
try {
369+
sentryCliPath = require.resolve('@sentry/cli/bin/sentry-cli', {
370+
paths: [process.cwd()],
371+
});
372+
} catch (error) {
373+
console.error('无法找到 Sentry CLI 工具,请确保已正确安装 @sentry/cli');
374+
return;
375+
}
376+
377+
if (!fs.existsSync(sentryCliPath)) {
378+
return;
379+
}
380+
381+
spawnSync(
382+
'node',
383+
[sentryCliPath, 'releases', 'set-commits', version, '--auto'],
384+
{
385+
stdio: 'inherit',
386+
},
387+
);
388+
console.log(`Sentry release created for version: ${version}`);
389+
390+
console.log('Uploading sourcemap');
391+
spawnSync(
392+
'node',
393+
[
394+
sentryCliPath,
395+
'releases',
396+
'files',
397+
version,
398+
'upload-sourcemaps',
399+
'--strip-prefix',
400+
path.join(process.cwd(), outputFolder),
401+
path.join(outputFolder, bundleName),
402+
path.join(outputFolder, `${bundleName}.map`),
403+
],
404+
{
405+
stdio: 'inherit',
406+
},
407+
);
408+
}
409+
}
410+
315411
async function pack(dir, output) {
316412
console.log('Packing');
317413
fs.ensureDirSync(path.dirname(output));
@@ -718,12 +814,16 @@ export const commands = {
718814
options.platform || (await question('平台(ios/android/harmony):')),
719815
);
720816

721-
const { bundleName, entryFile, intermediaDir, output, dev, sourcemap } =
817+
const { bundleName, entryFile, intermediaDir, output, dev } =
722818
translateOptions({
723819
...options,
724820
platform,
725821
});
726822

823+
const bundleParams = await checkPlugins();
824+
const sourcemap = bundleParams.sourcemap;
825+
const isSentry = bundleParams.sentry;
826+
727827
const sourcemapOutput = path.join(intermediaDir, `${bundleName}.map`);
728828

729829
const realOutput = output.replace(/\$\{time\}/g, `${Date.now()}`);
@@ -749,12 +849,21 @@ export const commands = {
749849

750850
const v = await question('是否现在上传此热更包?(Y/N)');
751851
if (v.toLowerCase() === 'y') {
752-
await this.publish({
852+
const versionName = await this.publish({
753853
args: [realOutput],
754854
options: {
755855
platform,
756856
},
757857
});
858+
if (isSentry) {
859+
await copyDebugidForSentry(bundleName, intermediaDir, sourcemapOutput);
860+
await uploadSourcemapForSentry(
861+
bundleName,
862+
intermediaDir,
863+
sourcemapOutput,
864+
versionName,
865+
);
866+
}
758867
}
759868
},
760869

src/utils/check-plugin.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { plugins } from './plugin-config';
2+
3+
interface BundleParams {
4+
sentry: boolean;
5+
minify: boolean;
6+
sourcemap: boolean;
7+
[key: string]: any;
8+
}
9+
10+
export async function checkPlugins(): Promise<BundleParams> {
11+
const params: BundleParams = {
12+
sentry: false,
13+
minify: true,
14+
sourcemap: false,
15+
};
16+
17+
for (const plugin of 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+
29+
return params;
30+
}

src/utils/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import AppInfoParser from './app-info-parser';
66
import semverSatisfies from 'semver/functions/satisfies';
77
import chalk from 'chalk';
88
import latestVersion from '@badisi/latest-version';
9+
import { checkPlugins } from './check-plugin';
910

1011
import { read } from 'read';
1112

@@ -225,3 +226,5 @@ export async function printVersionCommand() {
225226
}
226227

227228
export const pricingPageUrl = 'https://pushy.reactnative.cn/pricing.html';
229+
230+
export { checkPlugins };

src/utils/plugin-config.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import fs from 'fs-extra';
2+
3+
interface PluginConfig {
4+
name: string;
5+
bundleParams?: {
6+
minify?: boolean;
7+
[key: string]: any;
8+
};
9+
detect: () => Promise<boolean>;
10+
}
11+
12+
export const plugins: PluginConfig[] = [
13+
{
14+
name: 'sentry',
15+
bundleParams: {
16+
sentry: true,
17+
minify: false,
18+
sourcemap: true,
19+
},
20+
detect: async () => {
21+
try {
22+
await fs.access('ios/sentry.properties');
23+
return true;
24+
} catch {
25+
try {
26+
await fs.access('android/sentry.properties');
27+
return true;
28+
} catch {
29+
return false;
30+
}
31+
}
32+
}
33+
}
34+
];

src/versions.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,9 @@ export const commands = {
9797

9898
const { hash } = await uploadFile(fn);
9999

100+
const versionName = name || (await question('输入版本名称: ')) || '(未命名)';
100101
const { id } = await post(`/app/${appId}/version/create`, {
101-
name: name || (await question('输入版本名称: ')) || '(未命名)',
102+
name: versionName,
102103
hash,
103104
description: description || (await question('输入版本描述:')),
104105
metaInfo: metaInfo || (await question('输入自定义的 meta info:')),
@@ -111,6 +112,7 @@ export const commands = {
111112
if (v.toLowerCase() === 'y') {
112113
await this.update({ args: [], options: { versionId: id, platform } });
113114
}
115+
return versionName;
114116
},
115117
versions: async ({ options }) => {
116118
const platform = checkPlatform(

0 commit comments

Comments
 (0)