@percy/env 1.32.11-beta.0 → 1.32.11-beta.2
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/environment.js +76 -1
- package/package.json +3 -3
package/dist/environment.js
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
|
+
import os from 'os';
|
|
1
2
|
import { getCommitData, getJenkinsSha, github } from './utils.js';
|
|
2
3
|
import logger from '@percy/logger';
|
|
4
|
+
|
|
5
|
+
// machine ids are capped and restricted to header-safe characters on both
|
|
6
|
+
// sides; percy-api rejects anything longer or outside this alphabet
|
|
7
|
+
const MACHINE_ID_MAX_LENGTH = 128;
|
|
8
|
+
function machineToken(value) {
|
|
9
|
+
if (value == null || value === '') return null;
|
|
10
|
+
return String(value).replace(/[^A-Za-z0-9._-]/g, '-');
|
|
11
|
+
}
|
|
3
12
|
export class PercyEnv {
|
|
4
13
|
constructor(vars = process.env) {
|
|
5
14
|
this.vars = vars;
|
|
@@ -384,6 +393,70 @@ export class PercyEnv {
|
|
|
384
393
|
return !!partial && partial !== '0';
|
|
385
394
|
}
|
|
386
395
|
|
|
396
|
+
// machine identity for slow-build diagnostics (dead-CI-machine detection on
|
|
397
|
+
// parallel builds). percy-api validates all of these server-side and may
|
|
398
|
+
// discard any of them. Deliberately excluded from the getter debug logging
|
|
399
|
+
// below (like `token`) — env debug logs are uploaded with build logs, and
|
|
400
|
+
// hostnames should not ride along in them.
|
|
401
|
+
get machine() {
|
|
402
|
+
let hostname = null;
|
|
403
|
+
try {
|
|
404
|
+
hostname = os.hostname() || null;
|
|
405
|
+
} catch {
|
|
406
|
+
hostname = null;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// the per-shard index for providers that can run several shards on one
|
|
410
|
+
// host; without it every shard on that host would share a machine id and a
|
|
411
|
+
// dead shard would look alive as long as any sibling kept uploading
|
|
412
|
+
let index = null;
|
|
413
|
+
let runUrl = null;
|
|
414
|
+
switch (this.ci) {
|
|
415
|
+
case 'circle':
|
|
416
|
+
index = this.vars.CIRCLE_NODE_INDEX;
|
|
417
|
+
runUrl = this.vars.CIRCLE_BUILD_URL;
|
|
418
|
+
break;
|
|
419
|
+
case 'buildkite':
|
|
420
|
+
index = this.vars.BUILDKITE_PARALLEL_JOB;
|
|
421
|
+
// the build url is shared by every parallel job; the job id anchor is
|
|
422
|
+
// what lets the "stopped responding" link land on the dead agent's log
|
|
423
|
+
runUrl = this.vars.BUILDKITE_BUILD_URL && this.vars.BUILDKITE_JOB_ID ? `${this.vars.BUILDKITE_BUILD_URL}#${this.vars.BUILDKITE_JOB_ID}` : this.vars.BUILDKITE_BUILD_URL;
|
|
424
|
+
break;
|
|
425
|
+
case 'github':
|
|
426
|
+
runUrl = this.vars.GITHUB_SERVER_URL && this.vars.GITHUB_REPOSITORY && this.vars.GITHUB_RUN_ID ? `${this.vars.GITHUB_SERVER_URL}/${this.vars.GITHUB_REPOSITORY}/actions/runs/${this.vars.GITHUB_RUN_ID}` : null;
|
|
427
|
+
break;
|
|
428
|
+
case 'gitlab':
|
|
429
|
+
index = this.vars.CI_NODE_INDEX;
|
|
430
|
+
runUrl = this.vars.CI_JOB_URL;
|
|
431
|
+
break;
|
|
432
|
+
case 'jenkins':
|
|
433
|
+
case 'jenkins-prb':
|
|
434
|
+
index = this.vars.EXECUTOR_NUMBER;
|
|
435
|
+
break;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// stable id: sanitized hostname, suffixed with the sanitized shard index.
|
|
439
|
+
// The id travels as an HTTP header value on every snapshot POST, so every
|
|
440
|
+
// part of it must be header-safe — an unsanitized index with a stray
|
|
441
|
+
// newline would reject the whole upload.
|
|
442
|
+
let id = machineToken(hostname);
|
|
443
|
+
let shard = machineToken(index);
|
|
444
|
+
if (id && shard) id = `${id}.n${shard}`;
|
|
445
|
+
if (id) id = id.slice(0, MACHINE_ID_MAX_LENGTH);
|
|
446
|
+
// a hostname with no ASCII alphanumerics sanitizes to dashes alone, which
|
|
447
|
+
// identifies nothing and would collide across hosts — better no id at all
|
|
448
|
+
if (id && !/[A-Za-z0-9]/.test(id)) id = null;
|
|
449
|
+
return {
|
|
450
|
+
id,
|
|
451
|
+
hostname,
|
|
452
|
+
runUrl: runUrl || null,
|
|
453
|
+
// which CI product the agent belongs to ("jenkins", "buildkite", ...);
|
|
454
|
+
// percy-web maps it to a display name in the stopped-responding copy.
|
|
455
|
+
// The generic CI/unknown marker is not a product and is dropped.
|
|
456
|
+
platform: this.ci && this.ci !== 'CI/unknown' ? this.ci : null
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
|
|
387
460
|
// percy token
|
|
388
461
|
get token() {
|
|
389
462
|
return this.vars.PERCY_TOKEN || null;
|
|
@@ -422,7 +495,9 @@ Object.defineProperties(PercyEnv.prototype, Object.entries(Object.getOwnProperty
|
|
|
422
495
|
Object.defineProperty(this, key, {
|
|
423
496
|
value
|
|
424
497
|
});
|
|
425
|
-
|
|
498
|
+
// `machine` carries a hostname and these debug logs are uploaded
|
|
499
|
+
// with build logs — keep it out, like the token.
|
|
500
|
+
if (key !== 'token' && key !== 'machine') {
|
|
426
501
|
this.log.debug(`Detected ${key} as ${JSON.stringify(value)}`);
|
|
427
502
|
}
|
|
428
503
|
return value;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@percy/env",
|
|
3
|
-
"version": "1.32.11-beta.
|
|
3
|
+
"version": "1.32.11-beta.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"test:coverage": "yarn test --coverage"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@percy/logger": "1.32.11-beta.
|
|
35
|
+
"@percy/logger": "1.32.11-beta.2"
|
|
36
36
|
},
|
|
37
|
-
"gitHead": "
|
|
37
|
+
"gitHead": "a05b0ac1efc0d136fa15c2330b55e1e207c6e797"
|
|
38
38
|
}
|