@percy/core 1.28.3-beta.1 → 1.28.4-alpha.0
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/discovery.js +55 -43
- package/dist/percy.js +82 -42
- package/dist/secretPatterns.yml +7024 -0
- package/dist/timing.js +21 -0
- package/dist/utils.js +26 -0
- package/package.json +11 -9
- package/test/helpers/index.js +1 -0
package/dist/discovery.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import logger from '@percy/logger';
|
|
2
2
|
import Queue from './queue.js';
|
|
3
3
|
import { normalizeURL, hostnameMatches, createResource, createRootResource, createPercyCSSResource, createLogResource, yieldAll, snapshotLogName, withRetries } from './utils.js';
|
|
4
|
+
import { sha256hash } from '@percy/client/utils';
|
|
5
|
+
import Pako from 'pako';
|
|
6
|
+
import TimeIt from './timing.js';
|
|
4
7
|
|
|
5
8
|
// Logs verbose debug logs detailing various snapshot options.
|
|
6
9
|
function debugSnapshotOptions(snapshot) {
|
|
@@ -143,6 +146,12 @@ function processSnapshotResources({
|
|
|
143
146
|
var _log$meta$snapshot, _log$meta$snapshot2;
|
|
144
147
|
return ((_log$meta$snapshot = log.meta.snapshot) === null || _log$meta$snapshot === void 0 ? void 0 : _log$meta$snapshot.testCase) === snapshot.meta.snapshot.testCase && ((_log$meta$snapshot2 = log.meta.snapshot) === null || _log$meta$snapshot2 === void 0 ? void 0 : _log$meta$snapshot2.name) === snapshot.meta.snapshot.name;
|
|
145
148
|
})));
|
|
149
|
+
if (process.env.PERCY_GZIP) {
|
|
150
|
+
for (let index = 0; index < resources.length; index++) {
|
|
151
|
+
resources[index].content = Pako.gzip(resources[index].content);
|
|
152
|
+
resources[index].sha = sha256hash(resources[index].content);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
146
155
|
return {
|
|
147
156
|
...snapshot,
|
|
148
157
|
resources
|
|
@@ -304,6 +313,7 @@ export function createDiscoveryQueue(percy) {
|
|
|
304
313
|
concurrency
|
|
305
314
|
} = percy.config.discovery;
|
|
306
315
|
let queue = new Queue('discovery');
|
|
316
|
+
let timeit = new TimeIt();
|
|
307
317
|
let cache;
|
|
308
318
|
return queue.set({
|
|
309
319
|
concurrency
|
|
@@ -334,54 +344,56 @@ export function createDiscoveryQueue(percy) {
|
|
|
334
344
|
})
|
|
335
345
|
// discovery resources for snapshots and call the callback for each discovered snapshot
|
|
336
346
|
.handle('task', async function* (snapshot, callback) {
|
|
337
|
-
|
|
347
|
+
await timeit.measure('asset-discovery', snapshot.name, async () => {
|
|
348
|
+
percy.log.debug(`Discovering resources: ${snapshot.name}`, snapshot.meta);
|
|
338
349
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
350
|
+
// expectation explained in tests
|
|
351
|
+
/* istanbul ignore next: tested, but coverage is stripped */
|
|
352
|
+
let assetDiscoveryPageEnableJS = snapshot.cliEnableJavaScript && !snapshot.domSnapshot || (snapshot.enableJavaScript ?? !snapshot.domSnapshot);
|
|
353
|
+
percy.log.debug(`Asset discovery Browser Page enable JS: ${assetDiscoveryPageEnableJS}`);
|
|
354
|
+
await withRetries(async function* () {
|
|
355
|
+
// create a new browser page
|
|
356
|
+
let page = yield percy.browser.page({
|
|
357
|
+
enableJavaScript: assetDiscoveryPageEnableJS,
|
|
358
|
+
networkIdleTimeout: snapshot.discovery.networkIdleTimeout,
|
|
359
|
+
requestHeaders: snapshot.discovery.requestHeaders,
|
|
360
|
+
authorization: snapshot.discovery.authorization,
|
|
361
|
+
userAgent: snapshot.discovery.userAgent,
|
|
362
|
+
captureMockedServiceWorker: snapshot.discovery.captureMockedServiceWorker,
|
|
363
|
+
meta: snapshot.meta,
|
|
364
|
+
// enable network inteception
|
|
365
|
+
intercept: {
|
|
366
|
+
enableJavaScript: snapshot.enableJavaScript,
|
|
367
|
+
disableCache: snapshot.discovery.disableCache,
|
|
368
|
+
allowedHostnames: snapshot.discovery.allowedHostnames,
|
|
369
|
+
disallowedHostnames: snapshot.discovery.disallowedHostnames,
|
|
370
|
+
getResource: u => snapshot.resources.get(u) || cache.get(u),
|
|
371
|
+
saveResource: r => {
|
|
372
|
+
snapshot.resources.set(r.url, r);
|
|
373
|
+
if (!r.root) {
|
|
374
|
+
cache.set(r.url, r);
|
|
375
|
+
}
|
|
364
376
|
}
|
|
365
377
|
}
|
|
378
|
+
});
|
|
379
|
+
try {
|
|
380
|
+
yield* captureSnapshotResources(page, snapshot, {
|
|
381
|
+
captureWidths: !snapshot.domSnapshot && percy.deferUploads,
|
|
382
|
+
capture: callback,
|
|
383
|
+
captureForDevices: percy.deviceDetails || []
|
|
384
|
+
});
|
|
385
|
+
} finally {
|
|
386
|
+
// always close the page when done
|
|
387
|
+
await page.close();
|
|
366
388
|
}
|
|
389
|
+
}, {
|
|
390
|
+
count: snapshot.discovery.retry ? 3 : 1,
|
|
391
|
+
onRetry: () => {
|
|
392
|
+
percy.log.info(`Retrying snapshot: ${snapshotLogName(snapshot.name, snapshot.meta)}`, snapshot.meta);
|
|
393
|
+
},
|
|
394
|
+
signal: snapshot._ctrl.signal,
|
|
395
|
+
throwOn: ['AbortError']
|
|
367
396
|
});
|
|
368
|
-
try {
|
|
369
|
-
yield* captureSnapshotResources(page, snapshot, {
|
|
370
|
-
captureWidths: !snapshot.domSnapshot && percy.deferUploads,
|
|
371
|
-
capture: callback,
|
|
372
|
-
captureForDevices: percy.deviceDetails || []
|
|
373
|
-
});
|
|
374
|
-
} finally {
|
|
375
|
-
// always close the page when done
|
|
376
|
-
await page.close();
|
|
377
|
-
}
|
|
378
|
-
}, {
|
|
379
|
-
count: snapshot.discovery.retry ? 3 : 1,
|
|
380
|
-
onRetry: () => {
|
|
381
|
-
percy.log.info(`Retrying snapshot: ${snapshotLogName(snapshot.name, snapshot.meta)}`, snapshot.meta);
|
|
382
|
-
},
|
|
383
|
-
signal: snapshot._ctrl.signal,
|
|
384
|
-
throwOn: ['AbortError']
|
|
385
397
|
});
|
|
386
398
|
}).handle('error', ({
|
|
387
399
|
name,
|
package/dist/percy.js
CHANGED
|
@@ -2,10 +2,11 @@ import PercyClient from '@percy/client';
|
|
|
2
2
|
import PercyConfig from '@percy/config';
|
|
3
3
|
import logger from '@percy/logger';
|
|
4
4
|
import Browser from './browser.js';
|
|
5
|
+
import Pako from 'pako';
|
|
6
|
+
import { base64encode, generatePromise, yieldAll, yieldTo, redactSecrets } from './utils.js';
|
|
5
7
|
import { createPercyServer, createStaticServer } from './api.js';
|
|
6
8
|
import { gatherSnapshots, createSnapshotsQueue, validateSnapshotOptions } from './snapshot.js';
|
|
7
9
|
import { discoverSnapshotResources, createDiscoveryQueue } from './discovery.js';
|
|
8
|
-
import { generatePromise, yieldAll, yieldTo } from './utils.js';
|
|
9
10
|
import { WaitForJob } from './wait-for-job.js';
|
|
10
11
|
|
|
11
12
|
// A Percy instance will create a new build when started, handle snapshot creation, asset discovery,
|
|
@@ -146,6 +147,9 @@ export class Percy {
|
|
|
146
147
|
this.readyState = 0;
|
|
147
148
|
try {
|
|
148
149
|
var _this$build;
|
|
150
|
+
if (process.env.PERCY_CLIENT_ERROR_LOGS !== 'false') {
|
|
151
|
+
this.log.warn('Notice: Percy collects CI logs for service improvement, stored for 30 days. Opt-out anytime with export PERCY_CLIENT_ERROR_LOGS=false');
|
|
152
|
+
}
|
|
149
153
|
// start the snapshots queue immediately when not delayed or deferred
|
|
150
154
|
if (!this.delayUploads && !this.deferUploads) yield this.#snapshots.start();
|
|
151
155
|
// do not start the discovery queue when not needed
|
|
@@ -206,54 +210,61 @@ export class Percy {
|
|
|
206
210
|
// Stops the local API server and closes the browser and internal queues once snapshots have
|
|
207
211
|
// completed. Does nothing if not running. When `force` is true, any queued snapshots are cleared.
|
|
208
212
|
async *stop(force) {
|
|
209
|
-
var _this$server3;
|
|
210
213
|
// not started, but the browser was launched
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
214
|
+
try {
|
|
215
|
+
var _this$server3;
|
|
216
|
+
if (!this.readyState && this.browser.isConnected()) {
|
|
217
|
+
await this.browser.close();
|
|
218
|
+
}
|
|
219
|
+
if (this.syncQueue) this.syncQueue.stop();
|
|
220
|
+
// not started or already stopped
|
|
221
|
+
if (!this.readyState || this.readyState > 2) return;
|
|
222
|
+
|
|
223
|
+
// close queues asap
|
|
224
|
+
if (force) {
|
|
225
|
+
this.#discovery.close(true);
|
|
226
|
+
this.#snapshots.close(true);
|
|
227
|
+
}
|
|
223
228
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
229
|
+
// already stopping
|
|
230
|
+
if (this.readyState === 2) return;
|
|
231
|
+
this.readyState = 2;
|
|
227
232
|
|
|
228
|
-
|
|
229
|
-
|
|
233
|
+
// log when force stopping
|
|
234
|
+
if (force) this.log.info('Stopping percy...');
|
|
230
235
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
236
|
+
// used to log snapshot count information
|
|
237
|
+
let info = (state, size) => `${state} ` + `${size} snapshot${size !== 1 ? 's' : ''}`;
|
|
238
|
+
try {
|
|
239
|
+
// flush discovery and snapshot queues
|
|
240
|
+
yield* this.yield.flush((state, size) => {
|
|
241
|
+
this.log.progress(`${info(state, size)}...`, !!size);
|
|
242
|
+
});
|
|
243
|
+
} catch (error) {
|
|
244
|
+
// reset ready state when aborted
|
|
245
|
+
/* istanbul ignore else: all errors bubble */
|
|
246
|
+
if (error.name === 'AbortError') this.readyState = 1;
|
|
247
|
+
throw error;
|
|
248
|
+
}
|
|
244
249
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
250
|
+
// if dry-running, log the total number of snapshots
|
|
251
|
+
if (this.dryRun && this.#snapshots.size) {
|
|
252
|
+
this.log.info(info('Found', this.#snapshots.size));
|
|
253
|
+
}
|
|
249
254
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
255
|
+
// close server and end queues
|
|
256
|
+
await ((_this$server3 = this.server) === null || _this$server3 === void 0 ? void 0 : _this$server3.close());
|
|
257
|
+
await this.#discovery.end();
|
|
258
|
+
await this.#snapshots.end();
|
|
254
259
|
|
|
255
|
-
|
|
256
|
-
|
|
260
|
+
// mark instance as stopped
|
|
261
|
+
this.readyState = 3;
|
|
262
|
+
} catch (err) {
|
|
263
|
+
this.log.error(err);
|
|
264
|
+
throw err;
|
|
265
|
+
} finally {
|
|
266
|
+
await this.sendBuildLogs();
|
|
267
|
+
}
|
|
257
268
|
}
|
|
258
269
|
|
|
259
270
|
// Takes one or more snapshots of a page while discovering resources to upload with the resulting
|
|
@@ -412,5 +423,34 @@ export class Percy {
|
|
|
412
423
|
if (syncMode) options.sync = syncMode;
|
|
413
424
|
return syncMode;
|
|
414
425
|
}
|
|
426
|
+
async sendBuildLogs() {
|
|
427
|
+
if (!process.env.PERCY_TOKEN) return;
|
|
428
|
+
try {
|
|
429
|
+
var _this$build3, _this$build4, _this$build5, _this$build6;
|
|
430
|
+
const logsObject = {
|
|
431
|
+
clilogs: logger.query(() => true)
|
|
432
|
+
};
|
|
433
|
+
// Only add CI logs if not disabled voluntarily.
|
|
434
|
+
const sendCILogs = process.env.PERCY_CLIENT_ERROR_LOGS !== 'false';
|
|
435
|
+
if (sendCILogs) {
|
|
436
|
+
const redactedContent = redactSecrets(logger.query(() => true, true));
|
|
437
|
+
logsObject.cilogs = redactedContent;
|
|
438
|
+
}
|
|
439
|
+
const content = base64encode(Pako.gzip(JSON.stringify(logsObject)));
|
|
440
|
+
const referenceId = (_this$build3 = this.build) !== null && _this$build3 !== void 0 && _this$build3.id ? `build_${(_this$build4 = this.build) === null || _this$build4 === void 0 ? void 0 : _this$build4.id}` : (_this$build5 = this.build) === null || _this$build5 === void 0 ? void 0 : _this$build5.id;
|
|
441
|
+
const eventObject = {
|
|
442
|
+
content: content,
|
|
443
|
+
build_id: (_this$build6 = this.build) === null || _this$build6 === void 0 ? void 0 : _this$build6.id,
|
|
444
|
+
reference_id: referenceId,
|
|
445
|
+
service_name: 'cli',
|
|
446
|
+
base64encoded: true
|
|
447
|
+
};
|
|
448
|
+
// Ignore this will update once I implement logs controller.
|
|
449
|
+
const logsSHA = await this.client.sendBuildLogs(eventObject);
|
|
450
|
+
this.log.info(`Build's CLI${sendCILogs ? ' and CI' : ''} logs sent successfully. Please share this log ID with Percy team in case of any issues - ${logsSHA}`);
|
|
451
|
+
} catch (err) {
|
|
452
|
+
this.log.warn('Could not send the builds logs');
|
|
453
|
+
}
|
|
454
|
+
}
|
|
415
455
|
}
|
|
416
456
|
export default Percy;
|