@sharadtech/infralytiqs-sdk 1.0.2 → 1.0.3

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 (65) hide show
  1. package/buildScripts/Jenkinsfile.deploy +241 -125
  2. package/clients/publicis/arc/README.md +212 -0
  3. package/clients/publicis/arc/package-lock.json +808 -0
  4. package/clients/publicis/arc/package.json +23 -0
  5. package/clients/publicis/arc/rollup.config.mjs +28 -0
  6. package/clients/publicis/arc/src/index.js +2900 -0
  7. package/clients/publicis/atl/README.md +203 -0
  8. package/clients/publicis/atl/package-lock.json +808 -0
  9. package/clients/publicis/atl/package.json +23 -0
  10. package/clients/publicis/atl/rollup.config.mjs +28 -0
  11. package/clients/publicis/atl/src/index.js +2902 -0
  12. package/clients/publicis/colab/README.md +213 -0
  13. package/clients/publicis/colab/package-lock.json +808 -0
  14. package/clients/publicis/colab/package.json +23 -0
  15. package/clients/publicis/colab/rollup.config.mjs +28 -0
  16. package/clients/publicis/colab/src/index.js +2901 -0
  17. package/clients/publicis/fnacdarty/README.md +210 -0
  18. package/clients/publicis/fnacdarty/package-lock.json +808 -0
  19. package/clients/publicis/fnacdarty/package.json +23 -0
  20. package/clients/publicis/fnacdarty/rollup.config.mjs +28 -0
  21. package/clients/publicis/fnacdarty/src/index.js +2900 -0
  22. package/clients/publicis/garnier/README.md +206 -0
  23. package/clients/publicis/garnier/package-lock.json +808 -0
  24. package/clients/publicis/garnier/package.json +23 -0
  25. package/clients/publicis/garnier/rollup.config.mjs +28 -0
  26. package/clients/publicis/garnier/src/index.js +2894 -0
  27. package/clients/publicis/pmigtr/README.md +212 -0
  28. package/clients/publicis/pmigtr/package-lock.json +808 -0
  29. package/clients/publicis/pmigtr/package.json +23 -0
  30. package/clients/publicis/pmigtr/rollup.config.mjs +28 -0
  31. package/clients/publicis/pmigtr/src/index.js +2903 -0
  32. package/clients/publicis/ps/package-lock.json +2 -2
  33. package/clients/publicis/ps/package.json +1 -1
  34. package/clients/publicis/px/README.md +209 -0
  35. package/clients/publicis/px/package-lock.json +808 -0
  36. package/clients/publicis/px/package.json +23 -0
  37. package/clients/publicis/px/rollup.config.mjs +28 -0
  38. package/clients/publicis/px/src/index.js +2899 -0
  39. package/clients/publicis/pxp/README.md +212 -0
  40. package/clients/publicis/pxp/package-lock.json +808 -0
  41. package/clients/publicis/pxp/package.json +23 -0
  42. package/clients/publicis/pxp/rollup.config.mjs +28 -0
  43. package/clients/publicis/pxp/src/index.js +2900 -0
  44. package/clients/publicis/razorfish/README.md +210 -0
  45. package/clients/publicis/razorfish/package-lock.json +808 -0
  46. package/clients/publicis/razorfish/package.json +23 -0
  47. package/clients/publicis/razorfish/rollup.config.mjs +28 -0
  48. package/clients/publicis/razorfish/src/index.js +2900 -0
  49. package/clients/publicis/stellantis/README.md +208 -0
  50. package/clients/publicis/stellantis/package-lock.json +808 -0
  51. package/clients/publicis/stellantis/package.json +23 -0
  52. package/clients/publicis/stellantis/rollup.config.mjs +28 -0
  53. package/clients/publicis/stellantis/src/index.js +2895 -0
  54. package/clients/publicis/visa/README.md +208 -0
  55. package/clients/publicis/visa/package-lock.json +808 -0
  56. package/clients/publicis/visa/package.json +23 -0
  57. package/clients/publicis/visa/rollup.config.mjs +28 -0
  58. package/clients/publicis/visa/src/index.js +2894 -0
  59. package/dist/infralytiqs.js +243 -71
  60. package/dist/infralytiqs.min.js +2 -2
  61. package/package.json +1 -1
  62. package/src/envConfig.ts +1 -1
  63. package/src/remoteConfig.ts +164 -0
  64. package/src/tracker.ts +30 -0
  65. package/src/types.ts +10 -2
