Skip to content

Commit

Permalink
feat: add ignorePaths option (#1059)
Browse files Browse the repository at this point in the history
  • Loading branch information
subzero10 authored Apr 27, 2023
1 parent a39a9e9 commit 27c357e
Show file tree
Hide file tree
Showing 11 changed files with 217 additions and 79 deletions.
16 changes: 16 additions & 0 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
7 changes: 7 additions & 0 deletions packages/rollup-plugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ These plugin parameters correspond to the Honeybadger [Source Map Upload API](ht
<dd>This package implements fetch retry functionality via the <a href="https://github.com/vercel/fetch-retry">fetch-retry</a> package. Retrying helps fix issues like `ECONNRESET` and `SOCKETTIMEOUT` errors.
</dd>

<dt><code>ignorePaths</code> (optional &mdash; default: [])</dt>
<dd>An array of paths (glob patterns) to ignore when uploading sourcemaps. Uses <a href="https://github.com/micromatch/picomatch">picomatch</a> to match against paths.
</dd>

<dt><code>deployEndpoint</code> (optional &mdash; default: "https://api.honeybadger.io/v1/deploys")</dt>
<dd>Where to send deployment notifications.</dd>

<dt><code>deploy</code> (optional &mdash; default: false)</dt>
<dd>
Configuration for <a href="https://docs.honeybadger.io/api/reporting-deployments/">deployment notifications</a>. To disable deployment notifications, ignore this option. To enable deployment notifications, set this to <code>true</code>, or to an object containing any of the fields below. Your deploy's <code>revision</code> will be set to the same value as for your sourcemaps (see above).
Expand Down
3 changes: 2 additions & 1 deletion packages/rollup-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
8 changes: 4 additions & 4 deletions packages/rollup-plugin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand All @@ -22,12 +22,12 @@ export default function honeybadgerRollupPlugin(
return
}

const sourcemapData = extractSourcemapDataFromBundle(outputOptions, bundle)
const sourcemapData = extractSourcemapDataFromBundle(outputOptions, bundle, hbOptions.ignorePaths)
await uploadSourcemaps(sourcemapData, hbOptions)

if (hbOptions.deploy) {
await sendDeployNotification(hbOptions)
}
}
}
}
}
17 changes: 13 additions & 4 deletions packages/rollup-plugin/src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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(
Expand All @@ -36,13 +38,20 @@ 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) {
console.warn(`Using max retries: ${MAX_RETRIES}`)
}
options.retries = MAX_RETRIES
}

// Merge in our defaults
return { ...defaultOptions, ...options }
}
39 changes: 27 additions & 12 deletions packages/rollup-plugin/src/rollupUtils.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,50 @@
import path from 'node:path'
import picomatch from 'picomatch'

import type { OutputBundle, OutputAsset, OutputChunk, NormalizedOutputOptions } from 'rollup'
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<string> = []
): 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<string>) {
const isMatch = picomatch.isMatch(sourceMapInfo.jsFilePath, ignorePaths, { basename: true })

return !isMatch
}

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)
Expand All @@ -47,9 +62,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'
}
}
5 changes: 3 additions & 2 deletions packages/rollup-plugin/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ export interface HbPluginOptions {
revision: string;
silent: boolean;
deployEndpoint: string;
deploy: boolean | Deploy
deploy: boolean | Deploy;
ignorePaths: Array<string>;
}

export interface Deploy {
Expand All @@ -29,4 +30,4 @@ export interface SourcemapInfo {
sourcemapFilePath: string;
jsFilename: string;
jsFilePath: string;
}
}
42 changes: 39 additions & 3 deletions packages/rollup-plugin/test/fixtures/bundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,43 @@ 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 = {
'index.js.map': {
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': {
Expand All @@ -126,8 +155,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.sass","sources":[], "sourcesContent": [], "names":[],"mappings":""}',
type: 'asset' as const,
needsCodeReference: false
}
}
}


export default { ...chunks, ...assets }
export default { ...chunks, ...assets }
Loading

0 comments on commit 27c357e

Please sign in to comment.