@sentry/cli 1.77.1 → 1.77.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.
@@ -11,6 +11,10 @@ module.exports = {
11
11
  param: '--dist',
12
12
  type: 'string',
13
13
  },
14
+ decompress: {
15
+ param: '--decompress',
16
+ type: 'boolean',
17
+ },
14
18
  rewrite: {
15
19
  param: '--rewrite',
16
20
  invertedParam: '--no-rewrite',
@@ -20,6 +24,10 @@ module.exports = {
20
24
  invertedParam: '--no-sourcemap-reference',
21
25
  type: 'boolean',
22
26
  },
27
+ dedupe: {
28
+ invertedParam: '--no-dedupe',
29
+ type: 'boolean',
30
+ },
23
31
  stripPrefix: {
24
32
  param: '--strip-prefix',
25
33
  type: 'array',
@@ -44,4 +52,8 @@ module.exports = {
44
52
  param: '--ext',
45
53
  type: 'array',
46
54
  },
55
+ useArtifactBundle: {
56
+ param: '--use-artifact-bundle',
57
+ type: 'boolean',
58
+ },
47
59
  };
package/package.json CHANGED
@@ -1,43 +1,21 @@
1
1
  {
2
2
  "name": "@sentry/cli",
3
- "version": "1.77.1",
3
+ "version": "1.77.2",
4
4
  "description": "A command line utility to work with Sentry. https://docs.sentry.io/hosted/learn/cli/",
5
+ "repository": "git://github.com/getsentry/sentry-cli.git",
5
6
  "homepage": "https://docs.sentry.io/hosted/learn/cli/",
7
+ "author": "Sentry",
6
8
  "license": "BSD-3-Clause",
7
- "keywords": [
8
- "sentry",
9
- "sentry-cli",
10
- "cli"
11
- ],
12
- "repository": {
13
- "type": "git",
14
- "url": "https://github.com/getsentry/sentry-cli"
15
- },
16
- "bugs": {
17
- "url": "https://github.com/getsentry/sentry-cli/issues"
18
- },
19
9
  "engines": {
20
- "node": ">= 8"
10
+ "node": ">= 10"
21
11
  },
22
12
  "main": "js/index.js",
13
+ "types": "js/index.d.ts",
23
14
  "bin": {
24
15
  "sentry-cli": "bin/sentry-cli"
25
16
  },
26
- "scripts": {
27
- "install": "node ./scripts/install.js",
28
- "fix": "npm-run-all fix:eslint fix:prettier",
29
- "fix:eslint": "eslint --fix bin/* scripts/**/*.js js/**/*.js",
30
- "fix:prettier": "prettier --write bin/* scripts/**/*.js js/**/*.js",
31
- "test": "npm-run-all test:jest test:eslint test:prettier test:vercel-nft",
32
- "test:jest": "jest",
33
- "test:watch": "jest --watch --notify",
34
- "test:eslint": "eslint bin/* scripts/**/*.js js/**/*.js",
35
- "test:prettier": "prettier --check bin/* scripts/**/*.js js/**/*.js",
36
- "test:vercel-nft": "node scripts/test-vercel-nft.js"
37
- },
38
17
  "dependencies": {
39
18
  "https-proxy-agent": "^5.0.0",
40
- "mkdirp": "^0.5.5",
41
19
  "node-fetch": "^2.6.7",
42
20
  "progress": "^2.0.3",
43
21
  "proxy-from-env": "^1.1.0",
@@ -45,26 +23,42 @@
45
23
  },
46
24
  "devDependencies": {
47
25
  "@vercel/nft": "^0.22.1",
48
- "eslint": "^6.8.0",
49
- "eslint-config-airbnb-base": "^14.1.0",
50
- "eslint-config-prettier": "^6.10.1",
51
- "eslint-plugin-import": "^2.20.2",
52
- "jest": "^25.3.0",
26
+ "eslint": "^7.32.0",
27
+ "eslint-config-prettier": "^8.5.0",
28
+ "jest": "^27.5.1",
53
29
  "npm-run-all": "^4.1.5",
54
- "prettier": "^1.19.1"
30
+ "prettier": "2.8.8"
31
+ },
32
+ "optionalDependencies": {
33
+ "@sentry/cli-darwin": "1.77.2",
34
+ "@sentry/cli-linux-arm": "1.77.2",
35
+ "@sentry/cli-linux-arm64": "1.77.2",
36
+ "@sentry/cli-linux-i686": "1.77.2",
37
+ "@sentry/cli-linux-x64": "1.77.2",
38
+ "@sentry/cli-win32-i686": "1.77.2",
39
+ "@sentry/cli-win32-x64": "1.77.2"
40
+ },
41
+ "scripts": {
42
+ "postinstall": "node ./scripts/install.js",
43
+ "fix": "npm-run-all fix:eslint fix:prettier",
44
+ "fix:eslint": "eslint --fix bin/* scripts/**/*.js js/**/*.js",
45
+ "fix:prettier": "prettier --write bin/* scripts/**/*.js js/**/*.js",
46
+ "test": "npm-run-all test:jest test:eslint test:prettier test:vercel-nft",
47
+ "test:jest": "jest",
48
+ "test:watch": "jest --watch --notify",
49
+ "test:eslint": "eslint bin/* scripts/**/*.js js/**/*.js",
50
+ "test:prettier": "prettier --check bin/* scripts/**/*.js js/**/*.js",
51
+ "test:vercel-nft": "node scripts/test-vercel-nft.js"
55
52
  },
56
53
  "jest": {
57
- "collectCoverage": false,
54
+ "collectCoverage": true,
58
55
  "testEnvironment": "node",
59
56
  "testPathIgnorePatterns": [
60
- "src/utils"
57
+ "<rootDir>/src"
61
58
  ]
62
59
  },
63
60
  "volta": {
64
- "node": "10.24.1",
61
+ "node": "20.10.0",
65
62
  "yarn": "1.22.19"
66
- },
67
- "publishConfig": {
68
- "tag": "v1"
69
63
  }
70
64
  }
@@ -1,7 +1,7 @@
1
1
  #!/bin/bash
2
2
  set -eux
3
3
 
4
- DOCKER_IMAGE="getsentry/rust-musl-cross:${DOCKER_TAG}"
4
+ DOCKER_IMAGE="messense/rust-musl-cross:${DOCKER_TAG}"
5
5
  BUILD_DIR="/work"
6
6
 
7
7
  DOCKER_RUN_OPTS="
@@ -9,7 +9,6 @@ DOCKER_RUN_OPTS="
9
9
  -v $(pwd):${BUILD_DIR}:ro
10
10
  -v $(pwd)/target:${BUILD_DIR}/target
11
11
  -v $HOME/.cargo/registry:/root/.cargo/registry
12
- -e ARMV7_UNKNOWN_LINUX_MUSLEABI_OPENSSL_NO_VENDOR=1
13
12
  ${DOCKER_IMAGE}
14
13
  "
15
14
 
@@ -21,4 +21,17 @@ cargo update -p sentry-cli
21
21
 
22
22
  # Do not tag and commit changes made by "npm version"
23
23
  export npm_config_git_tag_version=false
24
+
25
+ # Bump main sentry cli npm package
24
26
  npm version "${TARGET}"
27
+
28
+ # Bump the binary npm distributions
29
+ for dir in $SCRIPT_DIR/../npm-binary-distributions/*; do
30
+ cd $dir
31
+ npm version "${TARGET}"
32
+ cd -
33
+ done
34
+
35
+ # Update the optional deps in the main cli npm package
36
+ # Requires jq to be installed - should be installed ootb on github runners
37
+ jq '.optionalDependencies |= map_values("'"${TARGET}"'")' $SCRIPT_DIR/../package.json > package.json.tmp && mv package.json.tmp $SCRIPT_DIR/../package.json
@@ -2,30 +2,348 @@
2
2
 
3
3
  'use strict';
4
4
 
5
- const http = require('http');
6
5
  const fs = require('fs');
6
+ const os = require('os');
7
7
  const path = require('path');
8
- const { downloadBinary } = require('../js/install');
9
-
10
- if (process.env.SENTRYCLI_LOCAL_CDNURL) {
11
- // For testing, mock the CDN by spawning a local server
12
- const server = http.createServer((request, response) => {
13
- const contents = fs.readFileSync(path.join(__dirname, '../js/__mocks__/sentry-cli'));
14
- response.writeHead(200, {
15
- 'Content-Type': 'application/octet-stream',
16
- 'Content-Length': String(contents.byteLength),
8
+ const crypto = require('crypto');
9
+ const zlib = require('zlib');
10
+ const stream = require('stream');
11
+ const process = require('process');
12
+
13
+ const fetch = require('node-fetch');
14
+ const HttpsProxyAgent = require('https-proxy-agent');
15
+ const ProgressBar = require('progress');
16
+ const Proxy = require('proxy-from-env');
17
+ const which = require('which');
18
+
19
+ const helper = require('../js/helper');
20
+ const pkgInfo = require('../package.json');
21
+ const Logger = require('../js/logger');
22
+
23
+ const logger = new Logger(getLogStream('stderr'));
24
+
25
+ const CDN_URL =
26
+ process.env.SENTRYCLI_LOCAL_CDNURL ||
27
+ process.env.npm_config_sentrycli_cdnurl ||
28
+ process.env.SENTRYCLI_CDNURL ||
29
+ 'https://downloads.sentry-cdn.com/sentry-cli';
30
+
31
+ function getLogStream(defaultStream) {
32
+ const logStream = process.env.SENTRYCLI_LOG_STREAM || defaultStream;
33
+
34
+ if (logStream === 'stdout') {
35
+ return process.stdout;
36
+ }
37
+
38
+ if (logStream === 'stderr') {
39
+ return process.stderr;
40
+ }
41
+
42
+ throw new Error(
43
+ `Incorrect SENTRYCLI_LOG_STREAM env variable. Possible values: 'stdout' | 'stderr'`
44
+ );
45
+ }
46
+
47
+ function shouldRenderProgressBar() {
48
+ const silentFlag = process.argv.some((v) => v === '--silent');
49
+ const silentConfig = process.env.npm_config_loglevel === 'silent';
50
+ const silentEnv = process.env.SENTRYCLI_NO_PROGRESS_BAR;
51
+ const ciEnv = process.env.CI === 'true' || process.env.CI === '1';
52
+ const notTTY = !process.stdout.isTTY;
53
+ // If any of possible options is set, skip rendering of progress bar
54
+ return !(silentFlag || silentConfig || silentEnv || ciEnv || notTTY);
55
+ }
56
+
57
+ function getDownloadUrl(platform, arch) {
58
+ const releasesUrl = `${CDN_URL}/${pkgInfo.version}/sentry-cli`;
59
+ let archString = '';
60
+ switch (arch) {
61
+ case 'x64':
62
+ archString = 'x86_64';
63
+ break;
64
+ case 'x86':
65
+ case 'ia32':
66
+ archString = 'i686';
67
+ break;
68
+ case 'arm64':
69
+ archString = 'aarch64';
70
+ break;
71
+ case 'arm':
72
+ archString = 'armv7';
73
+ break;
74
+ default:
75
+ archString = arch;
76
+ }
77
+ switch (platform) {
78
+ case 'darwin':
79
+ return `${releasesUrl}-Darwin-universal`;
80
+ case 'win32':
81
+ // Windows arm machines can run x64 binaries
82
+ if (arch === 'arm64') {
83
+ archString = 'x86_64';
84
+ }
85
+ return `${releasesUrl}-Windows-${archString}.exe`;
86
+ case 'linux':
87
+ case 'freebsd':
88
+ return `${releasesUrl}-Linux-${archString}`;
89
+ default:
90
+ return null;
91
+ }
92
+ }
93
+
94
+ function createProgressBar(name, total) {
95
+ const incorrectTotal = typeof total !== 'number' || Number.isNaN(total);
96
+
97
+ if (incorrectTotal || !shouldRenderProgressBar()) {
98
+ return {
99
+ tick: () => {},
100
+ };
101
+ }
102
+
103
+ const logStream = getLogStream('stdout');
104
+
105
+ if (logStream.isTTY) {
106
+ return new ProgressBar(`fetching ${name} :bar :percent :etas`, {
107
+ complete: '█',
108
+ incomplete: '░',
109
+ width: 20,
110
+ total,
17
111
  });
18
- response.end(contents);
19
- });
112
+ }
113
+
114
+ let pct = null;
115
+ let current = 0;
116
+ return {
117
+ tick: (length) => {
118
+ current += length;
119
+ const next = Math.round((current / total) * 100);
120
+ if (next > pct) {
121
+ pct = next;
122
+ logStream.write(`fetching ${name} ${pct}%\n`);
123
+ }
124
+ },
125
+ };
126
+ }
127
+
128
+ function npmCache() {
129
+ const keys = ['npm_config_cache', 'npm_config_cache_folder', 'npm_config_yarn_offline_mirror'];
130
+
131
+ for (let key of [...keys, ...keys.map((k) => k.toUpperCase())]) {
132
+ if (process.env[key]) return process.env[key];
133
+ }
134
+
135
+ if (process.env.APPDATA) {
136
+ return path.join(process.env.APPDATA, 'npm-cache');
137
+ }
20
138
 
21
- server.listen(8999);
22
- process.on('exit', () => server.close());
139
+ return path.join(os.homedir(), '.npm');
23
140
  }
24
141
 
25
- downloadBinary()
26
- .then(() => process.exit(0))
27
- .catch(e => {
28
- // eslint-disable-next-line no-console
29
- console.error(e.toString());
30
- process.exit(1);
142
+ function getCachedPath(url) {
143
+ const digest = crypto.createHash('md5').update(url).digest('hex').slice(0, 6);
144
+
145
+ return path.join(
146
+ npmCache(),
147
+ 'sentry-cli',
148
+ `${digest}-${path.basename(url).replace(/[^a-zA-Z0-9.]+/g, '-')}`
149
+ );
150
+ }
151
+
152
+ function getTempFile(cached) {
153
+ return `${cached}.${process.pid}-${Math.random().toString(16).slice(2)}.tmp`;
154
+ }
155
+
156
+ function validateChecksum(tempPath, name) {
157
+ let storedHash;
158
+ try {
159
+ const checksums = fs.readFileSync(path.join(__dirname, '../checksums.txt'), 'utf8');
160
+ const entries = checksums.split('\n');
161
+ for (let i = 0; i < entries.length; i++) {
162
+ const [key, value] = entries[i].split('=');
163
+ if (key === name) {
164
+ storedHash = value;
165
+ break;
166
+ }
167
+ }
168
+ } catch (e) {
169
+ logger.log(
170
+ 'Checksums are generated when the package is published to npm. They are not available directly in the source repository. Skipping validation.'
171
+ );
172
+ return;
173
+ }
174
+
175
+ if (!storedHash) {
176
+ logger.log(`Checksum for ${name} not found, skipping validation.`);
177
+ return;
178
+ }
179
+
180
+ const currentHash = crypto.createHash('sha256').update(fs.readFileSync(tempPath)).digest('hex');
181
+
182
+ if (storedHash !== currentHash) {
183
+ fs.unlinkSync(tempPath);
184
+ throw new Error(
185
+ `Checksum validation for ${name} failed.\nExpected: ${storedHash}\nReceived: ${currentHash}`
186
+ );
187
+ } else {
188
+ logger.log('Checksum validation passed.');
189
+ }
190
+ }
191
+
192
+ async function downloadBinary() {
193
+ const arch = os.arch();
194
+ const platform = os.platform();
195
+ const outputPath = helper.getFallbackBinaryPath();
196
+
197
+ if (process.env.SENTRYCLI_USE_LOCAL === '1') {
198
+ try {
199
+ const binPaths = which.sync('sentry-cli', { all: true });
200
+ if (!binPaths.length) throw new Error('Binary not found');
201
+ const binPath = binPaths[binPaths.length - 1];
202
+ logger.log(`Using local binary: ${binPath}`);
203
+ fs.copyFileSync(binPath, outputPath);
204
+ return Promise.resolve();
205
+ } catch (e) {
206
+ throw new Error(
207
+ 'Configured installation of local binary, but it was not found.' +
208
+ 'Make sure that `sentry-cli` executable is available in your $PATH or disable SENTRYCLI_USE_LOCAL env variable.'
209
+ );
210
+ }
211
+ }
212
+
213
+ const downloadUrl = getDownloadUrl(platform, arch);
214
+ if (!downloadUrl) {
215
+ throw new Error(`Unsupported target ${platform}-${arch}`);
216
+ }
217
+
218
+ const cachedPath = getCachedPath(downloadUrl);
219
+ if (fs.existsSync(cachedPath)) {
220
+ logger.log(`Using cached binary: ${cachedPath}`);
221
+ fs.copyFileSync(cachedPath, outputPath);
222
+ return;
223
+ }
224
+
225
+ const proxyUrl = Proxy.getProxyForUrl(downloadUrl);
226
+ const agent = proxyUrl ? new HttpsProxyAgent(proxyUrl) : null;
227
+
228
+ logger.log(`Downloading from ${downloadUrl}`);
229
+
230
+ if (proxyUrl) {
231
+ logger.log(`Using proxy URL: ${proxyUrl}`);
232
+ }
233
+
234
+ let response;
235
+ try {
236
+ response = await fetch(downloadUrl, {
237
+ agent,
238
+ compress: false,
239
+ headers: {
240
+ 'accept-encoding': 'gzip, deflate, br',
241
+ },
242
+ redirect: 'follow',
243
+ });
244
+ } catch (error) {
245
+ let errorMsg = `Unable to download sentry-cli binary from ${downloadUrl}.\nError message: ${error.message}`;
246
+ if (error.code) {
247
+ errorMsg += `\nError code: ${error.code}`;
248
+ }
249
+ throw new Error(errorMsg);
250
+ }
251
+
252
+ if (!response.ok) {
253
+ let errorMsg = `Unable to download sentry-cli binary from ${downloadUrl}.\nServer returned: ${response.status}`;
254
+ if (response.statusText) {
255
+ errorMsg += ` - ${response.statusText}`;
256
+ }
257
+ throw new Error(errorMsg);
258
+ }
259
+
260
+ const contentEncoding = response.headers.get('content-encoding');
261
+ let decompressor;
262
+ if (/\bgzip\b/.test(contentEncoding)) {
263
+ decompressor = zlib.createGunzip();
264
+ } else if (/\bdeflate\b/.test(contentEncoding)) {
265
+ decompressor = zlib.createInflate();
266
+ } else if (/\bbr\b/.test(contentEncoding)) {
267
+ decompressor = zlib.createBrotliDecompress();
268
+ } else {
269
+ decompressor = new stream.PassThrough();
270
+ }
271
+ const name = downloadUrl.match(/.*\/(.*?)$/)[1];
272
+ let downloadedBytes = 0;
273
+ const totalBytes = parseInt(response.headers.get('content-length'), 10);
274
+ const progressBar = createProgressBar(name, totalBytes);
275
+ const tempPath = getTempFile(cachedPath);
276
+ fs.mkdirSync(path.dirname(tempPath), { recursive: true });
277
+
278
+ await new Promise((resolve, reject) => {
279
+ response.body
280
+ .on('error', (e) => reject(e))
281
+ .on('data', (chunk) => {
282
+ downloadedBytes += chunk.length;
283
+ progressBar.tick(chunk.length);
284
+ })
285
+ .pipe(decompressor)
286
+ .pipe(fs.createWriteStream(tempPath, { mode: '0755' }))
287
+ .on('error', (e) => reject(e))
288
+ .on('close', () => {
289
+ if (downloadedBytes >= totalBytes) {
290
+ resolve();
291
+ } else {
292
+ reject(new Error('connection interrupted'));
293
+ }
294
+ });
31
295
  });
296
+
297
+ if (process.env.SENTRYCLI_SKIP_CHECKSUM_VALIDATION !== '1') {
298
+ validateChecksum(tempPath, name);
299
+ }
300
+
301
+ fs.copyFileSync(tempPath, cachedPath);
302
+ fs.copyFileSync(tempPath, outputPath);
303
+ fs.unlinkSync(tempPath);
304
+ }
305
+
306
+ async function checkVersion() {
307
+ const output = await helper.execute(['--version']);
308
+ const version = output.replace('sentry-cli ', '').trim();
309
+ const expected = pkgInfo.version;
310
+ if (version !== expected) {
311
+ throw new Error(`Unexpected sentry-cli version "${version}", expected "${expected}"`);
312
+ }
313
+ }
314
+
315
+ if (process.env.SENTRYCLI_SKIP_DOWNLOAD === '1') {
316
+ logger.log(`Skipping download because SENTRYCLI_SKIP_DOWNLOAD=1 detected.`);
317
+ process.exit(0);
318
+ }
319
+
320
+ const { packageName: distributionPackageName, subpath: distributionSubpath } =
321
+ helper.getDistributionForThisPlatform();
322
+
323
+ if (distributionPackageName === undefined) {
324
+ helper.throwUnsupportedPlatformError();
325
+ }
326
+
327
+ try {
328
+ require.resolve(`${distributionPackageName}/${distributionSubpath}`);
329
+ // If the `resolve` call succeeds it means a binary was installed successfully via optional dependencies so we can skip the manual postinstall download.
330
+ process.exit(0);
331
+ } catch (e) {
332
+ // Optional dependencies likely didn't get installed - proceed with fallback downloading manually
333
+ // Log message inspired by esbuild: https://github.com/evanw/esbuild/blob/914f6080c77cfe32a54888caa51ca6ea13873ce9/lib/npm/node-install.ts#L253
334
+ logger.log(
335
+ `Sentry CLI failed to locate the "${distributionPackageName}" package after installation!
336
+
337
+ This can happen if you use an option to disable optional dependencies during installation, like "--no-optional", "--ignore-optional", or "--omit=optional". Sentry CLI uses the "optionalDependencies" package.json feature to install the correct binary for your platform and operating system. This post-install script will now try to work around this by manually downloading the Sentry CLI binary from the Sentry CDN. If this fails, you need to remove the "--no-optional", "--ignore-optional", and "--omit=optional" flags for Sentry CLI to work.`
338
+ );
339
+
340
+ downloadBinary()
341
+ .then(() => checkVersion())
342
+ .then(() => {
343
+ process.exit(0);
344
+ })
345
+ .catch((e) => {
346
+ console.error(e);
347
+ process.exit(1);
348
+ });
349
+ }
@@ -1,27 +1,16 @@
1
- const major = process.versions.node.split('.')[0];
2
-
3
- // @vercel/nft doe not support Node.js v8
4
- if (major < 10) {
5
- process.exit(0);
6
- }
7
-
8
- // eslint-disable-next-line import/no-extraneous-dependencies
9
1
  const { nodeFileTrace } = require('@vercel/nft');
10
2
 
11
3
  const entryPoint = require.resolve('..');
12
4
 
13
5
  // Trace the module entrypoint
14
- nodeFileTrace([entryPoint]).then(result => {
15
- // eslint-disable-next-line no-console
6
+ nodeFileTrace([entryPoint]).then((result) => {
16
7
  console.log('@vercel/nft traced dependencies:', Array.from(result.fileList));
17
8
 
18
9
  // If either binary is picked up, fail the test
19
10
  if (result.fileList.has('sentry-cli') || result.fileList.has('sentry-cli.exe')) {
20
- // eslint-disable-next-line no-console
21
11
  console.error('ERROR: The sentry-cli binary should not be found by @vercel/nft');
22
12
  process.exit(-1);
23
13
  } else {
24
- // eslint-disable-next-line no-console
25
14
  console.log('The sentry-cli binary was not traced by @vercel/nft');
26
15
  }
27
16
  });