@@ -8,16 +8,21 @@
8
8
  // Served via : https://assets.infralytiqs.com/cdn/infralytiqs.min.js
9
9
  //
10
10
  // B) Per-client bootstraps (built directly from this git repository under
11
- // clients/<vendor>/<app>). Currently the only client wired in is:
11
+ // clients/<vendor>/<app>). Each client uploads to
12
+ // s3://infralytiqs/cl/<vendor>/<app>/infralytiqs-bootstrap.min.js and is
13
+ // served from https://assets.infralytiqs.com/cl/<vendor>/<app>/...min.js
12
14
  //
13
- // clients/publicis/ps -> s3://infralytiqs/cl/publicis/ps/infralytiqs-bootstrap.min.js
14
- // https://assets.infralytiqs.com/cl/publicis/ps/infralytiqs-bootstrap.min.js
15
- //
16
- // Additional clients can be wired in by adding another build/upload/
17
- // verify stage trio with its own boolean job parameter.
15
+ // The set of client bootstraps is data-driven: see the clientList() function
16
+ // near the bottom of this file. To wire in a new client you only need to:
17
+ // 1. add one booleanParam(name: 'DEPLOY_CLIENT_PUBLICIS_<KEY>', ...), and
18
+ // 2. add one row to clientList() ([key, dir, s3, name, label]).
19
+ // No new stages are required the Build / Upload / Verify stages iterate the
20
+ // selected clients. (This loop-based design also keeps the generated pipeline
21
+ // method under the JVM 64 KB bytecode limit that the previous one-stage-trio-
22
+ // per-client layout eventually blew past with a MethodTooLargeException.)
18
23
  //
19
24
  // Per-artifact stages can be toggled independently from the build form via
20
- // the DEPLOY_SDK and DEPLOY_CLIENT_PUBLICIS_PS boolean job parameters.
25
+ // the DEPLOY_SDK and DEPLOY_CLIENT_PUBLICIS_* boolean job parameters.
21
26
  //
22
27
  // Required Jenkins credentials:
23
28
  // - aws-infralytiqs-deploy : "Username with password" credential where
@@ -53,6 +58,61 @@ pipeline {
53
58
  defaultValue: true,
54
59
  description: 'Build clients/publicis/ps from THIS repository and upload its minified bootstrap to s3://infralytiqs/cl/publicis/ps/infralytiqs-bootstrap.min.js'
55
60
  )
