From 586c0f5b2e46601cc2d7bfbbb9f3fb4e966c010b Mon Sep 17 00:00:00 2001 From: Pangratios Cosma Date: Tue, 25 Apr 2023 09:30:07 +0300 Subject: [PATCH 1/6] feat: add ignorePaths option Fixes: #1053 --- packages/rollup-plugin/src/index.ts | 8 ++-- packages/rollup-plugin/src/options.ts | 17 +++++-- packages/rollup-plugin/src/rollupUtils.ts | 47 +++++++++++++----- packages/rollup-plugin/src/types.ts | 5 +- packages/rollup-plugin/test/index.test.ts | 46 +++++++++--------- packages/rollup-plugin/test/options.test.ts | 43 ++++++++++------- .../rollup-plugin/test/rollupUtils.test.ts | 48 ++++++++++++++----- 7 files changed, 139 insertions(+), 75 deletions(-) diff --git a/packages/rollup-plugin/src/index.ts b/packages/rollup-plugin/src/index.ts index f3013f1da..6d69d8f7d 100644 --- a/packages/rollup-plugin/src/index.ts +++ b/packages/rollup-plugin/src/index.ts @@ -10,9 +10,9 @@ export default function honeybadgerRollupPlugin( const hbOptions = cleanOptions(options) return { - name: 'honeybadger', + name: 'honeybadger', writeBundle: async ( - outputOptions: NormalizedOutputOptions, + outputOptions: NormalizedOutputOptions, bundle: OutputBundle ) => { if (isNonProdEnv()) { @@ -22,7 +22,7 @@ export default function honeybadgerRollupPlugin( return } - const sourcemapData = extractSourcemapDataFromBundle(outputOptions, bundle) + const sourcemapData = extractSourcemapDataFromBundle(outputOptions, bundle, hbOptions.ignorePaths) await uploadSourcemaps(sourcemapData, hbOptions) if (hbOptions.deploy) { @@ -30,4 +30,4 @@ export default function honeybadgerRollupPlugin( } } } -} \ No newline at end of file +} diff --git a/packages/rollup-plugin/src/options.ts b/packages/rollup-plugin/src/options.ts index bf7e94abf..563866b7d 100644 --- a/packages/rollup-plugin/src/options.ts +++ b/packages/rollup-plugin/src/options.ts @@ -7,6 +7,7 @@ export const DEFAULT_REVISION = 'main' export const DEFAULT_SILENT = false export const DEFAULT_DEPLOY = false export const DEPLOY_ENDPOINT = 'https://api.honeybadger.io/v1/deploys' +export const IGNORE_PATHS = [] /****************************** * Everything in this file is designed to be shared with the webpack plugin @@ -19,12 +20,13 @@ const required = [ ] const defaultOptions = { - endpoint: DEFAULT_ENDPOINT, - retries: DEFAULT_RETRIES, - revision: DEFAULT_REVISION, - silent: DEFAULT_SILENT, + endpoint: DEFAULT_ENDPOINT, + retries: DEFAULT_RETRIES, + revision: DEFAULT_REVISION, + silent: DEFAULT_SILENT, deploy: DEFAULT_DEPLOY, deployEndpoint: DEPLOY_ENDPOINT, + ignorePaths: IGNORE_PATHS, } export function cleanOptions( @@ -36,6 +38,12 @@ export function cleanOptions( throw new Error(`${field} is required`) } }) + + // Validate ignorePaths + if (options.ignorePaths && !Array.isArray(options.ignorePaths)) { + throw new Error('ignorePaths must be an array') + } + // Don't allow excessive retries if (options.retries && options.retries > MAX_RETRIES) { if (!options.silent) { @@ -43,6 +51,7 @@ export function cleanOptions( } options.retries = MAX_RETRIES } + // Merge in our defaults return { ...defaultOptions, ...options } } diff --git a/packages/rollup-plugin/src/rollupUtils.ts b/packages/rollup-plugin/src/rollupUtils.ts index 50a37bf12..bfc357805 100644 --- a/packages/rollup-plugin/src/rollupUtils.ts +++ b/packages/rollup-plugin/src/rollupUtils.ts @@ -6,30 +6,53 @@ import type { SourcemapInfo } from './types' /** * Extracts the data we need for sourcemap upload from the bundle */ -export function extractSourcemapDataFromBundle ( - outputOptions: NormalizedOutputOptions, - bundle: OutputBundle +export function extractSourcemapDataFromBundle ( + outputOptions: NormalizedOutputOptions, + bundle: OutputBundle, + ignorePaths: Array = [] ): SourcemapInfo[] { const sourceMaps = Object.values(bundle).filter(isSourcemap) - + return sourceMaps.map(sourcemap => { return formatSourcemapData(outputOptions, sourcemap) - }) + }).filter((sourcemap) => isNotIgnored(sourcemap, ignorePaths)) } function isSourcemap(file: OutputAsset | OutputChunk): file is OutputAsset { - return file.type === 'asset' && file.fileName.endsWith('.js.map') + if (file.type !== 'asset' || !file.fileName.endsWith('.js.map') || !file.source) { + return false + } + + const source = typeof file.source === 'string' ? file.source : file.source.toString() + const json = JSON.parse(source) + + return json.sourcesContent && json.sourcesContent.length > 0 +} + +function isNotIgnored(sourceMapInfo: SourcemapInfo, ignorePaths: Array) { + for (const ignorePath of ignorePaths) { + let regex = ignorePath + if (!(regex instanceof RegExp)) { + regex = new RegExp(regex) + } + + if (regex.test(sourceMapInfo.jsFilePath)) { + return false + } + } + + return true } function formatSourcemapData( - outputOptions: NormalizedOutputOptions, + outputOptions: NormalizedOutputOptions, sourcemap: OutputAsset): SourcemapInfo { // This fileName could include a path like 'subfolder/foo.js.map' const sourcemapFilename = sourcemap.fileName const sourcemapFilePath = path.resolve(outputOptions.dir || '', sourcemapFilename) - // It should be safe to assume that rollup will name the map with - // the same name as the js file... however we can pull the file name - // from the sourcemap source just in case. + // It should be safe to assume that rollup will name the map with + // the same name as the js file... however we can pull the file name + // from the sourcemap source just in case. let jsFilename: string if (typeof sourcemap.source === 'string') { const { file } = JSON.parse(sourcemap.source) @@ -47,9 +70,9 @@ function formatSourcemapData( /** * Determines if we are in a non-production environment * Note that in Vite setups, NODE_ENV should definitely be available - * In Rollup without Vite, it may or may not be available, + * In Rollup without Vite, it may or may not be available, * so if it's missing we'll assume prod */ export function isNonProdEnv(): boolean { return !!process.env.NODE_ENV && process.env.NODE_ENV !== 'production' -} \ No newline at end of file +} diff --git a/packages/rollup-plugin/src/types.ts b/packages/rollup-plugin/src/types.ts index 34924da20..5fa9a7ad0 100644 --- a/packages/rollup-plugin/src/types.ts +++ b/packages/rollup-plugin/src/types.ts @@ -6,7 +6,8 @@ export interface HbPluginOptions { revision: string; silent: boolean; deployEndpoint: string; - deploy: boolean | Deploy + deploy: boolean | Deploy; + ignorePaths: Array; } export interface Deploy { @@ -29,4 +30,4 @@ export interface SourcemapInfo { sourcemapFilePath: string; jsFilename: string; jsFilePath: string; -} \ No newline at end of file +} diff --git a/packages/rollup-plugin/test/index.test.ts b/packages/rollup-plugin/test/index.test.ts index 87562a93a..23fd05db9 100644 --- a/packages/rollup-plugin/test/index.test.ts +++ b/packages/rollup-plugin/test/index.test.ts @@ -5,10 +5,10 @@ import { HbPluginOptions } from '../src/types' describe('Index', () => { let honeybadgerRollupPlugin:(opts: Partial & Pick) => Plugin - let cleanOptionsMock, - isNonProdEnvMock, - extractSourcemapDataFromBundleMock, - uploadSourcemapsMock, + let cleanOptionsMock, + isNonProdEnvMock, + extractSourcemapDataFromBundleMock, + uploadSourcemapsMock, sendDeployNotificationMock const options = { apiKey: 'test_key', assetsUrl: 'https://foo.bar' } @@ -19,18 +19,18 @@ describe('Index', () => { uploadSourcemapsMock = td.func() sendDeployNotificationMock = td.func() - td.replace('../src/options', { - cleanOptions: cleanOptionsMock + td.replace('../src/options', { + cleanOptions: cleanOptionsMock }) td.replace('../src/rollupUtils', { extractSourcemapDataFromBundle: extractSourcemapDataFromBundleMock, isNonProdEnv: isNonProdEnvMock }) td.replace('../src/hbUtils', { - uploadSourcemaps: uploadSourcemapsMock, + uploadSourcemaps: uploadSourcemapsMock, sendDeployNotification: sendDeployNotificationMock }) - + const indexModule = await import('../src/index') honeybadgerRollupPlugin = indexModule.default }) @@ -44,7 +44,7 @@ describe('Index', () => { td.verify(cleanOptionsMock(options)) expect(plugin.name).to.equal('honeybadger') - expect(plugin.writeBundle).to.be.a('function') + expect(plugin.writeBundle).to.be.a('function') }) describe('writeBundle', () => { @@ -55,13 +55,13 @@ describe('Index', () => { it('should upload sourcemaps', async () => { td.when(isNonProdEnvMock()).thenReturn(false) - td.when(extractSourcemapDataFromBundleMock(outputOptions, bundle)).thenReturn(sourcemapData) + td.when(extractSourcemapDataFromBundleMock(outputOptions, bundle, undefined)).thenReturn(sourcemapData) td.when(cleanOptionsMock(options)).thenReturn(options) - + const plugin = honeybadgerRollupPlugin(options) //@ts-ignore await plugin.writeBundle(outputOptions, bundle) - + td.verify(uploadSourcemapsMock(sourcemapData, options)) }) @@ -70,11 +70,11 @@ describe('Index', () => { td.when(isNonProdEnvMock()).thenReturn(false) td.when(extractSourcemapDataFromBundleMock({ outputOptions, bundle })).thenReturn(sourcemapData) td.when(cleanOptionsMock(deployTrueOpt)).thenReturn(deployTrueOpt) - + const plugin = honeybadgerRollupPlugin(deployTrueOpt) //@ts-ignore await plugin.writeBundle(outputOptions, bundle) - + td.verify(sendDeployNotificationMock(deployTrueOpt)) }) @@ -83,11 +83,11 @@ describe('Index', () => { td.when(isNonProdEnvMock()).thenReturn(false) td.when(extractSourcemapDataFromBundleMock({ outputOptions, bundle })).thenReturn(sourcemapData) td.when(cleanOptionsMock(deployObjOpt)).thenReturn(deployObjOpt) - + const plugin = honeybadgerRollupPlugin(deployObjOpt) //@ts-ignore await plugin.writeBundle(outputOptions, bundle) - + td.verify(sendDeployNotificationMock(deployObjOpt)) }) @@ -96,23 +96,23 @@ describe('Index', () => { td.when(isNonProdEnvMock()).thenReturn(false) td.when(extractSourcemapDataFromBundleMock({ outputOptions, bundle })).thenReturn(sourcemapData) td.when(cleanOptionsMock(deployFalseOpt)).thenReturn(deployFalseOpt) - + const plugin = honeybadgerRollupPlugin(deployFalseOpt) //@ts-ignore await plugin.writeBundle(outputOptions, bundle) - + // Verify not called td.verify(sendDeployNotificationMock(), { times: 0, ignoreExtraArgs: true }) }) - + it('should do nothing in non-prod environments', async () => { td.when(isNonProdEnvMock()).thenReturn(true) td.when(cleanOptionsMock(options)).thenReturn(options) - + const plugin = honeybadgerRollupPlugin(options) //@ts-ignore await plugin.writeBundle(outputOptions, bundle) - + // Verify these were not called td.verify(extractSourcemapDataFromBundleMock(), { times: 0, ignoreExtraArgs: true }) td.verify(uploadSourcemapsMock(), { times: 0, ignoreExtraArgs: true }) @@ -120,5 +120,5 @@ describe('Index', () => { }) }) - -}) \ No newline at end of file + +}) diff --git a/packages/rollup-plugin/test/options.test.ts b/packages/rollup-plugin/test/options.test.ts index e05134a5b..4f0f44bff 100644 --- a/packages/rollup-plugin/test/options.test.ts +++ b/packages/rollup-plugin/test/options.test.ts @@ -1,11 +1,11 @@ import { expect } from 'chai' -import { - MAX_RETRIES, - DEFAULT_ENDPOINT, - DEFAULT_REVISION, +import { + MAX_RETRIES, + DEFAULT_ENDPOINT, + DEFAULT_REVISION, DEFAULT_SILENT, DEPLOY_ENDPOINT, - cleanOptions, + cleanOptions, } from '../src/options'; describe('Options', () => { @@ -14,32 +14,41 @@ describe('Options', () => { expect(cleanOptions.bind(cleanOptions, {})).to.throw('apiKey is required') }); + it('should error if ignorePaths is not an array', () => { + expect(cleanOptions.bind(cleanOptions, { + apiKey: 'test_key', + assetsUrl: 'https://foo.bar', + ignorePaths: 'foo' + })).to.throw('ignorePaths must be an array') + }); + it('should not allow retries above the MAX_RETRIES', () => { - const result = cleanOptions({ - apiKey: 'test_key', + const result = cleanOptions({ + apiKey: 'test_key', assetsUrl: 'https://foo.bar', - retries: 100 + retries: 100 }) expect(result.retries).to.equal(MAX_RETRIES) }) it('should merge in default options', () => { - const result = cleanOptions({ - apiKey: 'test_key', + const result = cleanOptions({ + apiKey: 'test_key', assetsUrl: 'https://foo.bar', - retries: 0, + retries: 0, deploy: { localUsername: 'BethanyBerkowitz' }, }) expect(result).to.deep.equal({ - apiKey: 'test_key', + apiKey: 'test_key', assetsUrl: 'https://foo.bar', - retries: 0, - endpoint: DEFAULT_ENDPOINT, - revision: DEFAULT_REVISION, - silent: DEFAULT_SILENT, + retries: 0, + endpoint: DEFAULT_ENDPOINT, + revision: DEFAULT_REVISION, + silent: DEFAULT_SILENT, deploy: { localUsername: 'BethanyBerkowitz' }, deployEndpoint: DEPLOY_ENDPOINT, + ignorePaths: [], }) }) }); -}); \ No newline at end of file +}); diff --git a/packages/rollup-plugin/test/rollupUtils.test.ts b/packages/rollup-plugin/test/rollupUtils.test.ts index a86ad3351..e769b499f 100644 --- a/packages/rollup-plugin/test/rollupUtils.test.ts +++ b/packages/rollup-plugin/test/rollupUtils.test.ts @@ -7,33 +7,55 @@ import * as td from 'testdouble' describe('extractSourcemapDataFromBundle', () => { const outputOptions = td.object() - outputOptions.dir = 'dist' + outputOptions.dir = 'dist' it('should return an array with sourcemap file data', () => { - const data = extractSourcemapDataFromBundle(outputOptions, bundle) + const data = extractSourcemapDataFromBundle(outputOptions, bundle, []) expect(data).to.be.an('array').lengthOf(3) expect(data).to.have.deep.members([ { - sourcemapFilename: 'index.js.map', - sourcemapFilePath: path.resolve('dist/index.js.map'), - jsFilename: 'index.js', + sourcemapFilename: 'index.js.map', + sourcemapFilePath: path.resolve('dist/index.js.map'), + jsFilename: 'index.js', jsFilePath: path.resolve('dist/index.js') - }, + }, { - sourcemapFilename: 'foo.js.map', - sourcemapFilePath: path.resolve('dist/foo.js.map'), - jsFilename: 'foo.js', + sourcemapFilename: 'foo.js.map', + sourcemapFilePath: path.resolve('dist/foo.js.map'), + jsFilename: 'foo.js', jsFilePath: path.resolve('dist/foo.js') }, { - sourcemapFilename: 'subfolder/bar.js.map', - sourcemapFilePath: path.resolve('dist/subfolder/bar.js.map'), - jsFilename: 'subfolder/bar.js', + sourcemapFilename: 'subfolder/bar.js.map', + sourcemapFilePath: path.resolve('dist/subfolder/bar.js.map'), + jsFilename: 'subfolder/bar.js', jsFilePath: path.resolve('dist/subfolder/bar.js') }, ]) }) -}); + + const itEach = ['foo.js', /foo.js/, 'foo.*', /foo.*/] + for (const ignorePath of itEach) { + it(`should ignore files that match the ignorePaths ${ignorePath}`, () => { + const data = extractSourcemapDataFromBundle(outputOptions, bundle, [ignorePath]) + expect(data).to.be.an('array').lengthOf(2) + expect(data).to.have.deep.members([ + { + sourcemapFilename: 'index.js.map', + sourcemapFilePath: path.resolve('dist/index.js.map'), + jsFilename: 'index.js', + jsFilePath: path.resolve('dist/index.js') + }, + { + sourcemapFilename: 'subfolder/bar.js.map', + sourcemapFilePath: path.resolve('dist/subfolder/bar.js.map'), + jsFilename: 'subfolder/bar.js', + jsFilePath: path.resolve('dist/subfolder/bar.js') + }, + ]) + }) + } +}) describe('isNonProdEnv', () => { let restore From 2c1354f8de511367daef8b1e48e0170edf12f2a1 Mon Sep 17 00:00:00 2001 From: Pangratios Cosma Date: Wed, 26 Apr 2023 08:20:55 +0300 Subject: [PATCH 2/6] chore: add test for empty sourcesContent Refs: #1053 --- packages/rollup-plugin/src/rollupUtils.ts | 2 +- .../rollup-plugin/test/fixtures/bundle.ts | 13 ++++++++--- .../rollup-plugin/test/rollupUtils.test.ts | 22 +++++++++++++++++++ 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/packages/rollup-plugin/src/rollupUtils.ts b/packages/rollup-plugin/src/rollupUtils.ts index bfc357805..283beaea6 100644 --- a/packages/rollup-plugin/src/rollupUtils.ts +++ b/packages/rollup-plugin/src/rollupUtils.ts @@ -26,7 +26,7 @@ function isSourcemap(file: OutputAsset | OutputChunk): file is OutputAsset { const source = typeof file.source === 'string' ? file.source : file.source.toString() const json = JSON.parse(source) - return json.sourcesContent && json.sourcesContent.length > 0 + return !!json.sourcesContent && json.sourcesContent.length > 0 } function isNotIgnored(sourceMapInfo: SourcemapInfo, ignorePaths: Array) { diff --git a/packages/rollup-plugin/test/fixtures/bundle.ts b/packages/rollup-plugin/test/fixtures/bundle.ts index abc8ff9ec..0469b98db 100644 --- a/packages/rollup-plugin/test/fixtures/bundle.ts +++ b/packages/rollup-plugin/test/fixtures/bundle.ts @@ -110,7 +110,7 @@ const assets = { fileName: 'index.js.map', name: undefined, source: '{"version":3,"file":"index.js","sources":["../src/index.js"],"sourcesContent":["import foo from \'./foo.js\';\\nimport bar from \'./subfolder/bar.js\'\\n\\nexport default function () {\\n console.log(foo)\\n console.log(bar)\\n}"],"names":[],"mappings":";;;;;AAGe,cAAQ,IAAI;AAC3B,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG,EAAC;AAClB,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG,EAAC;AAClB;;;;"}', - type: 'asset' as const, + type: 'asset' as const, needsCodeReference: false }, 'subfolder/bar.js.map': { @@ -126,8 +126,15 @@ const assets = { source: '{"version":3,"file":"foo.js","sources":["../src/foo.js"],"sourcesContent":["export default \'hello world!\'"],"names":[],"mappings":";;AAAA,UAAe;;;;"}', type: 'asset' as const, needsCodeReference: false + }, + 'empty.js.map': { + fileName: 'empty.js.map', + name: undefined, + source: '{"version":3,"file":"empty.js","sources":[], "sourcesContent": [], "names":[],"mappings":""}', + type: 'asset' as const, + needsCodeReference: false } -} +} -export default { ...chunks, ...assets } \ No newline at end of file +export default { ...chunks, ...assets } diff --git a/packages/rollup-plugin/test/rollupUtils.test.ts b/packages/rollup-plugin/test/rollupUtils.test.ts index e769b499f..5ed3153d4 100644 --- a/packages/rollup-plugin/test/rollupUtils.test.ts +++ b/packages/rollup-plugin/test/rollupUtils.test.ts @@ -55,6 +55,28 @@ describe('extractSourcemapDataFromBundle', () => { ]) }) } + + it('should ignore files with empty sourcesContent', () => { + expect(bundle).to.include.keys(['empty.js.map']) + expect(bundle['empty.js.map']).to.deep.equal({ + fileName: 'empty.js.map', + name: undefined, + source: '{"version":3,"file":"empty.js","sources":[], "sourcesContent": [], "names":[],"mappings":""}', + type: 'asset' as const, + needsCodeReference: false, + }) + + const data = extractSourcemapDataFromBundle(outputOptions, bundle, []) + expect(data).to.be.an('array').lengthOf(3) + expect(data).to.not.have.deep.members([ + { + sourcemapFilename: 'empty.js.map', + sourcemapFilePath: path.resolve('dist/empty.js.map'), + jsFilename: 'empty.js', + jsFilePath: path.resolve('dist/empty.js') + }, + ]) + }) }) describe('isNonProdEnv', () => { From f122206391b8ef47d05308c67685a465159daecd Mon Sep 17 00:00:00 2001 From: Pangratios Cosma Date: Wed, 26 Apr 2023 08:29:34 +0300 Subject: [PATCH 3/6] chore: update README Refs: #1053 --- packages/rollup-plugin/README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/rollup-plugin/README.md b/packages/rollup-plugin/README.md index 394155d0a..ad5f0cd79 100644 --- a/packages/rollup-plugin/README.md +++ b/packages/rollup-plugin/README.md @@ -42,6 +42,13 @@ These plugin parameters correspond to the Honeybadger [Source Map Upload API](ht
This package implements fetch retry functionality via the fetch-retry package. Retrying helps fix issues like `ECONNRESET` and `SOCKETTIMEOUT` errors.
+
ignorePaths (optional — default: [])
+
An array of paths to ignore when uploading sourcemaps. Regex is also supported. +
+ +
deployEndpoint (optional — default: "https://api.honeybadger.io/v1/deploys")
+
Where to send deployment notifications.
+
deploy (optional — default: false)
Configuration for deployment notifications. To disable deployment notifications, ignore this option. To enable deployment notifications, set this to true, or to an object containing any of the fields below. Your deploy's revision will be set to the same value as for your sourcemaps (see above). From 4bb32ebaaa9bac9f159db2b8cf3304588bdc7295 Mon Sep 17 00:00:00 2001 From: Pangratios Cosma Date: Wed, 26 Apr 2023 08:41:44 +0300 Subject: [PATCH 4/6] chore: run integration tests only when necessary --- .github/workflows/node.js.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 94f57db71..bd70cf0c2 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -36,8 +36,24 @@ jobs: - name: Run unit tests run: npm test + changes: + runs-on: ubuntu-latest + # Set job outputs to values from filter step + outputs: + core: ${{ steps.filter.outputs.core }} + steps: + - uses: dorny/paths-filter@v2 + id: filter + with: + filters: | + core: + - 'packages/core/**' + - 'packages/js/**' + integration: # integration tests from "js" package fail if they are executed at the same time + needs: changes + if: needs.changes.outputs.core == 'true' concurrency: js-concurrency runs-on: ubuntu-latest steps: From e5b7b3691b90823b90eab0a90ac8caadd46f6235 Mon Sep 17 00:00:00 2001 From: Pangratios Cosma Date: Wed, 26 Apr 2023 09:16:14 +0300 Subject: [PATCH 5/6] chore: use picomatch to match against glob patterns Refs: #1053 --- packages/rollup-plugin/README.md | 2 +- packages/rollup-plugin/package.json | 3 +- packages/rollup-plugin/src/rollupUtils.ts | 9 ++---- .../rollup-plugin/test/fixtures/bundle.ts | 31 ++++++++++++++++++- .../rollup-plugin/test/rollupUtils.test.ts | 6 ++-- 5 files changed, 39 insertions(+), 12 deletions(-) diff --git a/packages/rollup-plugin/README.md b/packages/rollup-plugin/README.md index ad5f0cd79..8724e12c9 100644 --- a/packages/rollup-plugin/README.md +++ b/packages/rollup-plugin/README.md @@ -43,7 +43,7 @@ These plugin parameters correspond to the Honeybadger [Source Map Upload API](ht
ignorePaths (optional — default: [])
-
An array of paths to ignore when uploading sourcemaps. Regex is also supported. +
An array of paths (glob patterns) to ignore when uploading sourcemaps. Uses picomatch to match against paths.
deployEndpoint (optional — default: "https://api.honeybadger.io/v1/deploys")
diff --git a/packages/rollup-plugin/package.json b/packages/rollup-plugin/package.json index 15c0e58dc..ddca630ab 100644 --- a/packages/rollup-plugin/package.json +++ b/packages/rollup-plugin/package.json @@ -46,7 +46,8 @@ "dependencies": { "fetch-retry": "^5.0.3", "form-data": "^4.0.0", - "node-fetch": "^2.6.9" + "node-fetch": "^2.6.9", + "picomatch": "^2.3.1" }, "main": "dist/cjs/index.js", "module": "dist/es/index.js", diff --git a/packages/rollup-plugin/src/rollupUtils.ts b/packages/rollup-plugin/src/rollupUtils.ts index 283beaea6..d9b79539e 100644 --- a/packages/rollup-plugin/src/rollupUtils.ts +++ b/packages/rollup-plugin/src/rollupUtils.ts @@ -1,4 +1,5 @@ import path from 'node:path' +import picomatch from 'picomatch' import type { OutputBundle, OutputAsset, OutputChunk, NormalizedOutputOptions } from 'rollup' import type { SourcemapInfo } from './types' @@ -31,12 +32,8 @@ function isSourcemap(file: OutputAsset | OutputChunk): file is OutputAsset { function isNotIgnored(sourceMapInfo: SourcemapInfo, ignorePaths: Array) { for (const ignorePath of ignorePaths) { - let regex = ignorePath - if (!(regex instanceof RegExp)) { - regex = new RegExp(regex) - } - - if (regex.test(sourceMapInfo.jsFilePath)) { + const isMatch = picomatch.isMatch(sourceMapInfo.jsFilePath, ignorePath, { basename: true }) + if (isMatch) { return false } } diff --git a/packages/rollup-plugin/test/fixtures/bundle.ts b/packages/rollup-plugin/test/fixtures/bundle.ts index 0469b98db..58355fe2d 100644 --- a/packages/rollup-plugin/test/fixtures/bundle.ts +++ b/packages/rollup-plugin/test/fixtures/bundle.ts @@ -103,6 +103,35 @@ const chunks = { 'module.exports = bar;\n', map: null }, + 'empty.sass': { + exports: [ 'default' ], + facadeModuleId: '/Users/bethanyberkowitz/projects/honeybadger/honeybadger-js/packages/rollup-plugin/examples/rollup/src/empty.sass', + isDynamicEntry: false, + isEntry: false, + isImplicitEntry: false, + moduleIds: [ + '/Users/bethanyberkowitz/projects/honeybadger/honeybadger-js/packages/rollup-plugin/examples/rollup/src/empty.sass' + ], + name: 'empty', + type: 'chunk' as const, + dynamicImports: [], + fileName: 'empty.sass', + implicitlyLoadedBefore: [], + importedBindings: {}, + imports: [], + modules: { + '/Users/bethanyberkowitz/projects/honeybadger/honeybadger-js/packages/rollup-plugin/examples/rollup/src/empty.sass': { + 'code': 'color: blue;', + 'originalLength': 12, + 'removedExports': [], + 'renderedExports': ['default'], + 'renderedLength': 12 + } + }, + referencedFiles: [], + code: 'color: blue;', + map: null + }, } const assets = { @@ -130,7 +159,7 @@ const assets = { 'empty.js.map': { fileName: 'empty.js.map', name: undefined, - source: '{"version":3,"file":"empty.js","sources":[], "sourcesContent": [], "names":[],"mappings":""}', + source: '{"version":3,"file":"empty.sass","sources":[], "sourcesContent": [], "names":[],"mappings":""}', type: 'asset' as const, needsCodeReference: false } diff --git a/packages/rollup-plugin/test/rollupUtils.test.ts b/packages/rollup-plugin/test/rollupUtils.test.ts index 5ed3153d4..b8415647c 100644 --- a/packages/rollup-plugin/test/rollupUtils.test.ts +++ b/packages/rollup-plugin/test/rollupUtils.test.ts @@ -34,9 +34,9 @@ describe('extractSourcemapDataFromBundle', () => { ]) }) - const itEach = ['foo.js', /foo.js/, 'foo.*', /foo.*/] + const itEach = ['foo.js', '**/foo.js', 'foo.*', '**/foo.*', 'foo.js*', '**/foo.js*'] for (const ignorePath of itEach) { - it(`should ignore files that match the ignorePaths ${ignorePath}`, () => { + it(`should ignore files that match the ignorePath ${ignorePath}`, () => { const data = extractSourcemapDataFromBundle(outputOptions, bundle, [ignorePath]) expect(data).to.be.an('array').lengthOf(2) expect(data).to.have.deep.members([ @@ -61,7 +61,7 @@ describe('extractSourcemapDataFromBundle', () => { expect(bundle['empty.js.map']).to.deep.equal({ fileName: 'empty.js.map', name: undefined, - source: '{"version":3,"file":"empty.js","sources":[], "sourcesContent": [], "names":[],"mappings":""}', + source: '{"version":3,"file":"empty.sass","sources":[], "sourcesContent": [], "names":[],"mappings":""}', type: 'asset' as const, needsCodeReference: false, }) From 7d3ada84615007e2c3a2fd64da13ec52094003af Mon Sep 17 00:00:00 2001 From: Pangratios Cosma Date: Thu, 27 Apr 2023 08:39:36 +0300 Subject: [PATCH 6/6] chore: pass array of paths to picomatch, remove regex refs Refs: #1053 --- packages/rollup-plugin/src/rollupUtils.ts | 13 ++++--------- packages/rollup-plugin/src/types.ts | 2 +- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/packages/rollup-plugin/src/rollupUtils.ts b/packages/rollup-plugin/src/rollupUtils.ts index d9b79539e..19a87394d 100644 --- a/packages/rollup-plugin/src/rollupUtils.ts +++ b/packages/rollup-plugin/src/rollupUtils.ts @@ -10,7 +10,7 @@ import type { SourcemapInfo } from './types' export function extractSourcemapDataFromBundle ( outputOptions: NormalizedOutputOptions, bundle: OutputBundle, - ignorePaths: Array = [] + ignorePaths: Array = [] ): SourcemapInfo[] { const sourceMaps = Object.values(bundle).filter(isSourcemap) @@ -30,15 +30,10 @@ function isSourcemap(file: OutputAsset | OutputChunk): file is OutputAsset { return !!json.sourcesContent && json.sourcesContent.length > 0 } -function isNotIgnored(sourceMapInfo: SourcemapInfo, ignorePaths: Array) { - for (const ignorePath of ignorePaths) { - const isMatch = picomatch.isMatch(sourceMapInfo.jsFilePath, ignorePath, { basename: true }) - if (isMatch) { - return false - } - } +function isNotIgnored(sourceMapInfo: SourcemapInfo, ignorePaths: Array) { + const isMatch = picomatch.isMatch(sourceMapInfo.jsFilePath, ignorePaths, { basename: true }) - return true + return !isMatch } function formatSourcemapData( diff --git a/packages/rollup-plugin/src/types.ts b/packages/rollup-plugin/src/types.ts index 5fa9a7ad0..6ad4e9745 100644 --- a/packages/rollup-plugin/src/types.ts +++ b/packages/rollup-plugin/src/types.ts @@ -7,7 +7,7 @@ export interface HbPluginOptions { silent: boolean; deployEndpoint: string; deploy: boolean | Deploy; - ignorePaths: Array; + ignorePaths: Array; } export interface Deploy {