@sentry/webpack-plugin 1.17.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.craft.yml ADDED
@@ -0,0 +1,13 @@
1
+ github:
2
+ owner: getsentry
3
+ repo: sentry-webpack-plugin
4
+ changelogPolicy: simple
5
+ preReleaseCommand: bash scripts/craft-pre-release.sh
6
+ statusProvider:
7
+ name: github
8
+ artifactProvider:
9
+ name: github
10
+ targets:
11
+ - name: npm
12
+ - name: github
13
+ tagPrefix: v
package/.eslintrc ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "extends": ["airbnb-base", "prettier"],
3
+ "settings": {
4
+ "excludedFiles": "*.spec.js"
5
+ }
6
+ }
package/.prettierrc ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "trailingComma": "es5",
3
+ "singleQuote": true,
4
+ "proseWrap": "always",
5
+ "printWidth": 80
6
+ }
package/CHANGELOG.md ADDED
@@ -0,0 +1,129 @@
1
+ # Changelog
2
+
3
+ ## Unreleased
4
+
5
+ - "Would I rather be feared or loved? Easy. Both. I want people to be afraid of how much they love me." — Michael Scott
6
+
7
+ ## v1.17.2
8
+
9
+ - docs: Fix description and default value for sourceMapReferences (#318)
10
+ - fix: Increase stack size of errors in CI (#319)
11
+ - fix: Enable plugin to be imported under ES6 (#316)
12
+ - fix: Add `options` to main plugin type (#314)
13
+ - fix: Update types of SentryCliPluginOptions.errorHandler (#308)
14
+
15
+ ## v1.17.1
16
+
17
+ - fix: Fix types and array normalization for `include` option (#302)
18
+
19
+ ## v1.17.0
20
+
21
+ - feat: Allow `include` option to be an object (#299)
22
+ - deps: Update sentry-cli to v1.68 (#297)
23
+
24
+ ## v1.16.0
25
+
26
+ - feat: Add `ignoreMissing` sub-option to `setCommits` option (#281)
27
+ - fix: Add missing `dist` option to `SentryCliPluginOptions` type (#285)
28
+ - deps: Update sentry-cli to v1.67
29
+
30
+ ## v1.15.1
31
+
32
+ - deps: Update sentry-cli to v1.64
33
+
34
+ ## v1.15.0
35
+
36
+ - feat: Add `cleanAftifacts` option to remove all previously uploaded files in a release (#264)
37
+ - feat: Add `runOnce` option to allow for skipping multiple uploads with the same config (#270)
38
+
39
+ ## v1.14.2
40
+
41
+ - deps: Update sentry-cli to v1.63 for ARM support
42
+
43
+ ## v1.14.1
44
+
45
+ - fix: Use `WebpackPluginInstance` type for Webpack v4 and v5 compatibility (#259)
46
+
47
+ ## v1.14.0
48
+
49
+ - feat: Add support for Webpack 5 entry descriptors (#241)
50
+
51
+ ## v1.13.0
52
+
53
+ - feat: Support minimal CLI options (#225)
54
+ - fix: Return an actual error for propagation (#224)
55
+ - deps: Bump sentry-cli to `1.58.0`
56
+
57
+ ## v1.12.1
58
+
59
+ - fix(deploy): change deploy to newDeploy in mocked CLI object (#206)
60
+ - fix(types): add deploy configuration to type definitions (#208)
61
+
62
+ ## v1.12.0
63
+
64
+ - feat: Allow to perform release deploys (#192)
65
+ - fix: CJS/TS Exports Interop (#190)
66
+ - fix: make setCommits.repo type optional (#200)
67
+ - deps: Bump sentry-cli to `1.55.0`
68
+
69
+ ## v1.11.1
70
+
71
+ - meta: Bump sentry-cli to `1.52.3` which fixes output handlers
72
+
73
+ ## v1.11.0
74
+
75
+ **This release sets `node.engine: >=8` which makes it incompatible with Node v6**
76
+ If you need to support Node v6, please pin your dependency to `1.10.0`
77
+ and use selective version resolution: https://classic.yarnpkg.com/en/docs/selective-version-resolutions/
78
+
79
+ - meta: Bump sentry-cli to `1.52.2`
80
+ - meta: Drop support for `node v6` due to new `sentry-cli` requiring `node >=8`
81
+ - chore: Fix setCommits types (#169)
82
+
83
+ ## v1.10.0
84
+
85
+ - feat: Allow for skiping release finalization (#157)
86
+ - fix: Ensure afterEmit hook exists (#165)
87
+ - chore: Update TS definitions (#168)
88
+
89
+ ## v1.9.3
90
+
91
+ - chore: Bump sentry-cli to `1.49.0`
92
+ - fix: Dont fail compilation if there is no release available (#155)
93
+ - fix: Update auto/repo logic for `setCommit` option (#156)
94
+
95
+ ## v1.9.2
96
+
97
+ - chore: Resolve Snyk as dependency issues (#152)
98
+
99
+ ## v1.9.1
100
+
101
+ - ref: Allow for nested setCommits (#142)
102
+ - fix: Fixed TS definitions export error (#145)
103
+
104
+ ## v1.9.0
105
+
106
+ - feat: Add `setCommits` options (#139)
107
+ - chore: Add `TypeScript` definition file (#137)
108
+ - meta: Bump sentry-cli to `1.48.0`
109
+
110
+ ## v1.8.1
111
+
112
+ - meta: Bump sentry-cli to `1.47.1`
113
+
114
+ ## v1.8.0
115
+
116
+ - feat: Add errorHandler option (#133)
117
+
118
+ ## v1.7.0
119
+
120
+ - feat: Add silent option to disable all output to stdout (#127)
121
+
122
+ ## v1.6.2
123
+
124
+ - fix: Extract loader name in more reliable way
125
+ - build: Craft integration
126
+
127
+ ## v1.6.1
128
+
129
+ - https://github.com/getsentry/sentry-webpack-plugin/releases
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Sentry
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,129 @@
1
+ <p align="center">
2
+ <a href="https://sentry.io" target="_blank" align="center">
3
+ <img src="https://sentry-brand.storage.googleapis.com/sentry-logo-black.png" width="280">
4
+ </a>
5
+ <br/>
6
+ <h1>Sentry Webpack Plugin</h1>
7
+ </p>
8
+
9
+ [![codecov](https://codecov.io/gh/getsentry/sentry-webpack-plugin/branch/master/graph/badge.svg)](https://codecov.io/gh/getsentry/sentry-webpack-plugin)
10
+ [![npm version](https://img.shields.io/npm/v/@sentry/webpack-plugin.svg)](https://www.npmjs.com/package/@sentry/webpack-plugin)
11
+ [![npm dm](https://img.shields.io/npm/dm/@sentry/webpack-plugin.svg)](https://www.npmjs.com/package/@sentry/webpack-plugin)
12
+ [![npm dt](https://img.shields.io/npm/dt/@sentry/webpack-plugin.svg)](https://www.npmjs.com/package/@sentry/webpack-plugin)
13
+
14
+ [![deps](https://david-dm.org/getsentry/sentry-webpack-plugin/status.svg)](https://david-dm.org/getsentry/sentry-webpack-plugin?view=list)
15
+ [![deps dev](https://david-dm.org/getsentry/sentry-webpack-plugin/dev-status.svg)](https://david-dm.org/getsentry/sentry-webpack-plugin?type=dev&view=list)
16
+ [![deps peer](https://david-dm.org/getsentry/sentry-webpack-plugin/peer-status.svg)](https://david-dm.org/getsentry/sentry-webpack-plugin?type=peer&view=list)
17
+
18
+ A webpack plugin acting as an interface to
19
+ [Sentry CLI](https://docs.sentry.io/learn/cli/).
20
+
21
+ ### Installation
22
+
23
+ Using npm:
24
+
25
+ ```bash
26
+ $ npm install @sentry/webpack-plugin --save-dev
27
+ ```
28
+
29
+ Using yarn:
30
+
31
+ ```bash
32
+ $ yarn add @sentry/webpack-plugin --dev
33
+ ```
34
+
35
+ ### CLI Configuration
36
+
37
+ You can use either `.sentryclirc` file or ENV variables described here
38
+ https://docs.sentry.io/cli/configuration.
39
+
40
+ ### Usage
41
+
42
+ ```js
43
+ const SentryCliPlugin = require('@sentry/webpack-plugin');
44
+
45
+ const config = {
46
+ plugins: [
47
+ new SentryCliPlugin({
48
+ include: '.',
49
+ ignoreFile: '.sentrycliignore',
50
+ ignore: ['node_modules', 'webpack.config.js'],
51
+ configFile: 'sentry.properties',
52
+ }),
53
+ ],
54
+ };
55
+ ```
56
+
57
+ Also, check the [example](example) directory.
58
+
59
+ #### Options
60
+
61
+ | Option | Type | Required | Description |
62
+ | ------------------ | ----------------------------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
63
+ | include | `string`/`array`/`object` | required | One or more paths that Sentry CLI should scan recursively for sources. It will upload all `.map` files and match associated `.js` files. Each path can be given as an object with path-specific options. See [table below](#include) for details. |
64
+ | org | `string` | optional | The slug of the Sentry organization associated with the app. |
65
+ | project | `string` | optional | The slug of the Sentry project associated with the app. |
66
+ | authToken | `string` | optional | The authentication token to use for all communication with Sentry. Can be obtained from https://sentry.io/settings/account/api/auth-tokens/. Required scopes: `project:releases` (and `org:read` if `setCommits` option is used). |
67
+ | url | `string` | optional | The base URL of your Sentry instance. Defaults to https://sentry.io/, which is the correct value for SAAS customers. |
68
+ | vcsRemote | `string` | optional | The name of the remote in the version control system. Defaults to `origin`. |
69
+ | release | `string` | optional | Unique identifier for the release. Defaults to the output of the `sentry-cli releases propose-version` command, which automatically detects values for Cordova, Heroku, AWS CodeBuild, CircleCI, Xcode, and Gradle, and otherwise uses `HEAD`'s commit SHA. (**For `HEAD` option, requires access to `git` CLI and for the root directory to be a valid repository**). |
70
+ | dist | `string` | optional | Unique identifier for the distribution, used to further segment your release. Usually your build number. |
71
+ | entries | `array`/`RegExp`/`function(key: string): bool` | optional | Filter for entry points that should be processed. By default, the release will be injected into all entry points. |
72
+ | ignoreFile | `string` | optional | Path to a file containing list of files/directories to ignore. Can point to `.gitignore` or anything with the same format. |
73
+ | ignore | `string`/`array` | optional | One or more paths to ignore during upload. Overrides entries in `ignoreFile` file. If neither `ignoreFile` nor `ignore` is present, defaults to `['node_modules']`. |
74
+ | configFile | `string` | optional | Path to Sentry CLI config properties, as described in https://docs.sentry.io/product/cli/configuration/#configuration-file. By default, the config file is looked for upwards from the current path, and defaults from `~/.sentryclirc` are always loaded |
75
+ | ext | `array` | optional | The file extensions to be considered. By default the following file extensions are processed: `js`, `map`, `jsbundle`, and `bundle`. |
76
+ | urlPrefix | `string` | optional | URL prefix to add to the beginning of all filenames. Defaults to `~/` but you might want to set this to the full URL. This is also useful if your files are stored in a sub folder. eg: `url-prefix '~/static/js'`. |
77
+ | urlSuffix | `string` | optional | URL suffix to add to the end of all filenames. Useful for appending query parameters. |
78
+ | validate | `boolean` | optional | When `true`, attempts source map validation before upload if rewriting is not enabled. It will spot a variety of issues with source maps and cancel the upload if any are found. Defaults to `false` to prevent false positives canceling upload. |
79
+ | stripPrefix | `array` | optional | When paired with `rewrite`, will remove a prefix from filename references inside of sourcemaps. Useful for removing a path that is build-machine-specific. Note that this will NOT change the names of uploaded files. |
80
+ | stripCommonPrefix | `boolean` | optional | When paired with `rewrite`, will add `~` to the `stripPrefix` array. Defaults to `false`. |
81
+ | sourceMapReference | `boolean` | optional | Determines whether sentry-cli should attempt to link minified files with their corresponding maps. By default, it will match files and maps based on name, and add a `Sourcemap` header to each minified file for which it finds a map. Can be disabled if all minified files contain `sourceMappingURL`. Defaults to `true`. |
82
+ | rewrite | `boolean` | optional | Enables rewriting of matching source maps so that indexed maps are flattened and missing sources are inlined if possible. Defaults to `true` |
83
+ | finalize | `boolean` | optional | Determines whether Sentry release record should be automatically finalized (`date_released` timestamp added) after artifact upload. Defaults to `true` |
84
+ | dryRun | `boolean` | optional | Attempts a dry run (useful for dev environments). Defaults to `false`. |
85
+ | debug | `boolean` | optional | Print useful debug information. Defaults to `false`. |
86
+ | silent | `boolean` | optional | Suppresses all logs (useful for `--json` option). Defaults to `false`. |
87
+ | cleanArtifacts | `boolean` | optional | Remove all the artifacts in the release before the upload. Defaults to `false`. |
88
+ | errorHandler | `function(err: Error, invokeErr: function(): void, compilation: Compilation): void` | optional | Function to call a when CLI error occurs. Webpack compilation failure can be triggered by calling `invokeErr` callback. Can emit a warning rather than an error (allowing compilation to continue) by setting this to `(err, invokeErr, compilation) => { compilation.warnings.push('Sentry CLI Plugin: ' + err.message) }`. Defaults to `(err, invokeErr) => { invokeErr() }`. |
89
+ | setCommits | `Object` | optional | Adds commits to Sentry. See [table below](#setCommits) for details. |
90
+ | deploy | `Object` | optional | Creates a new release deployment in Sentry. See [table below](#deploy) for details. |
91
+
92
+ #### <a name="include"></a>options.include:
93
+
94
+ | Option | Type | Required | Description |
95
+ | ------------------ | ---------------- | -------- | ---------------------------------------------- |
96
+ | paths | `array` | required | One or more paths to scan for files to upload. |
97
+ | ignoreFile | `string` | optional | See above. |
98
+ | ignore | `string`/`array` | optional | See above. |
99
+ | ext | `array` | optional | See above. |
100
+ | urlPrefix | `string` | optional | See above. |
101
+ | urlSuffix | `string` | optional | See above. |
102
+ | stripPrefix | `array` | optional | See above. |
103
+ | stripCommonPrefix | `boolean` | optional | See above. |
104
+ | sourceMapReference | `boolean` | optional | See above. |
105
+ | rewrite | `boolean` | optional | See above. |
106
+
107
+ #### <a name="setCommits"></a>options.setCommits:
108
+
109
+ | Option | Type | Required | Description |
110
+ | -------------- | --------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
111
+ | repo | `string` | see notes | The full git repo name as defined in Sentry. Required if `auto` option is not `true`, otherwise optional. |
112
+ | commit | `string` | see notes | The current (most recent) commit in the release. Required if `auto` option is not `true`, otherwise optional. |
113
+ | previousCommit | `string` | optional | The last commit of the previous release. Defaults to the most recent commit of the previous release in Sentry, or if no previous release is found, 10 commits back from `commit`. |
114
+ | auto | `boolean` | optional | Automatically set `commit` and `previousCommit`. Defaults `commit` to `HEAD` and `previousCommit` as described above. Overrides other options |
115
+ | ignoreMissing | `boolean` | optional | When the flag is set and the previous release commit was not found in the repository, will create a release with the default commits count (or the one specified with `--initial-depth`) instead of failing the command. |
116
+
117
+ #### <a name="deploy"></a>options.deploy:
118
+
119
+ | Option | Type | Required | Description |
120
+ | -------- | -------- | -------- | -------------------------------------------------------------------------------- |
121
+ | env | `string` | required | Environment value for the release, for example `production` or `staging`. |
122
+ | started | `number` | optional | UNIX timestamp for deployment start. |
123
+ | finished | `number` | optional | UNIX timestamp for deployment finish. |
124
+ | time | `number` | optional | Deployment duration in seconds. Can be used instead of `started` and `finished`. |
125
+ | name | `string` | optional | Human-readable name for this deployment. |
126
+ | url | `string` | optional | URL that points to the deployment. |
127
+
128
+ You can find more information about these options in our official docs:
129
+ https://docs.sentry.io/product/cli/releases/#sentry-cli-sourcemaps.
package/index.d.ts ADDED
@@ -0,0 +1,135 @@
1
+ import { Compiler, WebpackPluginInstance, Compilation } from 'webpack';
2
+ import {
3
+ SentryCliCommitsOptions,
4
+ SentryCliNewDeployOptions,
5
+ SentryCliOptions,
6
+ SentryCliUploadSourceMapsOptions,
7
+ SourceMapsPathDescriptor,
8
+ } from '@sentry/cli';
9
+
10
+ declare namespace SentryCliPlugin {
11
+ export interface SentryCliPluginOptions
12
+ extends Pick<
13
+ SentryCliOptions,
14
+ | 'url'
15
+ | 'authToken'
16
+ | 'org'
17
+ | 'project'
18
+ | 'vscRemote'
19
+ | 'dist'
20
+ | 'silent'
21
+ >,
22
+ Pick<
23
+ SentryCliUploadSourceMapsOptions,
24
+ | 'ignoreFile'
25
+ | 'rewrite'
26
+ | 'sourceMapReference'
27
+ | 'stripPrefix'
28
+ | 'stripCommonPrefix'
29
+ | 'validate'
30
+ | 'urlPrefix'
31
+ | 'urlSuffix'
32
+ | 'ext'
33
+ > {
34
+ /**
35
+ * Filepaths to scan recursively for source and source map files
36
+ */
37
+ include:
38
+ | string
39
+ | SourceMapsPathDescriptor
40
+ | Array<string | SourceMapsPathDescriptor>;
41
+
42
+ /**
43
+ * Filepaths to ignore when scanning for sources and source maps
44
+ */
45
+ ignore?: string | Array<string>;
46
+
47
+ /**
48
+ * Unique name of a release, must be a string, should uniquely identify your release,
49
+ * defaults to sentry-cli releases propose-version command which should always return the correct version
50
+ * (requires access to git CLI and root directory to be a valid repository).
51
+ */
52
+ release?: string;
53
+
54
+ /**
55
+ * A filter for entry points that should be processed.
56
+ * By default, the release will be injected into all entry points.
57
+ */
58
+ entries?: string[] | RegExp | ((key: string) => boolean);
59
+
60
+ /**
61
+ * Path to Sentry CLI config properties, as described in https://docs.sentry.io/learn/cli/configuration/#properties-files.
62
+ * By default, the config file is looked for upwards from the current path and defaults from ~/.sentryclirc are always loaded.
63
+ */
64
+ configFile?: string;
65
+
66
+ /**
67
+ * Determines whether processed release should be automatically finalized after artifacts upload.
68
+ * Defaults to `true`.
69
+ */
70
+ finalize?: boolean;
71
+
72
+ /**
73
+ * Determines whether plugin should be applied not more than once during whole webpack run.
74
+ * Useful when the process is performing multiple builds using the same config.
75
+ * Defaults to `false`.
76
+ */
77
+ runOnce?: boolean;
78
+
79
+ /**
80
+ * Attempts a dry run (useful for dev environments).
81
+ */
82
+ dryRun?: boolean;
83
+
84
+ /**
85
+ * Print some useful debug information.
86
+ */
87
+ debug?: boolean;
88
+
89
+ /**
90
+ * If true, will remove all previously uploaded artifacts from the configured release.
91
+ */
92
+ cleanArtifacts?: boolean;
93
+
94
+ /**
95
+ * when Cli error occurs, plugin calls this function.
96
+ * webpack compilation failure can be chosen by calling invokeErr callback or not.
97
+ * defaults to `(err, invokeErr) => { invokeErr() }`
98
+ */
99
+ errorHandler?: (
100
+ err: Error,
101
+ invokeErr: () => void,
102
+ compilation: Compilation
103
+ ) => void;
104
+
105
+ /**
106
+ * Adds commits to sentry
107
+ */
108
+ setCommits?: SentryCliCommitsOptions;
109
+
110
+ /**
111
+ * Creates a new release deployment
112
+ */
113
+ deploy?: SentryCliNewDeployOptions;
114
+ }
115
+ }
116
+
117
+ declare class SentryCliPlugin implements WebpackPluginInstance {
118
+ options: SentryCliPlugin.SentryCliPluginOptions;
119
+ constructor(options: SentryCliPlugin.SentryCliPluginOptions);
120
+ apply(compiler: Compiler): void;
121
+ }
122
+
123
+ // We need to use this older format (over `export default SentryCliPlugin`)
124
+ // because we don't want people using the plugin in their TS projects to be
125
+ // forced to set `esmoduleinterop` to `true`, which the newer syntax requires.
126
+ // See
127
+ // https://github.com/microsoft/TypeScript-Website/blob/6a36b3137182084c76cdf133c812fe3a5626dbf0/packages/documentation/copy/en/declaration-files/templates/module.d.ts.md#L95-L106
128
+ // (linking to the docs in their raw form on GH rather than on the TS docs site
129
+ // in case the docs site ever moves things around).
130
+ //
131
+ // Note that with this older format, no other top-level exports can exist, which
132
+ // is why the exported interface above is wrapped in a namespace. See the
133
+ // example in the above link and
134
+ // https://github.com/microsoft/TypeScript-Website/blob/6a36b3137182084c76cdf133c812fe3a5626dbf0/packages/documentation/copy/en/declaration-files/templates/module.d.ts.md#L195-L214.
135
+ export = SentryCliPlugin;
package/jest.config.js ADDED
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ collectCoverage: true,
3
+ testEnvironment: 'node',
4
+ testPathIgnorePatterns: ['example'],
5
+ };
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@sentry/webpack-plugin",
3
+ "description": "Official webpack plugin for Sentry",
4
+ "keywords": [
5
+ "sentry",
6
+ "sentry-cli",
7
+ "webpack",
8
+ "source-map"
9
+ ],
10
+ "author": "Sentry",
11
+ "version": "1.17.2",
12
+ "license": "MIT",
13
+ "repository": "git@github.com:getsentry/sentry-webpack-plugin.git",
14
+ "homepage": "https://github.com/getsentry/sentry-webpack-plugin",
15
+ "main": "src/cjs.js",
16
+ "types": "index.d.ts",
17
+ "engines": {
18
+ "node": ">= 8"
19
+ },
20
+ "dependencies": {
21
+ "@sentry/cli": "^1.68.0"
22
+ },
23
+ "devDependencies": {
24
+ "@types/webpack": "^4.0.0 || ^5.0.0",
25
+ "codecov": "^3.5.0",
26
+ "eslint": "^5.16.0",
27
+ "eslint-config-airbnb-base": "^13.1.0",
28
+ "eslint-config-prettier": "^4.3.0",
29
+ "eslint-plugin-import": "^2.17.3",
30
+ "jest": "^24.8.0",
31
+ "npm-run-all": "^4.1.5",
32
+ "prettier": "^1.18.2",
33
+ "prettier-check": "^2.0.0",
34
+ "webpack": "^4.39.3"
35
+ },
36
+ "scripts": {
37
+ "lint": "run-s lint:prettier lint:eslint",
38
+ "lint:prettier": "prettier-check 'src/**/*.js'",
39
+ "lint:eslint": "eslint src",
40
+ "fix": "run-s fix:eslint fix:prettier",
41
+ "fix:prettier": "prettier --write 'src/**/*.js'",
42
+ "fix:eslint": "eslint --fix src",
43
+ "test": "jest",
44
+ "test:integration": "cd example && yarn && yarn test",
45
+ "test:watch": "jest --watch --notify",
46
+ "codecov": "codecov"
47
+ }
48
+ }
@@ -0,0 +1,8 @@
1
+ #!/bin/bash
2
+ set -eux
3
+ OLD_VERSION="${1}"
4
+ NEW_VERSION="${2}"
5
+
6
+ # Do not tag and commit changes made by "npm version"
7
+ export npm_config_git_tag_version=false
8
+ npm version "${NEW_VERSION}"
package/src/cjs.js ADDED
@@ -0,0 +1,20 @@
1
+ module.exports = require('./index').default;
2
+
3
+ // The assignment to `default` below saves us from having to use
4
+ // `esModuleInterop` (which then would force our users to set the same option),
5
+ // by manually doing the one part of `esModuleInterop`'s job we actually need.
6
+ //
7
+ // (In order to avoid a breaking change, we need to stick with default-exporting
8
+ // `SentryCliPlugin`. This means that if we want to use ES6 imports (in our own
9
+ // use of the plugin), our options are:
10
+ //
11
+ // `import * as x from y`,
12
+ // `import x from y`, and
13
+ // `import {default as x} from y`.
14
+ //
15
+ // If we use the first option, it correctly pulls in the above `module.exports`
16
+ // value, but it treats it as a namespace, not a class, and therefore refuses to
17
+ // let it be used with `new`. If we use either of the other two, it looks for
18
+ // `module.exports.default`, which will be undefined unless either we do (or
19
+ // `esModuleInterop` does) the below.)
20
+ module.exports.default = module.exports;
package/src/index.js ADDED
@@ -0,0 +1,516 @@
1
+ const SentryCli = require('@sentry/cli');
2
+ const path = require('path');
3
+ const util = require('util');
4
+
5
+ const SENTRY_LOADER = path.resolve(__dirname, 'sentry.loader.js');
6
+ const SENTRY_MODULE = path.resolve(__dirname, 'sentry-webpack.module.js');
7
+
8
+ /**
9
+ * Helper function that ensures an object key is defined. This mutates target!
10
+ *
11
+ * @param {object} target The target object
12
+ * @param {string} key The object key
13
+ * @param {function} factory A function that creates the new element
14
+ * @returns {any} The existing or created element.
15
+ */
16
+ function ensure(target, key, factory) {
17
+ // eslint-disable-next-line no-param-reassign
18
+ target[key] = typeof target[key] !== 'undefined' ? target[key] : factory();
19
+ return target[key];
20
+ }
21
+
22
+ /** Deep copy of a given input */
23
+ function sillyClone(input) {
24
+ try {
25
+ return JSON.parse(JSON.stringify(input));
26
+ } catch (oO) {
27
+ return undefined;
28
+ }
29
+ }
30
+
31
+ /** Diffs two arrays */
32
+ function diffArray(prev, next) {
33
+ // eslint-disable-next-line no-param-reassign
34
+ prev = Array.isArray(prev) ? prev : [prev];
35
+ // eslint-disable-next-line no-param-reassign
36
+ next = Array.isArray(next) ? next : [next];
37
+
38
+ return {
39
+ removed: prev.filter(x => !next.includes(x)),
40
+ added: next.filter(x => !prev.includes(x)),
41
+ };
42
+ }
43
+
44
+ /** Extracts loader's name independently of Webpack's version */
45
+ function getLoaderName(entry) {
46
+ return (
47
+ entry.loader ||
48
+ (entry.use && entry.use[0] && entry.use[0].loader) ||
49
+ '<unknown loader>'
50
+ );
51
+ }
52
+
53
+ /**
54
+ * Wraps the given value in an array if it is not already an array itself.
55
+ * Ignores `undefined` and `null`, returning them as is.
56
+ *
57
+ * @param {any} value Either an array or a value that should be wrapped in an array
58
+ * @returns {array} The resulting array, or the original value if it's null/undefined
59
+ */
60
+ function toArray(value) {
61
+ if (Array.isArray(value) || value === null || value === undefined) {
62
+ return value;
63
+ }
64
+
65
+ return [value];
66
+ }
67
+
68
+ /** Backwards compatible version of `compiler.plugin.afterEmit.tapAsync()`. */
69
+ function attachAfterEmitHook(compiler, callback) {
70
+ if (compiler.hooks && compiler.hooks.afterEmit) {
71
+ compiler.hooks.afterEmit.tapAsync('SentryCliPlugin', callback);
72
+ } else {
73
+ compiler.plugin('after-emit', callback);
74
+ }
75
+ }
76
+
77
+ class SentryCliPlugin {
78
+ constructor(options = {}) {
79
+ const defaults = {
80
+ finalize: true,
81
+ rewrite: true,
82
+ };
83
+
84
+ this.options = Object.assign({}, defaults, options);
85
+
86
+ // the webpack plugin has looser type requirements than `@sentry/cli` -
87
+ // ensure `include` and `ignore` options are in the right format
88
+ if (options.include) {
89
+ this.options.include = toArray(options.include);
90
+ this.options.include.forEach(includeEntry => {
91
+ if (
92
+ typeof includeEntry === 'object' &&
93
+ includeEntry.ignore !== undefined
94
+ ) {
95
+ // eslint-disable-next-line no-param-reassign
96
+ includeEntry.ignore = toArray(includeEntry.ignore);
97
+ }
98
+ });
99
+ }
100
+
101
+ if (options.ignore) this.options.ignore = toArray(options.ignore);
102
+
103
+ this.cli = this.getSentryCli();
104
+ this.release = this.getReleasePromise();
105
+ }
106
+
107
+ /**
108
+ * Pretty-prints debug information
109
+ *
110
+ * @param {string} label Label to be printed as a prefix for the data
111
+ * @param {any} data Input to be pretty-printed
112
+ */
113
+ outputDebug(label, data) {
114
+ if (this.isSilent()) {
115
+ return;
116
+ }
117
+ if (data !== undefined) {
118
+ // eslint-disable-next-line no-console
119
+ console.log(
120
+ `[Sentry Webpack Plugin] ${label} ${util.inspect(
121
+ data,
122
+ false,
123
+ null,
124
+ true
125
+ )}`
126
+ );
127
+ } else {
128
+ // eslint-disable-next-line no-console
129
+ console.log(`[Sentry Webpack Plugin] ${label}`);
130
+ }
131
+ }
132
+
133
+ /** Returns whether this plugin should emit any data to stdout. */
134
+ isSilent() {
135
+ return this.options.silent === true;
136
+ }
137
+
138
+ /** Returns whether this plugin is in dryRun mode. */
139
+ isDryRun() {
140
+ return this.options.dryRun === true;
141
+ }
142
+
143
+ /** Creates a new Sentry CLI instance. */
144
+ getSentryCli() {
145
+ const cli = new SentryCli(this.options.configFile, {
146
+ silent: this.isSilent(),
147
+ org: this.options.org,
148
+ project: this.options.project,
149
+ authToken: this.options.authToken,
150
+ url: this.options.url,
151
+ vcsRemote: this.options.vcsRemote,
152
+ });
153
+
154
+ if (this.isDryRun()) {
155
+ this.outputDebug('DRY Run Mode');
156
+
157
+ return {
158
+ releases: {
159
+ proposeVersion: () =>
160
+ cli.releases.proposeVersion().then(version => {
161
+ this.outputDebug('Proposed version:\n', version);
162
+ return version;
163
+ }),
164
+ new: release => {
165
+ this.outputDebug('Creating new release:\n', release);
166
+ return Promise.resolve(release);
167
+ },
168
+ uploadSourceMaps: (release, config) => {
169
+ this.outputDebug('Calling upload-sourcemaps with:\n', config);
170
+ return Promise.resolve(release, config);
171
+ },
172
+ finalize: release => {
173
+ this.outputDebug('Finalizing release:\n', release);
174
+ return Promise.resolve(release);
175
+ },
176
+ setCommits: (release, config) => {
177
+ this.outputDebug('Calling set-commits with:\n', config);
178
+ return Promise.resolve(release, config);
179
+ },
180
+ newDeploy: (release, config) => {
181
+ this.outputDebug('Calling deploy with:\n', config);
182
+ return Promise.resolve(release, config);
183
+ },
184
+ },
185
+ };
186
+ }
187
+
188
+ return cli;
189
+ }
190
+
191
+ /**
192
+ * Returns a Promise that will solve to the configured release.
193
+ *
194
+ * If no release is specified, it uses Sentry CLI to propose a version.
195
+ * The release string is always trimmed.
196
+ * Returns undefined if proposeVersion failed.
197
+ */
198
+ getReleasePromise() {
199
+ return (this.options.release
200
+ ? Promise.resolve(this.options.release)
201
+ : this.cli.releases.proposeVersion()
202
+ )
203
+ .then(version => `${version}`.trim())
204
+ .catch(() => undefined);
205
+ }
206
+
207
+ /** Checks if the given named entry point should be handled. */
208
+ shouldInjectEntry(key) {
209
+ const { entries } = this.options;
210
+ if (entries == null) {
211
+ return true;
212
+ }
213
+
214
+ if (typeof entries === 'function') {
215
+ return entries(key);
216
+ }
217
+
218
+ if (entries instanceof RegExp) {
219
+ return entries.test(key);
220
+ }
221
+
222
+ if (Array.isArray(entries)) {
223
+ return entries.includes(key);
224
+ }
225
+
226
+ throw new Error(
227
+ 'Invalid `entries` option: Must be an array, RegExp or function'
228
+ );
229
+ }
230
+
231
+ /** Injects the release string into the given entry point. */
232
+ injectEntry(entry, sentryModule) {
233
+ if (!entry) {
234
+ return sentryModule;
235
+ }
236
+
237
+ /**
238
+ * in:
239
+ * entry: 'index.js'
240
+ * out:
241
+ * entry: ['sentry-webpack.module.js', 'index.js']
242
+ */
243
+ if (typeof entry === 'string') {
244
+ return [sentryModule, entry];
245
+ }
246
+
247
+ /**
248
+ * in:
249
+ * entry: ['index.js', 'header.js', 'footer.js']
250
+ * out:
251
+ * entry: ['sentry-webpack.module.js', 'index.js', 'header.js', 'footer.js']
252
+ */
253
+ if (Array.isArray(entry)) {
254
+ return [sentryModule].concat(entry);
255
+ }
256
+
257
+ /**
258
+ * in:
259
+ * entry: () => 'index.js'
260
+ * entry: () => ['index.js']
261
+ * out:
262
+ * entry: ['sentry-webpack.module.js', 'index.js']
263
+ * entry: ['sentry-webpack.module.js', 'index.js']
264
+ */
265
+ if (typeof entry === 'function') {
266
+ return () =>
267
+ Promise.resolve(entry()).then(resolvedEntry =>
268
+ this.injectEntry(resolvedEntry, sentryModule)
269
+ );
270
+ }
271
+
272
+ /**
273
+ * in:
274
+ * entry: {
275
+ * home: './home.js',
276
+ * about: ['./about.js'],
277
+ * contact: () => './contact.js',
278
+ * login: {
279
+ * import: './login.js',
280
+ * },
281
+ * logout: {
282
+ * import: ['./logout.js']
283
+ * }
284
+ * }
285
+ * out:
286
+ * entry: {
287
+ * home: ['sentry-webpack.module.js', './home.js'],
288
+ * about: ['sentry-webpack.module.js', './about.js'],
289
+ * contact: ['sentry-webpack.module.js', './contact.js'],
290
+ * login: {
291
+ * import: ['sentry-webpack.module.js', './login.js']
292
+ * },
293
+ * logout: {
294
+ * import: ['sentry-webpack.module.js', './logout.js']
295
+ * }
296
+ * }
297
+ */
298
+ const modifiedEntry = { ...entry };
299
+ Object.keys(modifiedEntry)
300
+ .filter(key => this.shouldInjectEntry(key))
301
+ .forEach(key => {
302
+ if (entry[key] && entry[key].import) {
303
+ modifiedEntry[key].import = this.injectEntry(
304
+ entry[key].import,
305
+ sentryModule
306
+ );
307
+ } else {
308
+ modifiedEntry[key] = this.injectEntry(entry[key], sentryModule);
309
+ }
310
+ });
311
+ return modifiedEntry;
312
+ }
313
+
314
+ /** Webpack 2: Adds a new loader for the release module. */
315
+ injectLoader(loaders) {
316
+ const loader = {
317
+ test: /sentry-webpack\.module\.js$/,
318
+ loader: SENTRY_LOADER,
319
+ options: {
320
+ releasePromise: this.release,
321
+ },
322
+ };
323
+
324
+ return (loaders || []).concat([loader]);
325
+ }
326
+
327
+ /** Webpack 3+: Injects a new rule for the release module. */
328
+ injectRule(rules) {
329
+ const rule = {
330
+ test: /sentry-webpack\.module\.js$/,
331
+ use: [
332
+ {
333
+ loader: SENTRY_LOADER,
334
+ options: {
335
+ releasePromise: this.release,
336
+ },
337
+ },
338
+ ],
339
+ };
340
+
341
+ return (rules || []).concat([rule]);
342
+ }
343
+
344
+ /** Injects the release entry points and rules into the given options. */
345
+ injectRelease(compilerOptions) {
346
+ const options = compilerOptions;
347
+ options.entry = this.injectEntry(options.entry, SENTRY_MODULE);
348
+ if (options.module.loaders) {
349
+ // Handle old `options.module.loaders` syntax
350
+ options.module.loaders = this.injectLoader(options.module.loaders);
351
+ } else {
352
+ options.module.rules = this.injectRule(options.module.rules);
353
+ }
354
+ }
355
+
356
+ /** injectRelease with printable debug info */
357
+ injectReleaseWithDebug(compilerOptions) {
358
+ const input = {
359
+ loaders: sillyClone(
360
+ compilerOptions.module.loaders || compilerOptions.module.rules
361
+ ).map(getLoaderName),
362
+ entry: sillyClone(compilerOptions.entry),
363
+ };
364
+
365
+ this.injectRelease(compilerOptions);
366
+
367
+ const output = {
368
+ loaders: sillyClone(
369
+ compilerOptions.module.loaders || compilerOptions.module.rules
370
+ ).map(getLoaderName),
371
+ entry: sillyClone(compilerOptions.entry),
372
+ };
373
+
374
+ const loaders = diffArray(input.loaders, output.loaders);
375
+ const entry = diffArray(input.entry, output.entry);
376
+
377
+ this.outputDebug('DEBUG: Injecting release code');
378
+ this.outputDebug('DEBUG: Loaders:\n', output.loaders);
379
+ this.outputDebug('DEBUG: Added loaders:\n', loaders.added);
380
+ this.outputDebug('DEBUG: Removed loaders:\n', loaders.removed);
381
+ this.outputDebug('DEBUG: Entry:\n', output.entry);
382
+ this.outputDebug('DEBUG: Added entry:\n', entry.added);
383
+ this.outputDebug('DEBUG: Removed entry:\n', entry.removed);
384
+ }
385
+
386
+ /** Creates and finalizes a release on Sentry. */
387
+ finalizeRelease(compilation) {
388
+ const {
389
+ include,
390
+ errorHandler = (_, invokeErr) => {
391
+ invokeErr();
392
+ },
393
+ } = this.options;
394
+
395
+ let release;
396
+ return this.release
397
+ .then(proposedVersion => {
398
+ release = proposedVersion;
399
+
400
+ if (!include) {
401
+ throw new Error(`\`include\` option is required`);
402
+ }
403
+
404
+ if (!release) {
405
+ throw new Error(
406
+ `Unable to determine version. Make sure to include \`release\` option or use the environment that supports auto-detection https://docs.sentry.io/cli/releases/#creating-releases`
407
+ );
408
+ }
409
+
410
+ return this.cli.releases.new(release);
411
+ })
412
+ .then(() => {
413
+ if (this.options.cleanArtifacts) {
414
+ return this.cli.releases.execute(
415
+ ['releases', 'files', release, 'delete', '--all'],
416
+ true
417
+ );
418
+ }
419
+ return undefined;
420
+ })
421
+ .then(() => this.cli.releases.uploadSourceMaps(release, this.options))
422
+ .then(() => {
423
+ const {
424
+ commit,
425
+ previousCommit,
426
+ repo,
427
+ auto,
428
+ ignoreMissing,
429
+ ignoreEmpty,
430
+ } = this.options.setCommits || this.options;
431
+
432
+ if (auto || (repo && commit)) {
433
+ return this.cli.releases.setCommits(release, {
434
+ commit,
435
+ previousCommit,
436
+ repo,
437
+ auto,
438
+ ignoreMissing,
439
+ ignoreEmpty,
440
+ });
441
+ }
442
+ return undefined;
443
+ })
444
+ .then(() => {
445
+ if (this.options.finalize) {
446
+ return this.cli.releases.finalize(release);
447
+ }
448
+ return undefined;
449
+ })
450
+ .then(() => {
451
+ const { env, started, finished, time, name, url } =
452
+ this.options.deploy || {};
453
+
454
+ if (env) {
455
+ return this.cli.releases.newDeploy(release, {
456
+ env,
457
+ started,
458
+ finished,
459
+ time,
460
+ name,
461
+ url,
462
+ });
463
+ }
464
+ return undefined;
465
+ })
466
+ .catch(err => {
467
+ errorHandler(
468
+ err,
469
+ () =>
470
+ compilation.errors.push(
471
+ new Error(`Sentry CLI Plugin: ${err.message}`)
472
+ ),
473
+ compilation
474
+ );
475
+ });
476
+ }
477
+
478
+ /** Webpack lifecycle hook to update compiler options. */
479
+ apply(compiler) {
480
+ /**
481
+ * Determines whether plugin should be applied not more than once during whole webpack run.
482
+ * Useful when the process is performing multiple builds using the same config.
483
+ * It cannot be stored on the instance, as every run is creating a new one.
484
+ */
485
+ if (this.options.runOnce && module.alreadyRun) {
486
+ if (this.options.debug) {
487
+ this.outputDebug(
488
+ '`runOnce` option set and plugin already ran. Skipping release.'
489
+ );
490
+ }
491
+ return;
492
+ }
493
+ module.alreadyRun = true;
494
+
495
+ const compilerOptions = compiler.options || {};
496
+ ensure(compilerOptions, 'module', Object);
497
+
498
+ if (this.options.debug) {
499
+ this.injectReleaseWithDebug(compilerOptions);
500
+ } else {
501
+ this.injectRelease(compilerOptions);
502
+ }
503
+
504
+ attachAfterEmitHook(compiler, (compilation, cb) => {
505
+ if (!this.options.include || !this.options.include.length) {
506
+ ensure(compilerOptions, 'output', Object);
507
+ if (compilerOptions.output.path) {
508
+ this.options.include = [compilerOptions.output.path];
509
+ }
510
+ }
511
+ this.finalizeRelease(compilation).then(() => cb());
512
+ });
513
+ }
514
+ }
515
+
516
+ module.exports.default = SentryCliPlugin;
@@ -0,0 +1 @@
1
+ // This will be replaced
@@ -0,0 +1,8 @@
1
+ module.exports = function sentryLoader(content, map, meta) {
2
+ const { releasePromise } = this.query;
3
+ const callback = this.async();
4
+ releasePromise.then(version => {
5
+ const sentryRelease = `(typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}).SENTRY_RELEASE={id:"${version}"};`;
6
+ callback(null, sentryRelease, map, meta);
7
+ });
8
+ };