61
+ booleanParam(
62
+ name: 'DEPLOY_CLIENT_PUBLICIS_ATL',
63
+ defaultValue: true,
64
+ description: 'Build clients/publicis/atl from THIS repository and upload its minified bootstrap to s3://infralytiqs/cl/publicis/atl/infralytiqs-bootstrap.min.js'
65
+ )
66
+ booleanParam(
67
+ name: 'DEPLOY_CLIENT_PUBLICIS_GARNIER',
68
+ defaultValue: true,
69
+ description: 'Build clients/publicis/garnier from THIS repository and upload its minified bootstrap to s3://infralytiqs/cl/publicis/garnier/infralytiqs-bootstrap.min.js'
70
+ )
71
+ booleanParam(
72
+ name: 'DEPLOY_CLIENT_PUBLICIS_PX',
73
+ defaultValue: true,
74
+ description: 'Build clients/publicis/px from THIS repository and upload its minified bootstrap to s3://infralytiqs/cl/publicis/px/infralytiqs-bootstrap.min.js'
75
+ )
76
+ booleanParam(
77
+ name: 'DEPLOY_CLIENT_PUBLICIS_VISA',
78
+ defaultValue: true,
79
+ description: 'Build clients/publicis/visa from THIS repository and upload its minified bootstrap to s3://infralytiqs/cl/publicis/visa/infralytiqs-bootstrap.min.js'
80
+ )
81
+ booleanParam(
82
+ name: 'DEPLOY_CLIENT_PUBLICIS_STELLANTIS',
83
+ defaultValue: true,
84
+ description: 'Build clients/publicis/stellantis from THIS repository and upload its minified bootstrap to s3://infralytiqs/cl/publicis/stellantis/infralytiqs-bootstrap.min.js'
85
+ )
86
+ booleanParam(
87
+ name: 'DEPLOY_CLIENT_PUBLICIS_COLAB',
88
+ defaultValue: true,
89
+ description: 'Build clients/publicis/colab from THIS repository and upload its minified bootstrap to s3://infralytiqs/cl/publicis/colab/infralytiqs-bootstrap.min.js'
90
+ )
91
+ booleanParam(
92
+ name: 'DEPLOY_CLIENT_PUBLICIS_ARC',
93
+ defaultValue: true,
94
+ description: 'Build clients/publicis/arc from THIS repository and upload its minified bootstrap to s3://infralytiqs/cl/publicis/arc/infralytiqs-bootstrap.min.js'
95
+ )
96
+ booleanParam(
97
+ name: 'DEPLOY_CLIENT_PUBLICIS_PXP',
98
+ defaultValue: true,
99
+ description: 'Build clients/publicis/pxp from THIS repository and upload its minified bootstrap to s3://infralytiqs/cl/publicis/pxp/infralytiqs-bootstrap.min.js'
100
+ )
101
+ booleanParam(
102
+ name: 'DEPLOY_CLIENT_PUBLICIS_RAZORFISH',
103
+ defaultValue: true,
104
+ description: 'Build clients/publicis/razorfish from THIS repository and upload its minified bootstrap to s3://infralytiqs/cl/publicis/razorfish/infralytiqs-bootstrap.min.js'
105
+ )
106
+ booleanParam(
107
+ name: 'DEPLOY_CLIENT_PUBLICIS_FNACDARTY',
108
+ defaultValue: true,
109
+ description: 'Build clients/publicis/fnacdarty from THIS repository and upload its minified bootstrap to s3://infralytiqs/cl/publicis/fnacdarty/infralytiqs-bootstrap.min.js'
110
+ )
111
+ booleanParam(
112
+ name: 'DEPLOY_CLIENT_PUBLICIS_PMIGTR',
113
+ defaultValue: true,
114
+ description: 'Build clients/publicis/pmigtr from THIS repository and upload its minified bootstrap to s3://infralytiqs/cl/publicis/pmigtr/infralytiqs-bootstrap.min.js'
115
+ )
56
116
  }
57
117
 
