@sentry/cli 1.76.0 → 1.77.1

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/CHANGELOG.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  "You know what they say. Fool me once, strike one, but fool me twice... strike three." — Michael Scott
4
4
 
5
+ ## 1.77.1
6
+
7
+ - feat: Expose downloadBinary function to install binary (#1817)
8
+
5
9
  ## 1.76.0
6
10
 
7
11
  ### Various fixes & improvements
package/checksums.txt CHANGED
@@ -1,9 +1,9 @@
1
- sentry-cli-Darwin-arm64=3ad86772148a987740c0edec2525bb6bb0127eb579a99e64adcef9be317c2acb
2
- sentry-cli-Darwin-universal=1fb8038738889e8afc6b9b24dc388ced67b98bb3153566e347a04965f5f4074a
3
- sentry-cli-Darwin-x86_64=21c2046608eb1d8d17f2c9d597fb06558633ff75ee16602132565176c6e29496
4
- sentry-cli-Linux-aarch64=bca2a0d97a0deb7f5cb98d47e1b448ffdefe61a1956b41d8cda6730125eced37
5
- sentry-cli-Linux-armv7=ed818dc2705fcbdb6db24d04b4ecfd42a9cc7b1580f19bd8b5705cb53e5d69cd
6
- sentry-cli-Linux-i686=b085e3e867b25afee4cf780348ebfdbff724da5a785046083fba8c893b274093
7
- sentry-cli-Linux-x86_64=e19d1e542fe97e711f5d7bb646289f441c4dc08ff92c3937e5289e9fcbfc72e6
8
- sentry-cli-Windows-i686.exe=7ae0f0cec3098665f9adc1a63e9eba7d945f660de357ea338849895940a784b7
9
- sentry-cli-Windows-x86_64.exe=6ba5df4f2f2ea5b4b2d5107b3f4c474ea666d9b413b3569bc3353dbcc198677d
1
+ sentry-cli-Darwin-arm64=10951f615c9a23b1d598887a5114936c41ccdaec85d0ef749ce5ed1be4409203
2
+ sentry-cli-Darwin-universal=1f1abe664a476b4488e018f1db775cb663aed3beb26a7a1a074346759277a935
3
+ sentry-cli-Darwin-x86_64=1cf1d7595d851bed60639a7ad092b8451c0d13bdc1724767f38e2d78af988047
4
+ sentry-cli-Linux-aarch64=e60603e05bad2a3449e6a18f5bc7d38525762faf32c99ed95bd95d7c5e13225e
5
+ sentry-cli-Linux-armv7=5a30a376de811641edbad5bffe1227cd6186c43fedcc5c544269c4bc0f80acff
6
+ sentry-cli-Linux-i686=44b2ea8ceb3bda57b6925316fb738892e8d84578802dfee0d1c481e4f0730826
7
+ sentry-cli-Linux-x86_64=79ca22a21cb4932f12658f687f931899fa994248d3833957870a172350a4a4f0
8
+ sentry-cli-Windows-i686.exe=45f30e37d3ff3fa48ecb77f91517a73c24d9f3fda0f385b38f396fbc674918a5
9
+ sentry-cli-Windows-x86_64.exe=41c1abafc6aef4c02ec14540c60eb8139b9ba5ef22f9804b49b714c64c954b2f
package/js/index.d.ts CHANGED
@@ -222,6 +222,13 @@ declare module '@sentry/cli' {
222
222
 
223
223
  public static getVersion(): string
224
224
  public static getPath(): string
225
+
226
+ /**
227
+ * Downloads the CLI binary.
228
+ * @returns {Promise<void>}
229
+ */
230
+ static downloadBinary(logger: { log(...args: unknown[]): void }): Promise<void>;
231
+
225
232
  public execute(args: string[], live: boolean): Promise<string>
226
233
  }
227
234
  }
package/js/index.js CHANGED
@@ -3,6 +3,7 @@
3
3
  const pkgInfo = require('../package.json');
4
4
  const helper = require('./helper');
5
5
  const Releases = require('./releases');
6
+ const install = require('./install');
6
7
 
