@argos-ci/core 0.7.0 → 0.7.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/index.mjs +143 -102
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import convict from 'convict';
|
|
2
|
+
import { execSync } from 'node:child_process';
|
|
3
|
+
import { execSync as execSync$1 } from 'child_process';
|
|
4
|
+
import createDebug from 'debug';
|
|
2
5
|
import envCi from 'env-ci';
|
|
3
|
-
import { execSync } from 'child_process';
|
|
4
6
|
import { resolve } from 'node:path';
|
|
5
7
|
import glob from 'fast-glob';
|
|
6
8
|
import { promisify } from 'node:util';
|
|
@@ -10,7 +12,6 @@ import { createReadStream } from 'node:fs';
|
|
|
10
12
|
import { createHash } from 'node:crypto';
|
|
11
13
|
import axios from 'axios';
|
|
12
14
|
import { readFile } from 'node:fs/promises';
|
|
13
|
-
import createDebug from 'debug';
|
|
14
15
|
|
|
15
16
|
const mustBeApiBaseUrl = (value)=>{
|
|
16
17
|
const URL_REGEX = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/;
|
|
@@ -41,14 +42,13 @@ const schema = {
|
|
|
41
42
|
},
|
|
42
43
|
commit: {
|
|
43
44
|
env: "ARGOS_COMMIT",
|
|
44
|
-
default:
|
|
45
|
+
default: null,
|
|
45
46
|
format: mustBeCommit
|
|
46
47
|
},
|
|
47
48
|
branch: {
|
|
48
49
|
env: "ARGOS_BRANCH",
|
|
49
50
|
default: null,
|
|
50
|
-
format: String
|
|
51
|
-
nullable: true
|
|
51
|
+
format: String
|
|
52
52
|
},
|
|
53
53
|
token: {
|
|
54
54
|
env: "ARGOS_TOKEN",
|
|
@@ -61,6 +61,12 @@ const schema = {
|
|
|
61
61
|
format: String,
|
|
62
62
|
nullable: true
|
|
63
63
|
},
|
|
64
|
+
prNumber: {
|
|
65
|
+
env: "ARGOS_PR_NUMBER",
|
|
66
|
+
format: Number,
|
|
67
|
+
default: null,
|
|
68
|
+
nullable: true
|
|
69
|
+
},
|
|
64
70
|
parallel: {
|
|
65
71
|
env: "ARGOS_PARALLEL",
|
|
66
72
|
default: false,
|
|
@@ -93,11 +99,6 @@ const schema = {
|
|
|
93
99
|
default: null,
|
|
94
100
|
nullable: true
|
|
95
101
|
},
|
|
96
|
-
prNumber: {
|
|
97
|
-
format: Number,
|
|
98
|
-
default: null,
|
|
99
|
-
nullable: true
|
|
100
|
-
},
|
|
101
102
|
owner: {
|
|
102
103
|
format: String,
|
|
103
104
|
default: null,
|
|
@@ -116,45 +117,54 @@ const createConfig = ()=>{
|
|
|
116
117
|
};
|
|
117
118
|
|
|
118
119
|
/**
|
|
119
|
-
*
|
|
120
|
-
*/ const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
120
|
+
* Returns the head commit.
|
|
121
|
+
*/ const head = ()=>{
|
|
122
|
+
try {
|
|
123
|
+
return execSync("git rev-parse HEAD").toString().trim();
|
|
124
|
+
} catch {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* Returns the current branch.
|
|
130
|
+
*/ const branch = ()=>{
|
|
131
|
+
try {
|
|
132
|
+
const headRef = execSync("git rev-parse --abbrev-ref HEAD").toString().trim();
|
|
133
|
+
if (headRef === "HEAD") {
|
|
134
|
+
return null;
|
|
125
135
|
}
|
|
126
|
-
|
|
127
|
-
|
|
136
|
+
return headRef;
|
|
137
|
+
} catch {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
128
140
|
};
|
|
129
141
|
|
|
130
142
|
const service$4 = {
|
|
143
|
+
name: "Buildkite",
|
|
131
144
|
detect: ({ env })=>Boolean(env.BUILDKITE),
|
|
132
145
|
config: ({ env })=>{
|
|
133
|
-
const ciProps = envCiDetection({
|
|
134
|
-
env
|
|
135
|
-
});
|
|
136
146
|
return {
|
|
137
|
-
|
|
138
|
-
commit:
|
|
139
|
-
branch: env.BUILDKITE_BRANCH || null,
|
|
147
|
+
// Buildkite doesn't work well so we fallback to git to ensure we have commit and branch
|
|
148
|
+
commit: env.BUILDKITE_COMMIT || head() || null,
|
|
149
|
+
branch: env.BUILDKITE_BRANCH || branch() || null,
|
|
140
150
|
owner: env.BUILDKITE_ORGANIZATION_SLUG || null,
|
|
141
151
|
repository: env.BUILDKITE_PROJECT_SLUG || null,
|
|
142
|
-
jobId:
|
|
143
|
-
runId:
|
|
152
|
+
jobId: null,
|
|
153
|
+
runId: null,
|
|
144
154
|
prNumber: env.BUILDKITE_PULL_REQUEST ? Number(env.BUILDKITE_PULL_REQUEST) : null
|
|
145
155
|
};
|
|
146
156
|
}
|
|
147
157
|
};
|
|
148
158
|
|
|
149
159
|
const service$3 = {
|
|
160
|
+
name: "Heroku",
|
|
150
161
|
detect: ({ env })=>Boolean(env.HEROKU_TEST_RUN_ID),
|
|
151
162
|
config: ({ env })=>({
|
|
152
|
-
name: "Heroku",
|
|
153
163
|
commit: env.HEROKU_TEST_RUN_COMMIT_VERSION || null,
|
|
154
164
|
branch: env.HEROKU_TEST_RUN_BRANCH || null,
|
|
155
165
|
owner: null,
|
|
156
166
|
repository: null,
|
|
157
|
-
jobId:
|
|
167
|
+
jobId: null,
|
|
158
168
|
runId: null,
|
|
159
169
|
prNumber: null
|
|
160
170
|
})
|
|
@@ -164,7 +174,7 @@ const getSha = ({ env })=>{
|
|
|
164
174
|
const isPr = env.GITHUB_EVENT_NAME === "pull_request" || env.GITHUB_EVENT_NAME === "pull_request_target";
|
|
165
175
|
if (isPr) {
|
|
166
176
|
const mergeCommitRegex = /^[a-z0-9]{40} [a-z0-9]{40}$/;
|
|
167
|
-
const mergeCommitMessage = execSync("git show --no-patch --format=%P").toString().trim();
|
|
177
|
+
const mergeCommitMessage = execSync$1("git show --no-patch --format=%P").toString().trim();
|
|
168
178
|
// console.log(
|
|
169
179
|
// `Handling PR with parent hash(es) '${mergeCommitMessage}' of current commit.`
|
|
170
180
|
// );
|
|
@@ -193,22 +203,22 @@ Please run "actions/checkout" with "fetch-depth: 2". Example:
|
|
|
193
203
|
}
|
|
194
204
|
return process.env.GITHUB_SHA ?? null;
|
|
195
205
|
};
|
|
196
|
-
|
|
206
|
+
const getBranch = ({ env })=>{
|
|
197
207
|
if (env.GITHUB_HEAD_REF) {
|
|
198
208
|
return env.GITHUB_HEAD_REF;
|
|
199
209
|
}
|
|
200
210
|
const branchRegex = /refs\/heads\/(.*)/;
|
|
201
|
-
const
|
|
202
|
-
if (
|
|
203
|
-
return
|
|
211
|
+
const matches = branchRegex.exec(env.GITHUB_REF || "");
|
|
212
|
+
if (matches) {
|
|
213
|
+
return matches[1];
|
|
204
214
|
}
|
|
205
215
|
return null;
|
|
206
|
-
}
|
|
207
|
-
|
|
216
|
+
};
|
|
217
|
+
const getRepository$1 = ({ env })=>{
|
|
208
218
|
if (!env.GITHUB_REPOSITORY) return null;
|
|
209
219
|
return env.GITHUB_REPOSITORY.split("/")[1];
|
|
210
|
-
}
|
|
211
|
-
const getPrNumber$
|
|
220
|
+
};
|
|
221
|
+
const getPrNumber$2 = ({ env })=>{
|
|
212
222
|
const branchRegex = /refs\/pull\/(\d+)/;
|
|
213
223
|
const branchMatches = branchRegex.exec(env.GITHUB_REF || "");
|
|
214
224
|
if (branchMatches) {
|
|
@@ -217,9 +227,9 @@ const getPrNumber$1 = ({ env })=>{
|
|
|
217
227
|
return null;
|
|
218
228
|
};
|
|
219
229
|
const service$2 = {
|
|
230
|
+
name: "GitHub Actions",
|
|
220
231
|
detect: ({ env })=>Boolean(env.GITHUB_ACTIONS),
|
|
221
232
|
config: ({ env })=>({
|
|
222
|
-
name: "GitHub Actions",
|
|
223
233
|
commit: getSha({
|
|
224
234
|
env
|
|
225
235
|
}),
|
|
@@ -227,73 +237,75 @@ const service$2 = {
|
|
|
227
237
|
env
|
|
228
238
|
}),
|
|
229
239
|
owner: env.GITHUB_REPOSITORY_OWNER || null,
|
|
230
|
-
repository: getRepository({
|
|
240
|
+
repository: getRepository$1({
|
|
231
241
|
env
|
|
232
242
|
}),
|
|
233
243
|
jobId: env.GITHUB_JOB || null,
|
|
234
244
|
runId: env.GITHUB_RUN_ID || null,
|
|
235
|
-
prNumber: getPrNumber$
|
|
245
|
+
prNumber: getPrNumber$2({
|
|
236
246
|
env
|
|
237
247
|
})
|
|
238
248
|
})
|
|
239
249
|
};
|
|
240
250
|
|
|
241
|
-
const getPrNumber = ({ env })=>{
|
|
251
|
+
const getPrNumber$1 = ({ env })=>{
|
|
242
252
|
const branchRegex = /pull\/(\d+)/;
|
|
243
|
-
const
|
|
244
|
-
if (
|
|
245
|
-
return Number(
|
|
253
|
+
const matches = branchRegex.exec(env.CIRCLE_PULL_REQUEST || "");
|
|
254
|
+
if (matches) {
|
|
255
|
+
return Number(matches[1]);
|
|
246
256
|
}
|
|
247
257
|
return null;
|
|
248
258
|
};
|
|
249
259
|
const service$1 = {
|
|
260
|
+
name: "CircleCI",
|
|
250
261
|
detect: ({ env })=>Boolean(env.CIRCLECI),
|
|
251
262
|
config: ({ env })=>{
|
|
252
|
-
const ciProps = envCiDetection({
|
|
253
|
-
env
|
|
254
|
-
});
|
|
255
263
|
return {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
prNumber: getPrNumber({
|
|
264
|
+
commit: env.CIRCLE_SHA1 || null,
|
|
265
|
+
branch: env.CIRCLE_BRANCH || null,
|
|
266
|
+
owner: env.CIRCLE_PROJECT_USERNAME || null,
|
|
267
|
+
repository: env.CIRCLE_PROJECT_REPONAME || null,
|
|
268
|
+
jobId: null,
|
|
269
|
+
runId: null,
|
|
270
|
+
prNumber: getPrNumber$1({
|
|
264
271
|
env
|
|
265
272
|
})
|
|
266
273
|
};
|
|
267
274
|
}
|
|
268
275
|
};
|
|
269
276
|
|
|
277
|
+
const getOwner = ({ env })=>{
|
|
278
|
+
if (!env.TRAVIS_REPO_SLUG) return null;
|
|
279
|
+
return env.TRAVIS_REPO_SLUG.split("/")[0] || null;
|
|
280
|
+
};
|
|
281
|
+
const getRepository = ({ env })=>{
|
|
282
|
+
if (!env.TRAVIS_REPO_SLUG) return null;
|
|
283
|
+
return env.TRAVIS_REPO_SLUG.split("/")[1] || null;
|
|
284
|
+
};
|
|
285
|
+
const getPrNumber = ({ env })=>{
|
|
286
|
+
if (env.TRAVIS_PULL_REQUEST) return Number(env.TRAVIS_PULL_REQUEST);
|
|
287
|
+
return null;
|
|
288
|
+
};
|
|
270
289
|
const service = {
|
|
290
|
+
name: "Travis CI",
|
|
271
291
|
detect: ({ env })=>Boolean(env.TRAVIS),
|
|
272
|
-
config: (
|
|
273
|
-
const
|
|
274
|
-
env
|
|
275
|
-
});
|
|
292
|
+
config: (ctx)=>{
|
|
293
|
+
const { env } = ctx;
|
|
276
294
|
return {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
prNumber: env.TRAVIS_PULL_REQUEST ? Number(env.TRAVIS_PULL_REQUEST) : null
|
|
295
|
+
commit: env.TRAVIS_COMMIT || null,
|
|
296
|
+
branch: env.TRAVIS_BRANCH || null,
|
|
297
|
+
owner: getOwner(ctx),
|
|
298
|
+
repository: getRepository(ctx),
|
|
299
|
+
jobId: null,
|
|
300
|
+
runId: null,
|
|
301
|
+
prNumber: getPrNumber(ctx)
|
|
285
302
|
};
|
|
286
303
|
}
|
|
287
304
|
};
|
|
288
305
|
|
|
289
|
-
const
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
service$1,
|
|
293
|
-
service,
|
|
294
|
-
service$4
|
|
295
|
-
];
|
|
296
|
-
const envCiDetection = (ctx)=>{
|
|
306
|
+
const debug = createDebug("@argos-ci/core");
|
|
307
|
+
|
|
308
|
+
const getCiEnvironmentFromEnvCi = (ctx)=>{
|
|
297
309
|
const ciContext = envCi(ctx);
|
|
298
310
|
const name = ciContext.isCi ? ciContext.name ?? null : ciContext.commit ? "Git" : null;
|
|
299
311
|
const commit = ciContext.commit ?? null;
|
|
@@ -315,16 +327,38 @@ const envCiDetection = (ctx)=>{
|
|
|
315
327
|
prNumber
|
|
316
328
|
} : null;
|
|
317
329
|
};
|
|
330
|
+
|
|
331
|
+
const services = [
|
|
332
|
+
service$3,
|
|
333
|
+
service$2,
|
|
334
|
+
service$1,
|
|
335
|
+
service,
|
|
336
|
+
service$4
|
|
337
|
+
];
|
|
318
338
|
const getCiEnvironment = ({ env =process.env } = {})=>{
|
|
319
339
|
const ctx = {
|
|
320
340
|
env
|
|
321
341
|
};
|
|
342
|
+
debug("Detecting CI environment", {
|
|
343
|
+
env
|
|
344
|
+
});
|
|
322
345
|
const service = services.find((service)=>service.detect(ctx));
|
|
323
|
-
//
|
|
346
|
+
// Service matched
|
|
324
347
|
if (service) {
|
|
325
|
-
|
|
348
|
+
debug("Internal service matched", service.name);
|
|
349
|
+
const variables = service.config(ctx);
|
|
350
|
+
const ciEnvironment = {
|
|
351
|
+
name: service.name,
|
|
352
|
+
...variables
|
|
353
|
+
};
|
|
354
|
+
debug("CI environment", ciEnvironment);
|
|
355
|
+
return ciEnvironment;
|
|
326
356
|
}
|
|
327
|
-
|
|
357
|
+
// We fallback on "env-ci" library, not very good but it's better than nothing
|
|
358
|
+
debug("Falling back on env-ci");
|
|
359
|
+
const ciEnvironment1 = getCiEnvironmentFromEnvCi(ctx);
|
|
360
|
+
debug("CI environment", ciEnvironment1);
|
|
361
|
+
return ciEnvironment1;
|
|
328
362
|
};
|
|
329
363
|
|
|
330
364
|
const discoverScreenshots = async (patterns, { root =process.cwd() , ignore } = {})=>{
|
|
@@ -395,11 +429,20 @@ const createArgosApiClient = (options)=>{
|
|
|
395
429
|
});
|
|
396
430
|
const call = async (method, path, data)=>{
|
|
397
431
|
try {
|
|
432
|
+
debug("Sending request", {
|
|
433
|
+
method,
|
|
434
|
+
path,
|
|
435
|
+
data
|
|
436
|
+
});
|
|
398
437
|
const response = await axiosInstance.request({
|
|
399
438
|
method,
|
|
400
439
|
url: path,
|
|
401
440
|
data
|
|
402
441
|
});
|
|
442
|
+
debug("Getting response", {
|
|
443
|
+
status: response.status,
|
|
444
|
+
data: response.data
|
|
445
|
+
});
|
|
403
446
|
return response.data;
|
|
404
447
|
} catch (error) {
|
|
405
448
|
if (error?.response?.data?.error?.message) {
|
|
@@ -434,45 +477,42 @@ const upload$1 = async (input)=>{
|
|
|
434
477
|
});
|
|
435
478
|
};
|
|
436
479
|
|
|
437
|
-
const debug = createDebug("@argos-ci/core");
|
|
438
|
-
|
|
439
480
|
const getConfigFromOptions = (options)=>{
|
|
440
481
|
const config = createConfig();
|
|
441
482
|
const ciEnv = getCiEnvironment();
|
|
442
|
-
|
|
443
|
-
config.
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
483
|
+
config.load({
|
|
484
|
+
apiBaseUrl: config.get("apiBaseUrl") ?? options.apiBaseUrl,
|
|
485
|
+
commit: config.get("commit") ?? options.commit ?? ciEnv?.commit ?? null,
|
|
486
|
+
branch: config.get("branch") ?? options.branch ?? ciEnv?.branch ?? null,
|
|
487
|
+
token: config.get("token") ?? options.token ?? null,
|
|
488
|
+
buildName: config.get("buildName") ?? options.buildName ?? null,
|
|
489
|
+
prNumber: config.get("prNumber") ?? options.prNumber ?? ciEnv?.prNumber ?? null,
|
|
490
|
+
ciService: ciEnv?.name ?? null,
|
|
491
|
+
owner: ciEnv?.owner ?? null,
|
|
492
|
+
repository: ciEnv?.repository ?? null,
|
|
493
|
+
jobId: ciEnv?.jobId ?? null,
|
|
494
|
+
runId: ciEnv?.runId ?? null
|
|
495
|
+
});
|
|
496
|
+
if (options.parallel) {
|
|
497
|
+
config.load({
|
|
498
|
+
parallel: Boolean(options.parallel),
|
|
499
|
+
parallelNonce: options.parallel ? options.parallel.nonce : null,
|
|
500
|
+
parallelTotal: options.parallel ? options.parallel.total : null
|
|
501
|
+
});
|
|
453
502
|
}
|
|
454
|
-
config.load(omitUndefined({
|
|
455
|
-
apiBaseUrl: options.apiBaseUrl,
|
|
456
|
-
commit: options.commit,
|
|
457
|
-
branch: options.branch,
|
|
458
|
-
token: options.token,
|
|
459
|
-
prNumber: options.prNumber,
|
|
460
|
-
buildName: options.buildName,
|
|
461
|
-
parallel: Boolean(options.parallel),
|
|
462
|
-
parallelNonce: options.parallel ? options.parallel.nonce : null,
|
|
463
|
-
parallelTotal: options.parallel ? options.parallel.total : null
|
|
464
|
-
}));
|
|
465
503
|
config.validate();
|
|
466
504
|
return config.get();
|
|
467
505
|
};
|
|
468
506
|
/**
|
|
469
507
|
* Upload screenshots to argos-ci.com.
|
|
470
508
|
*/ const upload = async (params)=>{
|
|
509
|
+
debug("Starting upload with params", params);
|
|
471
510
|
// Read config
|
|
472
511
|
const config = getConfigFromOptions(params);
|
|
473
512
|
const files = params.files ?? [
|
|
474
513
|
"**/*.{png,jpg,jpeg}"
|
|
475
514
|
];
|
|
515
|
+
debug("Using config and files", config, files);
|
|
476
516
|
const apiClient = createArgosApiClient({
|
|
477
517
|
baseUrl: config.apiBaseUrl,
|
|
478
518
|
bearerToken: getBearerToken(config)
|
|
@@ -482,6 +522,7 @@ const getConfigFromOptions = (options)=>{
|
|
|
482
522
|
root: params.root,
|
|
483
523
|
ignore: params.ignore
|
|
484
524
|
});
|
|
525
|
+
debug("Found screenshots", foundScreenshots);
|
|
485
526
|
// Optimize & compute hashes
|
|
486
527
|
const screenshots = await Promise.all(foundScreenshots.map(async (screenshot)=>{
|
|
487
528
|
const optimizedPath = await optimizeScreenshot(screenshot.path);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@argos-ci/core",
|
|
3
3
|
"description": "Visual testing solution to avoid visual regression. The core component of Argos SDK that handles build creation.",
|
|
4
|
-
"version": "0.7.
|
|
4
|
+
"version": "0.7.2",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"prebuild": "rm -rf dist",
|
|
7
7
|
"build": "rollup -c",
|
|
@@ -60,5 +60,5 @@
|
|
|
60
60
|
"rollup-plugin-dts": "^4.2.3",
|
|
61
61
|
"rollup-plugin-swc3": "^0.6.0"
|
|
62
62
|
},
|
|
63
|
-
"gitHead": "
|
|
63
|
+
"gitHead": "7adf2cb62ceb13887c7ddf675f4d19e2bd2572b9"
|
|
64
64
|
}
|