@flashcatcloud/hvigor-plugin
Advanced tools
+30
-0
| # Changelog | ||
| ## 0.1.5 | ||
| - Fix `uploadFlashcatSymbols` breaking task-graph resolution: the task declared | ||
| `dependencies: ['assembleHap','assembleHar']`, but a module has at most one of | ||
| those, so the missing one failed the build. The task now declares no build | ||
| dependencies — run it as its own hvigor invocation after a release build. | ||
| - A disabled task now says so. `enabled: false` used to return without a word, which | ||
| in a build log is indistinguishable from a successful upload. Every path that skips | ||
| the upload now states its reason. | ||
| - The build directory now follows the product being built (`-p product=beta` → | ||
| `build/beta`), read from the project's OHOS app context. `buildDir` stays as an | ||
| override for layouts that do not follow that convention; previously it defaulted | ||
| to `build/default` and silently scanned the wrong directory for every other | ||
| product. | ||
| - Log the directory being scanned and how it was chosen, and name that directory | ||
| in the "no sourceMaps.map found" message, so a wrong build dir is visible in the | ||
| build output instead of looking like missing sourcemap output. | ||
| - Run the upload task with `--no-daemon`. hvigor's daemon snapshots the | ||
| environment when it is first started and refreshes only a fixed allowlist of | ||
| variables, so a reused daemon can hand the plugin a stale or empty `process.env` | ||
| — silently skipping the upload, or uploading under the previous version number. | ||
| - An empty `buildDir` now counts as unset instead of resolving to the module root. | ||
| An unassigned `FLASHCAT_BUILD_DIR=` in CI reaches the option as `''`, and scanning | ||
| the module root collects every product's sourcemap — uploading an arbitrary one | ||
| under the current version, the same class of bug the product-aware default fixes. | ||
| - The "skipping symbol upload" warning now names the `apiKey` option rather than only | ||
| the environment variable, and points at `--no-daemon` — the likeliest reason the | ||
| value arrived empty. | ||
| - First tests for task registration and build-dir resolution (`plugin.ts` had none). | ||
| ## 0.1.3 | ||
@@ -4,0 +34,0 @@ |
+1
-1
@@ -33,3 +33,3 @@ "use strict"; | ||
| if (!sm) { | ||
| result.sourcemap.reason = 'no sourceMaps.map found (is obfuscation/sourcemap output enabled?)'; | ||
| result.sourcemap.reason = `no sourceMaps.map found under ${buildDir} (wrong build dir, or sourcemap output disabled?)`; | ||
| log(`flashcat: ${result.sourcemap.reason}`); | ||
@@ -36,0 +36,0 @@ } |
+29
-6
| export interface HvigorNode { | ||
| getNodePath(): string; | ||
| getParentNode?(): HvigorNode | undefined; | ||
| getContext?(pluginId: string): unknown; | ||
| registerTask(task: { | ||
@@ -23,5 +25,11 @@ name: string; | ||
| version: string; | ||
| /** module build dir relative to the module root; default 'build/default'. */ | ||
| /** Module build dir, relative to the module root. Optional — by default it follows | ||
| * the product being built (`-p product=beta` → `build/beta`). Set it only when the | ||
| * artifacts are somewhere that does not follow that layout. An empty string counts | ||
| * as unset: an unassigned `FLASHCAT_BUILD_DIR=` in CI must not turn into a scan of | ||
| * the whole module root, which would collect another product's sourcemap. */ | ||
| buildDir?: string; | ||
| /** when false the task is registered but does nothing (e.g. debug builds). Default true. */ | ||
| /** When false the task is registered but does nothing, and says so. Default true. | ||
| * Kept as an option because a pipeline variable is cheaper to flip than an edit to | ||
| * the build command — the same switch consumers otherwise hand-roll. */ | ||
| enabled?: boolean; | ||
@@ -31,6 +39,18 @@ pluginVersion?: string; | ||
| /** | ||
| * Registers an `uploadFlashcatSymbols` task on the module. Runs AFTER the module | ||
| * is assembled (`default@PackageHap` / `default@PackageHar` produce the sourcemap | ||
| * and native libs) and uploads ArkTS sourcemaps + native `.so` debug symbols. | ||
| * Absolute build-artifact dir to scan, plus how it was decided. The `how` string is | ||
| * logged so a wrong directory is visible in the build output instead of surfacing | ||
| * later as an unexplained "no sourceMaps.map found". | ||
| */ | ||
| export declare function resolveBuildDir(node: HvigorNode, explicit?: string): { | ||
| dir: string; | ||
| how: string; | ||
| }; | ||
| /** | ||
| * Registers an `uploadFlashcatSymbols` task on the module, which uploads ArkTS | ||
| * sourcemaps + native `.so` debug symbols for the product being built. | ||
| * | ||
| * The task declares no build dependencies: run it after a release build, as its | ||
| * own hvigor invocation. (Declaring `assembleHap`/`assembleHar` would break every | ||
| * module that has only one of them.) | ||
| * | ||
| * Wire it into a module's `hvigorfile.ts`: | ||
@@ -49,4 +69,7 @@ * ```ts | ||
| * ``` | ||
| * Run with: `hvigorw uploadFlashcatSymbols --mode module -p module=entry@default`. | ||
| * Run with `--no-daemon`: hvigor's daemon snapshots the environment when it is | ||
| * first started and does not refresh it, so without that flag a reused daemon can | ||
| * hand the plugin a stale (or empty) `process.env`. | ||
| * `hvigorw uploadFlashcatSymbols --no-daemon --mode module -p module=entry@default`. | ||
| */ | ||
| export declare function flashcatSymbolUploadPlugin(options: FlashcatPluginOptions): HvigorPlugin; |
+59
-11
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.resolveBuildDir = resolveBuildDir; | ||
| exports.flashcatSymbolUploadPlugin = flashcatSymbolUploadPlugin; | ||
@@ -10,7 +11,48 @@ const node_module_1 = require("node:module"); | ||
| const PACKAGE_VERSION = requirePackageJson('../package.json').version; | ||
| /** Plugin id hvigor registers the OHOS app (project-level) context under. */ | ||
| const OHOS_APP_PLUGIN_ID = 'com.ohos.app'; | ||
| /** Product hvigor builds when `-p product=` is omitted. */ | ||
| const DEFAULT_PRODUCT = 'default'; | ||
| /** | ||
| * Registers an `uploadFlashcatSymbols` task on the module. Runs AFTER the module | ||
| * is assembled (`default@PackageHap` / `default@PackageHar` produce the sourcemap | ||
| * and native libs) and uploads ArkTS sourcemaps + native `.so` debug symbols. | ||
| * The product hvigor is currently building (`-p product=beta`), read from the | ||
| * project node's OHOS app context. Returns null when that context is not | ||
| * reachable, so the caller can fall back to the default product and say so. | ||
| */ | ||
| function currentProductName(node) { | ||
| try { | ||
| const context = node.getParentNode?.()?.getContext?.(OHOS_APP_PLUGIN_ID); | ||
| const name = context?.getCurrentProduct?.()?.getProductName?.(); | ||
| return typeof name === 'string' && name.length > 0 ? name : null; | ||
| } | ||
| catch { | ||
| return null; | ||
| } | ||
| } | ||
| /** | ||
| * Absolute build-artifact dir to scan, plus how it was decided. The `how` string is | ||
| * logged so a wrong directory is visible in the build output instead of surfacing | ||
| * later as an unexplained "no sourceMaps.map found". | ||
| */ | ||
| function resolveBuildDir(node, explicit) { | ||
| const moduleRoot = node.getNodePath(); | ||
| if (explicit !== undefined && explicit !== '') { | ||
| return { dir: `${moduleRoot}/${explicit}`, how: 'buildDir option' }; | ||
| } | ||
| const product = currentProductName(node); | ||
| if (product === null) { | ||
| return { | ||
| dir: `${moduleRoot}/build/${DEFAULT_PRODUCT}`, | ||
| how: `product unavailable, assuming '${DEFAULT_PRODUCT}' — pass buildDir if this is wrong` | ||
| }; | ||
| } | ||
| return { dir: `${moduleRoot}/build/${product}`, how: `product '${product}'` }; | ||
| } | ||
| /** | ||
| * Registers an `uploadFlashcatSymbols` task on the module, which uploads ArkTS | ||
| * sourcemaps + native `.so` debug symbols for the product being built. | ||
| * | ||
| * The task declares no build dependencies: run it after a release build, as its | ||
| * own hvigor invocation. (Declaring `assembleHap`/`assembleHar` would break every | ||
| * module that has only one of them.) | ||
| * | ||
| * Wire it into a module's `hvigorfile.ts`: | ||
@@ -29,3 +71,6 @@ * ```ts | ||
| * ``` | ||
| * Run with: `hvigorw uploadFlashcatSymbols --mode module -p module=entry@default`. | ||
| * Run with `--no-daemon`: hvigor's daemon snapshots the environment when it is | ||
| * first started and does not refresh it, so without that flag a reused daemon can | ||
| * hand the plugin a stale (or empty) `process.env`. | ||
| * `hvigorw uploadFlashcatSymbols --no-daemon --mode module -p module=entry@default`. | ||
| */ | ||
@@ -38,8 +83,8 @@ function flashcatSymbolUploadPlugin(options) { | ||
| name: 'uploadFlashcatSymbols', | ||
| // hvigor semantics: `dependencies` are tasks that run BEFORE this task | ||
| // (`postDependencies` would schedule this task before them — i.e. before | ||
| // the build, uploading the previous build's symbols under the new version). | ||
| dependencies: ['assembleHap', 'assembleHar'], | ||
| run: async () => { | ||
| if (options.enabled === false) { | ||
| // Never return silently: in a build log, a deliberate skip and a | ||
| // successful upload would otherwise look exactly the same. | ||
| // eslint-disable-next-line no-console | ||
| console.warn('flashcat: upload disabled (enabled: false) — skipping symbol upload.'); | ||
| return; | ||
@@ -49,3 +94,4 @@ } | ||
| // eslint-disable-next-line no-console | ||
| console.warn('flashcat: FLASHCAT_API_KEY not set — skipping symbol upload.'); | ||
| console.warn('flashcat: apiKey is empty — skipping symbol upload. Set FLASHCAT_API_KEY, ' + | ||
| 'and pass --no-daemon so hvigor does not hand the plugin a cached environment.'); | ||
| return; | ||
@@ -70,5 +116,7 @@ } | ||
| }; | ||
| const buildDir = `${node.getNodePath()}/${options.buildDir ?? 'build/default'}`; | ||
| const { dir, how } = resolveBuildDir(node, options.buildDir); | ||
| // eslint-disable-next-line no-console | ||
| await (0, index_ts_1.uploadAll)(buildDir, cfg, (m) => console.log(m)); | ||
| console.log(`flashcat: scanning ${dir} (${how})`); | ||
| // eslint-disable-next-line no-console | ||
| await (0, index_ts_1.uploadAll)(dir, cfg, (m) => console.log(m)); | ||
| } | ||
@@ -75,0 +123,0 @@ }); |
+1
-1
| { | ||
| "name": "@flashcatcloud/hvigor-plugin", | ||
| "version": "0.1.3", | ||
| "version": "0.1.5", | ||
| "description": "FlashCat hvigor plugin: upload HarmonyOS ArkTS sourcemaps + native .so debug symbols to fc-rum for crash symbolication.", | ||
@@ -5,0 +5,0 @@ "license": "Apache-2.0", |
+41
-17
@@ -15,12 +15,5 @@ # @flashcatcloud/hvigor-plugin | ||
| The plugin is published on **npm**, not ohpm. Install it as a devDependency in | ||
| the project root `package.json` (not `oh-package.json5`): | ||
| The plugin is published on **npm**, not ohpm. Declare it in | ||
| `hvigor/hvigor-config.json5` — hvigor fetches it from npm itself: | ||
| ```sh | ||
| npm install -D @flashcatcloud/hvigor-plugin | ||
| ``` | ||
| Alternatively, declare it in `hvigor/hvigor-config.json5` `dependencies` — | ||
| hvigor still fetches it from npm: | ||
| ```json5 | ||
@@ -30,3 +23,3 @@ { | ||
| "dependencies": { | ||
| "@flashcatcloud/hvigor-plugin": "^0.1.3" | ||
| "@flashcatcloud/hvigor-plugin": "0.1.5" | ||
| } | ||
@@ -36,2 +29,15 @@ } | ||
| You can install it with npm instead, but a HarmonyOS project has no root | ||
| `package.json`, and `npm install` walks *up* the directory tree looking for one — | ||
| so run `npm init -y` in the project root first, or npm will install into whatever | ||
| unrelated project it finds in a parent directory (often your home directory): | ||
| ```sh | ||
| npm init -y # only if there is no root package.json | ||
| npm install -D @flashcatcloud/hvigor-plugin | ||
| ``` | ||
| Pin the exact version and commit the lock file: the plugin has zero runtime | ||
| dependencies, so the lock stays a few lines. | ||
| ## Usage (hvigor task) | ||
@@ -55,3 +61,3 @@ | ||
| version: '1.0.0', | ||
| enabled: process.env.FLASHCAT_UPLOAD === '1' // upload only when explicitly asked | ||
| enabled: process.env.FLASHCAT_UPLOAD === '1' // upload only when asked | ||
| }) | ||
@@ -62,9 +68,20 @@ ] | ||
| Then, after a release build: | ||
| Then, after a release build, run the task as its own hvigor invocation: | ||
| ```sh | ||
| FLASHCAT_UPLOAD=1 FLASHCAT_API_KEY=*** \ | ||
| hvigorw uploadFlashcatSymbols --mode module -p module=entry@default -p product=default | ||
| hvigorw uploadFlashcatSymbols --no-daemon \ | ||
| --mode module -p module=entry@beta -p product=beta | ||
| ``` | ||
| `--no-daemon` is not optional if you configure the plugin from environment | ||
| variables. hvigor builds through a long-lived daemon process, which copies the | ||
| environment once when it is *created* and afterwards refreshes only a fixed | ||
| allowlist (`DEVECO_SDK_HOME`, `OHOS_BASE_SDK_HOME`, and two incremental-build | ||
| flags). A reused daemon therefore sees the environment of whoever started it — an | ||
| IDE build, or an earlier command — not the one you just typed. The failure is easy | ||
| to miss: `FLASHCAT_UPLOAD` or `FLASHCAT_API_KEY` reads as unset and the task skips | ||
| with only a warning, or a stale version uploads the symbols under the wrong version | ||
| number. Values written directly into `hvigorfile.ts` are not affected. | ||
| Endpoint resolution (first match wins): | ||
@@ -79,6 +96,13 @@ | ||
| The task is registered with `dependencies: ['assembleHap','assembleHar']` (it runs | ||
| after the assemble tasks), so the sourcemap + native libs exist when it runs. A missing artifact or upload | ||
| failure is logged but never fails the build. | ||
| The task declares no build dependencies, so it works on HAP, HAR and HSP modules | ||
| alike — a module has at most one of `assembleHap`/`assembleHar`, and naming both | ||
| breaks task-graph resolution for every module. Build first, then run the upload | ||
| task. A missing artifact or an upload failure is logged but never fails the build, | ||
| so read the log: `flashcat: sourcemap upload OK (200)` is the success line. | ||
| The directory scanned follows the product being built (`-p product=beta` → | ||
| `<module>/build/beta`), read from the project's OHOS app context. Pass `buildDir` | ||
| only if your artifacts live somewhere else. Either way the resolved directory is | ||
| logged (`flashcat: scanning <dir> (...)`) so a wrong guess is visible immediately. | ||
| ## Programmatic / CI use | ||
@@ -90,3 +114,3 @@ | ||
| endpoint: process.env.FLASHCAT_SOURCEMAP_INTAKE_URL || 'https://ci.flashcat.cloud', | ||
| apiKey, service, version, pluginVersion: '0.1.3' | ||
| apiKey, service, version, pluginVersion: '0.1.5' | ||
| }, console.log); | ||
@@ -93,0 +117,0 @@ ``` |
44609
19.24%794
9.82%141
20.51%