antelope-cli 1.2.6 → 1.2.7
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/ansible/onboarding-ca/roles/onboard_ca/defaults/main.yml +1 -1
- package/ansible/onboarding-crm/Jenkinsfile +24 -24
- package/ansible/onboarding-crm/roles/onboard_crm/defaults/main.yml +3 -3
- package/ansible/onboarding-logos/Jenkinsfile +62 -49
- package/onboarding-crm/createConfig.js +1 -1
- package/package.json +1 -1
|
@@ -38,10 +38,10 @@ pipeline {
|
|
|
38
38
|
|
|
39
39
|
parameters {
|
|
40
40
|
// --- named exactly as configs.ts fields ---
|
|
41
|
-
string(name: '
|
|
41
|
+
string(name: 'antelope_id', defaultValue: '', trim: true,
|
|
42
42
|
description: 'Antelope ID (lowercase alphanumeric). configs.ts brandAssetsFolder / devBrandName / colorTheme / templateTheme / favicon all derive from this. e.g. uzumy')
|
|
43
|
-
string(name: '
|
|
44
|
-
description: 'Brand name. configs.ts title becomes "<
|
|
43
|
+
string(name: 'brand_name', defaultValue: '', trim: true,
|
|
44
|
+
description: 'Brand name. configs.ts title becomes "<brand_name> CRM". e.g. Excelttra')
|
|
45
45
|
choice(name: 'type', choices: ['CORP_FL', 'IB_FL', 'CORP_AFF_FL'],
|
|
46
46
|
description: 'configs.ts type')
|
|
47
47
|
string(name: 'baseUrl', defaultValue: '', trim: true,
|
|
@@ -54,9 +54,9 @@ pipeline {
|
|
|
54
54
|
string(name: 'languages', defaultValue: 'en', trim: true,
|
|
55
55
|
description: 'Comma-separated 2-letter language codes. e.g. en,ar')
|
|
56
56
|
string(name: 'logo_url', defaultValue: '', trim: true,
|
|
57
|
-
description: 'Logo URL. Must be https://logos-<
|
|
57
|
+
description: 'Logo URL. Must be https://logos-<antelope_id>.s3.eu-west-1.amazonaws.com/<brand_name>-logo.<ext>. Blank => derived.')
|
|
58
58
|
string(name: 'favicon', defaultValue: '', trim: true,
|
|
59
|
-
description: 'Favicon URL (configs.ts favicon). Must be https://logos-<
|
|
59
|
+
description: 'Favicon URL (configs.ts favicon). Must be https://logos-<antelope_id>.s3.eu-west-1.amazonaws.com/<brand_name>-favicon.<ext>. Blank => derived.')
|
|
60
60
|
string(name: 'jira_key_crm_branding', defaultValue: '', trim: true,
|
|
61
61
|
description: 'Jira key for the branding PRs. e.g. ATLP-47345')
|
|
62
62
|
// --- safety ---
|
|
@@ -83,11 +83,11 @@ pipeline {
|
|
|
83
83
|
def errs = []
|
|
84
84
|
def req = { v, n -> if (!v?.trim()) errs << "${n} is required" }
|
|
85
85
|
|
|
86
|
-
req(params.
|
|
87
|
-
if (params.
|
|
88
|
-
errs << "
|
|
86
|
+
req(params.antelope_id, 'antelope_id')
|
|
87
|
+
if (params.antelope_id && !(params.antelope_id ==~ /^[a-z0-9]+$/))
|
|
88
|
+
errs << "antelope_id must be lowercase alphanumeric (the Antelope ID); got '${params.antelope_id}'"
|
|
89
89
|
|
|
90
|
-
req(params.
|
|
90
|
+
req(params.brand_name, 'brand_name')
|
|
91
91
|
|
|
92
92
|
if (!CRM_TYPES.contains(params.type))
|
|
93
93
|
errs << "type must be one of ${CRM_TYPES}; got '${params.type}'"
|
|
@@ -103,16 +103,16 @@ pipeline {
|
|
|
103
103
|
if (!(params.languages ==~ /^[a-z]{2}(,[a-z]{2})*$/))
|
|
104
104
|
errs << "languages must be comma-separated 2-letter codes; got '${params.languages}'"
|
|
105
105
|
|
|
106
|
-
// logo/favicon must follow logos-<antelope_id>/<kind
|
|
106
|
+
// logo/favicon must follow logos-<antelope_id>/<brand_name>-<kind>.<ext> (when set; blank => derived)
|
|
107
107
|
def IMG_EXT = ['png', 'jpg', 'jpeg', 'svg', 'webp', 'ico', 'gif']
|
|
108
108
|
def checkImg = { url, kind ->
|
|
109
109
|
if (!url?.trim()) return null
|
|
110
|
-
def m = (url =~ /^https:\/\/logos-([a-z0-9]+)\.s3\.eu-west-1\.amazonaws\.com\/(logo|favicon)
|
|
111
|
-
if (!m) return "${kind} must look like https://logos-<id>.s3.eu-west-1.amazonaws.com
|
|
112
|
-
def (whole, bucketId,
|
|
113
|
-
if (
|
|
114
|
-
if (bucketId != params.
|
|
115
|
-
if (brand != params.
|
|
110
|
+
def m = (url =~ /^https:\/\/logos-([a-z0-9]+)\.s3\.eu-west-1\.amazonaws\.com\/(.+)-(logo|favicon)\.([A-Za-z0-9]+)$/)
|
|
111
|
+
if (!m) return "${kind} must look like https://logos-<id>.s3.eu-west-1.amazonaws.com/<brand>-${kind}.<ext>; got '${url}'"
|
|
112
|
+
def (whole, bucketId, brand, suffix, ext) = m[0]
|
|
113
|
+
if (suffix != kind) return "${kind} filename must end with '-${kind}' (got '-${suffix}')"
|
|
114
|
+
if (bucketId != params.antelope_id) return "${kind} bucket must be logos-${params.antelope_id} (got logos-${bucketId})"
|
|
115
|
+
if (brand != params.brand_name) return "${kind} filename brand must be '${params.brand_name}' (got '${brand}')"
|
|
116
116
|
if (!IMG_EXT.contains(ext.toLowerCase())) return "${kind} extension '${ext}' not allowed (${IMG_EXT.join('/')})"
|
|
117
117
|
return null
|
|
118
118
|
}
|
|
@@ -124,8 +124,8 @@ pipeline {
|
|
|
124
124
|
if (errs) {
|
|
125
125
|
error("Parameter validation failed:\n - " + errs.join("\n - "))
|
|
126
126
|
}
|
|
127
|
-
echo "✅ Parameters valid — antelope_id=${params.
|
|
128
|
-
currentBuild.displayName = "#${env.BUILD_NUMBER} ${params.
|
|
127
|
+
echo "✅ Parameters valid — antelope_id=${params.antelope_id}, type=${params.type}, dry_run=${params.DRY_RUN}"
|
|
128
|
+
currentBuild.displayName = "#${env.BUILD_NUMBER} ${params.brand_name}${params.DRY_RUN ? ' (dry-run)' : ''}"
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
131
|
}
|
|
@@ -138,8 +138,8 @@ pipeline {
|
|
|
138
138
|
sh label: 'ansible dry-run (no writes)', script: '''
|
|
139
139
|
cd "$PLAYBOOK_DIR"
|
|
140
140
|
ansible-playbook onboard-crm.yml \
|
|
141
|
-
-e antelope_id="$
|
|
142
|
-
-e brand_name="$
|
|
141
|
+
-e antelope_id="$antelope_id" \
|
|
142
|
+
-e brand_name="$brand_name" \
|
|
143
143
|
-e crm_type="$type" \
|
|
144
144
|
-e base_url="$baseUrl" \
|
|
145
145
|
-e affiliates_api_url="$affiliatesApiUrl" \
|
|
@@ -161,7 +161,7 @@ pipeline {
|
|
|
161
161
|
when { expression { !params.DRY_RUN } }
|
|
162
162
|
steps {
|
|
163
163
|
script {
|
|
164
|
-
input message: "Open web-crm PR(s) + write Consul crm_env + stamp Jira for '${params.
|
|
164
|
+
input message: "Open web-crm PR(s) + write Consul crm_env + stamp Jira for '${params.antelope_id}'?",
|
|
165
165
|
ok: 'Onboard'
|
|
166
166
|
}
|
|
167
167
|
}
|
|
@@ -175,8 +175,8 @@ pipeline {
|
|
|
175
175
|
sh label: 'ansible onboard-crm', script: '''
|
|
176
176
|
cd "$PLAYBOOK_DIR"
|
|
177
177
|
ansible-playbook onboard-crm.yml \
|
|
178
|
-
-e antelope_id="$
|
|
179
|
-
-e brand_name="$
|
|
178
|
+
-e antelope_id="$antelope_id" \
|
|
179
|
+
-e brand_name="$brand_name" \
|
|
180
180
|
-e crm_type="$type" \
|
|
181
181
|
-e base_url="$baseUrl" \
|
|
182
182
|
-e affiliates_api_url="$affiliatesApiUrl" \
|
|
@@ -206,6 +206,6 @@ void archiveGeneratedConfigs() {
|
|
|
206
206
|
if (fileExists(cfg)) {
|
|
207
207
|
sh "mkdir -p out && cp '${cfg}' out/configs.ts"
|
|
208
208
|
archiveArtifacts artifacts: 'out/configs.ts', allowEmptyArchive: true
|
|
209
|
-
currentBuild.description = "configs.ts generated for ${params.
|
|
209
|
+
currentBuild.description = "configs.ts generated for ${params.antelope_id}"
|
|
210
210
|
}
|
|
211
211
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
# Pinned published antelope-cli version that provides the `onboarding-crm` command.
|
|
3
|
-
antelope_cli_version: "1.2.
|
|
3
|
+
antelope_cli_version: "1.2.6"
|
|
4
4
|
|
|
5
5
|
# Where web-crm is cloned on the control node.
|
|
6
6
|
work_dir: "/tmp/onboard-crm/web-crm"
|
|
@@ -12,8 +12,8 @@ work_dir: "/tmp/onboard-crm/web-crm"
|
|
|
12
12
|
# DERIVED by the CLI (logos-<id>/favicon-<name>.png) and FCMSenderId is always '' (both placeholders).
|
|
13
13
|
antelope_id: ""
|
|
14
14
|
color: "" # --color hex; blank => default palette
|
|
15
|
-
logo_url: "https://logos-{{ antelope_id }}.s3.eu-west-1.amazonaws.com/
|
|
16
|
-
favicon: "https://logos-{{ antelope_id }}.s3.eu-west-1.amazonaws.com/
|
|
15
|
+
logo_url: "https://logos-{{ antelope_id }}.s3.eu-west-1.amazonaws.com/{{ brand_name }}-logo.png" # brand-logos.json entry; override with -e
|
|
16
|
+
favicon: "https://logos-{{ antelope_id }}.s3.eu-west-1.amazonaws.com/{{ brand_name }}-favicon.png" # --favicon => configs.ts favicon; blank => CLI derives the same
|
|
17
17
|
languages: "" # --languages: CSV "en,ar" or a YAML list [en, ar]
|
|
18
18
|
crm_type: "" # --type: one of allowed_crm_types (per-brand; from group_vars derivation)
|
|
19
19
|
# baseUrl uses the BE/CRM domain; affiliatesApiUrl uses the FE/CA domain (fe_server_url_list.0).
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
// Self-service logo/
|
|
1
|
+
// Self-service logo/asset upload — jenkins.xsites.xyz/job/self-service/job/onboarding/job/onboarding-logos
|
|
2
2
|
//
|
|
3
3
|
// Pipeline-as-Code (this file is the source of truth; the Jenkins job is a "Pipeline script from SCM"
|
|
4
4
|
// pointer at antelope-cli@master, path ansible/onboarding-logos/Jenkinsfile).
|
|
5
5
|
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
6
|
+
// Uploads a brand's asset images to its logos-<antelope_id> S3 bucket, renamed to our convention
|
|
7
|
+
// <brand_name>-<type>.<original ext>, for the four crmdb client_configuration assets:
|
|
8
|
+
// logo, logo_tiny, auth_bg, favicon
|
|
9
|
+
// Each is optional — only the ones you attach are uploaded. The resulting public S3 URLs are printed
|
|
10
|
+
// (paste them into crmdb.client_configuration / the CRM admin; this job does NOT write the DB).
|
|
10
11
|
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
// (
|
|
12
|
+
// Reads the brand's AWS creds from Consul (Antelope/<brand_name>/AWS_ACCESS_KEY_ID|AWS_SECRET_ACCESS_KEY|
|
|
13
|
+
// AWS_DEFAULT_REGION) via the op service account on the `jenkins` vault. Uploads are `stashedFile`
|
|
14
|
+
// params (preserve the original filename → we keep its extension). Reuses the onboarding-crm runner
|
|
15
|
+
// image (op + curl + jq + aws + uid-1000 user). Requires the file-parameters plugin.
|
|
14
16
|
pipeline {
|
|
15
17
|
agent {
|
|
16
18
|
dockerfile {
|
|
@@ -28,40 +30,39 @@ pipeline {
|
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
parameters {
|
|
31
|
-
string(name: '
|
|
32
|
-
description: 'Antelope ID (lowercase alphanumeric). Target bucket = logos-<
|
|
33
|
+
string(name: 'antelope_id', defaultValue: '', trim: true,
|
|
34
|
+
description: 'Antelope ID (lowercase alphanumeric). Target bucket = logos-<antelope_id>. e.g. uzumy')
|
|
33
35
|
string(name: 'brand_name', defaultValue: '', trim: true,
|
|
34
|
-
description: 'Brand name — the Consul folder Antelope/<brand_name>/ AND the filename token
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
description: 'Brand name — the Consul folder Antelope/<brand_name>/ (AWS creds) AND the filename token <brand_name>-<type>. e.g. excelttra')
|
|
37
|
+
stashedFile(name: 'logo', description: 'Main logo (black bg) → <brand_name>-logo.<ext>. Optional.')
|
|
38
|
+
stashedFile(name: 'logo_tiny', description: 'Tiny logo / icon → <brand_name>-logo_tiny.<ext>. Optional.')
|
|
39
|
+
stashedFile(name: 'auth_bg', description: 'Auth/login background → <brand_name>-auth_bg.<ext>. Optional.')
|
|
40
|
+
stashedFile(name: 'favicon', description: 'Favicon → <brand_name>-favicon.<ext>. Optional.')
|
|
39
41
|
booleanParam(name: 'DRY_RUN', defaultValue: true,
|
|
40
|
-
description: 'Preview only: resolve creds +
|
|
42
|
+
description: 'Preview only: resolve creds + compute names + aws s3 cp --dryrun (no actual upload)')
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
environment {
|
|
44
46
|
HOME = "${env.WORKSPACE}"
|
|
45
47
|
CONSUL_URL = 'https://consul.xsites.xyz'
|
|
48
|
+
ASSETS = 'logo logo_tiny auth_bg favicon'
|
|
46
49
|
}
|
|
47
50
|
|
|
48
51
|
stages {
|
|
49
52
|
stage('Validate parameters') {
|
|
50
53
|
steps {
|
|
51
54
|
script {
|
|
52
|
-
def IMG_EXT = ['png', 'jpg', 'jpeg', 'svg', 'webp', 'ico', 'gif']
|
|
53
55
|
def errs = []
|
|
54
|
-
if (!(params.
|
|
55
|
-
errs << "
|
|
56
|
-
// brand_name must be filename-safe so logo-<brand_name>.<ext> / favicon-<brand_name>.<ext> are valid keys
|
|
56
|
+
if (!(params.antelope_id ==~ /^[a-z0-9]+$/))
|
|
57
|
+
errs << "antelope_id must be lowercase alphanumeric (the Antelope ID); got '${params.antelope_id}'"
|
|
57
58
|
if (!(params.brand_name ==~ /^[A-Za-z0-9._-]+$/))
|
|
58
59
|
errs << "brand_name must be filename-safe (letters/digits/._-, no spaces); got '${params.brand_name}'"
|
|
59
|
-
if (!IMG_EXT.contains(params.logo_type)) errs << "logo_type '${params.logo_type}' not allowed"
|
|
60
|
-
if (!IMG_EXT.contains(params.favicon_type)) errs << "favicon_type '${params.favicon_type}' not allowed"
|
|
61
60
|
if (errs) error("Parameter validation failed:\n - " + errs.join("\n - "))
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
// Unstash each provided asset into its own dir (missing ones are skipped).
|
|
62
|
+
['logo', 'logo_tiny', 'auth_bg', 'favicon'].each { t ->
|
|
63
|
+
dir("_${t}") { deleteDir(); try { unstash t } catch (ignored) { echo "no '${t}' attached — skipping" } }
|
|
64
|
+
}
|
|
65
|
+
echo "✅ Valid — bucket=logos-${params.antelope_id}, brand=${params.brand_name}, dry_run=${params.DRY_RUN}"
|
|
65
66
|
currentBuild.displayName = "#${env.BUILD_NUMBER} ${params.brand_name}${params.DRY_RUN ? ' (dry-run)' : ''}"
|
|
66
67
|
}
|
|
67
68
|
}
|
|
@@ -70,28 +71,41 @@ pipeline {
|
|
|
70
71
|
stage('Upload to S3') {
|
|
71
72
|
steps {
|
|
72
73
|
withCredentials([string(credentialsId: 'onepassword-service-account-token', variable: 'OP_SERVICE_ACCOUNT_TOKEN')]) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
74
|
+
sh label: 'resolve Consul AWS creds + upload assets (extension preserved)', script: '''
|
|
75
|
+
set -eu
|
|
76
|
+
IMG_EXT=" png jpg jpeg svg webp ico gif "
|
|
77
|
+
ct() { case "$1" in png) echo image/png;; jpg|jpeg) echo image/jpeg;; svg) echo image/svg+xml;; webp) echo image/webp;; gif) echo image/gif;; ico) echo image/x-icon;; esac; }
|
|
78
|
+
|
|
79
|
+
CT=$(op read "op://jenkins/New_Consul_Token/password")
|
|
80
|
+
base="$CONSUL_URL/v1/kv/Antelope/$brand_name"
|
|
81
|
+
AWS_ACCESS_KEY_ID=$(curl -sf -H "X-Consul-Token: $CT" "$base/AWS_ACCESS_KEY_ID?raw")
|
|
82
|
+
AWS_SECRET_ACCESS_KEY=$(curl -sf -H "X-Consul-Token: $CT" "$base/AWS_SECRET_ACCESS_KEY?raw")
|
|
83
|
+
AWS_DEFAULT_REGION=$(curl -sf -H "X-Consul-Token: $CT" "$base/AWS_DEFAULT_REGION?raw" || echo eu-west-1)
|
|
84
|
+
export AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_DEFAULT_REGION
|
|
85
|
+
if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then
|
|
86
|
+
echo "ERROR: no AWS creds under Consul Antelope/$brand_name/ (AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY)"; exit 1
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
BUCKET="logos-$antelope_id"
|
|
90
|
+
aws s3api head-bucket --bucket "$BUCKET" 2>/dev/null || { echo "ERROR: bucket $BUCKET not found / not accessible with the brand's creds"; exit 1; }
|
|
91
|
+
DRY=""; [ "$DRY_RUN" = "true" ] && DRY="--dryrun"
|
|
92
|
+
|
|
93
|
+
uploaded=0
|
|
94
|
+
for t in $ASSETS; do
|
|
95
|
+
d="_$t"
|
|
96
|
+
src=$(ls -A "$d" 2>/dev/null | head -1 || true)
|
|
97
|
+
[ -n "$src" ] || { echo "- $t: not attached, skipped"; continue; }
|
|
98
|
+
ext=$(printf '%s' "${src##*.}" | tr '[:upper:]' '[:lower:]')
|
|
99
|
+
case "$IMG_EXT" in *" $ext "*) : ;; *) echo "ERROR: $t '$src' extension '.$ext' not a supported image ($IMG_EXT)"; exit 1 ;; esac
|
|
100
|
+
key="$brand_name-$t.$ext"
|
|
101
|
+
echo "- $t: $src -> $key"
|
|
102
|
+
aws s3 cp "$d/$src" "s3://$BUCKET/$key" --content-type "$(ct $ext)" $DRY
|
|
103
|
+
echo " https://$BUCKET.s3.$AWS_DEFAULT_REGION.amazonaws.com/$key"
|
|
104
|
+
uploaded=$((uploaded+1))
|
|
105
|
+
done
|
|
106
|
+
[ "$uploaded" -gt 0 ] || { echo "ERROR: no assets attached — nothing to upload"; exit 1; }
|
|
107
|
+
echo "${DRY:+[DRY-RUN] }$uploaded asset(s) processed for logos-$antelope_id"
|
|
108
|
+
'''
|
|
95
109
|
}
|
|
96
110
|
}
|
|
97
111
|
}
|
|
@@ -99,7 +113,6 @@ pipeline {
|
|
|
99
113
|
|
|
100
114
|
post {
|
|
101
115
|
always { cleanWs() }
|
|
102
|
-
|
|
103
|
-
failure { echo 'Logo upload failed — see the validation/aws output above.' }
|
|
116
|
+
failure { echo 'Asset upload failed — see the validation/aws output above.' }
|
|
104
117
|
}
|
|
105
118
|
}
|
|
@@ -32,7 +32,7 @@ const updateConfigFile = () => {
|
|
|
32
32
|
templateTheme: 'theme-template-${id}',
|
|
33
33
|
brandAssetsFolder: '${id}',
|
|
34
34
|
devBrandName: '${id}',
|
|
35
|
-
favicon: '${brand.favicon || `https://logos-${id}.s3.eu-west-1.amazonaws.com
|
|
35
|
+
favicon: '${brand.favicon || `https://logos-${id}.s3.eu-west-1.amazonaws.com/${brand.brandName}-favicon.png`}',
|
|
36
36
|
gaTrackingID: 'UA-70456753-2',
|
|
37
37
|
FCMSenderId: '',
|
|
38
38
|
isFnsStatusActive: true,
|