@percy/core 1.28.3 → 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 +47 -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 +10 -9
- package/test/helpers/index.js +1 -0
package/dist/discovery.js
CHANGED
|
@@ -3,6 +3,7 @@ import Queue from './queue.js';
|
|
|
3
3
|
import { normalizeURL, hostnameMatches, createResource, createRootResource, createPercyCSSResource, createLogResource, yieldAll, snapshotLogName, withRetries } from './utils.js';
|
|
4
4
|
import { sha256hash } from '@percy/client/utils';
|
|
5
5
|
import Pako from 'pako';
|
|
6
|
+
import TimeIt from './timing.js';
|
|
6
7
|
|
|
7
8
|
// Logs verbose debug logs detailing various snapshot options.
|
|
8
9
|
function debugSnapshotOptions(snapshot) {
|
|
@@ -312,6 +313,7 @@ export function createDiscoveryQueue(percy) {
|
|
|
312
313
|
concurrency
|
|
313
314
|
} = percy.config.discovery;
|
|
314
315
|
let queue = new Queue('discovery');
|
|
316
|
+
let timeit = new TimeIt();
|
|
315
317
|
let cache;
|
|
316
318
|
return queue.set({
|
|
317
319
|
concurrency
|
|
@@ -342,54 +344,56 @@ export function createDiscoveryQueue(percy) {
|
|
|
342
344
|
})
|
|
343
345
|
// discovery resources for snapshots and call the callback for each discovered snapshot
|
|
344
346
|
.handle('task', async function* (snapshot, callback) {
|
|
345
|
-
|
|
347
|
+
await timeit.measure('asset-discovery', snapshot.name, async () => {
|
|
348
|
+
percy.log.debug(`Discovering resources: ${snapshot.name}`, snapshot.meta);
|
|
346
349
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
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
|
+
}
|
|
372
376
|
}
|
|
373
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();
|
|
374
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']
|
|
375
396
|
});
|
|
376
|
-
try {
|
|
377
|
-
yield* captureSnapshotResources(page, snapshot, {
|
|
378
|
-
captureWidths: !snapshot.domSnapshot && percy.deferUploads,
|
|
379
|
-
capture: callback,
|
|
380
|
-
captureForDevices: percy.deviceDetails || []
|
|
381
|
-
});
|
|
382
|
-
} finally {
|
|
383
|
-
// always close the page when done
|
|
384
|
-
await page.close();
|
|
385
|
-
}
|
|
386
|
-
}, {
|
|
387
|
-
count: snapshot.discovery.retry ? 3 : 1,
|
|
388
|
-
onRetry: () => {
|
|
389
|
-
percy.log.info(`Retrying snapshot: ${snapshotLogName(snapshot.name, snapshot.meta)}`, snapshot.meta);
|
|
390
|
-
},
|
|
391
|
-
signal: snapshot._ctrl.signal,
|
|
392
|
-
throwOn: ['AbortError']
|
|
393
397
|
});
|
|
394
398
|
}).handle('error', ({
|
|
395
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;
|