From 88cc294d858da0d8ed537eea25412d276b3beba6 Mon Sep 17 00:00:00 2001 From: Suejung Shin Date: Thu, 12 Sep 2024 15:36:08 -0700 Subject: [PATCH 1/5] fix: Add extended options to cli, export types in bundle-analyzer lib --- .changeset/eleven-deers-divide.md | 9 ++ examples/bundle-analyzer-lib-cjs/analyze.js | 27 ------ examples/bundle-analyzer-lib-cjs/analyze.ts | 33 ++++++++ examples/bundle-analyzer-lib-cjs/package.json | 4 +- .../{analyze.js => analyze.ts} | 0 examples/bundle-analyzer-lib-esm/package.json | 4 +- packages/bundle-analyzer/README.md | 12 +-- packages/bundle-analyzer/package.json | 6 +- packages/bundle-analyzer/src/cli.ts | 83 +++++++++++++++++-- packages/bundle-analyzer/src/index.ts | 5 +- .../bundler-plugin-core/src/utils/Output.ts | 8 +- 11 files changed, 141 insertions(+), 50 deletions(-) delete mode 100644 examples/bundle-analyzer-lib-cjs/analyze.js create mode 100644 examples/bundle-analyzer-lib-cjs/analyze.ts rename examples/bundle-analyzer-lib-esm/{analyze.js => analyze.ts} (100%) diff --git a/.changeset/eleven-deers-divide.md b/.changeset/eleven-deers-divide.md index dd736ef7..2e16cb76 100644 --- a/.changeset/eleven-deers-divide.md +++ b/.changeset/eleven-deers-divide.md @@ -1,5 +1,14 @@ --- "@codecov/bundle-analyzer": minor +"@codecov/bundler-plugin-core": minor +"@codecov/nextjs-webpack-plugin": minor +"@codecov/nuxt-plugin": minor +"@codecov/remix-vite-plugin": minor +"@codecov/rollup-plugin": minor +"@codecov/solidstart-plugin": minor +"@codecov/sveltekit-plugin": minor +"@codecov/vite-plugin": minor +"@codecov/webpack-plugin": minor --- Add support for setups without a standard bundler through new Bundle Analyzer library and CLI diff --git a/examples/bundle-analyzer-lib-cjs/analyze.js b/examples/bundle-analyzer-lib-cjs/analyze.js deleted file mode 100644 index 46c7ad17..00000000 --- a/examples/bundle-analyzer-lib-cjs/analyze.js +++ /dev/null @@ -1,27 +0,0 @@ -const { createAndUploadReport } = require("@codecov/bundle-analyzer"); - -const buildDirs = ["../../../examples/bundle-analyzer-lib-cjs/example-dist"]; - -const coreOpts = { - dryRun: false, - uploadToken: process.env.BUNDLE_ANALYZER_UPLOAD_TOKEN, - retryCount: 3, - apiUrl: "https://api.codecov.io", - bundleName: "@codecov/example-bundle-analyzer-cjs", - enableBundleAnalysis: true, - debug: true, -}; - -const bundleAnalyzerOpts = { - beforeReportUpload: async (original) => original, - ignorePatterns: ["*.map"], - normalizeAssetsPattern: "[name]-[hash].js", -}; - -createAndUploadReport(buildDirs, coreOpts, bundleAnalyzerOpts) - .then((reportAsJson) => - console.log(`Report successfully generated and uploaded: ${reportAsJson}`), - ) - .catch((error) => - console.error("Failed to generate or upload report:", error), - ); diff --git a/examples/bundle-analyzer-lib-cjs/analyze.ts b/examples/bundle-analyzer-lib-cjs/analyze.ts new file mode 100644 index 00000000..6711b245 --- /dev/null +++ b/examples/bundle-analyzer-lib-cjs/analyze.ts @@ -0,0 +1,33 @@ +import { + createAndUploadReport, + type BundleAnalyzerOptions, + type Options, +} from "@codecov/bundle-analyzer"; + +const buildDirs: string[] = [ + "../../../examples/bundle-analyzer-lib-cjs/example-dist", +]; + +const coreOpts: Options = { + dryRun: false, + uploadToken: process.env.BUNDLE_ANALYZER_UPLOAD_TOKEN as string, + retryCount: 3, + apiUrl: "https://api.codecov.io", + bundleName: "@codecov/example-bundle-analyzer-cjs", + enableBundleAnalysis: true, + debug: true, +}; + +const bundleAnalyzerOpts: BundleAnalyzerOptions = { + beforeReportUpload: async (original: any) => original, + ignorePatterns: ["*.map"], + normalizeAssetsPattern: "[name]-[hash].js", +}; + +createAndUploadReport(buildDirs, coreOpts, bundleAnalyzerOpts) + .then((reportAsJson: string) => + console.log(`Report successfully generated and uploaded: ${reportAsJson}`), + ) + .catch((error: Error) => + console.error("Failed to generate or upload report:", error), + ); diff --git a/examples/bundle-analyzer-lib-cjs/package.json b/examples/bundle-analyzer-lib-cjs/package.json index 68461ae0..63a9fec0 100644 --- a/examples/bundle-analyzer-lib-cjs/package.json +++ b/examples/bundle-analyzer-lib-cjs/package.json @@ -2,9 +2,9 @@ "name": "@codecov/example-bundle-analyzer-library-cjs", "version": "1.0.0", "private": true, - "main": "analyze.js", + "main": "analyze.ts", "scripts": { - "build": "node analyze.js" + "build": "npx tsx analyze.ts" }, "devDependencies": { "@codecov/bundle-analyzer": "workspace:^" diff --git a/examples/bundle-analyzer-lib-esm/analyze.js b/examples/bundle-analyzer-lib-esm/analyze.ts similarity index 100% rename from examples/bundle-analyzer-lib-esm/analyze.js rename to examples/bundle-analyzer-lib-esm/analyze.ts diff --git a/examples/bundle-analyzer-lib-esm/package.json b/examples/bundle-analyzer-lib-esm/package.json index 1a4ca7cf..c7a6f0dc 100644 --- a/examples/bundle-analyzer-lib-esm/package.json +++ b/examples/bundle-analyzer-lib-esm/package.json @@ -2,10 +2,10 @@ "name": "@codecov/example-bundle-analyzer-library-mjs", "version": "1.0.0", "private": true, - "main": "analyze.js", + "main": "analyze.ts", "type": "module", "scripts": { - "build": "node analyze.js" + "build": "npx tsx analyze.ts" }, "devDependencies": { "@codecov/bundle-analyzer": "workspace:^" diff --git a/packages/bundle-analyzer/README.md b/packages/bundle-analyzer/README.md index 4fd906dc..228cb799 100644 --- a/packages/bundle-analyzer/README.md +++ b/packages/bundle-analyzer/README.md @@ -6,11 +6,9 @@ # Codecov Bundle Analyzer -> [!WARNING] -> This bundle-analyzer package is subject to change. -> -> An importable library + CLI for Codecov bundle analysis support. -> +An importable library + CLI for Codecov bundle analysis support. + +> [!NOTE] > The plugin does not support code coverage, see our [docs](https://docs.codecov.com/docs/quick-start) to set up coverage today! ## Installation @@ -33,7 +31,7 @@ Using pnpm: pnpm add @codecov/bundle-analyzer --save-dev ``` -## Example +## Example - Custom Script This example shows how the package can be imported as a library. @@ -68,6 +66,8 @@ createAndUploadReport(buildDirs, coreOpts, bundleAnalyzerOpts) ); ``` +## Example - CLI + This example shows how the package can be used as a CLI. ``` diff --git a/packages/bundle-analyzer/package.json b/packages/bundle-analyzer/package.json index 3db115b9..75a7ce4f 100644 --- a/packages/bundle-analyzer/package.json +++ b/packages/bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@codecov/bundle-analyzer", - "version": "0.0.1-beta.12", + "version": "1.0.1", "description": "Official Codecov Bundle Analyzer", "author": "Codecov", "license": "MIT", @@ -8,7 +8,9 @@ "Codecov", "bundle-analyzer", "bundler", - "analyzer" + "analyzer", + "cli", + "script" ], "type": "module", "bin": { diff --git a/packages/bundle-analyzer/src/cli.ts b/packages/bundle-analyzer/src/cli.ts index 5b6c54fb..9e30e8b9 100644 --- a/packages/bundle-analyzer/src/cli.ts +++ b/packages/bundle-analyzer/src/cli.ts @@ -1,21 +1,43 @@ #!/usr/bin/env node import path from "node:path"; +import fs from "node:fs"; import yargs from "yargs"; import { hideBin } from "yargs/helpers"; import { createAndUploadReport } from "./index.js"; import { red, type Options } from "@codecov/bundler-plugin-core"; import { type BundleAnalyzerOptions } from "./options"; -interface Argv { +interface Argv extends BaseArgs, ConfigFileArgs {} + +// Base arguments that can be supplied in a flag or an optional config file. These are the more common configurations options +interface BaseArgs { buildDirectories: string[]; - dryRun?: boolean; - uploadToken?: string; + + // Bundle Analyzer Options + ignorePatterns?: string[]; + normalizeAssetsPattern?: string; + + // Core Options apiUrl?: string; + uploadToken?: string; bundleName: string; debug?: boolean; - ignorePatterns?: string[]; - normalizeAssetsPattern?: string; + dryRun?: boolean; + + configFile?: string; +} + +// ConfigFileArgs arguments that can be supplied in an optional config file. These are less common configurations options +interface ConfigFileArgs { + // Core Options + gitService?: string; + uploadOverridesBranch?: string; + uploadOverridesBuild?: string; + uploadOverridesPr?: string; + uploadOverridesSha?: string; + oidcUseGitHubOIDC?: boolean; + oidcGitHubOIDCTokenAudience?: string; } const argv = yargs(hideBin(process.argv)) @@ -71,11 +93,48 @@ const argv = yargs(hideBin(process.argv)) type: "string", description: "Pattern to normalize asset names, e.g., '[name]-[hash].js'", }, + "config-file": { + alias: "c", + type: "string", + description: "Path to a JSON configuration file", + }, }) .strict() .help("h") .alias("h", "help") - .parseSync() as unknown as Argv; + .parseSync() as unknown as BaseArgs; + +const getConfigFileArgs = (): Partial => { + // Load and merge config file if provided + const loadConfigFile = (filePath: string): Partial => { + try { + const configContent = fs.readFileSync(filePath, "utf-8"); + return JSON.parse(configContent) as Partial; + } catch (error) { + red(`Failed to load configuration file: ${error}`); + process.exit(1); + } + }; + + let configFromFile: Partial = {}; + if (argv.configFile) { + configFromFile = loadConfigFile(argv.configFile); + } + + return configFromFile; +}; + +const resolveArgs = (): Argv => { + const configFromFile = getConfigFileArgs(); + + // Merge CLI flag arguments with config file values (CLI flag takes precedence) + const mergedArgs: Argv = { + ...configFromFile, + ...argv, + }; + + return mergedArgs; +}; const prepareCoreOptions = (argv: Argv): Options => { return { @@ -94,7 +153,14 @@ const prepareBundleAnalyzerOptions = (argv: Argv): BundleAnalyzerOptions => { }; }; -export const runCli = async (argv: Argv): Promise => { +export const runCli = async (): Promise => { + const argv = resolveArgs(); + + if (argv.buildDirectories.length === 0) { + red("Error: No build directories provided."); + process.exit(1); + } + const resolvedDirectoryPaths = argv.buildDirectories.map((dir) => path.resolve(process.cwd(), dir), ); @@ -109,12 +175,11 @@ export const runCli = async (argv: Argv): Promise => { ); if (coreOptions.dryRun) { - // eslint-disable-next-line no-console console.log(reportAsJson); } }; -runCli(argv).catch((error) => { +runCli().catch((error) => { red(`An error occurred: ${error}`); process.exit(1); }); diff --git a/packages/bundle-analyzer/src/index.ts b/packages/bundle-analyzer/src/index.ts index 9f409e36..07f6731f 100644 --- a/packages/bundle-analyzer/src/index.ts +++ b/packages/bundle-analyzer/src/index.ts @@ -12,6 +12,9 @@ import { } from "./options"; import { getAssets } from "./assets"; +export { type Options } from "@codecov/bundler-plugin-core"; +export { type BundleAnalyzerOptions } from "./options"; + /** * Generates a Codecov bundle stats report and optionally uploads it to Codecov. This function can * be imported into your code or used via the bundle-analyzer CLI. @@ -74,7 +77,7 @@ export const createAndUploadReport = async ( } if (!coreOptions.dryRun) { - await finalReport.write(); + await finalReport.write(true); } return finalReport.bundleStatsToJson(); diff --git a/packages/bundler-plugin-core/src/utils/Output.ts b/packages/bundler-plugin-core/src/utils/Output.ts index 7584f80f..a25502cc 100644 --- a/packages/bundler-plugin-core/src/utils/Output.ts +++ b/packages/bundler-plugin-core/src/utils/Output.ts @@ -129,7 +129,7 @@ class Output { this.#internalLocks.pluginDetails = false; } - async write() { + async write(emitError?: boolean) { if (this.dryRun) return; if (!this.bundleName || this.bundleName === "") return; @@ -156,6 +156,9 @@ class Output { serviceParams: provider, }); } catch (error) { + if (emitError) { + throw error; + } return; } @@ -167,6 +170,9 @@ class Output { retryCount: this?.retryCount, }); } catch (error) { + if (emitError) { + throw error; + } return; } From 2a90505505740d2b68258681998b1cc3a1cbdb0a Mon Sep 17 00:00:00 2001 From: Suejung Shin Date: Fri, 13 Sep 2024 01:42:44 -0700 Subject: [PATCH 2/5] add config file to cli, fix tests --- examples/bundle-analyzer-lib-cjs/analyze.js | 27 ++++++++ examples/bundle-analyzer-lib-cjs/analyze.ts | 33 ---------- examples/bundle-analyzer-lib-cjs/package.json | 4 +- examples/bundle-analyzer-lib-esm/analyze.ts | 12 ++-- packages/bundle-analyzer/src/assets.test.ts | 39 ------------ packages/bundle-analyzer/src/assets.ts | 15 +---- packages/bundle-analyzer/src/cli.test.ts | 51 ++++++++++++++- packages/bundle-analyzer/src/cli.ts | 62 ++++++++++++------- 8 files changed, 126 insertions(+), 117 deletions(-) create mode 100644 examples/bundle-analyzer-lib-cjs/analyze.js delete mode 100644 examples/bundle-analyzer-lib-cjs/analyze.ts diff --git a/examples/bundle-analyzer-lib-cjs/analyze.js b/examples/bundle-analyzer-lib-cjs/analyze.js new file mode 100644 index 00000000..b4ed3246 --- /dev/null +++ b/examples/bundle-analyzer-lib-cjs/analyze.js @@ -0,0 +1,27 @@ +const { createAndUploadReport } = require("@codecov/bundle-analyzer"); + +const buildDirs = ["../../examples/bundle-analyzer-lib-cjs/example-dist"]; + +const coreOpts = { + dryRun: false, + uploadToken: process.env.BUNDLE_ANALYZER_UPLOAD_TOKEN, + retryCount: 3, + apiUrl: "https://api.codecov.io", + bundleName: "@codecov/example-bundle-analyzer-cjs", + enableBundleAnalysis: true, + debug: true, +}; + +const bundleAnalyzerOpts = { + beforeReportUpload: async (original) => original, + ignorePatterns: ["*.map"], + normalizeAssetsPattern: "[name]-[hash].js", +}; + +createAndUploadReport(buildDirs, coreOpts, bundleAnalyzerOpts) + .then((reportAsJson) => + console.log(`Report successfully generated and uploaded: ${reportAsJson}`), + ) + .catch((error) => + console.error("Failed to generate or upload report:", error), + ); diff --git a/examples/bundle-analyzer-lib-cjs/analyze.ts b/examples/bundle-analyzer-lib-cjs/analyze.ts deleted file mode 100644 index 6711b245..00000000 --- a/examples/bundle-analyzer-lib-cjs/analyze.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { - createAndUploadReport, - type BundleAnalyzerOptions, - type Options, -} from "@codecov/bundle-analyzer"; - -const buildDirs: string[] = [ - "../../../examples/bundle-analyzer-lib-cjs/example-dist", -]; - -const coreOpts: Options = { - dryRun: false, - uploadToken: process.env.BUNDLE_ANALYZER_UPLOAD_TOKEN as string, - retryCount: 3, - apiUrl: "https://api.codecov.io", - bundleName: "@codecov/example-bundle-analyzer-cjs", - enableBundleAnalysis: true, - debug: true, -}; - -const bundleAnalyzerOpts: BundleAnalyzerOptions = { - beforeReportUpload: async (original: any) => original, - ignorePatterns: ["*.map"], - normalizeAssetsPattern: "[name]-[hash].js", -}; - -createAndUploadReport(buildDirs, coreOpts, bundleAnalyzerOpts) - .then((reportAsJson: string) => - console.log(`Report successfully generated and uploaded: ${reportAsJson}`), - ) - .catch((error: Error) => - console.error("Failed to generate or upload report:", error), - ); diff --git a/examples/bundle-analyzer-lib-cjs/package.json b/examples/bundle-analyzer-lib-cjs/package.json index 63a9fec0..68461ae0 100644 --- a/examples/bundle-analyzer-lib-cjs/package.json +++ b/examples/bundle-analyzer-lib-cjs/package.json @@ -2,9 +2,9 @@ "name": "@codecov/example-bundle-analyzer-library-cjs", "version": "1.0.0", "private": true, - "main": "analyze.ts", + "main": "analyze.js", "scripts": { - "build": "npx tsx analyze.ts" + "build": "node analyze.js" }, "devDependencies": { "@codecov/bundle-analyzer": "workspace:^" diff --git a/examples/bundle-analyzer-lib-esm/analyze.ts b/examples/bundle-analyzer-lib-esm/analyze.ts index 06d94526..a8f9fe72 100644 --- a/examples/bundle-analyzer-lib-esm/analyze.ts +++ b/examples/bundle-analyzer-lib-esm/analyze.ts @@ -1,8 +1,12 @@ -import { createAndUploadReport } from "@codecov/bundle-analyzer"; +import { + BundleAnalyzerOptions, + createAndUploadReport, + Options, +} from "@codecov/bundle-analyzer"; -const buildDirs = ["../../../examples/bundle-analyzer-lib-esm/example-dist"]; +const buildDirs = ["../../examples/bundle-analyzer-lib-esm/example-dist"]; -const coreOpts = { +const coreOpts: Options = { dryRun: false, uploadToken: process.env.BUNDLE_ANALYZER_UPLOAD_TOKEN, retryCount: 3, @@ -12,7 +16,7 @@ const coreOpts = { debug: true, }; -const bundleAnalyzerOpts = { +const bundleAnalyzerOpts: BundleAnalyzerOptions = { beforeReportUpload: async (original) => original, ignorePatterns: ["*.map"], normalizeAssetsPattern: "[name]-[hash].js", diff --git a/packages/bundle-analyzer/src/assets.test.ts b/packages/bundle-analyzer/src/assets.test.ts index 4bfc6b64..cdcd41c7 100644 --- a/packages/bundle-analyzer/src/assets.test.ts +++ b/packages/bundle-analyzer/src/assets.test.ts @@ -255,42 +255,3 @@ describe("getAllAssets", () => { ]); }); }); - -describe("Module System Compatibility", () => { - let fileName: string; - let __dirname: string; - - const setCommonJSContext = () => { - // @ts-expect-error - ignore ts error for module cleanup - global.module = { exports: {} }; - fileName = __filename; - __dirname = path.dirname(fileName); - }; - - const setESModulesContext = () => { - // @ts-expect-error - ignore ts error for module cleanup - delete global.module; - fileName = fileURLToPath(import.meta.url); - __dirname = path.dirname(fileName); - }; - - afterEach(() => { - // clean up the global context after each test - // @ts-expect-error - ignore ts error for module cleanup - delete global.module; - }); - - it("should correctly set fileName and __dirname in CommonJS environment", () => { - setCommonJSContext(); - - expect(fileName).toBe(__filename); - expect(__dirname).toBe(path.dirname(__filename)); - }); - - it("should correctly set fileName and __dirname in ESModules environment", () => { - setESModulesContext(); - - expect(fileName).toBe(fileURLToPath(import.meta.url)); - expect(__dirname).toBe(path.dirname(fileURLToPath(import.meta.url))); - }); -}); diff --git a/packages/bundle-analyzer/src/assets.ts b/packages/bundle-analyzer/src/assets.ts index 37e95ce8..cd60f746 100644 --- a/packages/bundle-analyzer/src/assets.ts +++ b/packages/bundle-analyzer/src/assets.ts @@ -5,21 +5,8 @@ import { normalizePath, type Asset, } from "@codecov/bundler-plugin-core"; -import { fileURLToPath } from "node:url"; import micromatch from "micromatch"; -let fileName: string; -let __dirname: string; -const isCommonJSEnvironment = - typeof module !== "undefined" && module.exports !== undefined; -if (isCommonJSEnvironment) { - fileName = __filename; - __dirname = path.dirname(fileName); -} else { - fileName = fileURLToPath(import.meta.url); - __dirname = path.dirname(fileName); -} - /* getAssets gets assets from the starting paths to include in a bundle stats report */ export const getAssets = async ( buildDirectoryPaths: string[], @@ -28,7 +15,7 @@ export const getAssets = async ( ): Promise => { const allAssets = await Promise.all( buildDirectoryPaths.map(async (buildDirectoryPath) => { - const absoluteAssetsDir = path.resolve(__dirname, buildDirectoryPath); + const absoluteAssetsDir = path.resolve(buildDirectoryPath); const files = await listChildFilePaths(absoluteAssetsDir); // apply filtering only if ignorePatterns contains patterns diff --git a/packages/bundle-analyzer/src/cli.test.ts b/packages/bundle-analyzer/src/cli.test.ts index 07a32c4a..9ebf95a1 100644 --- a/packages/bundle-analyzer/src/cli.test.ts +++ b/packages/bundle-analyzer/src/cli.test.ts @@ -165,7 +165,7 @@ describe("test CLI functions to count for code coverage", () => { expect(consoleSpy).toHaveBeenCalled(); }); - it("should run and return error", async () => { + it("should run and return error if directory does not exist", async () => { process.argv = [ "node", "cli.ts", @@ -188,4 +188,53 @@ describe("test CLI functions to count for code coverage", () => { await expect(cliModule.runCli(argv)).rejects.toThrowError(); }); + + // vi.mock("node:fs"); + // vi.mock("node:path"); + + // it("should load config file and merge with base args", async () => { + // vi.mock("node:fs"); + + // const baseArgs = { + // buildDirectories: ["build-dir"], + // bundleName: "test-bundle", + // configFile: "config.json", + // }; + + // fs.readFileSync.mockReturnValue( + // JSON.stringify({ + // uploadOverridesBranch: "main", + // }), + // ); + // path.resolve.mockImplementation((cwd, dir) => `${cwd}/${dir}`); + + // await runCli(baseArgs); + + // expect(fs.readFileSync).toHaveBeenCalledWith("config.json", "utf-8"); + // expect(createAndUploadReport).toHaveBeenCalledWith( + // [expect.stringContaining("build-dir")], + // expect.objectContaining({ + // uploadOverridesBranch: "main", + // }), + // expect.any(Object), + // ); + // }); + + // it("should exit with an error when failing to load config file", async () => { + // const baseArgs = { + // buildDirectories: ["build-dir"], + // bundleName: "test-bundle", + // configFile: "config.json", + // }; + + // fs.readFileSync.mockImplementation(() => { + // throw new Error("File not found"); + // }); + + // await runCli(baseArgs); + + // expect(red).toHaveBeenCalledWith( + // "Failed to load configuration file: Error: File not found", + // ); + // }); }); diff --git a/packages/bundle-analyzer/src/cli.ts b/packages/bundle-analyzer/src/cli.ts index 9e30e8b9..bce56730 100644 --- a/packages/bundle-analyzer/src/cli.ts +++ b/packages/bundle-analyzer/src/cli.ts @@ -31,16 +31,20 @@ interface BaseArgs { // ConfigFileArgs arguments that can be supplied in an optional config file. These are less common configurations options interface ConfigFileArgs { // Core Options + retryCount?: number; + enableBundleAnalysis?: boolean; gitService?: string; uploadOverridesBranch?: string; uploadOverridesBuild?: string; uploadOverridesPr?: string; + uploadOverridesCompareSha?: string; uploadOverridesSha?: string; + uploadOverridesSlug?: string; oidcUseGitHubOIDC?: boolean; oidcGitHubOIDCTokenAudience?: string; } -const argv = yargs(hideBin(process.argv)) +const baseArgs = yargs(hideBin(process.argv)) .usage("Usage: $0 [options]") .command( "$0 ", @@ -104,33 +108,26 @@ const argv = yargs(hideBin(process.argv)) .alias("h", "help") .parseSync() as unknown as BaseArgs; -const getConfigFileArgs = (): Partial => { - // Load and merge config file if provided - const loadConfigFile = (filePath: string): Partial => { - try { - const configContent = fs.readFileSync(filePath, "utf-8"); - return JSON.parse(configContent) as Partial; - } catch (error) { - red(`Failed to load configuration file: ${error}`); - process.exit(1); - } - }; - - let configFromFile: Partial = {}; - if (argv.configFile) { - configFromFile = loadConfigFile(argv.configFile); +const getConfigFileArgs = (filePath: string): Partial => { + try { + const configContent = fs.readFileSync(filePath, "utf-8"); + return JSON.parse(configContent) as Partial; + } catch (error) { + red(`Failed to load configuration file: ${error}`); + process.exit(1); } - - return configFromFile; }; -const resolveArgs = (): Argv => { - const configFromFile = getConfigFileArgs(); +const addConfigFileArgs = (baseArgs: BaseArgs): Argv => { + let configFromFile: ConfigFileArgs | undefined; + if (baseArgs.configFile) { + configFromFile = getConfigFileArgs(baseArgs.configFile); + } // Merge CLI flag arguments with config file values (CLI flag takes precedence) const mergedArgs: Argv = { ...configFromFile, - ...argv, + ...baseArgs, }; return mergedArgs; @@ -139,10 +136,26 @@ const resolveArgs = (): Argv => { const prepareCoreOptions = (argv: Argv): Options => { return { apiUrl: argv.apiUrl, + // @ts-expect-error - validate value at normalizeOptions + gitService: argv.gitService, dryRun: argv.dryRun, uploadToken: argv.uploadToken ?? process.env.CODECOV_UPLOAD_TOKEN, + retryCount: argv.retryCount, bundleName: argv.bundleName ?? "", + enableBundleAnalysis: argv.enableBundleAnalysis, debug: argv.debug, + uploadOverrides: { + branch: argv.uploadOverridesBranch, + build: argv.uploadOverridesBuild, + compareSha: argv.uploadOverridesCompareSha, + pr: argv.uploadOverridesPr, + sha: argv.uploadOverridesSha, + slug: argv.uploadOverridesSlug, + }, + oidc: { + useGitHubOIDC: argv.oidcUseGitHubOIDC ?? false, + gitHubOIDCTokenAudience: argv.oidcGitHubOIDCTokenAudience, + }, }; }; @@ -153,8 +166,8 @@ const prepareBundleAnalyzerOptions = (argv: Argv): BundleAnalyzerOptions => { }; }; -export const runCli = async (): Promise => { - const argv = resolveArgs(); +export const runCli = async (baseArgs: BaseArgs): Promise => { + const argv = addConfigFileArgs(baseArgs); if (argv.buildDirectories.length === 0) { red("Error: No build directories provided."); @@ -175,11 +188,12 @@ export const runCli = async (): Promise => { ); if (coreOptions.dryRun) { + // eslint-disable-next-line no-console console.log(reportAsJson); } }; -runCli().catch((error) => { +runCli(baseArgs).catch((error) => { red(`An error occurred: ${error}`); process.exit(1); }); From f457ebf61b4d59728f675ee0e0c2929525d46828 Mon Sep 17 00:00:00 2001 From: Suejung Shin Date: Fri, 13 Sep 2024 11:07:13 -0700 Subject: [PATCH 3/5] fix tests --- examples/bundle-analyzer-cli/baconfig.json | 7 + examples/bundle-analyzer-cli/package.json | 2 +- packages/bundle-analyzer/README.md | 19 +- packages/bundle-analyzer/src/assets.test.ts | 11 +- packages/bundle-analyzer/src/cli.test.ts | 188 +++++++++----------- packages/bundle-analyzer/src/cli.ts | 95 +++------- 6 files changed, 135 insertions(+), 187 deletions(-) create mode 100644 examples/bundle-analyzer-cli/baconfig.json diff --git a/examples/bundle-analyzer-cli/baconfig.json b/examples/bundle-analyzer-cli/baconfig.json new file mode 100644 index 00000000..c4b00927 --- /dev/null +++ b/examples/bundle-analyzer-cli/baconfig.json @@ -0,0 +1,7 @@ +{ + "gitService": "github", + "oidc": { + "useGitHubOIDC": false + }, + "ignorePatterns": ["*.map"] +} diff --git a/examples/bundle-analyzer-cli/package.json b/examples/bundle-analyzer-cli/package.json index 84c9e1a7..185f79b4 100644 --- a/examples/bundle-analyzer-cli/package.json +++ b/examples/bundle-analyzer-cli/package.json @@ -18,7 +18,7 @@ }, "type": "module", "scripts": { - "build": "rollup -c && pnpm bundle-analyzer ./dist --bundle-name=@codecov/example-bundle-analyzer-cli --upload-token=$BUNDLE_ANALYZER_UPLOAD_TOKEN" + "build": "rollup -c && pnpm bundle-analyzer ./dist --bundle-name=@codecov/example-bundle-analyzer-cli --upload-token=$BUNDLE_ANALYZER_UPLOAD_TOKEN --config-file=./baconfig.json" }, "devDependencies": { "@codecov/bundle-analyzer": "workspace:^", diff --git a/packages/bundle-analyzer/README.md b/packages/bundle-analyzer/README.md index 228cb799..45d9e4a2 100644 --- a/packages/bundle-analyzer/README.md +++ b/packages/bundle-analyzer/README.md @@ -6,7 +6,7 @@ # Codecov Bundle Analyzer -An importable library + CLI for Codecov bundle analysis support. +The bundle analyzer is an importable library and CLI for Codecov bundle analysis. It is designed for users who operate without a standard bundler that is otherwise supported by Codecov's bundler plugins. > [!NOTE] > The plugin does not support code coverage, see our [docs](https://docs.codecov.com/docs/quick-start) to set up coverage today! @@ -74,6 +74,23 @@ This example shows how the package can be used as a CLI. npx @codecov/bundle-analyzer ./dist --bundle-name=my-identifier --upload-token=abcd --dry-run ``` +[OPTIONAL] - A config file can be passed for any extended options matching those described [here](https://codecov.github.io/codecov-javascript-bundler-plugins/interfaces/_codecov_bundler_plugin_core.Options.html). + +``` +npx @codecov/bundle-analyzer ./dist --bundle-name=my-identifier --upload-token=abcd --dry-run --config-file=./config.json +``` + +``` +// config.json +{ + "gitService": "github", + "oidc": { + "useGitHubOIDC": false + } +} + +``` + ## Supported Platforms The CLI tool supports the following operating systems: diff --git a/packages/bundle-analyzer/src/assets.test.ts b/packages/bundle-analyzer/src/assets.test.ts index cdcd41c7..62ec630c 100644 --- a/packages/bundle-analyzer/src/assets.test.ts +++ b/packages/bundle-analyzer/src/assets.test.ts @@ -1,12 +1,4 @@ -import { - describe, - it, - expect, - vi, - beforeEach, - type Mock, - afterEach, -} from "vitest"; +import { describe, it, expect, vi, beforeEach, type Mock } from "vitest"; import path from "node:path"; import fs from "node:fs/promises"; import { getAssets, getAsset, listChildFilePaths } from "./assets"; @@ -15,7 +7,6 @@ import { getCompressedSize, normalizePath, } from "@codecov/bundler-plugin-core"; -import { fileURLToPath } from "url"; vi.mock("node:fs/promises"); vi.mock("@codecov/bundler-plugin-core", () => ({ diff --git a/packages/bundle-analyzer/src/cli.test.ts b/packages/bundle-analyzer/src/cli.test.ts index 9ebf95a1..65693a87 100644 --- a/packages/bundle-analyzer/src/cli.test.ts +++ b/packages/bundle-analyzer/src/cli.test.ts @@ -124,117 +124,95 @@ describe("CLI script", () => { expect(output).not.toContain(".map"); expect(output).not.toContain(".test.js"); }); -}); - -describe("test CLI functions to count for code coverage", () => { - let consoleSpy: ReturnType; - - beforeEach(() => { - consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { - return; - }) as unknown as ReturnType; - }); - - afterEach(() => { - vi.restoreAllMocks(); - }); - - it("should run with dry run and log the report", async () => { - process.argv = [ - "node", - "cli.ts", - ".", - "--bundle-name=my-bundle", - "--dry-run", - ]; - - // import the CLI module only after process.argv set - const cliModule = await import("./cli"); - const argv = { - buildDirectories: ["."], - apiUrl: "https://custom-api.io", - dryRun: true, - uploadToken: "fake-token", - bundleName: "test-bundle", - debug: false, - }; - - await cliModule.runCli(argv); + it("should log an error for invalid CLI arguments", () => { + const output = runCLI([ + "./src", + "../bundle-analyzer", + "--bundle-name=someName", + "--invalid-option", + ]); - expect(consoleSpy).toHaveBeenCalled(); + expect(output).toContain("Unknown argument"); }); - it("should run and return error if directory does not exist", async () => { - process.argv = [ - "node", - "cli.ts", - "/directory/that/doesnt/exist", - "--bundle-name=my-bundle", - "--dry-run", - ]; + describe("test CLI functions directly", () => { + let consoleSpy: ReturnType; + // eslint-disable-next-line @typescript-eslint/consistent-type-imports + let cliModule: typeof import("./cli"); + beforeAll(async () => { + process.argv = ["node", "cli.ts", ".", "--dry-run", "--bundle-name=test"]; + cliModule = await import("./cli"); + }); + + beforeEach(() => { + vi.restoreAllMocks(); + consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { + return; + }) as unknown as ReturnType; + }); + + it("should run with dry run and log the report", async () => { + const argv = { + buildDirectories: ["."], + apiUrl: "https://custom-api.io", + dryRun: true, + uploadToken: "fake-token", + bundleName: "test-bundle", + debug: false, + }; + + await cliModule.runCli(argv); + + expect(consoleSpy).toHaveBeenCalled(); + expect(consoleSpy.mock.calls[1]?.[0]).toContain("test-bundle"); + }); + + it("should run and return error if directory does not exist", async () => { + const argv = { + buildDirectories: ["/directory/that/doesnt/exist"], + apiUrl: "https://custom-api.io", + dryRun: true, + uploadToken: "fake-token", + bundleName: "test-bundle", + debug: false, + }; + + await expect(cliModule.runCli(argv)).rejects.toThrowError(); + }); + + it("should load options from a configuration file", async () => { + const argv = { + buildDirectories: ["."], + apiUrl: "https://custom-api.io", + dryRun: true, + uploadToken: "fake-token", + bundleName: "this-is-the-name", + debug: false, + }; + + const configFilePath = path.resolve("test-config.json"); + + // Create a dummy config file for the test + fs.writeFileSync( + configFilePath, + JSON.stringify({ + bundleName: "this-name-should-be-ignored", + oidc: { + useGitHubOIDC: false, + }, + }), + ); - // import the CLI module only after process.argv set - const cliModule = await import("./cli"); + await cliModule.runCli(argv); - const argv = { - buildDirectories: ["/directory/that/doesnt/exist"], - apiUrl: "https://custom-api.io", - dryRun: true, - uploadToken: "fake-token", - bundleName: "test-bundle", - debug: false, - }; + fs.unlinkSync(configFilePath); // Clean up after test - await expect(cliModule.runCli(argv)).rejects.toThrowError(); + expect(consoleSpy).toHaveBeenCalled(); + // the CLI argument should override anythign supplied in the config file + expect(consoleSpy.mock.calls[0]?.[0]).toContain( + `bundleName":"this-is-the-name"`, + ); + }); }); - - // vi.mock("node:fs"); - // vi.mock("node:path"); - - // it("should load config file and merge with base args", async () => { - // vi.mock("node:fs"); - - // const baseArgs = { - // buildDirectories: ["build-dir"], - // bundleName: "test-bundle", - // configFile: "config.json", - // }; - - // fs.readFileSync.mockReturnValue( - // JSON.stringify({ - // uploadOverridesBranch: "main", - // }), - // ); - // path.resolve.mockImplementation((cwd, dir) => `${cwd}/${dir}`); - - // await runCli(baseArgs); - - // expect(fs.readFileSync).toHaveBeenCalledWith("config.json", "utf-8"); - // expect(createAndUploadReport).toHaveBeenCalledWith( - // [expect.stringContaining("build-dir")], - // expect.objectContaining({ - // uploadOverridesBranch: "main", - // }), - // expect.any(Object), - // ); - // }); - - // it("should exit with an error when failing to load config file", async () => { - // const baseArgs = { - // buildDirectories: ["build-dir"], - // bundleName: "test-bundle", - // configFile: "config.json", - // }; - - // fs.readFileSync.mockImplementation(() => { - // throw new Error("File not found"); - // }); - - // await runCli(baseArgs); - - // expect(red).toHaveBeenCalledWith( - // "Failed to load configuration file: Error: File not found", - // ); - // }); }); diff --git a/packages/bundle-analyzer/src/cli.ts b/packages/bundle-analyzer/src/cli.ts index bce56730..66c0139f 100644 --- a/packages/bundle-analyzer/src/cli.ts +++ b/packages/bundle-analyzer/src/cli.ts @@ -8,10 +8,10 @@ import { createAndUploadReport } from "./index.js"; import { red, type Options } from "@codecov/bundler-plugin-core"; import { type BundleAnalyzerOptions } from "./options"; -interface Argv extends BaseArgs, ConfigFileArgs {} +interface Argv extends CLIArgs, Options, BundleAnalyzerOptions {} -// Base arguments that can be supplied in a flag or an optional config file. These are the more common configurations options -interface BaseArgs { +// CLI arguments that can be supplied via CLI flag or an optional config file +interface CLIArgs { buildDirectories: string[]; // Bundle Analyzer Options @@ -21,30 +21,14 @@ interface BaseArgs { // Core Options apiUrl?: string; uploadToken?: string; - bundleName: string; + bundleName?: string; debug?: boolean; dryRun?: boolean; configFile?: string; } -// ConfigFileArgs arguments that can be supplied in an optional config file. These are less common configurations options -interface ConfigFileArgs { - // Core Options - retryCount?: number; - enableBundleAnalysis?: boolean; - gitService?: string; - uploadOverridesBranch?: string; - uploadOverridesBuild?: string; - uploadOverridesPr?: string; - uploadOverridesCompareSha?: string; - uploadOverridesSha?: string; - uploadOverridesSlug?: string; - oidcUseGitHubOIDC?: boolean; - oidcGitHubOIDCTokenAudience?: string; -} - -const baseArgs = yargs(hideBin(process.argv)) +const cliArgs = yargs(hideBin(process.argv)) .usage("Usage: $0 [options]") .command( "$0 ", @@ -79,7 +63,6 @@ const baseArgs = yargs(hideBin(process.argv)) alias: "n", type: "string", description: "Set the bundle identifier in Codecov", - demandOption: true, }, debug: { alias: "v", @@ -106,67 +89,34 @@ const baseArgs = yargs(hideBin(process.argv)) .strict() .help("h") .alias("h", "help") - .parseSync() as unknown as BaseArgs; + .parseSync() as unknown as CLIArgs; -const getConfigFileArgs = (filePath: string): Partial => { +const getConfigFileArgs = ( + filePath: string, +): Partial => { try { const configContent = fs.readFileSync(filePath, "utf-8"); - return JSON.parse(configContent) as Partial; + return JSON.parse(configContent) as Partial< + Options & BundleAnalyzerOptions + >; } catch (error) { red(`Failed to load configuration file: ${error}`); process.exit(1); } }; -const addConfigFileArgs = (baseArgs: BaseArgs): Argv => { - let configFromFile: ConfigFileArgs | undefined; +const addConfigFileArgs = (baseArgs: CLIArgs): Argv => { + let configFromFile: Partial = {}; + if (baseArgs.configFile) { configFromFile = getConfigFileArgs(baseArgs.configFile); } // Merge CLI flag arguments with config file values (CLI flag takes precedence) - const mergedArgs: Argv = { - ...configFromFile, - ...baseArgs, - }; - - return mergedArgs; + return { ...configFromFile, ...baseArgs }; }; -const prepareCoreOptions = (argv: Argv): Options => { - return { - apiUrl: argv.apiUrl, - // @ts-expect-error - validate value at normalizeOptions - gitService: argv.gitService, - dryRun: argv.dryRun, - uploadToken: argv.uploadToken ?? process.env.CODECOV_UPLOAD_TOKEN, - retryCount: argv.retryCount, - bundleName: argv.bundleName ?? "", - enableBundleAnalysis: argv.enableBundleAnalysis, - debug: argv.debug, - uploadOverrides: { - branch: argv.uploadOverridesBranch, - build: argv.uploadOverridesBuild, - compareSha: argv.uploadOverridesCompareSha, - pr: argv.uploadOverridesPr, - sha: argv.uploadOverridesSha, - slug: argv.uploadOverridesSlug, - }, - oidc: { - useGitHubOIDC: argv.oidcUseGitHubOIDC ?? false, - gitHubOIDCTokenAudience: argv.oidcGitHubOIDCTokenAudience, - }, - }; -}; - -const prepareBundleAnalyzerOptions = (argv: Argv): BundleAnalyzerOptions => { - return { - ignorePatterns: argv.ignorePatterns, - normalizeAssetsPattern: argv.normalizeAssetsPattern, - }; -}; - -export const runCli = async (baseArgs: BaseArgs): Promise => { +export const runCli = async (baseArgs: CLIArgs): Promise => { const argv = addConfigFileArgs(baseArgs); if (argv.buildDirectories.length === 0) { @@ -178,8 +128,13 @@ export const runCli = async (baseArgs: BaseArgs): Promise => { path.resolve(process.cwd(), dir), ); - const coreOptions = prepareCoreOptions(argv); - const bundleAnalyzerOptions = prepareBundleAnalyzerOptions(argv); + const coreOptions: Options = { + ...argv, + }; + + const bundleAnalyzerOptions: BundleAnalyzerOptions = { + ...argv, + }; const reportAsJson = await createAndUploadReport( resolvedDirectoryPaths, @@ -193,7 +148,7 @@ export const runCli = async (baseArgs: BaseArgs): Promise => { } }; -runCli(baseArgs).catch((error) => { +runCli(cliArgs).catch((error) => { red(`An error occurred: ${error}`); process.exit(1); }); From c8d5d15ee0bcdff9920da3d6cc74126354d57450 Mon Sep 17 00:00:00 2001 From: Suejung Shin Date: Fri, 13 Sep 2024 11:57:46 -0700 Subject: [PATCH 4/5] add tests --- .../bundle-analyzer/dotenv-vercel/analyze.js | 4 +- packages/bundle-analyzer/src/cli.test.ts | 179 ++++++++++-------- .../src/utils/__tests__/Output.test.ts | 46 +++++ 3 files changed, 151 insertions(+), 78 deletions(-) diff --git a/integration-tests/test-apps/bundle-analyzer/dotenv-vercel/analyze.js b/integration-tests/test-apps/bundle-analyzer/dotenv-vercel/analyze.js index 85df8b82..a471707c 100644 --- a/integration-tests/test-apps/bundle-analyzer/dotenv-vercel/analyze.js +++ b/integration-tests/test-apps/bundle-analyzer/dotenv-vercel/analyze.js @@ -1,8 +1,6 @@ import { createAndUploadReport } from "@codecov/bundle-analyzer"; -const buildDirs = [ - "../../../integration-tests/test-apps/bundle-analyzer/dotenv-vercel/dist", -]; +const buildDirs = ["./dist"]; const apiUrl = process.env.API_URL || "https://api.codecov.io"; diff --git a/packages/bundle-analyzer/src/cli.test.ts b/packages/bundle-analyzer/src/cli.test.ts index 65693a87..167912c8 100644 --- a/packages/bundle-analyzer/src/cli.test.ts +++ b/packages/bundle-analyzer/src/cli.test.ts @@ -135,84 +135,113 @@ describe("CLI script", () => { expect(output).toContain("Unknown argument"); }); +}); - describe("test CLI functions directly", () => { - let consoleSpy: ReturnType; - // eslint-disable-next-line @typescript-eslint/consistent-type-imports - let cliModule: typeof import("./cli"); - beforeAll(async () => { - process.argv = ["node", "cli.ts", ".", "--dry-run", "--bundle-name=test"]; - cliModule = await import("./cli"); - }); - - beforeEach(() => { - vi.restoreAllMocks(); - consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { - return; - }) as unknown as ReturnType; - }); - - it("should run with dry run and log the report", async () => { - const argv = { - buildDirectories: ["."], - apiUrl: "https://custom-api.io", - dryRun: true, - uploadToken: "fake-token", - bundleName: "test-bundle", - debug: false, - }; - - await cliModule.runCli(argv); - - expect(consoleSpy).toHaveBeenCalled(); - expect(consoleSpy.mock.calls[1]?.[0]).toContain("test-bundle"); - }); - - it("should run and return error if directory does not exist", async () => { - const argv = { - buildDirectories: ["/directory/that/doesnt/exist"], - apiUrl: "https://custom-api.io", - dryRun: true, - uploadToken: "fake-token", - bundleName: "test-bundle", - debug: false, - }; - - await expect(cliModule.runCli(argv)).rejects.toThrowError(); - }); - - it("should load options from a configuration file", async () => { - const argv = { - buildDirectories: ["."], - apiUrl: "https://custom-api.io", - dryRun: true, - uploadToken: "fake-token", - bundleName: "this-is-the-name", - debug: false, - }; - - const configFilePath = path.resolve("test-config.json"); - - // Create a dummy config file for the test - fs.writeFileSync( - configFilePath, - JSON.stringify({ - bundleName: "this-name-should-be-ignored", - oidc: { - useGitHubOIDC: false, - }, - }), - ); +describe("test CLI functions directly", () => { + let consoleSpy: ReturnType; + // eslint-disable-next-line @typescript-eslint/consistent-type-imports + let cliModule: typeof import("./cli"); + beforeAll(async () => { + process.argv = ["node", "cli.ts", ".", "--dry-run", "--bundle-name=test"]; + cliModule = await import("./cli"); + }); - await cliModule.runCli(argv); + beforeEach(() => { + vi.restoreAllMocks(); + consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { + return; + }) as unknown as ReturnType; + }); - fs.unlinkSync(configFilePath); // Clean up after test + it("should run with dry run and log the report", async () => { + const argv = { + buildDirectories: ["."], + apiUrl: "https://custom-api.io", + dryRun: true, + uploadToken: "fake-token", + bundleName: "test-bundle", + debug: false, + }; - expect(consoleSpy).toHaveBeenCalled(); - // the CLI argument should override anythign supplied in the config file - expect(consoleSpy.mock.calls[0]?.[0]).toContain( - `bundleName":"this-is-the-name"`, - ); - }); + await cliModule.runCli(argv); + + expect(consoleSpy).toHaveBeenCalled(); + }); + + it("should run and return error if directory does not exist", async () => { + const argv = { + buildDirectories: ["/directory/that/doesnt/exist"], + apiUrl: "https://custom-api.io", + dryRun: true, + uploadToken: "fake-token", + bundleName: "test-bundle", + debug: false, + }; + + await expect(cliModule.runCli(argv)).rejects.toThrowError(); + }); + + it("should return error if directories not supplied", async () => { + const argv = { + buildDirectories: [], + apiUrl: "https://custom-api.io", + dryRun: true, + uploadToken: "fake-token", + bundleName: "test-bundle", + debug: false, + }; + + await expect(cliModule.runCli(argv)).rejects.toThrowError(); + }); + + it("should load options from a configuration file successfully", async () => { + const configFilePath = path.resolve("test-config.json"); + + const argv = { + buildDirectories: ["."], + apiUrl: "https://custom-api.io", + dryRun: true, + uploadToken: "fake-token", + bundleName: "this-is-the-name", + debug: false, + configFile: configFilePath, + }; + + // Create a dummy config file for the test + fs.writeFileSync( + configFilePath, + JSON.stringify({ + bundleName: "this-name-should-be-ignored", + oidc: { + useGitHubOIDC: false, + }, + }), + ); + + await cliModule.runCli(argv); + + fs.unlinkSync(configFilePath); // Clean up after test + + expect(consoleSpy).toHaveBeenCalled(); + // the CLI argument should override anything supplied in the config file + expect(consoleSpy.mock.calls[0]?.[0]).toContain( + `bundleName":"this-is-the-name"`, + ); + }); + + it("should load options from a configuration file with error if file does not exist", async () => { + const configFilePath = path.resolve("not-exists.json"); + + const argv = { + buildDirectories: ["."], + apiUrl: "https://custom-api.io", + dryRun: true, + uploadToken: "fake-token", + bundleName: "this-is-the-name", + debug: false, + configFile: configFilePath, + }; + + await expect(cliModule.runCli(argv)).rejects.toThrowError(); }); }); diff --git a/packages/bundler-plugin-core/src/utils/__tests__/Output.test.ts b/packages/bundler-plugin-core/src/utils/__tests__/Output.test.ts index 2c5fd56d..38e9a7df 100644 --- a/packages/bundler-plugin-core/src/utils/__tests__/Output.test.ts +++ b/packages/bundler-plugin-core/src/utils/__tests__/Output.test.ts @@ -337,6 +337,27 @@ describe("Output", () => { await output.write(); }); + + it("optionally emits error", async () => { + setup({ urlSendError: true }); + + const output = new Output({ + apiUrl: "http://localhost", + bundleName: "output-test", + debug: false, + dryRun: false, + enableBundleAnalysis: true, + retryCount: 1, + uploadToken: "token", + }); + + output.start(); + output.end(); + + await expect(output.write(true)).rejects.toThrow( + "Failed to fetch pre-signed URL", + ); + }); }); describe("successful fetch of pre-signed URL", () => { @@ -408,6 +429,31 @@ describe("Output", () => { await output.write(); }); + + it("optionally emits error", async () => { + setup({ + urlData: { url: "http://localhost/upload/stats/" }, + urlStatus: 200, + statsSendError: true, + }); + + const output = new Output({ + apiUrl: "http://localhost", + bundleName: "output-test", + debug: false, + dryRun: false, + enableBundleAnalysis: true, + retryCount: 1, + uploadToken: "token", + }); + + output.start(); + output.end(); + + await expect(output.write(true)).rejects.toThrow( + "Failed to upload stats", + ); + }); }); describe("successful uploading of stats", () => { From 6b0a88206f5f36e6d53b78f5eb69e7cd96a8d91c Mon Sep 17 00:00:00 2001 From: Suejung Shin Date: Fri, 13 Sep 2024 12:14:23 -0700 Subject: [PATCH 5/5] unlint tsconfig.json file --- integration-tests/test-api/tsconfig.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integration-tests/test-api/tsconfig.json b/integration-tests/test-api/tsconfig.json index c829ef88..9136c143 100644 --- a/integration-tests/test-api/tsconfig.json +++ b/integration-tests/test-api/tsconfig.json @@ -2,6 +2,6 @@ "compilerOptions": { "strict": true, "jsx": "react-jsx", - "jsxImportSource": "hono/jsx", - }, + "jsxImportSource": "hono/jsx" + } }