@percy/client 1.30.0 → 1.30.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/dist/client.js CHANGED
@@ -105,21 +105,33 @@ export class PercyClient {
105
105
  }
106
106
 
107
107
  // Performs a GET request for an API endpoint with appropriate headers.
108
- get(path) {
109
- return request(`${this.apiUrl}/${path}`, {
110
- headers: this.headers(),
111
- method: 'GET'
108
+ // we create a copy of meta as we update it in request and we wont want those updates
109
+ // to go back to caller - should be only limited to current function
110
+ get(path, {
111
+ ...meta
112
+ } = {}) {
113
+ return logger.measure('client:get', meta.identifier, meta, () => {
114
+ return request(`${this.apiUrl}/${path}`, {
115
+ headers: this.headers(),
116
+ method: 'GET',
117
+ meta
118
+ });
112
119
  });
113
120
  }
114
121
 
115
122
  // Performs a POST request to a JSON API endpoint with appropriate headers.
116
- post(path, body = {}) {
117
- return request(`${this.apiUrl}/${path}`, {
118
- headers: this.headers({
119
- 'Content-Type': 'application/vnd.api+json'
120
- }),
121
- method: 'POST',
122
- body
123
+ post(path, body = {}, {
124
+ ...meta
125
+ } = {}) {
126
+ return logger.measure('client:post', meta.identifier || 'Unknown', meta, () => {
127
+ return request(`${this.apiUrl}/${path}`, {
128
+ headers: this.headers({
129
+ 'Content-Type': 'application/vnd.api+json'
130
+ }),
131
+ method: 'POST',
132
+ body,
133
+ meta
134
+ });
123
135
  });
124
136
  }
125
137
 
@@ -185,7 +197,9 @@ export class PercyClient {
185
197
  validateId('build', buildId);
186
198
  let qs = all ? 'all-shards=true' : '';
187
199
  this.log.debug(`Finalizing build ${buildId}...`);
188
- return this.post(`builds/${buildId}/finalize?${qs}`);
200
+ return this.post(`builds/${buildId}/finalize?${qs}`, {}, {
201
+ identifier: 'build.finalze'
202
+ });
189
203
  }
190
204
 
191
205
  // Retrieves build data by id. Requires a read access token.
@@ -327,7 +341,7 @@ export class PercyClient {
327
341
  sha,
328
342
  filepath,
329
343
  content
330
- } = {}) {
344
+ } = {}, meta = {}) {
331
345
  validateId('build', buildId);
332
346
  if (filepath) {
333
347
  content = await fs.promises.readFile(filepath);
@@ -336,8 +350,8 @@ export class PercyClient {
336
350
  }
337
351
  }
338
352
  let encodedContent = base64encode(content);
339
- this.log.debug(`Uploading ${formatBytes(encodedContent.length)} resource: ${url}...`);
340
- this.mayBeLogUploadSize(encodedContent.length);
353
+ this.log.debug(`Uploading ${formatBytes(encodedContent.length)} resource: ${url}`, meta);
354
+ this.mayBeLogUploadSize(encodedContent.length, meta);
341
355
  return this.post(`builds/${buildId}/resources`, {
342
356
  data: {
343
357
  type: 'resources',
@@ -346,16 +360,25 @@ export class PercyClient {
346
360
  'base64-content': encodedContent
347
361
  }
348
362
  }
363
+ }, {
364
+ identifier: 'resource.post',
365
+ ...meta
349
366
  });
350
367
  }
351
368
 
352
369
  // Uploads resources to the active build concurrently, two at a time.
353
- async uploadResources(buildId, resources) {
370
+ async uploadResources(buildId, resources, meta = {}) {
354
371
  validateId('build', buildId);
355
- this.log.debug(`Uploading resources for ${buildId}...`);
372
+ this.log.debug(`Uploading resources for ${buildId}...`, meta);
356
373
  return pool(function* () {
357
374
  for (let resource of resources) {
358
- yield this.uploadResource(buildId, resource);
375
+ let resourceMeta = {
376
+ url: resource.url,
377
+ sha: resource.sha,
378
+ ...meta
379
+ };
380
+ yield this.uploadResource(buildId, resource, resourceMeta);
381
+ this.log.debug(`Uploaded resource ${resource.url}`, resourceMeta);
359
382
  }
360
383
  }, this, 2);
361
384
  }
@@ -375,20 +398,22 @@ export class PercyClient {
375
398
  testCase,
376
399
  labels,
377
400
  thTestCaseExecutionId,
378
- resources = []
401
+ resources = [],
402
+ meta
379
403
  } = {}) {
380
404
  validateId('build', buildId);
381
405
  this.addClientInfo(clientInfo);
382
406
  this.addEnvironmentInfo(environmentInfo);
383
407
  if (!this.clientInfo.size || !this.environmentInfo.size) {
384
- this.log.warn('Warning: Missing `clientInfo` and/or `environmentInfo` properties');
408
+ this.log.warn('Warning: Missing `clientInfo` and/or `environmentInfo` properties', meta);
385
409
  }
386
410
  let tagsArr = tagsList(labels);
387
- this.log.debug(`Creating snapshot: ${name}...`);
411
+ this.log.debug(`Validating resources: ${name}...`, meta);
388
412
  for (let resource of resources) {
389
413
  if (resource.sha || resource.content || !resource.filepath) continue;
390
414
  resource.content = await fs.promises.readFile(resource.filepath);
391
415
  }
416
+ this.log.debug(`Creating snapshot: ${name}...`, meta);
392
417
  return this.post(`builds/${buildId}/snapshots`, {
393
418
  data: {
394
419
  type: 'snapshots',
@@ -420,31 +445,44 @@ export class PercyClient {
420
445
  }
421
446
  }
422
447
  }
448
+ }, {
449
+ identifier: 'snapshot.post',
450
+ ...meta
423
451
  });
424
452
  }
425
453
 
426
454
  // Finalizes a snapshot.
427
- async finalizeSnapshot(snapshotId) {
455
+ async finalizeSnapshot(snapshotId, meta = {}) {
428
456
  validateId('snapshot', snapshotId);
429
- this.log.debug(`Finalizing snapshot ${snapshotId}...`);
430
- return this.post(`snapshots/${snapshotId}/finalize`);
457
+ this.log.debug(`Finalizing snapshot ${snapshotId}...`, meta);
458
+ return this.post(`snapshots/${snapshotId}/finalize`, {}, {
459
+ identifier: 'snapshot.finalze',
460
+ ...meta
461
+ });
431
462
  }
432
463
 
433
464
  // Convenience method for creating a snapshot for the active build, uploading
434
465
  // missing resources for the snapshot, and finalizing the snapshot.
435
466
  async sendSnapshot(buildId, options) {
436
467
  var _snapshot$data$relati;
468
+ let {
469
+ meta = {}
470
+ } = options;
437
471
  let snapshot = await this.createSnapshot(buildId, options);
472
+ meta.snapshotId = snapshot.data.id;
438
473
  let missing = (_snapshot$data$relati = snapshot.data.relationships) === null || _snapshot$data$relati === void 0 || (_snapshot$data$relati = _snapshot$data$relati['missing-resources']) === null || _snapshot$data$relati === void 0 ? void 0 : _snapshot$data$relati.data;
474
+ this.log.debug(`${(missing === null || missing === void 0 ? void 0 : missing.length) || 0} Missing resources: ${options.name}...`, meta);
439
475
  if (missing !== null && missing !== void 0 && missing.length) {
440
476
  let resources = options.resources.reduce((acc, r) => Object.assign(acc, {
441
477
  [r.sha]: r
442
478
  }), {});
443
479
  await this.uploadResources(buildId, missing.map(({
444
480
  id
445
- }) => resources[id]));
481
+ }) => resources[id]), meta);
446
482
  }
447
- await this.finalizeSnapshot(snapshot.data.id);
483
+ this.log.debug(`Resources uploaded: ${options.name}...`, meta);
484
+ await this.finalizeSnapshot(snapshot.data.id, meta);
485
+ this.log.debug(`Finalized snapshot: ${options.name}...`, meta);
448
486
  return snapshot;
449
487
  }
