@argos-ci/core 4.1.5 → 4.2.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.
Files changed (3) hide show
  1. package/dist/index.d.ts +212 -109
  2. package/dist/index.js +192 -122
  3. package/package.json +8 -8
package/dist/index.d.ts CHANGED
@@ -1,123 +1,133 @@
1
- import * as _argos_ci_util from '@argos-ci/util';
2
1
  import { ArgosAPISchema } from '@argos-ci/api-client';
2
+ import { ScreenshotMetadata } from '@argos-ci/util';
3
3
 
4
- type BuildMetadata = ArgosAPISchema.components["schemas"]["BuildMetadata"];
5
- interface UploadParameters {
4
+ interface Config {
6
5
  /**
7
- * Globs matching image file paths to upload
6
+ * Base URL of the Argos API.
7
+ * Use this to target a self-hosted installation.
8
+ * @default "https://api.argos-ci.com/v2/"
8
9
  */
9
- files?: string[];
10
+ apiBaseUrl: string;
10
11
  /**
11
- * Root directory to look for image to upload
12
- * @default process.cwd()
12
+ * Git commit SHA.
13
13
  */
14
- root?: string;
14
+ commit: string;
15
15
  /**
16
- * Globs matching image file paths to ignore
17
- * @default ["**\/*.\{png,jpg,jpeg\}"]
16
+ * Git branch name of the build.
17
+ * @example "main", "develop", "release/1.0"
18
18
  */
19
- ignore?: string[];
19
+ branch: string;
20
20
  /**
21
- * Base URL of Argos API
22
- * @default "https://api.argos-ci.com/v2/"
21
+ * Argos repository access token.
23
22
  */
24
- apiBaseUrl?: string;
23
+ token: string | null;
25
24
  /**
26
- * Git commit
25
+ * Custom build name.
26
+ * Useful for multi-build setups on the same commit.
27
27
  */
28
- commit?: string;
28
+ buildName: string | null;
29
29
  /**
30
- * Git branch
30
+ * Whether this build is split across multiple parallel jobs.
31
+ * @default false
31
32
  */
32
- branch?: string;
33
+ parallel: boolean;
33
34
  /**
34
- * Argos repository token
35
+ * Unique identifier shared by all parallel jobs.
35
36
  */
36
- token?: string;
37
+ parallelNonce: string | null;
37
38
  /**
38
- * Pull-request number
39
+ * Index of the current parallel job.
40
+ * Must be between 1 and `parallelTotal`, or null if not set.
39
41
  */
40
- prNumber?: number;
42
+ parallelIndex: number | null;
41
43
  /**
42
- * Name of the build used to trigger multiple Argos builds on one commit
44
+ * Total number of parallel jobs.
45
+ * Use -1 if unknown, or null if not set.
43
46
  */
44
- buildName?: string;
47
+ parallelTotal: number | null;
45
48
  /**
46
- * Mode of comparison applied
47
- * @default "ci"
49
+ * Git branch used as the baseline for screenshot comparison.
48
50
  */
49
- mode?: "ci" | "monitoring";
51
+ referenceBranch: string | null;
50
52
  /**
51
- Parallel test suite mode
53
+ * Git commit SHA used as the baseline for screenshot comparison.
52
54
  */
53
- parallel?: {
54
- /** Unique build ID for this parallel build */
55
- nonce: string;
56
- /** The number of parallel nodes being ran */
57
- total: number;
58
- /** The index of the parallel node */
59
- index?: number;
60
- } | false;
55
+ referenceCommit: string | null;
61
56
  /**
62
- * Branch used as baseline for screenshot comparison
57
+ * Repository slug of the source repository.
58
+ * Example: "my-org/my-repo" or "my-user/my-repo".
59
+ * If from a fork, this refers to the fork repository.
63
60
  */
64
- referenceBranch?: string;
61
+ repository: string | null;
65
62
  /**
66
- * Commit used as baseline for screenshot comparison
63
+ * Repository slug of the original (base) repository.
64
+ * Example: "my-org/my-repo" or "my-user/my-repo".
65
+ * If from a fork, this refers to the base repository.
67
66
  */
68
- referenceCommit?: string;
67
+ originalRepository: string | null;
69
68
  /**
70
- * Sensitivity threshold between 0 and 1.
71
- * The higher the threshold, the less sensitive the diff will be.
72
- * @default 0.5
69
+ * CI job identifier (if provided by the CI environment).
73
70
  */
74
- threshold?: number;
71
+ jobId: string | null;
75
72
  /**
76
- * Build metadata.
73
+ * CI run identifier (if provided by the CI environment).
77
74
  */
78
- metadata?: BuildMetadata;
75
+ runId: string | null;
79
76
  /**
80
- * Preview URL configuration.
81
- * Accepts a base URL or a function that receives the URL and returns the preview URL.
77
+ * CI run attempt number (if provided by the CI environment).
82
78
  */
83
- previewUrl?: {
84
- baseUrl: string;
85
- } | ((url: string) => string);
79
+ runAttempt: number | null;
80
+ /**
81
+ * Pull request number associated with the build.
82
+ */
83
+ prNumber: number | null;
84
+ /**
85
+ * Pull request head commit SHA (if available).
86
+ */
87
+ prHeadCommit: string | null;
88
+ /**
89
+ * Pull request base branch (if available).
90
+ */
91
+ prBaseBranch: string | null;
92
+ /**
93
+ * Build mode to use.
94
+ * - "ci": Review visual changes introduced by a feature branch and prevent regressions.
95
+ * - "monitoring": Track visual changes outside the standard CI flow, either on a schedule or before a release.
96
+ * @see https://argos-ci.com/docs/build-modes
97
+ */
98
+ mode: "ci" | "monitoring" | null;
99
+ /**
100
+ * Name of the detected CI provider (if available).
101
+ * @example "github-actions", "gitlab-ci", "circleci"
102
+ */
103
+ ciProvider: string | null;
104
+ /**
105
+ * Diff sensitivity threshold between 0 and 1.
106
+ * Higher values make Argos less sensitive to differences.
107
+ */
108
+ threshold: number | null;
109
+ /**
110
+ * Base URL to use for preview links.
111
+ * @example "https://my-preview.example.com"
112
+ */
113
+ previewBaseUrl: string | null;
114
+ /**
115
+ * Skip this build.
116
+ * No screenshots are uploaded, and the commit status is marked as success.
117
+ */
118
+ skipped?: boolean;
86
119
  }
87
- /**
88
- * Upload screenshots to Argos.
89
- */
90
- declare function upload(params: UploadParameters): Promise<{
91
- build: {
92
- id: ArgosAPISchema.components["schemas"]["BuildId"];
93
- number: number;
94
- status: ("accepted" | "rejected") | ("no-changes" | "changes-detected") | ("expired" | "pending" | "progress" | "error" | "aborted");
95
- url: string;
96
- notification: {
97
- description: string;
98
- context: string;
99
- github: {
100
- state: "pending" | "success" | "error" | "failure";
101
- };
102
- gitlab: {
103
- state: "pending" | "running" | "success" | "failed" | "canceled";
104
- };
105
- } | null;
106
- };
107
- screenshots: {
108
- hash: string;
109
- optimizedPath: string;
110
- metadata: _argos_ci_util.ScreenshotMetadata | null;
111
- threshold: number | null;
112
- baseName: string | null;
113
- pwTrace: {
114
- path: string;
115
- hash: string;
116
- } | null;
117
- name: string;
118
- path: string;
119
- }[];
120
- }>;
120
+ declare function readConfig(options?: Partial<Config>): Promise<Config>;
121
+ declare function getConfigFromOptions({ parallel, ...options }: Omit<Partial<Config>, "parallel"> & {
122
+ parallel?: {
123
+ /** Unique build ID for this parallel build */
124
+ nonce: string;
125
+ /** The number of parallel nodes being ran */
126
+ total: number;
127
+ /** The index of the parallel node */
128
+ index?: number;
129
+ } | false | undefined;
130
+ }): Promise<Config>;
121
131
 
122
132
  interface components {
123
133
  schemas: {
@@ -136,6 +146,11 @@ interface components {
136
146
  name: string;
137
147
  baseName?: string | null;
138
148
  metadata?: {
149
+ /**
150
+ * @description Ignored. Can be set to get completions, validations and documentation in some editors.
151
+ * @example https://api.argos-ci.com/v2/screenshot-metadata.json
152
+ */
153
+ $schema?: string;
139
154
  /** @description The URL of the page that was screenshotted */
140
155
  url?: string | null;
141
156
  /** @description An URL to an accessible preview of the screenshot */
@@ -292,30 +307,118 @@ declare function finalize(params: FinalizeParameters): Promise<{
292
307
  builds: components["schemas"]["Build"][];
293
308
  }>;
294
309
 
295
- interface Config {
296
- apiBaseUrl: string;
297
- commit: string;
298
- branch: string;
299
- token: string | null;
300
- buildName: string | null;
301
- parallel: boolean;
302
- parallelNonce: string | null;
303
- parallelIndex: number | null;
304
- parallelTotal: number | null;
305
- referenceBranch: string | null;
306
- referenceCommit: string | null;
307
- repository: string | null;
308
- jobId: string | null;
309
- runId: string | null;
310
- runAttempt: number | null;
311
- prNumber: number | null;
312
- prHeadCommit: string | null;
313
- prBaseBranch: string | null;
314
- mode: "ci" | "monitoring" | null;
315
- ciProvider: string | null;
310
+ type BuildMetadata = ArgosAPISchema.components["schemas"]["BuildMetadata"];
311
+ interface UploadParameters {
312
+ /**
313
+ * Globs that match image file paths to upload.
314
+ */
315
+ files?: string[];
316
+ /**
317
+ * Root directory used to resolve image paths.
318
+ * @default process.cwd()
319
+ */
320
+ root?: string;
321
+ /**
322
+ * Globs that match image file paths to exclude from upload.
323
+ * @default ["**\/*.{png,jpg,jpeg}"]
324
+ */
325
+ ignore?: string[];
326
+ /**
327
+ * Base URL of the Argos API.
328
+ * @default "https://api.argos-ci.com/v2/"
329
+ */
330
+ apiBaseUrl?: string;
331
+ /**
332
+ * Git commit SHA of the build.
333
+ */
334
+ commit?: string;
335
+ /**
336
+ * Git branch name of the build.
337
+ */
338
+ branch?: string;
339
+ /**
340
+ * Argos repository access token.
341
+ */
342
+ token?: string;
343
+ /**
344
+ * Pull request number associated with the build.
345
+ */
346
+ prNumber?: number;
347
+ /**
348
+ * Custom build name. Useful when triggering multiple Argos builds
349
+ * for the same commit.
350
+ */
351
+ buildName?: string;
352
+ /**
353
+ * Build mode to use.
354
+ * - "ci": Review the visual changes introduced by a feature branch and prevent regressions.
355
+ * - "monitoring": Track visual changes outside the standard CI flow, either on a schedule or before a release.
356
+ * @see https://argos-ci.com/docs/build-modes
357
+ * @default "ci"
358
+ */
359
+ mode?: "ci" | "monitoring";
360
+ /**
361
+ * Parallel test suite configuration.
362
+ * @default false
363
+ */
364
+ parallel?: {
365
+ /** Unique build identifier shared across parallel jobs. */
366
+ nonce: string;
367
+ /** Total number of parallel jobs, set to -1 to finalize manually. */
368
+ total: number;
369
+ /** Index of the current job (must start from 1). */
370
+ index?: number;
371
+ } | false;
372
+ /**
373
+ * Branch used as the baseline for screenshot comparison.
374
+ */
375
+ referenceBranch?: string;
376
+ /**
377
+ * Commit SHA used as the baseline for screenshot comparison.
378
+ */
379
+ referenceCommit?: string;
380
+ /**
381
+ * Diff sensitivity threshold between 0 and 1.
382
+ * Higher values make Argos less sensitive to differences.
383
+ * @default 0.5
384
+ */
385
+ threshold?: number;
386
+ /**
387
+ * Additional build metadata.
388
+ */
389
+ metadata?: BuildMetadata;
390
+ /**
391
+ * Preview URL configuration.
392
+ * Can be a fixed base URL or a function to transform URLs dynamically.
393
+ */
394
+ previewUrl?: {
395
+ baseUrl: string;
396
+ } | ((url: string) => string);
397
+ /**
398
+ * Mark this build as skipped.
399
+ * No screenshots are uploaded, and the commit status is marked as success.
400
+ */
401
+ skipped?: boolean;
402
+ }
403
+ interface Screenshot {
404
+ hash: string;
405
+ optimizedPath: string;
406
+ metadata: ScreenshotMetadata | null;
316
407
  threshold: number | null;
317
- previewBaseUrl: string | null;
408
+ baseName: string | null;
409
+ pwTrace: {
410
+ path: string;
411
+ hash: string;
412
+ } | null;
413
+ name: string;
414
+ path: string;
318
415
  }
319
- declare function readConfig(options?: Partial<Config>): Promise<Config>;
416
+ /**
417
+ * Upload screenshots to Argos.
418
+ */
419
+ declare function upload(params: UploadParameters): Promise<{
420
+ build: ArgosAPISchema.components["schemas"]["Build"];
421
+ screenshots: Screenshot[];
422
+ }>;
320
423
 
321
- export { type Config, type FinalizeParameters, type UploadParameters, finalize, readConfig, upload };
424
+ export { type Config, type FinalizeParameters, type UploadParameters, finalize, getConfigFromOptions, readConfig, upload };
package/dist/index.js CHANGED
@@ -1,6 +1,3 @@
1
- // src/upload.ts
2
- import { createClient, throwAPIError } from "@argos-ci/api-client";
3
-
4
1
  // src/config.ts
5
2
  import convict from "convict";
6
3
 
@@ -131,10 +128,12 @@ var service = {
131
128
  detect: ({ env }) => Boolean(env.BITRISE_IO),
132
129
  config: (context) => {
133
130
  const { env } = context;
131
+ const repository = getRepository(context);
134
132
  return {
135
133
  commit: env.BITRISE_GIT_COMMIT || null,
136
134
  branch: env.BITRISE_GIT_BRANCH || null,
137
- repository: getRepository(context),
135
+ repository,
136
+ originalRepository: repository,
138
137
  jobId: null,
139
138
  runId: null,
140
139
  runAttempt: null,
@@ -178,11 +177,13 @@ var service2 = {
178
177
  detect: ({ env }) => Boolean(env.BUILDKITE),
179
178
  config: (context) => {
180
179
  const { env } = context;
180
+ const repository = getRepository2(context);
181
181
  return {
182
182
  // Buildkite doesn't work well so we fallback to git to ensure we have commit and branch
183
183
  commit: env.BUILDKITE_COMMIT || head() || null,
184
184
  branch: env.BUILDKITE_BRANCH || branch() || null,
185
- repository: getRepository2(context),
185
+ repository,
186
+ originalRepository: repository,
186
187
  jobId: null,
187
188
  runId: null,
188
189
  runAttempt: null,
@@ -207,6 +208,7 @@ var service3 = {
207
208
  branch: env.HEROKU_TEST_RUN_BRANCH || null,
208
209
  owner: null,
209
210
  repository: null,
211
+ originalRepository: null,
210
212
  jobId: null,
211
213
  runId: null,
212
214
  runAttempt: null,
@@ -306,13 +308,16 @@ function getBranchFromPayload(payload) {
306
308
  return null;
307
309
  }
308
310
  function getRepository3(context, payload) {
309
- const { env } = context;
310
311
  if (payload && "pull_request" in payload && payload.pull_request) {
311
312
  const pr = payload.pull_request;
312
313
  if (pr.head && pr.head.repo && pr.head.repo.full_name) {
313
314
  return pr.head.repo.full_name;
314
315
  }
315
316
  }
317
+ return getOriginalRepository(context);
318
+ }
319
+ function getOriginalRepository(context) {
320
+ const { env } = context;
316
321
  return env.GITHUB_REPOSITORY || null;
317
322
  }
318
323
  function readEventPayload({ env }) {
@@ -351,6 +356,7 @@ var service4 = {
351
356
  return {
352
357
  commit: sha,
353
358
  repository: getRepository3(context, payload),
359
+ originalRepository: getOriginalRepository(context),
354
360
  jobId: env.GITHUB_JOB || null,
355
361
  runId: env.GITHUB_RUN_ID || null,
356
362
  runAttempt: env.GITHUB_RUN_ATTEMPT ? Number(env.GITHUB_RUN_ATTEMPT) : null,
@@ -380,6 +386,10 @@ function getRepository4(context) {
380
386
  if (env.CIRCLE_PR_REPONAME && env.CIRCLE_PR_USERNAME) {
381
387
  return `${env.CIRCLE_PR_USERNAME}/${env.CIRCLE_PR_REPONAME}`;
382
388
  }
389
+ return getOriginalRepository2(context);
390
+ }
391
+ function getOriginalRepository2(context) {
392
+ const { env } = context;
383
393
  if (env.CIRCLE_PROJECT_USERNAME && env.CIRCLE_PROJECT_REPONAME) {
384
394
  return `${env.CIRCLE_PROJECT_USERNAME}/${env.CIRCLE_PROJECT_REPONAME}`;
385
395
  }
@@ -395,6 +405,7 @@ var service5 = {
395
405
  commit: env.CIRCLE_SHA1 || null,
396
406
  branch: env.CIRCLE_BRANCH || null,
397
407
  repository: getRepository4(context),
408
+ originalRepository: getOriginalRepository2(context),
398
409
  jobId: null,
399
410
  runId: null,
400
411
  runAttempt: null,
@@ -415,10 +426,11 @@ function getRepository5(context) {
415
426
  if (env.TRAVIS_PULL_REQUEST_SLUG) {
416
427
  return env.TRAVIS_PULL_REQUEST_SLUG;
417
428
  }
418
- if (env.TRAVIS_REPO_SLUG) {
419
- return env.TRAVIS_REPO_SLUG;
420
- }
421
- return null;
429
+ return getOriginalRepository3(context);
430
+ }
431
+ function getOriginalRepository3(context) {
432
+ const { env } = context;
433
+ return env.TRAVIS_REPO_SLUG || null;
422
434
  }
423
435
  function getPrNumber3(context) {
424
436
  const { env } = context;
@@ -437,6 +449,7 @@ var service6 = {
437
449
  commit: env.TRAVIS_COMMIT || null,
438
450
  branch: env.TRAVIS_BRANCH || null,
439
451
  repository: getRepository5(ctx),
452
+ originalRepository: getOriginalRepository3(ctx),
440
453
  jobId: null,
441
454
  runId: null,
442
455
  runAttempt: null,
@@ -457,6 +470,10 @@ function getRepository6(context) {
457
470
  if (env.CI_MERGE_REQUEST_PROJECT_PATH) {
458
471
  return env.CI_MERGE_REQUEST_PROJECT_PATH;
459
472
  }
473
+ return getOriginalRepository4(context);
474
+ }
475
+ function getOriginalRepository4(context) {
476
+ const { env } = context;
460
477
  return env.CI_PROJECT_PATH || null;
461
478
  }
462
479
  var service7 = {
@@ -469,6 +486,7 @@ var service7 = {
469
486
  commit: env.CI_COMMIT_SHA || null,
470
487
  branch: env.CI_COMMIT_REF_NAME || null,
471
488
  repository: getRepository6(context),
489
+ originalRepository: getOriginalRepository4(context),
472
490
  jobId: null,
473
491
  runId: null,
474
492
  runAttempt: null,
@@ -496,10 +514,12 @@ var service8 = {
496
514
  key: "git",
497
515
  detect: () => checkIsGitRepository(),
498
516
  config: () => {
517
+ const repository = getRepository7();
499
518
  return {
500
519
  commit: head() || null,
501
520
  branch: branch() || null,
502
- repository: getRepository7(),
521
+ repository,
522
+ originalRepository: repository,
503
523
  jobId: null,
504
524
  runId: null,
505
525
  runAttempt: null,
@@ -731,6 +751,11 @@ var schema = {
731
751
  default: null,
732
752
  nullable: true
733
753
  },
754
+ originalRepository: {
755
+ format: String,
756
+ default: null,
757
+ nullable: true
758
+ },
734
759
  ciProvider: {
735
760
  format: String,
736
761
  default: null,
@@ -747,6 +772,11 @@ var schema = {
747
772
  format: String,
748
773
  default: null,
749
774
  nullable: true
775
+ },
776
+ skipped: {
777
+ env: "ARGOS_SKIPPED",
778
+ format: Boolean,
779
+ default: false
750
780
  }
751
781
  };
752
782
  function createConfig() {
@@ -777,6 +807,7 @@ async function readConfig(options = {}) {
777
807
  referenceBranch: options.referenceBranch || defaultConfig.referenceBranch || null,
778
808
  referenceCommit: options.referenceCommit || defaultConfig.referenceCommit || null,
779
809
  repository: ciEnv?.repository || null,
810
+ originalRepository: ciEnv?.originalRepository || null,
780
811
  jobId: ciEnv?.jobId || null,
781
812
  runId: ciEnv?.runId || null,
782
813
  runAttempt: ciEnv?.runAttempt || null,
@@ -786,7 +817,8 @@ async function readConfig(options = {}) {
786
817
  parallelIndex: options.parallelIndex ?? defaultConfig.parallelIndex ?? null,
787
818
  mode: options.mode || defaultConfig.mode || null,
788
819
  ciProvider: ciEnv?.key || null,
789
- previewBaseUrl: defaultConfig.previewBaseUrl || null
820
+ previewBaseUrl: defaultConfig.previewBaseUrl || null,
821
+ skipped: options.skipped ?? defaultConfig.skipped ?? false
790
822
  });
791
823
  if (!config.get("branch") || !config.get("commit")) {
792
824
  throw new Error(
@@ -796,6 +828,83 @@ async function readConfig(options = {}) {
796
828
  config.validate();
797
829
  return config.get();
798
830
  }
831
+ async function getConfigFromOptions({
832
+ parallel,
833
+ ...options
834
+ }) {
835
+ return readConfig({
836
+ ...options,
837
+ parallel: parallel !== void 0 ? Boolean(parallel) : void 0,
838
+ parallelNonce: parallel ? parallel.nonce : void 0,
839
+ parallelTotal: parallel ? parallel.total : void 0,
840
+ parallelIndex: parallel ? parallel.index : void 0
841
+ });
842
+ }
843
+
844
+ // src/finalize.ts
845
+ import { createClient, throwAPIError } from "@argos-ci/api-client";
846
+
847
+ // src/auth.ts
848
+ var base64Encode = (obj) => Buffer.from(JSON.stringify(obj), "utf8").toString("base64");
849
+ function getAuthToken(args) {
850
+ const {
851
+ token,
852
+ ciProvider,
853
+ originalRepository: repository,
854
+ jobId,
855
+ runId,
856
+ prNumber
857
+ } = args;
858
+ if (token) {
859
+ return token;
860
+ }
861
+ switch (ciProvider) {
862
+ case "github-actions": {
863
+ if (!repository || !jobId || !runId) {
864
+ throw new Error(
865
+ `Automatic GitHub Actions variables detection failed. Please add the 'ARGOS_TOKEN'`
866
+ );
867
+ }
868
+ const [owner, repo] = repository.split("/");
869
+ return `tokenless-github-${base64Encode({
870
+ owner,
871
+ repository: repo,
872
+ jobId,
873
+ runId,
874
+ prNumber: prNumber ?? void 0
875
+ })}`;
876
+ }
877
+ default:
878
+ throw new Error("Missing Argos repository token 'ARGOS_TOKEN'");
879
+ }
880
+ }
881
+
882
+ // src/finalize.ts
883
+ async function finalize(params) {
884
+ const config = await readConfig({
885
+ parallelNonce: params.parallel?.nonce
886
+ });
887
+ const authToken = getAuthToken(config);
888
+ const apiClient = createClient({
889
+ baseUrl: config.apiBaseUrl,
890
+ authToken
891
+ });
892
+ if (!config.parallelNonce) {
893
+ throw new Error("parallel.nonce is required to finalize the build");
894
+ }
895
+ const finalizeBuildsResult = await apiClient.POST("/builds/finalize", {
896
+ body: {
897
+ parallelNonce: config.parallelNonce
898
+ }
899
+ });
900
+ if (finalizeBuildsResult.error) {
901
+ throwAPIError(finalizeBuildsResult.error);
902
+ }
903
+ return finalizeBuildsResult.data;
904
+ }
905
+
906
+ // src/upload.ts
907
+ import { createClient as createClient2, throwAPIError as throwAPIError2 } from "@argos-ci/api-client";
799
908
 
800
909
  // src/discovery.ts
801
910
  import { resolve } from "path";
@@ -896,40 +1005,6 @@ var hashFile = async (filepath) => {
896
1005
  return hash.digest("hex");
897
1006
  };
898
1007
 
899
- // src/auth.ts
900
- var base64Encode = (obj) => Buffer.from(JSON.stringify(obj), "utf8").toString("base64");
901
- function getAuthToken({
902
- token,
903
- ciProvider,
904
- repository,
905
- jobId,
906
- runId,
907
- prNumber
908
- }) {
909
- if (token) {
910
- return token;
911
- }
912
- switch (ciProvider) {
913
- case "github-actions": {
914
- if (!repository || !jobId || !runId) {
915
- throw new Error(
916
- `Automatic GitHub Actions variables detection failed. Please add the 'ARGOS_TOKEN'`
917
- );
918
- }
919
- const [owner, repo] = repository.split("/");
920
- return `tokenless-github-${base64Encode({
921
- owner,
922
- repository: repo,
923
- jobId,
924
- runId,
925
- prNumber: prNumber ?? void 0
926
- })}`;
927
- }
928
- default:
929
- throw new Error("Missing Argos repository token 'ARGOS_TOKEN'");
930
- }
931
- }
932
-
933
1008
  // src/s3.ts
934
1009
  import { readFile } from "fs/promises";
935
1010
  async function uploadFile(input) {
@@ -962,7 +1037,10 @@ var chunk = (collection, size) => {
962
1037
  };
963
1038
 
964
1039
  // src/upload.ts
965
- import { getPlaywrightTracePath, readMetadata } from "@argos-ci/util";
1040
+ import {
1041
+ getPlaywrightTracePath,
1042
+ readMetadata
1043
+ } from "@argos-ci/util";
966
1044
 
967
1045
  // src/version.ts
968
1046
  import { readVersionFromPackage } from "@argos-ci/util";
@@ -976,66 +1054,48 @@ async function getArgosCoreSDKIdentifier() {
976
1054
 
977
1055
  // src/upload.ts
978
1056
  var CHUNK_SIZE = 10;
979
- async function getConfigFromOptions({
980
- parallel,
981
- ...options
982
- }) {
983
- return readConfig({
984
- ...options,
985
- parallel: parallel !== void 0 ? Boolean(parallel) : void 0,
986
- parallelNonce: parallel ? parallel.nonce : void 0,
987
- parallelTotal: parallel ? parallel.total : void 0,
988
- parallelIndex: parallel ? parallel.index : void 0
989
- });
990
- }
991
- async function uploadFilesToS3(files) {
992
- debug(`Split files in chunks of ${CHUNK_SIZE}`);
993
- const chunks = chunk(files, CHUNK_SIZE);
994
- debug(`Starting upload of ${chunks.length} chunks`);
995
- for (let i = 0; i < chunks.length; i++) {
996
- debug(`Uploading chunk ${i + 1}/${chunks.length}`);
997
- const timeLabel = `Chunk ${i + 1}/${chunks.length}`;
998
- debugTime(timeLabel);
999
- const chunk2 = chunks[i];
1000
- if (!chunk2) {
1001
- throw new Error(`Invariant: chunk ${i} is empty`);
1002
- }
1003
- await Promise.all(
1004
- chunk2.map(async ({ url, path, contentType }) => {
1005
- await uploadFile({
1006
- url,
1007
- path,
1008
- contentType
1009
- });
1010
- })
1011
- );
1012
- debugTimeEnd(timeLabel);
1013
- }
1014
- }
1015
- function formatPreviewUrl(url, formatter) {
1016
- if (typeof formatter === "function") {
1017
- return formatter(url);
1018
- }
1019
- const urlObj = new URL(url);
1020
- return new URL(
1021
- urlObj.pathname + urlObj.search + urlObj.hash,
1022
- formatter.baseUrl
1023
- ).href;
1024
- }
1025
1057
  async function upload(params) {
1026
1058
  debug("Starting upload with params", params);
1027
1059
  const [config, argosSdk] = await Promise.all([
1028
1060
  getConfigFromOptions(params),
1029
1061
  getArgosCoreSDKIdentifier()
1030
1062
  ]);
1031
- const previewUrlFormatter = params.previewUrl ?? (config.previewBaseUrl ? { baseUrl: config.previewBaseUrl } : void 0);
1032
- const files = params.files ?? ["**/*.{png,jpg,jpeg}"];
1033
- debug("Using config and files", config, files);
1034
1063
  const authToken = getAuthToken(config);
1035
- const apiClient = createClient({
1064
+ const apiClient = createClient2({
1036
1065
  baseUrl: config.apiBaseUrl,
1037
1066
  authToken
1038
1067
  });
1068
+ if (config.skipped) {
1069
+ const createBuildResponse2 = await apiClient.POST("/builds", {
1070
+ body: {
1071
+ commit: config.commit,
1072
+ branch: config.branch,
1073
+ name: config.buildName,
1074
+ mode: config.mode,
1075
+ parallel: config.parallel,
1076
+ parallelNonce: config.parallelNonce,
1077
+ prNumber: config.prNumber,
1078
+ prHeadCommit: config.prHeadCommit,
1079
+ referenceBranch: config.referenceBranch,
1080
+ referenceCommit: config.referenceCommit,
1081
+ argosSdk,
1082
+ ciProvider: config.ciProvider,
1083
+ runId: config.runId,
1084
+ runAttempt: config.runAttempt,
1085
+ skipped: true,
1086
+ screenshotKeys: [],
1087
+ pwTraceKeys: [],
1088
+ parentCommits: []
1089
+ }
1090
+ });
1091
+ if (createBuildResponse2.error) {
1092
+ throwAPIError2(createBuildResponse2.error);
1093
+ }
1094
+ return { build: createBuildResponse2.data.build, screenshots: [] };
1095
+ }
1096
+ const previewUrlFormatter = params.previewUrl ?? (config.previewBaseUrl ? { baseUrl: config.previewBaseUrl } : void 0);
1097
+ const files = params.files ?? ["**/*.{png,jpg,jpeg}"];
1098
+ debug("Using config and files", config, files);
1039
1099
  const foundScreenshots = await discoverScreenshots(files, {
1040
1100
  root: params.root,
1041
1101
  ignore: params.ignore
@@ -1077,7 +1137,7 @@ async function upload(params) {
1077
1137
  debug("Fetch project");
1078
1138
  const projectResponse = await apiClient.GET("/project");
1079
1139
  if (projectResponse.error) {
1080
- throwAPIError(projectResponse.error);
1140
+ throwAPIError2(projectResponse.error);
1081
1141
  }
1082
1142
  debug("Project fetched", projectResponse.data);
1083
1143
  const { defaultBaseBranch, hasRemoteContentAccess } = projectResponse.data;
@@ -1148,7 +1208,7 @@ async function upload(params) {
1148
1208
  }
1149
1209
  });
1150
1210
  if (createBuildResponse.error) {
1151
- throwAPIError(createBuildResponse.error);
1211
+ throwAPIError2(createBuildResponse.error);
1152
1212
  }
1153
1213
  const result = createBuildResponse.data;
1154
1214
  debug("Got uploads url", result);
@@ -1202,37 +1262,47 @@ async function upload(params) {
1202
1262
  }
1203
1263
  });
1204
1264
  if (uploadBuildResponse.error) {
1205
- throwAPIError(uploadBuildResponse.error);
1265
+ throwAPIError2(uploadBuildResponse.error);
1206
1266
  }
1207
1267
  return { build: uploadBuildResponse.data.build, screenshots };
1208
1268
  }
1209
-
1210
- // src/finalize.ts
1211
- import { createClient as createClient2, throwAPIError as throwAPIError2 } from "@argos-ci/api-client";
1212
- async function finalize(params) {
1213
- const config = await readConfig({
1214
- parallelNonce: params.parallel?.nonce
1215
- });
1216
- const authToken = getAuthToken(config);
1217
- const apiClient = createClient2({
1218
- baseUrl: config.apiBaseUrl,
1219
- authToken
1220
- });
1221
- if (!config.parallelNonce) {
1222
- throw new Error("parallel.nonce is required to finalize the build");
1223
- }
1224
- const finalizeBuildsResult = await apiClient.POST("/builds/finalize", {
1225
- body: {
1226
- parallelNonce: config.parallelNonce
1269
+ async function uploadFilesToS3(files) {
1270
+ debug(`Split files in chunks of ${CHUNK_SIZE}`);
1271
+ const chunks = chunk(files, CHUNK_SIZE);
1272
+ debug(`Starting upload of ${chunks.length} chunks`);
1273
+ for (let i = 0; i < chunks.length; i++) {
1274
+ debug(`Uploading chunk ${i + 1}/${chunks.length}`);
1275
+ const timeLabel = `Chunk ${i + 1}/${chunks.length}`;
1276
+ debugTime(timeLabel);
1277
+ const chunk2 = chunks[i];
1278
+ if (!chunk2) {
1279
+ throw new Error(`Invariant: chunk ${i} is empty`);
1227
1280
  }
1228
- });
1229
- if (finalizeBuildsResult.error) {
1230
- throwAPIError2(finalizeBuildsResult.error);
1281
+ await Promise.all(
1282
+ chunk2.map(async ({ url, path, contentType }) => {
1283
+ await uploadFile({
1284
+ url,
1285
+ path,
1286
+ contentType
1287
+ });
1288
+ })
1289
+ );
1290
+ debugTimeEnd(timeLabel);
1231
1291
  }
1232
- return finalizeBuildsResult.data;
1292
+ }
1293
+ function formatPreviewUrl(url, formatter) {
1294
+ if (typeof formatter === "function") {
1295
+ return formatter(url);
1296
+ }
1297
+ const urlObj = new URL(url);
1298
+ return new URL(
1299
+ urlObj.pathname + urlObj.search + urlObj.hash,
1300
+ formatter.baseUrl
1301
+ ).href;
1233
1302
  }
1234
1303
  export {
1235
1304
  finalize,
1305
+ getConfigFromOptions,
1236
1306
  readConfig,
1237
1307
  upload
1238
1308
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@argos-ci/core",
3
3
  "description": "Node.js SDK for visual testing with Argos.",
4
- "version": "4.1.5",
4
+ "version": "4.2.0",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
7
7
  "exports": {
@@ -40,20 +40,20 @@
40
40
  "access": "public"
41
41
  },
42
42
  "dependencies": {
43
- "@argos-ci/api-client": "0.11.0",
44
- "@argos-ci/util": "3.1.0",
43
+ "@argos-ci/api-client": "0.12.0",
44
+ "@argos-ci/util": "3.1.1",
45
45
  "convict": "^6.2.4",
46
- "debug": "^4.4.0",
46
+ "debug": "^4.4.3",
47
47
  "fast-glob": "^3.3.3",
48
- "sharp": "^0.34.3",
49
- "tmp": "^0.2.3"
48
+ "sharp": "^0.34.4",
49
+ "tmp": "^0.2.5"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@octokit/webhooks": "^14.1.3",
53
53
  "@types/convict": "^6.1.6",
54
54
  "@types/debug": "^4.1.12",
55
55
  "@types/tmp": "^0.2.6",
56
- "msw": "^2.10.4",
56
+ "msw": "^2.11.3",
57
57
  "vitest": "catalog:"
58
58
  },
59
59
  "scripts": {
@@ -64,5 +64,5 @@
64
64
  "lint": "eslint .",
65
65
  "test": "vitest"
66
66
  },
67
- "gitHead": "a865ca5004133efd5bf86e866116afabe3c1a478"
67
+ "gitHead": "867a93c5ffc01d55c7385d3ac3903c4c3ab270b6"
68
68
  }