From 3173bab2596c9d48cc8b01be1d86ad2aa78a40cf Mon Sep 17 00:00:00 2001 From: Ahmed Mahmoud Date: Mon, 15 Jul 2024 10:43:52 +0300 Subject: [PATCH 1/4] feat: export upload utils --- .gitignore | 2 + cli/commands/UploadSoFiles.ts | 38 ++++++++++++++++ cli/commands/UploadSourcemaps.ts | 40 +++++++++++++++++ cli/index.ts | 4 +- cli/upload/index.ts | 2 + .../uploadSoFiles.ts} | 40 +---------------- .../uploadSourcemaps.ts} | 43 +------------------ examples/default/scripts/upload.ts | 21 +++++++++ rollup.config.js | 39 +++++++++++------ tsconfig.upload.json | 10 +++++ upload/package.json | 5 +++ 11 files changed, 149 insertions(+), 95 deletions(-) create mode 100755 cli/commands/UploadSoFiles.ts create mode 100755 cli/commands/UploadSourcemaps.ts create mode 100644 cli/upload/index.ts rename cli/{UploadSoFiles.ts => upload/uploadSoFiles.ts} (52%) rename cli/{UploadSourcemaps.ts => upload/uploadSourcemaps.ts} (50%) mode change 100755 => 100644 create mode 100644 examples/default/scripts/upload.ts create mode 100644 tsconfig.upload.json create mode 100644 upload/package.json diff --git a/.gitignore b/.gitignore index 50fb3439f..4033aaa3b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ # Distribution dist/ bin/ +upload/* +!upload/package.json # NodeJS node_modules/ diff --git a/cli/commands/UploadSoFiles.ts b/cli/commands/UploadSoFiles.ts new file mode 100755 index 000000000..99b23e3e4 --- /dev/null +++ b/cli/commands/UploadSoFiles.ts @@ -0,0 +1,38 @@ +import { Command, Option } from 'commander'; +import { uploadSoFiles, UploadSoFilesOptions } from '../upload/uploadSoFiles'; + +/** + * This script uploads .so files to the specified endpoint used in NDK crash reporting. + * Usage: node upload-so-files.js --arch --file --api_key --token --name + */ + +export const UploadSoFilesCommand = new Command(); + +UploadSoFilesCommand.name('upload-so-files') + .addOption( + new Option('-arch, --arch ', 'arch') + .choices(['x86', 'x86_64', 'arm64-v8a', 'armeabi-v7a']) + .makeOptionMandatory(), + ) + .addOption( + new Option( + '-f, --file ', + 'The path of the symbol files in Zip format', + ).makeOptionMandatory(), + ) + .addOption(new Option('--api_key ', 'Your App key').makeOptionMandatory()) + .addOption( + new Option('-t, --token ', 'Your App Token') + .env('INSTABUG_APP_TOKEN') + .makeOptionMandatory(), + ) + .addOption( + new Option('-n, --name ', 'The app version name') + .env('INSTABUG_APP_VERSION_NAME') + .makeOptionMandatory(), + ) + .action(function (this: Command) { + const options = this.opts(); + uploadSoFiles(options); + }) + .showHelpAfterError(); diff --git a/cli/commands/UploadSourcemaps.ts b/cli/commands/UploadSourcemaps.ts new file mode 100755 index 000000000..5199693e7 --- /dev/null +++ b/cli/commands/UploadSourcemaps.ts @@ -0,0 +1,40 @@ +import { Command, Option } from 'commander'; +import { uploadSourcemaps, UploadSourcemapsOptions } from '../upload/uploadSourcemaps'; + +export const uploadSourcemapsCommand = new Command(); + +uploadSourcemapsCommand + .name('upload-sourcemaps') + .addOption( + new Option('-p, --platform ', 'Platform') + .choices(['ios', 'android']) + .makeOptionMandatory(), + ) + .addOption( + new Option('-f, --file ', 'The path of the source map file').makeOptionMandatory(), + ) + .addOption( + new Option('-t, --token ', 'Your App Token') + .env('INSTABUG_APP_TOKEN') + .makeOptionMandatory(), + ) + .addOption( + new Option('-n, --name ', 'The app version name') + .env('INSTABUG_APP_VERSION_NAME') + .makeOptionMandatory(), + ) + .addOption( + new Option('-c, --code ', 'The app version code') + .env('INSTABUG_APP_VERSION_CODE') + .makeOptionMandatory(), + ) + .addOption( + new Option('-l, --label ', "The CodePush label if it's a CodePush release").env( + 'INSTABUG_APP_VERSION_LABEL', + ), + ) + .action(function (this: Command) { + const options = this.opts(); + uploadSourcemaps(options); + }) + .showHelpAfterError(); diff --git a/cli/index.ts b/cli/index.ts index c1731d67a..8df747e75 100644 --- a/cli/index.ts +++ b/cli/index.ts @@ -1,8 +1,8 @@ #!/usr/bin/env node import { Command } from 'commander'; -import { uploadSourcemapsCommand } from './UploadSourcemaps'; -import { UploadSoFilesCommand } from './UploadSoFiles'; +import { uploadSourcemapsCommand } from './commands/UploadSourcemaps'; +import { UploadSoFilesCommand } from './commands/UploadSoFiles'; const program = new Command(); diff --git a/cli/upload/index.ts b/cli/upload/index.ts new file mode 100644 index 000000000..b09f4b243 --- /dev/null +++ b/cli/upload/index.ts @@ -0,0 +1,2 @@ +export * from './uploadSourcemaps'; +export * from './uploadSoFiles'; diff --git a/cli/UploadSoFiles.ts b/cli/upload/uploadSoFiles.ts similarity index 52% rename from cli/UploadSoFiles.ts rename to cli/upload/uploadSoFiles.ts index 6329f4d27..acaac0113 100755 --- a/cli/UploadSoFiles.ts +++ b/cli/upload/uploadSoFiles.ts @@ -1,52 +1,16 @@ import axios from 'axios'; -import { Command, Option } from 'commander'; import FormData from 'form-data'; import fs from 'fs'; -interface UploadSoFilesOptions { +export interface UploadSoFilesOptions { arch: 'x86' | 'x86_64' | 'arm64-v8a' | 'armeabi-v7a'; file: string; token: string; name: string; api_key: string; } -/** - * This script uploads .so files to the specified endpoint used in NDK crash reporting. - * Usage: node upload-so-files.js --arch --file --api_key --token --name - */ -export const UploadSoFilesCommand = new Command(); - -UploadSoFilesCommand.name('upload-so-files') - .addOption( - new Option('-arch, --arch ', 'arch') - .choices(['x86', 'x86_64', 'arm64-v8a', 'armeabi-v7a']) - .makeOptionMandatory(), - ) - .addOption( - new Option( - '-f, --file ', - 'The path of the symbol files in Zip format', - ).makeOptionMandatory(), - ) - .addOption(new Option('--api_key ', 'Your App key').makeOptionMandatory()) - .addOption( - new Option('-t, --token ', 'Your App Token') - .env('INSTABUG_APP_TOKEN') - .makeOptionMandatory(), - ) - .addOption( - new Option('-n, --name ', 'The app version name') - .env('INSTABUG_APP_VERSION_NAME') - .makeOptionMandatory(), - ) - .action(function (this: Command) { - const options = this.opts(); - UploadSoFiles(options); - }) - .showHelpAfterError(); - -const UploadSoFiles = async (opts: UploadSoFilesOptions) => { +export const uploadSoFiles = async (opts: UploadSoFilesOptions) => { const fileName = opts.file; if (fileName == null) { console.error('Failed to upload So Files: invalid file path'); diff --git a/cli/UploadSourcemaps.ts b/cli/upload/uploadSourcemaps.ts old mode 100755 new mode 100644 similarity index 50% rename from cli/UploadSourcemaps.ts rename to cli/upload/uploadSourcemaps.ts index 939629cb5..2498fe8f9 --- a/cli/UploadSourcemaps.ts +++ b/cli/upload/uploadSourcemaps.ts @@ -1,9 +1,8 @@ import axios from 'axios'; -import { Command, Option } from 'commander'; import FormData from 'form-data'; import fs from 'fs'; -interface UploadSourcemapsOptions { +export interface UploadSourcemapsOptions { platform: 'android' | 'ios'; file: string; token: string; @@ -12,45 +11,7 @@ interface UploadSourcemapsOptions { label?: string; } -export const uploadSourcemapsCommand = new Command(); - -uploadSourcemapsCommand - .name('upload-sourcemaps') - .addOption( - new Option('-p, --platform ', 'Platform') - .choices(['ios', 'android']) - .makeOptionMandatory(), - ) - .addOption( - new Option('-f, --file ', 'The path of the source map file').makeOptionMandatory(), - ) - .addOption( - new Option('-t, --token ', 'Your App Token') - .env('INSTABUG_APP_TOKEN') - .makeOptionMandatory(), - ) - .addOption( - new Option('-n, --name ', 'The app version name') - .env('INSTABUG_APP_VERSION_NAME') - .makeOptionMandatory(), - ) - .addOption( - new Option('-c, --code ', 'The app version code') - .env('INSTABUG_APP_VERSION_CODE') - .makeOptionMandatory(), - ) - .addOption( - new Option('-l, --label ', "The CodePush label if it's a CodePush release").env( - 'INSTABUG_APP_VERSION_LABEL', - ), - ) - .action(function (this: Command) { - const options = this.opts(); - uploadSourcemaps(options); - }) - .showHelpAfterError(); - -const uploadSourcemaps = async (opts: UploadSourcemapsOptions) => { +export const uploadSourcemaps = async (opts: UploadSourcemapsOptions) => { const fileName = `${opts.platform}-sourcemap.json`; const fileBlob = fs.readFileSync(opts.file); diff --git a/examples/default/scripts/upload.ts b/examples/default/scripts/upload.ts new file mode 100644 index 000000000..902dfe7e6 --- /dev/null +++ b/examples/default/scripts/upload.ts @@ -0,0 +1,21 @@ +import { uploadSoFiles, uploadSourcemaps } from 'instabug-reactnative/upload'; + +const result = await uploadSourcemaps({ + code: 'your-app-code', + file: 'path-to-your-sourcemap-file', + platform: 'ios', + name: 'your-sourcemap-name', + token: 'your-app-token', + label: 'your-sourcemap-label', +}); + +const so = await uploadSoFiles({ + code: 'your-app-code', + file: 'path-to-your-sourcemap-file', + platform: 'ios', + name: 'your-sourcemap-name', + token: 'your-app-token', + label: 'your-sourcemap-label', +}); + +console.log(result); diff --git a/rollup.config.js b/rollup.config.js index 9b3068d89..ae91a8906 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -5,19 +5,30 @@ import typescript from '@rollup/plugin-typescript'; import cleanup from 'rollup-plugin-cleanup'; import shebang from 'rollup-plugin-preserve-shebang'; +const commonPlugins = [ + shebang(), + json(), + nodeResolve({ preferBuiltins: true }), + commonjs(), + cleanup(), +]; + /** @type import('rollup').RollupOptions */ -export default { - input: ['cli/index.ts'], - output: { - dir: 'bin', - format: 'cjs', +export default [ + { + input: ['cli/index.ts'], + output: { + dir: 'bin', + format: 'cjs', + }, + plugins: [...commonPlugins, typescript({ tsconfig: './tsconfig.cli.json' })], + }, + { + input: ['cli/upload/index.ts'], + output: { + dir: 'upload', + format: 'cjs', + }, + plugins: [...commonPlugins, typescript({ tsconfig: './tsconfig.upload.json' })], }, - plugins: [ - typescript({ tsconfig: './tsconfig.cli.json' }), - shebang(), - json(), - nodeResolve({ preferBuiltins: true }), - commonjs(), - cleanup(), - ], -}; +]; diff --git a/tsconfig.upload.json b/tsconfig.upload.json new file mode 100644 index 000000000..5ade7ea9a --- /dev/null +++ b/tsconfig.upload.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "include": ["cli/upload/**/*"], + "exclude": [], + "compilerOptions": { + "lib": ["dom"], + "outDir": "upload", + "module": "esnext" + } +} diff --git a/upload/package.json b/upload/package.json new file mode 100644 index 000000000..778c7ebf5 --- /dev/null +++ b/upload/package.json @@ -0,0 +1,5 @@ +{ + "main": "index.js", + "module": "index.mjs", + "types": "index.d.ts" +} From af182d34755deeb8c72ee6aef36bc167b324bf9d Mon Sep 17 00:00:00 2001 From: Ahmed Mahmoud Date: Mon, 15 Jul 2024 13:51:26 +0300 Subject: [PATCH 2/4] chore: remove unused upload.ts script --- examples/default/scripts/upload.ts | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 examples/default/scripts/upload.ts diff --git a/examples/default/scripts/upload.ts b/examples/default/scripts/upload.ts deleted file mode 100644 index 902dfe7e6..000000000 --- a/examples/default/scripts/upload.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { uploadSoFiles, uploadSourcemaps } from 'instabug-reactnative/upload'; - -const result = await uploadSourcemaps({ - code: 'your-app-code', - file: 'path-to-your-sourcemap-file', - platform: 'ios', - name: 'your-sourcemap-name', - token: 'your-app-token', - label: 'your-sourcemap-label', -}); - -const so = await uploadSoFiles({ - code: 'your-app-code', - file: 'path-to-your-sourcemap-file', - platform: 'ios', - name: 'your-sourcemap-name', - token: 'your-app-token', - label: 'your-sourcemap-label', -}); - -console.log(result); From b82c5f84435fb66e9c7cc5302fb2b89fd875fdc6 Mon Sep 17 00:00:00 2001 From: Ahmed Mahmoud Date: Mon, 15 Jul 2024 14:01:54 +0300 Subject: [PATCH 3/4] chore: update changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba9af205a..ec063a2fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [Unreleased](https://github.com/Instabug/Instabug-React-Native/compare/v13.2.0...dev) + +### Added + +- Export `uploadSourcemaps` and `uploadSoFiles` utilities in the `instabug-reactnative/upload` sub-package for usage in custom Node.js upload scripts ([#1252](https://github.com/Instabug/Instabug-React-Native/pull/1252)). + ## [13.2.0](https://github.com/Instabug/Instabug-React-Native/compare/v13.1.1...v13.2.0) (July 7, 2024) ### Changed From 8c1f86005b335dd30376a45e2fa2acab1bfda25e Mon Sep 17 00:00:00 2001 From: Ahmed Mahmoud Date: Wed, 17 Jul 2024 18:39:53 +0300 Subject: [PATCH 4/4] feat: return upload result and allow disabling logs --- cli/upload/uploadSoFiles.ts | 88 ++++++++++++++++++++++++++++------ cli/upload/uploadSourcemaps.ts | 39 +++++++++++---- 2 files changed, 105 insertions(+), 22 deletions(-) diff --git a/cli/upload/uploadSoFiles.ts b/cli/upload/uploadSoFiles.ts index acaac0113..fb25f6063 100755 --- a/cli/upload/uploadSoFiles.ts +++ b/cli/upload/uploadSoFiles.ts @@ -8,24 +8,54 @@ export interface UploadSoFilesOptions { token: string; name: string; api_key: string; + + /** + * Disables logging to the console and prevents process exit on error. + * + * @default false + * */ + silent?: boolean; } -export const uploadSoFiles = async (opts: UploadSoFilesOptions) => { +/** + * Uploads NDK `.so` files to Instabug. + * + * @param opts Options for the `.so` files upload process. + * @returns A promise that resolves to a boolean indicating whether the upload was successful. + */ +export const uploadSoFiles = async (opts: UploadSoFilesOptions): Promise => { const fileName = opts.file; - if (fileName == null) { - console.error('Failed to upload So Files: invalid file path'); - process.exit(1); + + const validFilePath = assert( + fileName != null, + 'Failed to upload So Files: invalid file path', + opts.silent, + ); + + if (!validFilePath) { + return false; } - if (fs.existsSync(fileName) === false) { - console.error('Failed to upload So Files: File not found'); - process.exit(1); + const fileExists = assert( + fs.existsSync(fileName), + 'Failed to upload So Files: File not found', + opts.silent, + ); + + if (!fileExists) { + return false; } - var fileExt = fileName.split('.').pop(); - if (fileExt !== 'zip') { - console.error('Failed to upload So Files: You can only upload ZIP files'); - process.exit(1); + const fileExt = fileName.split('.').pop(); + + const isZipFile = assert( + fileExt === 'zip', + 'Failed to upload So Files: You can only upload ZIP files', + opts.silent, + ); + + if (!isZipFile) { + return false; } const fileBlob = fs.readFileSync(opts.file); @@ -37,16 +67,46 @@ export const uploadSoFiles = async (opts: UploadSoFilesOptions) => { form.append('api_key', opts.api_key); form.append('arch', opts.arch); - console.log('Uploading So files...'); + if (!opts.silent) { + console.log('Uploading So files...'); + } + const uploadEndpoint = 'https://api.instabug.com/api/web/public/so_files'; try { await axios.post(uploadEndpoint, form, { headers: form.getHeaders(), }); - console.log(`Successfully uploaded So Files for version: ${opts.name} with arch ${opts.arch}`); + if (!opts.silent) { + console.log( + `Successfully uploaded So Files for version: ${opts.name} with arch ${opts.arch}`, + ); + } + + return true; } catch (err) { - console.error('Failed to upload So Files:', axios.isAxiosError(err) ? err.response?.data : err); + if (!opts.silent) { + console.error( + 'Failed to upload So Files:', + axios.isAxiosError(err) ? err.response?.data : err, + ); + + process.exit(1); + } + + return false; + } +}; + +export const assert = (condition: unknown, message: string, silent?: boolean): boolean => { + if (silent) { + return Boolean(condition); + } + + if (!condition) { + console.error(message); process.exit(1); } + + return true; }; diff --git a/cli/upload/uploadSourcemaps.ts b/cli/upload/uploadSourcemaps.ts index 2498fe8f9..701ce9ead 100644 --- a/cli/upload/uploadSourcemaps.ts +++ b/cli/upload/uploadSourcemaps.ts @@ -9,9 +9,22 @@ export interface UploadSourcemapsOptions { name: string; code: string; label?: string; + + /** + * Disables logging to the console and prevents process exit on error. + * + * @default false + * */ + silent?: boolean; } -export const uploadSourcemaps = async (opts: UploadSourcemapsOptions) => { +/** + * Uploads JavaScript sourcemaps to Instabug. + * + * @param opts Options for the sourcemaps upload process. + * @returns A promise that resolves to a boolean indicating whether the upload was successful. + */ +export const uploadSourcemaps = async (opts: UploadSourcemapsOptions): Promise => { const fileName = `${opts.platform}-sourcemap.json`; const fileBlob = fs.readFileSync(opts.file); @@ -28,7 +41,9 @@ export const uploadSourcemaps = async (opts: UploadSourcemapsOptions) => { form.append('platform', 'react_native'); form.append('os', opts.platform); - console.log('Uploading Source map file...'); + if (!opts.silent) { + console.log('Uploading Source map file...'); + } try { const response = await axios.post('https://api.instabug.com/api/sdk/v3/symbols_files', form, { @@ -39,12 +54,20 @@ export const uploadSourcemaps = async (opts: UploadSourcemapsOptions) => { ? `${version.name} (${version.code})+codepush:${version.codepush}` : `${version.name} (${version.code})`; - console.log(`Successfully uploaded Source maps for version: ${appVersion}`); - console.log(response.data); + if (!opts.silent) { + console.log(`Successfully uploaded Source maps for version: ${appVersion}`); + console.log(response.data); + } + + return true; } catch (err) { - console.error( - 'Failed to upload source maps:', - axios.isAxiosError(err) ? err.response?.data : err, - ); + if (!opts.silent) { + console.error( + 'Failed to upload source maps:', + axios.isAxiosError(err) ? err.response?.data : err, + ); + } + + return false; } };