Skip to content

Commit 33b335e

Browse files
authored
feat: Validate bundle name (#86)
Validate the provided bundle name to match how Sentry validates metric names via regex, as well as validate the other options for non-TypeScript users. GH codecov/engineering-team#1255
1 parent 09e062e commit 33b335e

File tree

18 files changed

+444
-39
lines changed

18 files changed

+444
-39
lines changed

.changeset/flat-mails-buy.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"@codecov/bundler-plugin-core": patch
3+
"@codecov/rollup-plugin": patch
4+
"@codecov/vite-plugin": patch
5+
"@codecov/webpack-plugin": patch
6+
---
7+
8+
Normalize options to set default values as well as validate bundle names ensuring they follow the correct pattern.

.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const config = {
1515
"**/node_modules/**",
1616
"**/test-apps/**",
1717
"**/integration-tests/**/*.cjs",
18+
"**/integration-tests/test-api/**/*",
1819
],
1920
parserOptions: {
2021
ecmaVersion: "latest",

integration-tests/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "@codecov/plugin-integration-tests",
2+
"name": "@codecov/integration-tests",
33
"version": "1.0.0",
44
"description": "",
55
"private": true,

integration-tests/tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@
88
"fixtures/**/*.cjs",
99
],
1010
"compilerOptions": {
11-
"types": ["node", "jest"],
11+
"types": ["node"],
1212
},
1313
}

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
"build": "pnpm -r --filter='./packages/*' run build",
1111
"dev": "pnpm -r --parallel --filter='./packages/*' run dev",
1212
"clean": "pnpm -r --filter='./packages/*' clean && rm -rf node_modules",
13-
"type-check": "pnpm -r --filter='./packages/*' --filter='integration-tests' run type-check",
14-
"lint": "pnpm -r --filter='./packages/*' --filter='integration-tests' lint",
15-
"lint:fix": "pnpm -r --filter='./packages/*' --filter='integration-tests' lint:fix",
13+
"type-check": "pnpm -r --filter='./packages/*' run type-check",
14+
"lint": "pnpm -r --filter='./packages/*' lint",
15+
"lint:fix": "pnpm -r --filter='./packages/*' lint:fix",
1616
"format": "pnpm -r format && prettier --write '*.{cjs,json}' --ignore-unknown --no-error-on-unmatched-pattern",
1717
"format:check": "pnpm -r --filter='./packages/*' format:check && prettier --check '*.{cjs,json}' --ignore-unknown --no-error-on-unmatched-pattern",
1818
"test:unit": "pnpm -r --filter='./packages/*' run test:unit",