7
8
  /**
8
9
  * Interface to and wrapper around the `sentry-cli` executable.
@@ -54,6 +55,15 @@ class SentryCli {
54
55
  return helper.getPath();
55
56
  }
56
57
 
58
+ /**
59
+ * Downloads the CLI binary.
60
+ * @param {any} [configFile] Optional logger to log installation information. Defaults to printing to the terminal.
61
+ * @returns {Promise<void>}
62
+ */
63
+ static downloadBinary(logger) {
64
+ return install.downloadBinary(logger);
65
+ }
66
+
57
67
  /**
58
68
  * See {helper.execute} docs.
59
69
  * @param {string[]} args Command line arguments passed to `sentry-cli`.
package/js/install.js ADDED
@@ -0,0 +1,305 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const http = require('http');
5
+ const os = require('os');
6
+ const path = require('path');
7
+ const crypto = require('crypto');
8
+ const zlib = require('zlib');
9
+ const stream = require('stream');
10
+ const process = require('process');
11
+
12
+ const HttpsProxyAgent = require('https-proxy-agent');
13
+ const fetch = require('node-fetch');
14
+ const ProgressBar = require('progress');
15
+ const Proxy = require('proxy-from-env');
16
+ // NOTE: Can be dropped in favor of `fs.mkdirSync(path, { recursive: true })` once we stop supporting Node 8.x
17
+ const mkdirp = require('mkdirp');
18
+ const which = require('which');
19
+
20
+ const helper = require('./helper');
21
+ const pkgInfo = require('../package.json');
22
+ const Logger = require('./logger');
23
+
24
+ function getLogStream(defaultStream) {
25
+ const logStream = process.env.SENTRYCLI_LOG_STREAM || defaultStream;
26
+
27
+ if (logStream === 'stdout') {
28
+ return process.stdout;
29
+ }
30
+
31
+ if (logStream === 'stderr') {
32
+ return process.stderr;
33
+ }
34
+
35
+ throw new Error(
36
+ `Incorrect SENTRYCLI_LOG_STREAM env variable. Possible values: 'stdout' | 'stderr'`
37
+ );
38
+ }
39
+
40
+ const ttyLogger = new Logger(getLogStream('stderr'));
41
+
42
+ const CDN_URL =
43
+ process.env.SENTRYCLI_LOCAL_CDNURL ||
44
+ process.env.npm_config_sentrycli_cdnurl ||
45
+ process.env.SENTRYCLI_CDNURL ||
46
+ 'https://downloads.sentry-cdn.com/sentry-cli';
47
+
48
+ function shouldRenderProgressBar() {
49
+ const silentFlag = process.argv.some((v) => v === '--silent');
50
+ const silentConfig = process.env.npm_config_loglevel === 'silent';
51
+ // Leave `SENTRY_NO_PROGRESS_BAR` for backwards compatibility
52
+ const silentEnv = process.env.SENTRYCLI_NO_PROGRESS_BAR || process.env.SENTRY_NO_PROGRESS_BAR;
53
+ const ciEnv = process.env.CI === 'true';
54
+ // If any of possible options is set, skip rendering of progress bar
55
+ return !(silentFlag || silentConfig || silentEnv || ciEnv);
56
+ }
57
+
58
+ function getDownloadUrl(platform, arch) {
59
+ const releasesUrl = `${CDN_URL}/${pkgInfo.version}/sentry-cli`;
60
+ let archString = '';
61
+ switch (arch) {
62
+ case 'x64':
63
+ archString = 'x86_64';
64
+ break;
65
+ case 'x86':
66
+ case 'ia32':
67
+ archString = 'i686';
68
+ break;
69
+ case 'arm64':
70
+ archString = 'aarch64';
71
+ break;
72
+ case 'arm':
73
+ archString = 'armv7';
74
+ break;
75
+ default:
76
+ archString = arch;
77
+ }
78
+ switch (platform) {
79
+ case 'darwin':
80
+ return `${releasesUrl}-Darwin-universal`;
81
+ case 'win32':
82
+ return `${releasesUrl}-Windows-${archString}.exe`;
83
+ case 'linux':
84
+ case 'freebsd':
85
+ return `${releasesUrl}-Linux-${archString}`;
86
+ default:
87
+ return null;
88
+ }
89
+ }
90
+
91
+ function createProgressBar(name, total) {
92
+ const incorrectTotal = typeof total !== 'number' || Number.isNaN(total);
93
+
94
+ if (incorrectTotal || !shouldRenderProgressBar()) {
95
+ return {
96
+ tick: () => {},
97
+ };
98
+ }
99
+
100
+ const logStream = getLogStream('stdout');
101
+
102
+ if (logStream.isTTY) {
103
+ return new ProgressBar(`fetching ${name} :bar :percent :etas`, {
104
+ complete: '█',
105
+ incomplete: '░',
106
+ width: 20,
107
+ total,
108
+ });
109
+ }
110
+
111
+ let pct = null;
112
+ let current = 0;
113
+ return {
114
+ tick: (length) => {
115
+ current += length;
116
+ const next = Math.round((current / total) * 100);
117
+ if (next > pct) {
118
+ pct = next;
119
+ logStream.write(`fetching ${name} ${pct}%\n`);
120
+ }
121
+ },
122
+ };
123
+ }
124
+
125
+ function npmCache() {
126
+ const env = process.env;
127
+ return (
128
+ env.npm_config_cache ||
129
+ env.npm_config_cache_folder ||
130
+ env.npm_config_yarn_offline_mirror ||
131
+ (env.APPDATA ? path.join(env.APPDATA, 'npm-cache') : path.join(os.homedir(), '.npm'))
132
+ );
133
+ }
134
+
135
+ function getCachedPath(url) {
136
+ const digest = crypto.createHash('md5').update(url).digest('hex').slice(0, 6);
137
+
138
+ return path.join(
139
+ npmCache(),
140
+ 'sentry-cli',
141
+ `${digest}-${path.basename(url).replace(/[^a-zA-Z0-9.]+/g, '-')}`
142
+ );
143
+ }
144
+
145
+ function getTempFile(cached) {
146
+ return `${cached}.${process.pid}-${Math.random().toString(16).slice(2)}.tmp`;
147
+ }
148
+
149
+ function validateChecksum(tempPath, name, logger) {
150
+ let storedHash;
151
+ try {
152
+ const checksums = fs.readFileSync(path.join(__dirname, '../checksums.txt'), 'utf8');
153
+ const entries = checksums.split('\n');
154
+ for (let i = 0; i < entries.length; i++) {
155
+ const [key, value] = entries[i].split('=');
156
+ if (key === name) {
157
+ storedHash = value;
158
+ break;
159
+ }
160
+ }
161
+ } catch (e) {
162
+ logger.log(
163
+ 'Checksums are generated when the package is published to npm. They are not available directly in the source repository. Skipping validation.'
164
+ );
165
+ return;
166
+ }
167
+
168
+ if (!storedHash) {
169
+ logger.log(`Checksum for ${name} not found, skipping validation.`);
170
+ return;
171
+ }
172
+
173
+ const currentHash = crypto.createHash('sha256').update(fs.readFileSync(tempPath)).digest('hex');
174
+
175
+ if (storedHash !== currentHash) {
176
+ fs.unlinkSync(tempPath);
177
+ throw new Error(
178
+ `Checksum validation for ${name} failed.\nExpected: ${storedHash}\nReceived: ${currentHash}`
179
+ );
180
+ } else {
181
+ logger.log('Checksum validation passed.');
182
+ }
183
+ }
184
+
185
+ function checkVersion() {
186
+ return helper.execute(['--version']).then((output) => {
187
+ const version = output.replace('sentry-cli ', '').trim();
188
+ const expected = process.env.SENTRYCLI_LOCAL_CDNURL ? 'DEV' : pkgInfo.version;
189
+ if (version !== expected) {
190
+ throw new Error(`Unexpected sentry-cli version "${version}", expected "${expected}"`);
191
+ }
192
+ });
193
+ }
194
+
195
+ function downloadBinary(logger = ttyLogger) {
196
+ if (process.env.SENTRYCLI_SKIP_DOWNLOAD === '1') {
197
+ logger.log(`Skipping download because SENTRYCLI_SKIP_DOWNLOAD=1 detected.`);
198
+ return;
199
+ }
200
+
201
+ const arch = os.arch();
202
+ const platform = os.platform();
203
+ const outputPath = helper.getPath();
204
+
205
+ if (process.env.SENTRYCLI_USE_LOCAL === '1') {
206
+ try {
207
+ const binPath = which.sync('sentry-cli');
208
+ logger.log(`Using local binary: ${binPath}`);
209
+ fs.copyFileSync(binPath, outputPath);
210
+ return Promise.resolve();
211
+ } catch (e) {
212
+ throw new Error(
213
+ 'Configured installation of local binary, but it was not found.' +
214
+ 'Make sure that `sentry-cli` executable is available in your $PATH or disable SENTRYCLI_USE_LOCAL env variable.'
215
+ );
216
+ }
217
+ }
218
+
219
+ const downloadUrl = getDownloadUrl(platform, arch);
220
+ if (!downloadUrl) {
221
+ return Promise.reject(new Error(`Unsupported target ${platform}-${arch}`));
222
+ }
223
+
224
+ const cachedPath = getCachedPath(downloadUrl);
225
+ if (fs.existsSync(cachedPath)) {
226
+ logger.log(`Using cached binary: ${cachedPath}`);
227
+ fs.copyFileSync(cachedPath, outputPath);
228
+ return Promise.resolve();
229
+ }
230
+
231
+ const proxyUrl = Proxy.getProxyForUrl(downloadUrl);
232
+ const agent = proxyUrl ? new HttpsProxyAgent(proxyUrl) : null;
233
+
234
+ logger.log(`Downloading from ${downloadUrl}`);
235
+
236
+ if (proxyUrl) {
237
+ logger.log(`Using proxy URL: ${proxyUrl}`);
238
+ }
239
+
240
+ return fetch(downloadUrl, {
241
+ agent,
242
+ compress: false,
243
+ headers: {
244
+ 'accept-encoding': 'gzip, deflate, br',
245
+ },
246
+ redirect: 'follow',
247
+ })
248
+ .then((response) => {
249
+ if (!response.ok) {
250
+ throw new Error(
251
+ `Unable to download sentry-cli binary from ${downloadUrl}.\nServer returned ${response.status}: ${response.statusText}.`
252
+ );
253
+ }
254
+
255
+ const contentEncoding = response.headers.get('content-encoding');
256
+ let decompressor;
257
+ if (/\bgzip\b/.test(contentEncoding)) {
258
+ decompressor = zlib.createGunzip();
259
+ } else if (/\bdeflate\b/.test(contentEncoding)) {
260
+ decompressor = zlib.createInflate();
261
+ } else if (/\bbr\b/.test(contentEncoding)) {
262
+ decompressor = zlib.createBrotliDecompress();
263
+ } else {
264
+ decompressor = new stream.PassThrough();
265
+ }
266
+ const name = downloadUrl.match(/.*\/(.*?)$/)[1];
267
+ const total = parseInt(response.headers.get('content-length'), 10);
268
+ const progressBar = createProgressBar(name, total);
269
+ const tempPath = getTempFile(cachedPath);
270
+ mkdirp.sync(path.dirname(tempPath));
271
+
272
+ return new Promise((resolve, reject) => {
273
+ response.body
274
+ .on('error', (e) => reject(e))
275
+ .on('data', (chunk) => progressBar.tick(chunk.length))
276
+ .pipe(decompressor)
277
+ .pipe(fs.createWriteStream(tempPath, { mode: '0755' }))
278
+ .on('error', (e) => reject(e))
279
+ .on('close', () => resolve());
280
+ }).then(() => {
281
+ if (process.env.SENTRYCLI_SKIP_CHECKSUM_VALIDATION !== '1') {
282
+ validateChecksum(tempPath, name, logger);
283
+ }
284
+ fs.copyFileSync(tempPath, cachedPath);
285
+ fs.copyFileSync(tempPath, outputPath);
286
+ fs.unlinkSync(tempPath);
287
+ });
288
+ })
289
+ .then(() => {
290
+ return checkVersion();
291
+ })
292
+ .catch((error) => {
293
+ if (error instanceof fetch.FetchError) {
294
+ throw new Error(
295
+ `Unable to download sentry-cli binary from ${downloadUrl}.\nError code: ${error.code}`
296
+ );
297
+ } else {
298
+ throw error;
299
+ }
300
+ });
301
+ }
302
+
303
+ module.exports = {
304
+ downloadBinary,
305
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentry/cli",
3
- "version": "1.76.0",
3
+ "version": "1.77.1",
4
4
  "description": "A command line utility to work with Sentry. https://docs.sentry.io/hosted/learn/cli/",
5
5
  "homepage": "https://docs.sentry.io/hosted/learn/cli/",
6
6
  "license": "BSD-3-Clause",
@@ -2,306 +2,10 @@
2
2
 
3
3
  'use strict';
4
4
 
5
- const fs = require('fs');
6
5
  const http = require('http');
7
- const os = require('os');
6
+ const fs = require('fs');
8
7
  const path = require('path');
9
- const crypto = require('crypto');
10
- const zlib = require('zlib');
11
- const stream = require('stream');
12
- const process = require('process');
13
-
14
- const HttpsProxyAgent = require('https-proxy-agent');
15
- const fetch = require('node-fetch');
16
- const ProgressBar = require('progress');
17
- const Proxy = require('proxy-from-env');
18
- // NOTE: Can be dropped in favor of `fs.mkdirSync(path, { recursive: true })` once we stop supporting Node 8.x
19
- const mkdirp = require('mkdirp');
20
- const which = require('which');
21
-
22
- const helper = require('../js/helper');
23
- const pkgInfo = require('../package.json');
24
- const Logger = require('../js/logger');
25
-
26
- function getLogStream(defaultStream) {
27
- const logStream = process.env.SENTRYCLI_LOG_STREAM || defaultStream;
28
-
29
- if (logStream === 'stdout') {
30
- return process.stdout;
31
- }
32
-
33
- if (logStream === 'stderr') {
34
- return process.stderr;
35
- }
36
-
37
- throw new Error(
38
- `Incorrect SENTRYCLI_LOG_STREAM env variable. Possible values: 'stdout' | 'stderr'`
39
- );
40
- }
41
-
42
- const logger = new Logger(getLogStream('stderr'));
43
-
44
- const CDN_URL =
45
- process.env.SENTRYCLI_LOCAL_CDNURL ||
46
- process.env.npm_config_sentrycli_cdnurl ||
47
- process.env.SENTRYCLI_CDNURL ||
48
- 'https://downloads.sentry-cdn.com/sentry-cli';
49
-
50
- function shouldRenderProgressBar() {
51
- const silentFlag = process.argv.some(v => v === '--silent');
52
- const silentConfig = process.env.npm_config_loglevel === 'silent';
53
- // Leave `SENTRY_NO_PROGRESS_BAR` for backwards compatibility
54
- const silentEnv = process.env.SENTRYCLI_NO_PROGRESS_BAR || process.env.SENTRY_NO_PROGRESS_BAR;
55
- const ciEnv = process.env.CI === 'true';
56
- // If any of possible options is set, skip rendering of progress bar
57
- return !(silentFlag || silentConfig || silentEnv || ciEnv);
58
- }
59
-
60
- function getDownloadUrl(platform, arch) {
61
- const releasesUrl = `${CDN_URL}/${pkgInfo.version}/sentry-cli`;
62
- let archString = '';
63
- switch (arch) {
64
- case 'x64':
65
- archString = 'x86_64';
66
- break;
67
- case 'x86':
68
- case 'ia32':
69
- archString = 'i686';
70
- break;
71
- case 'arm64':
72
- archString = 'aarch64';
73
- break;
74
- case 'arm':
75
- archString = 'armv7';
76
- break;
77
- default:
78
- archString = arch;
79
- }
80
- switch (platform) {
81
- case 'darwin':
82
- return `${releasesUrl}-Darwin-universal`;
83
- case 'win32':
84
- return `${releasesUrl}-Windows-${archString}.exe`;
85
- case 'linux':
86
- case 'freebsd':
87
- return `${releasesUrl}-Linux-${archString}`;
88
- default:
89
- return null;
90
- }
91
- }
92
-
93
- function createProgressBar(name, total) {
94
- const incorrectTotal = typeof total !== 'number' || Number.isNaN(total);
95
-
96
- if (incorrectTotal || !shouldRenderProgressBar()) {
97
- return {
98
- tick: () => {},
99
- };
100
- }
101
-
102
- const logStream = getLogStream('stdout');
103
-
104
- if (logStream.isTTY) {
105
- return new ProgressBar(`fetching ${name} :bar :percent :etas`, {
106
- complete: '█',
107
- incomplete: '░',
108
- width: 20,
109
- total,
110
- });
111
- }
112
-
113
- let pct = null;
114
- let current = 0;
115
- return {
116
- tick: length => {
117
- current += length;
118
- const next = Math.round((current / total) * 100);
119
- if (next > pct) {
120
- pct = next;
121
- logStream.write(`fetching ${name} ${pct}%\n`);
122
- }
123
- },
124
- };
125
- }
126
-
127
- function npmCache() {
128
- const env = process.env;
129
- return (
130
- env.npm_config_cache ||
131
- env.npm_config_cache_folder ||
132
- env.npm_config_yarn_offline_mirror ||
133
- (env.APPDATA ? path.join(env.APPDATA, 'npm-cache') : path.join(os.homedir(), '.npm'))
134
- );
135
- }
136
-
137
- function getCachedPath(url) {
138
- const digest = crypto
139
- .createHash('md5')
140
- .update(url)
141
- .digest('hex')
142
- .slice(0, 6);
143
-
144
- return path.join(
145
- npmCache(),
146
- 'sentry-cli',
147
- `${digest}-${path.basename(url).replace(/[^a-zA-Z0-9.]+/g, '-')}`
148
- );
149
- }
150
-
151
- function getTempFile(cached) {
152
- return `${cached}.${process.pid}-${Math.random()
153
- .toString(16)
154
- .slice(2)}.tmp`;
155
- }
156
-
157
- function validateChecksum(tempPath, name) {
158
- let storedHash;
159
- try {
160
- const checksums = fs.readFileSync(path.join(__dirname, '../checksums.txt'), 'utf8');
161
- const entries = checksums.split('\n');
162
- for (let i = 0; i < entries.length; i++) {
163
- const [key, value] = entries[i].split('=');
164
- if (key === name) {
165
- storedHash = value;
166
- break;
167
- }
168
- }
169
- } catch (e) {
170
- logger.log(
171
- 'Checksums are generated when the package is published to npm. They are not available directly in the source repository. Skipping validation.'
172
- );
173
- return;
174
- }
175
-
176
- if (!storedHash) {
177
- logger.log(`Checksum for ${name} not found, skipping validation.`);
178
- return;
179
- }
180
-
181
- const currentHash = crypto
182
- .createHash('sha256')
183
- .update(fs.readFileSync(tempPath))
184
- .digest('hex');
185
-
186
- if (storedHash !== currentHash) {
187
- fs.unlinkSync(tempPath);
188
- throw new Error(
189
- `Checksum validation for ${name} failed.\nExpected: ${storedHash}\nReceived: ${currentHash}`
190
- );
191
- } else {
192
- logger.log('Checksum validation passed.');
193
- }
194
- }
195
-
196
- function downloadBinary() {
197
- const arch = os.arch();
198
- const platform = os.platform();
199
- const outputPath = helper.getPath();
200
-
201
- if (process.env.SENTRYCLI_USE_LOCAL === '1') {
202
- try {
203
- const binPath = which.sync('sentry-cli');
204
- logger.log(`Using local binary: ${binPath}`);
205
- fs.copyFileSync(binPath, outputPath);
206
- return Promise.resolve();
207
- } catch (e) {
208
- throw new Error(
209
- 'Configured installation of local binary, but it was not found.' +
210
- 'Make sure that `sentry-cli` executable is available in your $PATH or disable SENTRYCLI_USE_LOCAL env variable.'
211
- );
212
- }
213
- }
214
-
215
- const downloadUrl = getDownloadUrl(platform, arch);
216
- if (!downloadUrl) {
217
- return Promise.reject(new Error(`Unsupported target ${platform}-${arch}`));
218
- }
219
-
220
- const cachedPath = getCachedPath(downloadUrl);
221
- if (fs.existsSync(cachedPath)) {
222
- logger.log(`Using cached binary: ${cachedPath}`);
223
- fs.copyFileSync(cachedPath, outputPath);
224
- return Promise.resolve();
225
- }
226
-
227
- const proxyUrl = Proxy.getProxyForUrl(downloadUrl);
228
- const agent = proxyUrl ? new HttpsProxyAgent(proxyUrl) : null;
229
-
230
- logger.log(`Downloading from ${downloadUrl}`);
231
-
232
- if (proxyUrl) {
233
- logger.log(`Using proxy URL: ${proxyUrl}`);
234
- }
235
-
236
- return fetch(downloadUrl, {
237
- agent,
238
- compress: false,
239
- headers: {
240
- 'accept-encoding': 'gzip, deflate, br',
241
- },
242
- redirect: 'follow',
243
- })
244
- .then(response => {
245
- if (!response.ok) {
246
- throw new Error(
247
- `Unable to download sentry-cli binary from ${downloadUrl}.\nServer returned ${response.status}: ${response.statusText}.`
248
- );
249
- }
250
-
251
- const contentEncoding = response.headers.get('content-encoding');
252
- let decompressor;
253
- if (/\bgzip\b/.test(contentEncoding)) {
254
- decompressor = zlib.createGunzip();
255
- } else if (/\bdeflate\b/.test(contentEncoding)) {
256
- decompressor = zlib.createInflate();
257
- } else if (/\bbr\b/.test(contentEncoding)) {
258
- decompressor = zlib.createBrotliDecompress();
259
- } else {
260
- decompressor = new stream.PassThrough();
261
- }
262
- const name = downloadUrl.match(/.*\/(.*?)$/)[1];
263
- const total = parseInt(response.headers.get('content-length'), 10);
264
- const progressBar = createProgressBar(name, total);
265
- const tempPath = getTempFile(cachedPath);
266
- mkdirp.sync(path.dirname(tempPath));
267
-
268
- return new Promise((resolve, reject) => {
269
- response.body
270
- .on('error', e => reject(e))
271
- .on('data', chunk => progressBar.tick(chunk.length))
272
- .pipe(decompressor)
273
- .pipe(fs.createWriteStream(tempPath, { mode: '0755' }))
274
- .on('error', e => reject(e))
275
- .on('close', () => resolve());
276
- }).then(() => {
277
- if (process.env.SENTRYCLI_SKIP_CHECKSUM_VALIDATION !== '1') {
278
- validateChecksum(tempPath, name);
279
- }
280
- fs.copyFileSync(tempPath, cachedPath);
281
- fs.copyFileSync(tempPath, outputPath);
282
- fs.unlinkSync(tempPath);
283
- });
284
- })
285
- .catch(error => {
286
- if (error instanceof fetch.FetchError) {
287
- throw new Error(
288
- `Unable to download sentry-cli binary from ${downloadUrl}.\nError code: ${error.code}`
289
- );
290
- } else {
291
- throw error;
292
- }
293
- });
294
- }
295
-
296
- function checkVersion() {
297
- return helper.execute(['--version']).then(output => {
298
- const version = output.replace('sentry-cli ', '').trim();
299
- const expected = process.env.SENTRYCLI_LOCAL_CDNURL ? 'DEV' : pkgInfo.version;
300
- if (version !== expected) {
301
- throw new Error(`Unexpected sentry-cli version "${version}", expected "${expected}"`);
302
- }
303
- });
304
- }
8
+ const { downloadBinary } = require('../js/install');
305
9
 
306
10
  if (process.env.SENTRYCLI_LOCAL_CDNURL) {
307
11
  // For testing, mock the CDN by spawning a local server
@@ -318,13 +22,7 @@ if (process.env.SENTRYCLI_LOCAL_CDNURL) {
318
22
  process.on('exit', () => server.close());
319
23
  }
320
24
 
321
- if (process.env.SENTRYCLI_SKIP_DOWNLOAD === '1') {
322
- logger.log(`Skipping download because SENTRYCLI_SKIP_DOWNLOAD=1 detected.`);
323
- process.exit(0);
324
- }
325
-
326
25
  downloadBinary()
327
- .then(() => checkVersion())
328
26
  .then(() => process.exit(0))
329
27
  .catch(e => {
330
28
  // eslint-disable-next-line no-console