58
118
  options {
@@ -94,15 +154,14 @@ pipeline {
94
154
  CDN_VERIFY_RETRIES = '6' // number of attempts
95
155
  CDN_VERIFY_SLEEP_SEC = '10' // delay between attempts
96
156
 
97
- // ---- clients/publicis/ps (client-specific bootstrap) ----
157
+ // ---- Client bootstrap build/upload constants ----
98
158
  // The git repository is checked out into this subdirectory by the
99
159
  // "Checkout Source" stage so it doesn't collide with the npm artifact
100
160
  // tarball or the AWS CLI binaries downloaded into the workspace root.
161
+ // The per-client source dir / S3 prefix / etc. are data-driven — see
162
+ // clientList() at the bottom of this file.
101
163
  REPO_SRC_DIR = 'repo-src'
102
- CLIENT_PS_REL_DIR = 'clients/publicis/ps'
103
- CLIENT_PS_BOOTSTRAP_MIN = 'infralytiqs-bootstrap.min.js'
104
- CLIENT_PS_S3_KEY_PREFIX = 'cl/publicis/ps'
105
- CLIENT_PS_CDN_VERIFY_PATH = 'cl/publicis/ps/infralytiqs-bootstrap.min.js'
164
+ CLIENT_BOOTSTRAP_MIN = 'infralytiqs-bootstrap.min.js'
106
165
  }
107
166
 
108
167
  // If you use the Jenkins NodeJS plugin, uncomment and set the tool name:
@@ -117,8 +176,9 @@ pipeline {
117
176
  // use deleteDir() to wipe the workspace before every build.
118
177
  deleteDir()
119
178
  script {
120
- if (!params.DEPLOY_SDK && !params.DEPLOY_CLIENT_PUBLICIS_PS) {
121
- error "Nothing to do: both DEPLOY_SDK and DEPLOY_CLIENT_PUBLICIS_PS are unchecked."
179
+ def clients = selectedClients()
180
+ if (!params.DEPLOY_SDK && clients.isEmpty()) {
181
+ error "Nothing to do: DEPLOY_SDK and all DEPLOY_CLIENT_PUBLICIS_* parameters are unchecked."
122
182
  }
123
183
  def labelParts = []
124
184
  if (params.DEPLOY_SDK) {
@@ -127,9 +187,7 @@ pipeline {
127
187
  }
128
188
  labelParts << "sdk:${params.DEPLOY_VERSION}"
129
189
  }
130
- if (params.DEPLOY_CLIENT_PUBLICIS_PS) {
131
- labelParts << 'publicis/ps'
132
- }
190
+ clients.each { c -> labelParts << c.label }
133
191
  currentBuild.displayName = "#${env.BUILD_NUMBER} • ${labelParts.join(' + ')}"
134
192
  }
135
193
  }
@@ -212,7 +270,7 @@ pipeline {
212
270
 
213
271
  // ---------------------------------------------------------------------
214
272
  stage('Checkout Source (client builds)') {
215
- when { expression { return params.DEPLOY_CLIENT_PUBLICIS_PS } }
273
+ when { expression { return !selectedClients().isEmpty() } }
216
274
  steps {
217
275
  // The repository is checked out into a sub-folder so it
218
276
  // doesn't collide with the npm pack output (artifact/) or
@@ -227,34 +285,11 @@ pipeline {
227
285
  }
228
286
 
229
287
  // ---------------------------------------------------------------------
230
- stage('Build Client — publicis/ps') {
231
- when { expression { return params.DEPLOY_CLIENT_PUBLICIS_PS } }
288
+ stage('Build Clients') {
289
+ when { expression { return !selectedClients().isEmpty() } }
232
290
  steps {
233
- sh '''
234
- set -eu
235
- cd "${REPO_SRC_DIR}/${CLIENT_PS_REL_DIR}"
236
- echo "Building client bootstrap in $(pwd) ..."
237
- # `npm ci` requires package-lock.json; fall back to install
238
- # for a fresh checkout that doesn't carry one yet.
239
- if [ -f package-lock.json ]; then
240
- npm ci --no-audit --no-fund
241
- else
242
- npm install --no-audit --no-fund
243
- fi
244
- npm run build
245
- ls -la dist
246
- '''
247
-
248
291
  script {
249
- def relMin = "${env.REPO_SRC_DIR}/${env.CLIENT_PS_REL_DIR}/dist/${env.CLIENT_PS_BOOTSTRAP_MIN}"
250
- if (!fileExists(relMin)) {
251
- error "Build did not produce expected client bootstrap: ${relMin}"
252
- }
253
- env.LOCAL_CLIENT_PS_MIN_PATH = relMin
254
- archiveArtifacts artifacts: "${env.REPO_SRC_DIR}/${env.CLIENT_PS_REL_DIR}/dist/*.js",
255
- fingerprint: true,
256
- onlyIfSuccessful: true
257
- echo "Built client bootstrap: ${relMin}"
292
+ selectedClients().each { c -> buildClient(c) }
258
293
  }
259
294
  }
260
295
  }
@@ -394,83 +429,21 @@ pipeline {
394
429
  }
395
430
 
396
431
  // ---------------------------------------------------------------------
397
- stage('Upload Client publicis/ps') {
398
- when { expression { return params.DEPLOY_CLIENT_PUBLICIS_PS } }
432
+ // Upload + verify every selected client bootstrap. Both the upload and
433
+ // the CDN verification for a given client run back-to-back so a failure
434
+ // is attributed to the right client in the log.
435
+ stage('Upload + Verify Clients') {
436
+ when { expression { return !selectedClients().isEmpty() } }
399
437
  steps {
400
- withCredentials([usernamePassword(
401
- credentialsId: env.AWS_CREDENTIALS_ID,
402
- usernameVariable: 'AWS_ACCESS_KEY_ID',
403
- passwordVariable: 'AWS_SECRET_ACCESS_KEY'
404
- )]) {
405
- sh '''
406
- set -eu
407
- export AWS_DEFAULT_REGION="${AWS_REGION}"
408
- unset AWS_SESSION_TOKEN || true
409
-
410
- "${AWS_CLI_BIN}" --version
411
-
412
- S3_TARGET="s3://${S3_BUCKET}/${CLIENT_PS_S3_KEY_PREFIX}/${CLIENT_PS_BOOTSTRAP_MIN}"
413
- echo "Uploading ${LOCAL_CLIENT_PS_MIN_PATH} -> ${S3_TARGET}"
414
-
415
- "${AWS_CLI_BIN}" s3 cp "${LOCAL_CLIENT_PS_MIN_PATH}" "${S3_TARGET}" \
416
- --region "${AWS_REGION}" \
417
- --content-type "${S3_CONTENT_TYPE}" \
418
- --cache-control "${S3_CACHE_CONTROL}" \
419
- --metadata "client=publicis-ps build-number=${BUILD_NUMBER}"
420
-
421
- echo "S3 head-object verification:"
422
- "${AWS_CLI_BIN}" s3api head-object \
423
- --region "${AWS_REGION}" \
424
- --bucket "${S3_BUCKET}" \
425
- --key "${CLIENT_PS_S3_KEY_PREFIX}/${CLIENT_PS_BOOTSTRAP_MIN}"
426
- '''
438
+ script {
439
+ selectedClients().each { c ->
440
+ uploadClient(c)
441
+ verifyClientOnCdn(c)
442
+ }
427
443
  }
428
444
  }
429
445
  }
430
446
 
431
- // ---------------------------------------------------------------------
432
- stage('Verify Client — publicis/ps on CDN') {
433
- when { expression { return params.DEPLOY_CLIENT_PUBLICIS_PS } }
434
- steps {
435
- sh '''
436
- set -eu
437
- CDN_URL="${CDN_BASE_URL}/${CLIENT_PS_CDN_VERIFY_PATH}"
438
- LOCAL_BANNER=$(head -n 1 "${LOCAL_CLIENT_PS_MIN_PATH}" | tr -d "\n")
439
- echo "Verifying CDN URL: ${CDN_URL}"
440
- echo "Expected banner : ${LOCAL_BANNER}"
441
-
442
- i=1
443
- while [ "${i}" -le "${CDN_VERIFY_RETRIES}" ]; do
444
- STATUS=$(curl -sS -o /tmp/client-ps-cdn.js -w "%{http_code}" \
445
- "${CDN_URL}?cb=$(date +%s)-${BUILD_NUMBER}-${i}" || echo "000")
446
-
447
- if [ "${STATUS}" = "200" ]; then
448
- CDN_BANNER=$(head -n 1 /tmp/client-ps-cdn.js | tr -d "\n")
449
- if [ "${CDN_BANNER}" = "${LOCAL_BANNER}" ]; then
450
- echo "CDN OK — client bootstrap served from ${CDN_URL}"
451
- echo " banner: ${CDN_BANNER}"
452
- exit 0
453
- else
454
- echo "Attempt ${i}: HTTP 200 but banner mismatch (likely CDN cache lag)."
455
- echo " cdn : ${CDN_BANNER}"
456
- echo " local: ${LOCAL_BANNER}"
457
- fi
458
- else
459
- echo "Attempt ${i}: HTTP ${STATUS} from ${CDN_URL}"
460
- fi
461
-
462
- i=$((i + 1))
463
- if [ "${i}" -le "${CDN_VERIFY_RETRIES}" ]; then
464
- sleep "${CDN_VERIFY_SLEEP_SEC}"
465
- fi
466
- done
467
-
468
- echo "CDN verification FAILED after ${CDN_VERIFY_RETRIES} attempts."
469
- exit 1
470
- '''
471
- }
472
- }
473
-
474
447
  // ---------------------------------------------------------------------
475
448
  stage('Finish') {
476
449
  steps {
@@ -485,13 +458,11 @@ pipeline {
485
458
  } else {
486
459
  echo " SDK upload skipped (DEPLOY_SDK = false)."
487
460
  }
488
- if (params.DEPLOY_CLIENT_PUBLICIS_PS) {
489
- echo " Client: publicis/ps"
490
- echo " Source : ${env.REPO_SRC_DIR}/${env.CLIENT_PS_REL_DIR}"
491
- echo " S3 destination : s3://${env.S3_BUCKET}/${env.CLIENT_PS_S3_KEY_PREFIX}/${env.CLIENT_PS_BOOTSTRAP_MIN}"
492
- echo " CDN URL : ${env.CDN_BASE_URL}/${env.CLIENT_PS_CDN_VERIFY_PATH}"
493
- } else {
494
- echo " Client publicis/ps upload skipped (DEPLOY_CLIENT_PUBLICIS_PS = false)."
461
+ selectedClients().each { c ->
462
+ echo " Client: ${c.label}"
463
+ echo " Source : ${env.REPO_SRC_DIR}/${c.dir}"
464
+ echo " S3 destination : s3://${env.S3_BUCKET}/${c.s3}/${env.CLIENT_BOOTSTRAP_MIN}"
465
+ echo " CDN URL : ${env.CDN_BASE_URL}/${c.s3}/${env.CLIENT_BOOTSTRAP_MIN}"
495
466
  }
496
467
  echo "==============================================================="
497
468
  }
@@ -506,8 +477,8 @@ pipeline {
506
477
  if (params.DEPLOY_SDK) {
507
478
  messages << "${env.NPM_PACKAGE_NAME}@${params.DEPLOY_VERSION} -> ${env.CDN_BASE_URL}/${env.CDN_VERIFY_PATH}"
508
479
  }
509
- if (params.DEPLOY_CLIENT_PUBLICIS_PS) {
510
- messages << "publicis/ps -> ${env.CDN_BASE_URL}/${env.CLIENT_PS_CDN_VERIFY_PATH}"
480
+ selectedClients().each { c ->
481
+ messages << "${c.label} -> ${env.CDN_BASE_URL}/${c.s3}/${env.CLIENT_BOOTSTRAP_MIN}"
511
482
  }
512
483
  echo "SUCCESS: Deployed ${messages.join(' ; ')}"
513
484
  }
@@ -521,3 +492,148 @@ pipeline {
521
492
  // installed on this Jenkins.
522
493
  }
523
494
  }
495
+
496
+ // =============================================================================
497
+ // Helper functions (defined at script top level so they are real methods of
498
+ // the WorkflowScript class and are therefore reachable from every script{}
499
+ // block above — unlike top-level `def` variables, which are not).
500
+ // =============================================================================
501
+
502
+ // The single source of truth for the per-client bootstraps this pipeline can
503
+ // deploy. Each row drives the build/upload/verify loops. To add a client:
504
+ // 1. add a booleanParam(name: 'DEPLOY_CLIENT_PUBLICIS_<KEY>') above, and
505
+ // 2. add a row here with the matching uppercased KEY.
506
+ def clientList() {
507
+ return [
508
+ [key: 'PS', dir: 'clients/publicis/ps', s3: 'cl/publicis/ps', name: 'publicis-ps', label: 'publicis/ps'],
509
+ [key: 'ATL', dir: 'clients/publicis/atl', s3: 'cl/publicis/atl', name: 'publicis-atl', label: 'publicis/atl'],
510
+ [key: 'GARNIER', dir: 'clients/publicis/garnier', s3: 'cl/publicis/garnier', name: 'publicis-garnier', label: 'publicis/garnier'],
511
+ [key: 'PX', dir: 'clients/publicis/px', s3: 'cl/publicis/px', name: 'publicis-px', label: 'publicis/px'],
512
+ [key: 'VISA', dir: 'clients/publicis/visa', s3: 'cl/publicis/visa', name: 'publicis-visa', label: 'publicis/visa'],
513
+ [key: 'STELLANTIS', dir: 'clients/publicis/stellantis', s3: 'cl/publicis/stellantis', name: 'publicis-stellantis', label: 'publicis/stellantis'],
514
+ [key: 'COLAB', dir: 'clients/publicis/colab', s3: 'cl/publicis/colab', name: 'publicis-colab', label: 'publicis/colab'],
515
+ [key: 'ARC', dir: 'clients/publicis/arc', s3: 'cl/publicis/arc', name: 'publicis-arc', label: 'publicis/arc'],
516
+ [key: 'PXP', dir: 'clients/publicis/pxp', s3: 'cl/publicis/pxp', name: 'publicis-pxp', label: 'publicis/pxp'],
517
+ [key: 'RAZORFISH', dir: 'clients/publicis/razorfish', s3: 'cl/publicis/razorfish', name: 'publicis-razorfish', label: 'publicis/razorfish'],
518
+ [key: 'FNACDARTY', dir: 'clients/publicis/fnacdarty', s3: 'cl/publicis/fnacdarty', name: 'publicis-fnacdarty', label: 'publicis/fnacdarty'],
519
+ [key: 'PMIGTR', dir: 'clients/publicis/pmigtr', s3: 'cl/publicis/pmigtr', name: 'publicis-pmigtr', label: 'publicis/pmigtr'],
520
+ ]
521
+ }
522
+
523
+ // The subset of clientList() whose DEPLOY_CLIENT_PUBLICIS_<KEY> param is ticked.
524
+ def selectedClients() {
525
+ return clientList().findAll { c -> params["DEPLOY_CLIENT_PUBLICIS_${c.key}"] }
526
+ }
527
+
528
+ // The deterministic local path of a freshly-built client bootstrap. Derived
529
+ // from the client row so we never need to stash it in env between stages
530
+ // (dynamic env subscript assignment is blocked by the Groovy sandbox).
531
+ def clientLocalMin(c) {
532
+ return "${env.REPO_SRC_DIR}/${c.dir}/dist/${env.CLIENT_BOOTSTRAP_MIN}"
533
+ }
534
+
535
+ // Build one client bootstrap from source.
536
+ def buildClient(c) {
537
+ env.CUR_REL_DIR = c.dir
538
+ sh '''
539
+ set -eu
540
+ cd "${REPO_SRC_DIR}/${CUR_REL_DIR}"
541
+ echo "Building client bootstrap in $(pwd) ..."
542
+ # `npm ci` requires package-lock.json; fall back to install for a fresh
543
+ # checkout that doesn't carry one yet.
544
+ if [ -f package-lock.json ]; then
545
+ npm ci --no-audit --no-fund
546
+ else
547
+ npm install --no-audit --no-fund
548
+ fi
549
+ npm run build
550
+ ls -la dist
551
+ '''
552
+ def relMin = clientLocalMin(c)
553
+ if (!fileExists(relMin)) {
554
+ error "Build did not produce expected client bootstrap: ${relMin}"
555
+ }
556
+ archiveArtifacts artifacts: "${env.REPO_SRC_DIR}/${c.dir}/dist/*.js",
557
+ fingerprint: true,
558
+ onlyIfSuccessful: true
559
+ echo "Built client bootstrap: ${relMin}"
560
+ }
561
+
562
+ // Upload one client bootstrap to S3.
563
+ def uploadClient(c) {
564
+ env.CUR_S3_PREFIX = c.s3
565
+ env.CUR_LOCAL_MIN = clientLocalMin(c)
566
+ env.CUR_CLIENT_NAME = c.name
567
+ withCredentials([usernamePassword(
568
+ credentialsId: env.AWS_CREDENTIALS_ID,
569
+ usernameVariable: 'AWS_ACCESS_KEY_ID',
570
+ passwordVariable: 'AWS_SECRET_ACCESS_KEY'
571
+ )]) {
572
+ sh '''
573
+ set -eu
574
+ export AWS_DEFAULT_REGION="${AWS_REGION}"
575
+ unset AWS_SESSION_TOKEN || true
576
+
577
+ "${AWS_CLI_BIN}" --version
578
+
579
+ S3_TARGET="s3://${S3_BUCKET}/${CUR_S3_PREFIX}/${CLIENT_BOOTSTRAP_MIN}"
580
+ echo "Uploading ${CUR_LOCAL_MIN} -> ${S3_TARGET}"
581
+
582
+ "${AWS_CLI_BIN}" s3 cp "${CUR_LOCAL_MIN}" "${S3_TARGET}" \
583
+ --region "${AWS_REGION}" \
584
+ --content-type "${S3_CONTENT_TYPE}" \
585
+ --cache-control "${S3_CACHE_CONTROL}" \
586
+ --metadata "client=${CUR_CLIENT_NAME} build-number=${BUILD_NUMBER}"
587
+
588
+ echo "S3 head-object verification:"
589
+ "${AWS_CLI_BIN}" s3api head-object \
590
+ --region "${AWS_REGION}" \
591
+ --bucket "${S3_BUCKET}" \
592
+ --key "${CUR_S3_PREFIX}/${CLIENT_BOOTSTRAP_MIN}"
593
+ '''
594
+ }
595
+ }
596
+
597
+ // Verify one client bootstrap is served from the CDN with the banner matching
598
+ // the freshly-built local artifact (retrying through CDN cache lag).
599
+ def verifyClientOnCdn(c) {
600
+ env.CUR_CDN_PATH = "${c.s3}/${env.CLIENT_BOOTSTRAP_MIN}"
601
+ env.CUR_LOCAL_MIN = clientLocalMin(c)
602
+ env.CUR_TMP_FILE = "/tmp/client-${c.key}-cdn.js"
603
+ sh '''
604
+ set -eu
605
+ CDN_URL="${CDN_BASE_URL}/${CUR_CDN_PATH}"
606
+ LOCAL_BANNER=$(head -n 1 "${CUR_LOCAL_MIN}" | tr -d "\n")
607
+ echo "Verifying CDN URL: ${CDN_URL}"
608
+ echo "Expected banner : ${LOCAL_BANNER}"
609
+
610
+ i=1
611
+ while [ "${i}" -le "${CDN_VERIFY_RETRIES}" ]; do
612
+ STATUS=$(curl -sS -o "${CUR_TMP_FILE}" -w "%{http_code}" \
613
+ "${CDN_URL}?cb=$(date +%s)-${BUILD_NUMBER}-${i}" || echo "000")
614
+
615
+ if [ "${STATUS}" = "200" ]; then
616
+ CDN_BANNER=$(head -n 1 "${CUR_TMP_FILE}" | tr -d "\n")
617
+ if [ "${CDN_BANNER}" = "${LOCAL_BANNER}" ]; then
618
+ echo "CDN OK — client bootstrap served from ${CDN_URL}"
619
+ echo " banner: ${CDN_BANNER}"
620
+ exit 0
621
+ else
622
+ echo "Attempt ${i}: HTTP 200 but banner mismatch (likely CDN cache lag)."
623
+ echo " cdn : ${CDN_BANNER}"
624
+ echo " local: ${LOCAL_BANNER}"
625
+ fi
626
+ else
627
+ echo "Attempt ${i}: HTTP ${STATUS} from ${CDN_URL}"
628
+ fi
629
+
630
+ i=$((i + 1))
631
+ if [ "${i}" -le "${CDN_VERIFY_RETRIES}" ]; then
632
+ sleep "${CDN_VERIFY_SLEEP_SEC}"
633
+ fi
634
+ done
635
+
636
+ echo "CDN verification FAILED after ${CDN_VERIFY_RETRIES} attempts."
637
+ exit 1
638
+ '''
639
+ }