@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.
Files changed (2) hide show
  1. package/dist/index.mjs +143 -102
  2. 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
- * Omit undefined properties from an object.
120
- */ const omitUndefined = (obj)=>{
121
- const result = {};
122
- Object.keys(obj).forEach((key)=>{
123
- if (obj[key] !== undefined) {
124
- result[key] = obj[key];
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
- return result;
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
- name: "Buildkite",
138
- commit: ciProps?.commit || null,
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: env.BUILDKITE_JOB_ID || null,
143
- runId: ciProps?.runId || null,
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: env.HEROKU_TEST_RUN_ID || null,
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
- function getBranch({ env }) {
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 branchMatches = branchRegex.exec(env.GITHUB_REF || "");
202
- if (branchMatches) {
203
- return branchMatches[1];
211
+ const matches = branchRegex.exec(env.GITHUB_REF || "");
212
+ if (matches) {
213
+ return matches[1];
204
214
  }
205
215
  return null;
206
- }
207
- function getRepository({ env }) {
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$1 = ({ env })=>{
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$1({
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 branchMatches = branchRegex.exec(env.CIRCLE_PULL_REQUEST || "");
244
- if (branchMatches) {
245
- return Number(branchMatches[1]);
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
- name: "CircleCI",
257
- commit: ciProps?.commit || null,
258
- branch: ciProps?.branch || null,
259
- owner: ciProps?.owner || null,
260
- repository: ciProps?.repository || null,
261
- jobId: ciProps?.jobId || null,
262
- runId: ciProps?.runId || null,
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: ({ env })=>{
273
- const ciProps = envCiDetection({
274
- env
275
- });
292
+ config: (ctx)=>{
293
+ const { env } = ctx;
276
294
  return {
277
- name: "Travis CI",
278
- commit: ciProps?.commit || null,
279
- branch: ciProps?.branch || null,
280
- owner: ciProps?.owner || null,
281
- repository: ciProps?.repository || null,
282
- jobId: ciProps?.jobId || null,
283
- runId: ciProps?.runId || null,
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 services = [
290
- service$3,
291
- service$2,
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
- // Internal service matched
346
+ // Service matched
324
347
  if (service) {
325
- return service.config(ctx);
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
- return envCiDetection(ctx);
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
- if (ciEnv) {
443
- config.load(omitUndefined({
444
- commit: ciEnv.commit,
445
- branch: ciEnv.branch,
446
- ciService: ciEnv.name,
447
- owner: ciEnv.owner,
448
- repository: ciEnv.repository,
449
- jobId: ciEnv.jobId,
450
- runId: ciEnv.runId,
451
- prNumber: ciEnv.prNumber
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.0",
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": "a7603beaf95ec4be8be9405450a445bfe94a6a12"
63
+ "gitHead": "7adf2cb62ceb13887c7ddf675f4d19e2bd2572b9"
64
64
  }