packages/bundler-plugin-core/src/bundle-analysis/__tests__/bundleAnalysisPluginFactory.test.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,14 @@ import { bundleAnalysisPluginFactory } from "../bundleAnalysisPluginFactory";
33
describe("bundleAnalysisPluginFactory", () => {
44
it("returns a plugin functions", () => {
55
const plugin = bundleAnalysisPluginFactory({
6-
userOptions: { bundleName: "test" },
6+
options: {
7+
bundleName: "test",
8+
apiUrl: "http://localhost",
9+
dryRun: true,
10+
enableBundleAnalysis: true,
11+
retryCount: 3,
12+
uploadToken: "test-token",
13+
},
714
bundleAnalysisUploadPlugin: () => ({
815
version: "1",
916
name: "plugin-name",

packages/bundler-plugin-core/src/bundle-analysis/bundleAnalysisPluginFactory.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,32 @@
1-
import { detectProvider } from "../utils/provider.ts";
1+
import { type UnpluginOptions } from "unplugin";
22
import {
33
type BundleAnalysisUploadPlugin,
4-
type Options,
54
type Output,
65
type ProviderUtilInputs,
76
type UploadOverrides,
87
} from "../types.ts";
9-
import { type UnpluginOptions } from "unplugin";
108
import { getPreSignedURL } from "../utils/getPreSignedURL.ts";
9+
import { type NormalizedOptions } from "../utils/normalizeOptions.ts";
10+
import { detectProvider } from "../utils/provider.ts";
1111
import { uploadStats } from "../utils/uploadStats.ts";
1212

1313
interface BundleAnalysisUploadPluginArgs {
14-
userOptions: Options;
14+
options: NormalizedOptions;
1515
bundleAnalysisUploadPlugin: BundleAnalysisUploadPlugin;
1616
}
1717

1818
export const bundleAnalysisPluginFactory = ({
19-
userOptions,
19+
options,
2020
bundleAnalysisUploadPlugin,
2121
}: BundleAnalysisUploadPluginArgs): UnpluginOptions => {
2222
const output: Output = {
2323
version: "1",
24-
bundleName: userOptions.bundleName ?? "",
24+
bundleName: options.bundleName,
2525
};
2626

2727
const { pluginVersion, version, ...pluginOpts } = bundleAnalysisUploadPlugin({
2828
output,
29-
userOptions,
29+
options,
3030
});
3131

3232
output.version = version;
@@ -45,23 +45,23 @@ export const bundleAnalysisPluginFactory = ({
4545
},
4646
writeBundle: async () => {
4747
// don't need to do anything here if dryRun is true
48-
if (userOptions?.dryRun) return;
48+
if (options.dryRun) return;
4949

5050
// don't need to do anything if the bundle name is not present or empty
51-
if (!userOptions.bundleName || userOptions.bundleName === "") return;
51+
if (!options.bundleName || options.bundleName === "") return;
5252

53-
const args: UploadOverrides = userOptions.uploadOverrides ?? {};
53+
const args: UploadOverrides = options.uploadOverrides ?? {};
5454
const envs = process.env;
5555
const inputs: ProviderUtilInputs = { envs, args };
5656
const provider = await detectProvider(inputs);
5757

5858
let url = "";
5959
try {
6060
url = await getPreSignedURL({
61-
apiURL: userOptions?.apiUrl ?? "https://api.codecov.io",
62-
uploadToken: userOptions?.uploadToken,
61+
apiURL: options?.apiUrl ?? "https://api.codecov.io",
62+
uploadToken: options?.uploadToken,
6363
serviceParams: provider,
64-
retryCount: userOptions?.retryCount,
64+
retryCount: options?.retryCount,
6565
});
6666
} catch (error) {
6767
return;
@@ -72,7 +72,7 @@ export const bundleAnalysisPluginFactory = ({
7272
preSignedUrl: url,
7373
bundleName: output.bundleName,
7474
message: JSON.stringify(output),
75-
retryCount: userOptions?.retryCount,
75+
retryCount: options?.retryCount,
7676
});
7777
} catch {}
7878
},

packages/bundler-plugin-core/src/index.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
import { red } from "./utils/logging.ts";
1515
import { normalizePath } from "./utils/normalizePath.ts";
1616
import { bundleAnalysisPluginFactory } from "./bundle-analysis/bundleAnalysisPluginFactory.ts";
17+
import { normalizeOptions } from "./utils/normalizeOptions.ts";
1718

1819
const NODE_VERSION_RANGE = ">=18.18.0";
1920

@@ -27,6 +28,15 @@ function codecovUnpluginFactory({
2728
return createUnplugin<Options, true>((userOptions, unpluginMetaContext) => {
2829
const plugins: UnpluginOptions[] = [];
2930

31+
const normalizedOptions = normalizeOptions(userOptions);
32+
33+
if (!normalizedOptions.success) {
34+
for (const error of normalizedOptions.errors) {
35+
red(error);
36+
}
37+
return [];
38+
}
39+
3040
if (!satisfies(process.version, NODE_VERSION_RANGE)) {
3141
red(
3242
`Codecov ${unpluginMetaContext.framework} bundler plugin requires Node.js ${NODE_VERSION_RANGE}. You are using Node.js ${process.version}. Please upgrade your Node.js version.`,
@@ -35,10 +45,11 @@ function codecovUnpluginFactory({
3545
return plugins;
3646
}
3747

38-
if (userOptions?.enableBundleAnalysis) {
48+
const options = normalizedOptions.options;
49+
if (options?.enableBundleAnalysis) {
3950
plugins.push(
4051
bundleAnalysisPluginFactory({
41-
userOptions,
52+
options,
4253
bundleAnalysisUploadPlugin,
4354
}),
4455
);

packages/bundler-plugin-core/src/types.ts

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { type UnpluginOptions } from "unplugin";
2+
import { type NormalizedOptions } from "./utils/normalizeOptions";
23

34
export interface Dependency {
45
name: string;
@@ -47,7 +48,7 @@ export interface Output {
4748

4849
export interface BundleAnalysisUploadPluginArgs {
4950
output: Output;
50-
userOptions: Options;
51+
options: NormalizedOptions;
5152
}
5253

5354
export interface Options {
@@ -76,12 +77,6 @@ export interface Options {
7677
*/
7778
retryCount?: number;
7879

79-
/** Whether you would like bundle analysis to be enabled. */
80-
enableBundleAnalysis?: boolean;
81-
82-
/** Override values for passing custom information to API. */
83-
uploadOverrides?: UploadOverrides;
84-
8580
/**
8681
* When enabled information will not be uploaded to Codecov.
8782
*
@@ -94,9 +89,21 @@ export interface Options {
9489
*
9590
* Required for uploading bundle analysis information.
9691
*
97-
* Example: `rollup-package`
92+
* The name must match the pattern `/^[\w\d_:/@\.{}\[\]$-]+$/`.
93+
*
94+
* Example: `@codecov/rollup-plugin`
9895
*/
9996
bundleName?: string;
97+
98+
/**
99+
* Whether you would like bundle analysis to be enabled. *
100+
*
101+
* Defaults to `false`
102+
*/
103+
enableBundleAnalysis?: boolean;
104+
105+
/** Override values for passing custom information to API. */
106+
uploadOverrides?: UploadOverrides;
100107
}
101108

102109
export type BundleAnalysisUploadPlugin = (

0 commit comments

Comments
 (0)