450
488
  async createComparison(snapshotId, {
@@ -455,11 +493,12 @@ export class PercyClient {
455
493
  domInfoSha,
456
494
  consideredElementsData,
457
495
  metadata,
458
- sync
496
+ sync,
497
+ meta = {}
459
498
  } = {}) {
460
499
  validateId('snapshot', snapshotId);
461
500
  // Remove post percy api deploy
462
- this.log.debug(`Creating comparision: ${tag.name}...`);
501
+ this.log.debug(`Creating comparision: ${tag.name}...`, meta);
463
502
  for (let tile of tiles) {
464
503
  if (tile.sha) continue;
465
504
  if (tile.content && typeof tile.content === 'string') {
@@ -469,6 +508,7 @@ export class PercyClient {
469
508
  tile.content = await fs.promises.readFile(tile.filepath);
470
509
  }
471
510
  }
511
+ this.log.debug(`${tiles.length} tiles for comparision: ${tag.name}...`, meta);
472
512
  return this.post(`snapshots/${snapshotId}/comparisons`, {
473
513
  data: {
474
514
  type: 'comparisons',
@@ -512,6 +552,9 @@ export class PercyClient {
512
552
  }
513
553
  }
514
554
  }
555
+ }, {
556
+ identifier: 'comparison.post',
557
+ ...meta
515
558
  });
516
559
  }
517
560
  async uploadComparisonTile(comparisonId, {
@@ -520,14 +563,14 @@ export class PercyClient {
520
563
  filepath,
521
564
  content,
522
565
  sha
523
- } = {}) {
566
+ } = {}, meta = {}) {
524
567
  validateId('comparison', comparisonId);
525
568
  if (sha) {
526
569
  return await this.verify(comparisonId, sha);
527
570
  }
528
571
  if (filepath && !content) content = await fs.promises.readFile(filepath);
529
572
  let encodedContent = base64encode(content);
530
- this.log.debug(`Uploading ${formatBytes(encodedContent.length)} comparison tile: ${index + 1}/${total} (${comparisonId})...`);
573
+ this.log.debug(`Uploading ${formatBytes(encodedContent.length)} comparison tile: ${index + 1}/${total} (${comparisonId})...`, meta);
531
574
  this.mayBeLogUploadSize(encodedContent.length);
532
575
  return this.post(`comparisons/${comparisonId}/tiles`, {
533
576
  data: {
@@ -537,6 +580,9 @@ export class PercyClient {
537
580
  index
538
581
  }
539
582
  }
583
+ }, {
584
+ identifier: 'comparison.tile.post',
585
+ ...meta
540
586
  });
541
587
  }
542
588
 
@@ -559,9 +605,9 @@ export class PercyClient {
559
605
  }
560
606
  return true;
561
607
  }
