1
0
mirror of https://gitcode.com/github-mirrors/react-native-update-cli.git synced 2025-09-16 09:41:38 +08:00
Code Issues Packages Projects Releases Wiki Activity GitHub Gitee

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
This commit is contained in:
波仔糕
2025-01-23 22:02:13 +08:00
committed by GitHub
parent b24b27d100
commit 0b08c7760d
5 changed files with 182 additions and 4 deletions

View File

@@ -3,7 +3,7 @@ import { getRNVersion, translateOptions } from './utils';
import * as fs from 'fs-extra';
import { ZipFile } from 'yazl';
import { open as openZipFile } from 'yauzl';
import { question, printVersionCommand } from './utils';
import { question, checkPlugins } from './utils';
import { checkPlatform } from './app';
import { spawn, spawnSync } from 'node:child_process';
import semverSatisfies from 'semver/functions/satisfies';
@@ -86,6 +86,9 @@ async function runReactNativeBundleCommand(
});
}
}
const bundleParams = await checkPlugins();
const minifyOption = bundleParams.minify;
const isSentry = bundleParams.sentry;
const bundleCommand = usingExpo
? 'export:embed'
: platform === 'harmony'
@@ -123,6 +126,8 @@ async function runReactNativeBundleCommand(
'--platform',
platform,
'--reset-cache',
'--minify',
minifyOption,
]);
if (sourcemapOutput) {
@@ -190,6 +195,7 @@ async function runReactNativeBundleCommand(
bundleName,
outputFolder,
sourcemapOutput,
!isSentry,
);
}
resolve(null);
@@ -253,6 +259,7 @@ async function compileHermesByteCode(
bundleName,
outputFolder,
sourcemapOutput,
shouldCleanSourcemap,
) {
console.log('Hermes enabled, now compiling to hermes bytecode:\n');
// >= rn 0.69
@@ -309,9 +316,98 @@ async function compileHermesByteCode(
},
);
}
if (shouldCleanSourcemap) {
fs.removeSync(path.join(outputFolder, `${bundleName}.txt.map`));
}
}
async function copyDebugidForSentry(bundleName, outputFolder, sourcemapOutput) {
if (sourcemapOutput) {
let copyDebugidPath;
try {
copyDebugidPath = require.resolve(
'@sentry/react-native/scripts/copy-debugid.js',
{
paths: [process.cwd()],
},
);
} catch (error) {
console.error(
'无法找到 Sentry copy-debugid.js 脚本文件,请确保已正确安装 @sentry/react-native',
);
return;
}
if (!fs.existsSync(copyDebugidPath)) {
return;
}
console.log('Copying debugid');
spawnSync(
'node',
[
copyDebugidPath,
path.join(outputFolder, `${bundleName}.txt.map`),
path.join(outputFolder, `${bundleName}.map`),
],
{
stdio: 'ignore',
},
);
}
fs.removeSync(path.join(outputFolder, `${bundleName}.txt.map`));
}
async function uploadSourcemapForSentry(
bundleName,
outputFolder,
sourcemapOutput,
version,
) {
if (sourcemapOutput) {
let sentryCliPath;
try {
sentryCliPath = require.resolve('@sentry/cli/bin/sentry-cli', {
paths: [process.cwd()],
});
} catch (error) {
console.error('无法找到 Sentry CLI 工具,请确保已正确安装 @sentry/cli');
return;
}
if (!fs.existsSync(sentryCliPath)) {
return;
}
spawnSync(
'node',
[sentryCliPath, 'releases', 'set-commits', version, '--auto'],
{
stdio: 'inherit',
},
);
console.log(`Sentry release created for version: ${version}`);
console.log('Uploading sourcemap');
spawnSync(
'node',
[
sentryCliPath,
'releases',
'files',
version,
'upload-sourcemaps',
'--strip-prefix',
path.join(process.cwd(), outputFolder),
path.join(outputFolder, bundleName),
path.join(outputFolder, `${bundleName}.map`),
],
{
stdio: 'inherit',
},
);
}
}
async function pack(dir, output) {
console.log('Packing');
fs.ensureDirSync(path.dirname(output));
@@ -718,12 +814,16 @@ export const commands = {
options.platform || (await question('平台(ios/android/harmony):')),
);
const { bundleName, entryFile, intermediaDir, output, dev, sourcemap } =
const { bundleName, entryFile, intermediaDir, output, dev } =
translateOptions({
...options,
platform,
});
const bundleParams = await checkPlugins();
const sourcemap = bundleParams.sourcemap;
const isSentry = bundleParams.sentry;
const sourcemapOutput = path.join(intermediaDir, `${bundleName}.map`);
const realOutput = output.replace(/\$\{time\}/g, `${Date.now()}`);
@@ -749,12 +849,21 @@ export const commands = {
const v = await question('是否现在上传此热更包?(Y/N)');
if (v.toLowerCase() === 'y') {
await this.publish({
const versionName = await this.publish({
args: [realOutput],
options: {
platform,
},
});
if (isSentry) {
await copyDebugidForSentry(bundleName, intermediaDir, sourcemapOutput);
await uploadSourcemapForSentry(
bundleName,
intermediaDir,
sourcemapOutput,
versionName,
);
}
}
},

30
src/utils/check-plugin.ts Normal file
View File

@@ -0,0 +1,30 @@
import { plugins } from './plugin-config';
interface BundleParams {
sentry: boolean;
minify: boolean;
sourcemap: boolean;
[key: string]: any;
}
export async function checkPlugins(): Promise<BundleParams> {
const params: BundleParams = {
sentry: false,
minify: true,
sourcemap: false,
};
for (const plugin of plugins) {
try {
const isEnabled = await plugin.detect();
if (isEnabled && plugin.bundleParams) {
Object.assign(params, plugin.bundleParams);
console.log(`检测到 ${plugin.name} 插件,应用相应打包配置`);
}
} catch (err) {
console.warn(`检测 ${plugin.name} 插件时出错:`, err);
}
}
return params;
}

View File

@@ -6,6 +6,7 @@ import AppInfoParser from './app-info-parser';
import semverSatisfies from 'semver/functions/satisfies';
import chalk from 'chalk';
import latestVersion from '@badisi/latest-version';
import { checkPlugins } from './check-plugin';
import { read } from 'read';
@@ -225,3 +226,5 @@ export async function printVersionCommand() {
}
export const pricingPageUrl = 'https://pushy.reactnative.cn/pricing.html';
export { checkPlugins };

View File

@@ -0,0 +1,34 @@
import fs from 'fs-extra';
interface PluginConfig {
name: string;
bundleParams?: {
minify?: boolean;
[key: string]: any;
};
detect: () => Promise<boolean>;
}
export const plugins: PluginConfig[] = [
{
name: 'sentry',
bundleParams: {
sentry: true,
minify: false,
sourcemap: true,
},
detect: async () => {
try {
await fs.access('ios/sentry.properties');
return true;
} catch {
try {
await fs.access('android/sentry.properties');
return true;
} catch {
return false;
}
}
}
}
];

View File

@@ -97,8 +97,9 @@ export const commands = {
const { hash } = await uploadFile(fn);
const versionName = name || (await question('输入版本名称: ')) || '(未命名)';
const { id } = await post(`/app/${appId}/version/create`, {
name: name || (await question('输入版本名称: ')) || '(未命名)',
name: versionName,
hash,
description: description || (await question('输入版本描述:')),
metaInfo: metaInfo || (await question('输入自定义的 meta info:')),
@@ -111,6 +112,7 @@ export const commands = {
if (v.toLowerCase() === 'y') {
await this.update({ args: [], options: { versionId: id, platform } });
}
return versionName;
},
versions: async ({ options }) => {
const platform = checkPlatform(