@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 +108 -42
- package/dist/utils.js +13 -1
- package/package.json +4 -4
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
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
|
|
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
|
-
|
|
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(`
|
|
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
|
-
|
|
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 =
|
|
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.
|
|
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.
|
|
37
|
-
"@percy/logger": "1.30.
|
|
36
|
+
"@percy/env": "1.30.1",
|
|
37
|
+
"@percy/logger": "1.30.1",
|
|
38
38
|
"pako": "^2.1.0"
|
|
39
39
|
},
|
|
40
|
-
"gitHead": "
|
|
40
|
+
"gitHead": "2f8fc42f57c3989de0c5ceca207854d8f66272d3"
|
|
41
41
|
}
|