562
- async verifyComparisonTile(comparisonId, sha) {
608
+ async verifyComparisonTile(comparisonId, sha, meta = {}) {
563
609
  validateId('comparison', comparisonId);
564
- this.log.debug(`Verifying comparison tile with sha: ${sha}`);
610
+ this.log.debug(`Verifying comparison tile with sha: ${sha}`, meta);
565
611
  try {
566
612
  return await this.post(`comparisons/${comparisonId}/tiles/verify`, {
567
613
  data: {
@@ -570,6 +616,9 @@ export class PercyClient {
570
616
  sha: sha
571
617
  }
572
618
  }
619
+ }, {
620
+ identifier: 'comparison.tile.verify',
621
+ ...meta
573
622
  });
574
623
  } catch (error) {
575
624
  this.log.error(error);
@@ -592,46 +641,63 @@ export class PercyClient {
592
641
  }
593
642
  }, this, 2);
594
643
  }
595
- async finalizeComparison(comparisonId) {
644
+ async finalizeComparison(comparisonId, meta = {}) {
596
645
  validateId('comparison', comparisonId);
597
646
  this.log.debug(`Finalizing comparison ${comparisonId}...`);
598
- return this.post(`comparisons/${comparisonId}/finalize`);
647
+ return this.post(`comparisons/${comparisonId}/finalize`, {}, {
648
+ identifier: 'comparison.finalize',
649
+ ...meta
650
+ });
599
651
  }
600
652
  async sendComparison(buildId, options) {
653
+ let {
654
+ meta
655
+ } = options;
601
656
  if (!validateTiles(options.tiles)) {
602
657
  throw new Error('sha, filepath or content should be present in tiles object');
603
658
  }
604
659
  let snapshot = await this.createSnapshot(buildId, options);
605
660
  let comparison = await this.createComparison(snapshot.data.id, options);
606
661
  await this.uploadComparisonTiles(comparison.data.id, options.tiles);
662
+ this.log.debug(`Created comparison: ${comparison.data.id} ${options.tag.name}`, meta);
607
663
  await this.finalizeComparison(comparison.data.id);
664
+ this.log.debug(`Finalized comparison: ${comparison.data.id} ${options.tag.name}`, meta);
608
665
  return comparison;
609
666
  }
610
- async sendBuildEvents(buildId, body) {
667
+ async sendBuildEvents(buildId, body, meta = {}) {
611
668
  validateId('build', buildId);
612
669
  this.log.debug('Sending Build Events');
613
670
  return this.post(`builds/${buildId}/send-events`, {
614
671
  data: body
672
+ }, {
673
+ identifier: 'build.send_events',
674
+ ...meta
615
675
  });
616
676
  }
617
- async sendBuildLogs(body) {
618
- this.log.debug('Sending Build Logs');
677
+ async sendBuildLogs(body, meta = {}) {
678
+ this.log.debug('Sending Build Logs', meta);
619
679
  return this.post('logs', {
620
680
  data: body
681
+ }, {
682
+ identifier: 'build.send_logs',
683
+ ...meta
621
684
  });
622
685
  }
623
- async getErrorAnalysis(errors) {
686
+ async getErrorAnalysis(errors, meta = {}) {
624
687
  const errorLogs = formatLogErrors(errors);
625
- this.log.debug('Sending error logs for analysis');
688
+ this.log.debug('Sending error logs for analysis', meta);
626
689
  return this.post('suggestions/from_logs', {
627
690
  data: errorLogs
691
+ }, {
692
+ identifier: 'error.analysis.get',
693
+ ...meta
628
694
  });
629
695
  }
630
- mayBeLogUploadSize(contentSize) {
696
+ mayBeLogUploadSize(contentSize, meta = {}) {
631
697
  if (contentSize >= 25 * 1024 * 1024) {
632
- this.log.error('Uploading resource above 25MB might fail the build...');
698
+ this.log.error('Uploading resource above 25MB might fail the build...', meta);
633
699
  } else if (contentSize >= 20 * 1024 * 1024) {
634
- this.log.warn('Uploading resource above 20MB might slow the build...');
700
+ this.log.warn('Uploading resource above 20MB might slow the build...', meta);
635
701
  }
636
702
  }
637
703
 
package/dist/utils.js CHANGED
@@ -128,6 +128,7 @@ export async function request(url, options = {}, callback) {
128
128
  interval,
129
129
  noProxy,
130
130
  buffer,
131
+ meta = {},
131
132
  ...requestOptions
132
133
  } = options;
133
134
  let {
@@ -169,9 +170,17 @@ export async function request(url, options = {}, callback) {
169
170
  let handleError = error => {
170
171
  if (handleError.handled) return;
171
172
  handleError.handled = true;
173
+ const response = error.response;
174
+ meta.responseCode = error.code;
175
+ meta.errorCount = (meta.errorCount || 0) + 1;
176
+ if (response) {
177
+ meta.responseCode = response.statusCode;
178
+ meta.xRequestId = response.headers['x-request-id'];
179
+ meta.cfRay = response.headers['cf-ray'];
180
+ }
172
181
 
173
182
  // maybe retry 404s, always retry 500s, or retry specific errors
174
- let shouldRetry = error.response ? retryNotFound && error.response.statusCode === 404 || error.response.statusCode >= 500 && error.response.statusCode < 600 : !!error.code && RETRY_ERROR_CODES.includes(error.code);
183
+ let shouldRetry = response ? retryNotFound && response.statusCode === 404 || response.statusCode >= 500 && response.statusCode < 600 : !!error.code && RETRY_ERROR_CODES.includes(error.code);
175
184
  return shouldRetry ? retry(error) : reject(error);
176
185
  };
177
186
  let handleFinished = async (body, res) => {
@@ -183,6 +192,9 @@ export async function request(url, options = {}, callback) {
183
192
 
184
193
  // only return a buffer when requested
185
194
  if (buffer !== true) body = raw;
195
+ meta.responseCode = statusCode;
196
+ meta.xRequestId = headers['x-request-id'];
197
+ meta.cfRay = headers['cf-ray'];
186
198
 
187
199
  // attempt to parse the body as json
188
200
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@percy/client",
3
- "version": "1.30.0",
3
+ "version": "1.30.1",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -33,9 +33,9 @@
33
33
  "test:coverage": "yarn test --coverage"
34
34
  },
35
35
  "dependencies": {
36
- "@percy/env": "1.30.0",
37
- "@percy/logger": "1.30.0",
36
+ "@percy/env": "1.30.1",
37
+ "@percy/logger": "1.30.1",
38
38
  "pako": "^2.1.0"
39
39
  },
40
- "gitHead": "0f9c627b5100eaf4d7262c6671764ffb38d23d33"
40
+ "gitHead": "2f8fc42f57c3989de0c5ceca207854d8f66272d3"
41
41
  }