Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add ignorePaths option #1059

Merged
merged 6 commits into from
Apr 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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'
subzero10 marked this conversation as resolved.
Show resolved Hide resolved
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>
subzero10 marked this conversation as resolved.
Show resolved Hide resolved
<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