antelope-cli 1.2.2 → 1.2.4
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/README.md +105 -105
- package/ansible/onboarding-ca/onboard-ca.yml +43 -51
- package/ansible/onboarding-ca/requirements.yml +8 -8
- package/ansible/onboarding-ca/roles/onboard_ca/defaults/main.yml +77 -49
- package/ansible/onboarding-ca/roles/onboard_ca/meta/main.yml +10 -10
- package/ansible/onboarding-ca/roles/onboard_ca/tasks/main.yml +311 -193
- package/ansible/onboarding-ca/roles/onboard_ca/tasks/per_branch.yml +114 -107
- package/ansible/onboarding-ca/roles/onboard_ca/vars/main.yml +9 -9
- package/ansible/onboarding-crm/README.md +107 -0
- package/ansible/onboarding-crm/onboard-crm.yml +60 -0
- package/ansible/onboarding-crm/requirements.yml +8 -0
- package/ansible/onboarding-crm/roles/onboard_crm/defaults/main.yml +99 -0
- package/ansible/onboarding-crm/roles/onboard_crm/meta/main.yml +10 -0
- package/ansible/onboarding-crm/roles/onboard_crm/tasks/main.yml +324 -0
- package/ansible/onboarding-crm/roles/onboard_crm/tasks/per_branch.yml +121 -0
- package/ansible/onboarding-crm/roles/onboard_crm/vars/main.yml +9 -0
- package/index.js +12 -12
- package/onboarding/brand.js +21 -21
- package/onboarding/createConfig.js +71 -71
- package/onboarding/favicon.js +24 -24
- package/onboarding/index.js +62 -62
- package/onboarding/logo.js +16 -16
- package/onboarding/themes.js +92 -92
- package/onboarding/translations.js +41 -41
- package/onboarding/variablesColors.js +58 -58
- package/onboarding-ca/brand.js +13 -13
- package/onboarding-ca/index.js +94 -94
- package/onboarding-ca/riskDisclaimer.js +27 -27
- package/onboarding-ca/scss.js +24 -24
- package/onboarding-ca/templates/risk-disclaimer.html +12 -12
- package/onboarding-crm/brand.js +22 -22
- package/onboarding-crm/brandLogos.js +31 -0
- package/onboarding-crm/createConfig.js +40 -40
- package/onboarding-crm/index.js +175 -171
- package/onboarding-crm/themes.js +1 -1
- package/onboarding-crm/variablesColors.js +2 -3
- package/package.json +30 -30
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
---
|
|
2
|
+
# --- Resolve secrets: prefer the provided value, else fall back to 1Password (op CLI) ---
|
|
3
|
+
# The op fallback needs a signed-in `op` on the control node (op signin, or
|
|
4
|
+
# OP_SERVICE_ACCOUNT_TOKEN). A missing/failed op is tolerated here; the validate step
|
|
5
|
+
# below reports the still-empty token with a clear message.
|
|
6
|
+
- name: Fetch the Bitbucket API token from 1Password
|
|
7
|
+
when: (bitbucket_token | default('') | length) == 0
|
|
8
|
+
ansible.builtin.command:
|
|
9
|
+
argv:
|
|
10
|
+
- op
|
|
11
|
+
- item
|
|
12
|
+
- get
|
|
13
|
+
- "{{ onepassword_bitbucket_item }}"
|
|
14
|
+
- "--vault"
|
|
15
|
+
- "{{ onepassword_vault }}"
|
|
16
|
+
- "--fields"
|
|
17
|
+
- "label={{ onepassword_bitbucket_field }}"
|
|
18
|
+
- "--reveal"
|
|
19
|
+
register: op_bitbucket
|
|
20
|
+
changed_when: false
|
|
21
|
+
failed_when: false
|
|
22
|
+
no_log: true
|
|
23
|
+
|
|
24
|
+
- name: Adopt the 1Password Bitbucket token
|
|
25
|
+
when:
|
|
26
|
+
- (bitbucket_token | default('') | length) == 0
|
|
27
|
+
- op_bitbucket is not skipped
|
|
28
|
+
- (op_bitbucket.rc | default(1)) == 0
|
|
29
|
+
- (op_bitbucket.stdout | default('') | length) > 0
|
|
30
|
+
ansible.builtin.set_fact:
|
|
31
|
+
bitbucket_token: "{{ op_bitbucket.stdout | trim }}"
|
|
32
|
+
no_log: true
|
|
33
|
+
|
|
34
|
+
# Consul token is only needed when destination branches are derived (no dest_branches override).
|
|
35
|
+
- name: Resolve the Consul token from the environment
|
|
36
|
+
when: (consul_token | default('') | length) == 0
|
|
37
|
+
ansible.builtin.set_fact:
|
|
38
|
+
consul_token: "{{ lookup('env', 'CONSUL_HTTP_TOKEN') }}"
|
|
39
|
+
no_log: true
|
|
40
|
+
|
|
41
|
+
- name: Fetch the Consul token from 1Password
|
|
42
|
+
when:
|
|
43
|
+
- (consul_token | default('') | length) == 0
|
|
44
|
+
- (dest_branches | default('') | length) == 0
|
|
45
|
+
ansible.builtin.command:
|
|
46
|
+
argv:
|
|
47
|
+
- op
|
|
48
|
+
- item
|
|
49
|
+
- get
|
|
50
|
+
- "{{ onepassword_consul_item }}"
|
|
51
|
+
- "--vault"
|
|
52
|
+
- "{{ onepassword_vault }}"
|
|
53
|
+
- "--fields"
|
|
54
|
+
- "label={{ onepassword_consul_field }}"
|
|
55
|
+
- "--reveal"
|
|
56
|
+
register: op_consul
|
|
57
|
+
changed_when: false
|
|
58
|
+
failed_when: false
|
|
59
|
+
no_log: true
|
|
60
|
+
|
|
61
|
+
- name: Adopt the 1Password Consul token
|
|
62
|
+
when:
|
|
63
|
+
- (consul_token | default('') | length) == 0
|
|
64
|
+
- op_consul is not skipped
|
|
65
|
+
- (op_consul.rc | default(1)) == 0
|
|
66
|
+
- (op_consul.stdout | default('') | length) > 0
|
|
67
|
+
ansible.builtin.set_fact:
|
|
68
|
+
consul_token: "{{ op_consul.stdout | trim }}"
|
|
69
|
+
no_log: true
|
|
70
|
+
|
|
71
|
+
- name: Validate required inputs
|
|
72
|
+
ansible.builtin.assert:
|
|
73
|
+
that:
|
|
74
|
+
- antelope_id is defined and (antelope_id | length) > 0
|
|
75
|
+
- brand_name is defined and (brand_name | length) > 0
|
|
76
|
+
- jira_key_crm_branding is defined and (jira_key_crm_branding | length) > 0
|
|
77
|
+
- logo_url is defined and (logo_url | length) > 0
|
|
78
|
+
- favicon_url is defined and (favicon_url | length) > 0
|
|
79
|
+
- languages is defined and (languages | length) > 0
|
|
80
|
+
- fcm_sender_id is defined and (fcm_sender_id | length) > 0
|
|
81
|
+
- crm_type is defined and (crm_type | length) > 0
|
|
82
|
+
- crm_type in allowed_crm_types
|
|
83
|
+
- bitbucket_token is defined and (bitbucket_token | length) > 0
|
|
84
|
+
- bitbucket_email is defined and (bitbucket_email | length) > 0
|
|
85
|
+
fail_msg: >-
|
|
86
|
+
Required: antelope_id, brand_name, jira_key_crm_branding, logo_url, favicon_url, languages,
|
|
87
|
+
fcm_sender_id, crm_type (one of {{ allowed_crm_types | join(', ') }}), bitbucket_email.
|
|
88
|
+
bitbucket_token must be provided (via --extra-vars / prompt) or resolvable from 1Password
|
|
89
|
+
item '{{ onepassword_bitbucket_item }}' field '{{ onepassword_bitbucket_field }}' (op signin).
|
|
90
|
+
|
|
91
|
+
# The CRM CLI keys everything off the Antelope ID (connectedBrandName); normalize it the same
|
|
92
|
+
# way the CLI does (lowercase, no spaces) so the branch name / assets folder match the repo.
|
|
93
|
+
- name: Normalize the brand id
|
|
94
|
+
ansible.builtin.set_fact:
|
|
95
|
+
antelope_id_norm: "{{ antelope_id | lower | regex_replace(' ', '') }}"
|
|
96
|
+
|
|
97
|
+
# languages may arrive as a YAML list (brand_vars) or a CSV string (prompt / extra-var);
|
|
98
|
+
# the CLI wants a comma-separated string.
|
|
99
|
+
- name: Normalize languages to a CSV string
|
|
100
|
+
ansible.builtin.set_fact:
|
|
101
|
+
languages_csv: "{{ (languages | join(',')) if (languages is not string) else languages }}"
|
|
102
|
+
|
|
103
|
+
# --- Destination branches: derived from the release train in Consul ------------------
|
|
104
|
+
# develop is always onboarded. master-<version/prod> tracks the live release; while a new
|
|
105
|
+
# release is staged (version/staging != version/prod) its master-<version/staging> exists
|
|
106
|
+
# too and is onboarded as well. Once staging == prod (the release has shipped) there is a
|
|
107
|
+
# single master branch. An explicit dest_branches extra-var bypasses the lookup entirely.
|
|
108
|
+
- name: Resolve destination branches from Consul
|
|
109
|
+
when: (dest_branches | default('') | length) == 0
|
|
110
|
+
block:
|
|
111
|
+
- name: Consul token is required to derive destination branches
|
|
112
|
+
ansible.builtin.assert:
|
|
113
|
+
that:
|
|
114
|
+
- consul_token is defined and (consul_token | length) > 0
|
|
115
|
+
fail_msg: >-
|
|
116
|
+
consul_token is required to read version/prod and version/staging. Provide it via
|
|
117
|
+
-e consul_token=..., $CONSUL_HTTP_TOKEN, or 1Password item '{{ onepassword_consul_item }}'
|
|
118
|
+
(op signin); or pass -e dest_branches=develop,master-XX.Y to bypass the Consul lookup.
|
|
119
|
+
|
|
120
|
+
- name: Read the prod release version from Consul
|
|
121
|
+
ansible.builtin.uri:
|
|
122
|
+
url: "{{ consul_url }}/v1/kv/version/prod?raw=1"
|
|
123
|
+
headers:
|
|
124
|
+
X-Consul-Token: "{{ consul_token }}"
|
|
125
|
+
return_content: true
|
|
126
|
+
register: consul_prod
|
|
127
|
+
|
|
128
|
+
- name: Read the staging release version from Consul
|
|
129
|
+
ansible.builtin.uri:
|
|
130
|
+
url: "{{ consul_url }}/v1/kv/version/staging?raw=1"
|
|
131
|
+
headers:
|
|
132
|
+
X-Consul-Token: "{{ consul_token }}"
|
|
133
|
+
return_content: true
|
|
134
|
+
register: consul_staging
|
|
135
|
+
|
|
136
|
+
- name: Derive the destination branch list from the release versions
|
|
137
|
+
ansible.builtin.set_fact:
|
|
138
|
+
dest_branch_list: >-
|
|
139
|
+
{{ ['develop', 'master-' + (consul_prod.content | trim)]
|
|
140
|
+
+ (['master-' + (consul_staging.content | trim)]
|
|
141
|
+
if (consul_staging.content | trim) != (consul_prod.content | trim) else []) }}
|
|
142
|
+
|
|
143
|
+
- name: Normalize destination branch list (explicit override)
|
|
144
|
+
when: (dest_branches | default('') | length) > 0
|
|
145
|
+
ansible.builtin.set_fact:
|
|
146
|
+
dest_branch_list: "{{ dest_branches.split(',') | map('trim') | reject('equalto', '') | list }}"
|
|
147
|
+
|
|
148
|
+
- name: Show the resolved destination branches
|
|
149
|
+
ansible.builtin.debug:
|
|
150
|
+
msg: "Destination branches: {{ dest_branch_list }}"
|
|
151
|
+
|
|
152
|
+
# --- Jira Fix Version: DangerJS fails any web-crm PR whose linked issue has no
|
|
153
|
+
# Fix Version, so stamp the release version (V<version/prod>) on the ticket BEFORE the
|
|
154
|
+
# branches are pushed. Non-fatal — a missing token / unmatched version warns and skips.
|
|
155
|
+
- name: Set the Jira Fix Version on the branding ticket
|
|
156
|
+
when: manage_jira_fix_version | bool
|
|
157
|
+
block:
|
|
158
|
+
- name: Fetch the Jira token from 1Password
|
|
159
|
+
when: (jira_token | default('') | length) == 0
|
|
160
|
+
ansible.builtin.command:
|
|
161
|
+
argv:
|
|
162
|
+
- op
|
|
163
|
+
- item
|
|
164
|
+
- get
|
|
165
|
+
- "{{ onepassword_jira_item }}"
|
|
166
|
+
- "--vault"
|
|
167
|
+
- "{{ onepassword_vault }}"
|
|
168
|
+
- "--fields"
|
|
169
|
+
- "label={{ onepassword_jira_field }}"
|
|
170
|
+
- "--reveal"
|
|
171
|
+
register: op_jira
|
|
172
|
+
changed_when: false
|
|
173
|
+
failed_when: false
|
|
174
|
+
no_log: true
|
|
175
|
+
|
|
176
|
+
- name: Adopt the 1Password Jira token
|
|
177
|
+
when:
|
|
178
|
+
- (jira_token | default('') | length) == 0
|
|
179
|
+
- op_jira is not skipped
|
|
180
|
+
- (op_jira.rc | default(1)) == 0
|
|
181
|
+
- (op_jira.stdout | default('') | length) > 0
|
|
182
|
+
ansible.builtin.set_fact:
|
|
183
|
+
jira_token: "{{ op_jira.stdout | trim }}"
|
|
184
|
+
no_log: true
|
|
185
|
+
|
|
186
|
+
# master-<ver> / release-<ver> destination branches → Fix Version names (e.g. V27.0).
|
|
187
|
+
- name: Derive the release Fix Version name(s)
|
|
188
|
+
ansible.builtin.set_fact:
|
|
189
|
+
jira_fix_versions: >-
|
|
190
|
+
{{ dest_branch_list
|
|
191
|
+
| select('match', '^(master|release)-')
|
|
192
|
+
| map('regex_replace', '^(master|release)-', jira_version_prefix)
|
|
193
|
+
| list | unique }}
|
|
194
|
+
|
|
195
|
+
- name: Warn when the Fix Version cannot be set
|
|
196
|
+
when: (jira_token | default('') | length) == 0 or (jira_fix_versions | length) == 0
|
|
197
|
+
ansible.builtin.debug:
|
|
198
|
+
msg: >-
|
|
199
|
+
Skipping Jira Fix Version ({{ 'no jira_token — provide -e jira_token= or 1Password item '
|
|
200
|
+
~ onepassword_jira_item if (jira_token | default('') | length) == 0
|
|
201
|
+
else 'no master-<ver> destination branch to derive the version from' }}).
|
|
202
|
+
DangerJS will fail until a Fix Version is set on {{ jira_key_crm_branding }}.
|
|
203
|
+
|
|
204
|
+
- name: Look up the Jira project versions
|
|
205
|
+
when:
|
|
206
|
+
- (jira_token | default('') | length) > 0
|
|
207
|
+
- (jira_fix_versions | length) > 0
|
|
208
|
+
ansible.builtin.uri:
|
|
209
|
+
url: "{{ jira_base_url }}/rest/api/2/project/{{ jira_project_key }}/versions"
|
|
210
|
+
url_username: "{{ jira_email }}"
|
|
211
|
+
url_password: "{{ jira_token }}"
|
|
212
|
+
force_basic_auth: true
|
|
213
|
+
return_content: true
|
|
214
|
+
register: jira_versions
|
|
215
|
+
failed_when: false
|
|
216
|
+
no_log: true
|
|
217
|
+
|
|
218
|
+
- name: Map Fix Version name(s) to id(s)
|
|
219
|
+
when:
|
|
220
|
+
- jira_versions is defined
|
|
221
|
+
- (jira_versions.status | default(0)) == 200
|
|
222
|
+
ansible.builtin.set_fact:
|
|
223
|
+
jira_fix_version_ids: >-
|
|
224
|
+
{{ jira_versions.json
|
|
225
|
+
| selectattr('name', 'in', jira_fix_versions)
|
|
226
|
+
| map(attribute='id')
|
|
227
|
+
| map('community.general.dict_kv', 'id')
|
|
228
|
+
| list }}
|
|
229
|
+
|
|
230
|
+
- name: Report Fix Version names not found in the project
|
|
231
|
+
when:
|
|
232
|
+
- jira_versions is defined
|
|
233
|
+
- (jira_versions.status | default(0)) == 200
|
|
234
|
+
- (jira_fix_version_ids | default([]) | length) < (jira_fix_versions | length)
|
|
235
|
+
ansible.builtin.debug:
|
|
236
|
+
msg: >-
|
|
237
|
+
Some Fix Version name(s) in {{ jira_fix_versions }} do not exist in project
|
|
238
|
+
{{ jira_project_key }} — create them in Jira first. Setting only the matched ones.
|
|
239
|
+
|
|
240
|
+
# Additive (keeps any existing fixVersions); Jira dedups by id, so re-runs are idempotent.
|
|
241
|
+
- name: Set the Fix Version on {{ jira_key_crm_branding }}
|
|
242
|
+
when: (jira_fix_version_ids | default([]) | length) > 0
|
|
243
|
+
ansible.builtin.uri:
|
|
244
|
+
url: "{{ jira_base_url }}/rest/api/2/issue/{{ jira_key_crm_branding }}"
|
|
245
|
+
method: PUT
|
|
246
|
+
url_username: "{{ jira_email }}"
|
|
247
|
+
url_password: "{{ jira_token }}"
|
|
248
|
+
force_basic_auth: true
|
|
249
|
+
body_format: json
|
|
250
|
+
body:
|
|
251
|
+
update:
|
|
252
|
+
fixVersions: "{{ jira_fix_version_ids | map('community.general.dict_kv', 'add') | list }}"
|
|
253
|
+
status_code: [204]
|
|
254
|
+
register: jira_fixver_set
|
|
255
|
+
failed_when: false
|
|
256
|
+
no_log: true
|
|
257
|
+
|
|
258
|
+
- name: Confirm the Fix Version result
|
|
259
|
+
ansible.builtin.debug:
|
|
260
|
+
msg: >-
|
|
261
|
+
{{ 'Set Fix Version ' ~ jira_fix_versions | join(', ') ~ ' on ' ~ jira_key_crm_branding
|
|
262
|
+
if (jira_fixver_set.status | default(0)) == 204
|
|
263
|
+
else 'Fix Version not set (HTTP ' ~ (jira_fixver_set.status | default('n/a')) ~ ')' }}
|
|
264
|
+
when: jira_fixver_set is defined and (jira_fixver_set is not skipped)
|
|
265
|
+
|
|
266
|
+
# --- Reviewers: pull from the repo's Bitbucket default-reviewers config -------------
|
|
267
|
+
- name: Resolve reviewers from repo default-reviewers config
|
|
268
|
+
when: (reviewers | length) == 0
|
|
269
|
+
block:
|
|
270
|
+
- name: Identify the authenticating Bitbucket account (PR author)
|
|
271
|
+
ansible.builtin.uri:
|
|
272
|
+
url: "{{ api_base }}/user"
|
|
273
|
+
url_username: "{{ bitbucket_email }}"
|
|
274
|
+
url_password: "{{ bitbucket_token }}"
|
|
275
|
+
force_basic_auth: true
|
|
276
|
+
return_content: true
|
|
277
|
+
register: bb_user
|
|
278
|
+
|
|
279
|
+
- name: Fetch the repository default reviewers
|
|
280
|
+
ansible.builtin.uri:
|
|
281
|
+
url: "{{ api_base }}/repositories/{{ workspace }}/{{ repo_slug }}/default-reviewers?pagelen=100"
|
|
282
|
+
url_username: "{{ bitbucket_email }}"
|
|
283
|
+
url_password: "{{ bitbucket_token }}"
|
|
284
|
+
force_basic_auth: true
|
|
285
|
+
return_content: true
|
|
286
|
+
register: bb_default_reviewers
|
|
287
|
+
|
|
288
|
+
# Bitbucket rejects a PR whose author is also a reviewer, so drop the authenticating account.
|
|
289
|
+
# The REST API does not auto-apply default reviewers, so we pass them explicitly.
|
|
290
|
+
# Bitbucket's PR-create reviewers array is keyed by uuid; exclude the author by account_id.
|
|
291
|
+
# Built in a single expression (not an accumulating set_fact loop, which is nondeterministic).
|
|
292
|
+
- name: Build reviewers list (excluding the PR author)
|
|
293
|
+
ansible.builtin.set_fact:
|
|
294
|
+
reviewers: >-
|
|
295
|
+
{{ bb_default_reviewers.json['values']
|
|
296
|
+
| rejectattr('account_id', 'equalto', bb_user.json.account_id)
|
|
297
|
+
| map(attribute='uuid')
|
|
298
|
+
| map('community.general.dict_kv', 'uuid')
|
|
299
|
+
| list }}
|
|
300
|
+
|
|
301
|
+
- name: Ensure clone parent directory exists
|
|
302
|
+
ansible.builtin.file:
|
|
303
|
+
path: "{{ work_dir | dirname }}"
|
|
304
|
+
state: directory
|
|
305
|
+
mode: "0755"
|
|
306
|
+
|
|
307
|
+
- name: Clone / refresh web-crm over SSH
|
|
308
|
+
ansible.builtin.git:
|
|
309
|
+
repo: "{{ repo_ssh_url }}"
|
|
310
|
+
dest: "{{ work_dir }}"
|
|
311
|
+
version: "{{ dest_branch_list[0] }}"
|
|
312
|
+
update: true
|
|
313
|
+
force: true
|
|
314
|
+
accept_hostkey: true
|
|
315
|
+
|
|
316
|
+
- name: Onboard the brand on each destination branch
|
|
317
|
+
ansible.builtin.include_tasks: per_branch.yml
|
|
318
|
+
loop: "{{ dest_branch_list }}"
|
|
319
|
+
loop_control:
|
|
320
|
+
loop_var: dest_branch
|
|
321
|
+
|
|
322
|
+
- name: Summary of pull requests
|
|
323
|
+
ansible.builtin.debug:
|
|
324
|
+
msg: "{{ pr_results | default([]) }}"
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
---
|
|
2
|
+
# Runs once per destination branch. `dest_branch` is the loop var.
|
|
3
|
+
|
|
4
|
+
- name: "[{{ dest_branch }}] Compose source branch name"
|
|
5
|
+
ansible.builtin.set_fact:
|
|
6
|
+
branch_prefix: "{{ 'hotfix' if dest_branch is match('(master|release)') else 'feature' }}"
|
|
7
|
+
|
|
8
|
+
# Suffix the release version onto master/release targets so each destination gets its OWN
|
|
9
|
+
# source branch. Without it, master-27.0 and master-27.1 (both present during a staged
|
|
10
|
+
# release, e.g. after a code freeze) collapse to one hotfix branch → the 2nd PR reuses the
|
|
11
|
+
# 1st's branch (wrong base) and close_source_branch on either merge kills the other PR.
|
|
12
|
+
- name: "[{{ dest_branch }}] Set source branch"
|
|
13
|
+
ansible.builtin.set_fact:
|
|
14
|
+
source_branch: >-
|
|
15
|
+
{{ branch_prefix }}/{{ jira_key_crm_branding }}-onboarding-crm-{{ antelope_id_norm }}{{
|
|
16
|
+
('-' ~ (dest_branch | regex_replace('^(master|release)-', '')))
|
|
17
|
+
if dest_branch is match('(master|release)') else '' }}
|
|
18
|
+
|
|
19
|
+
- name: "[{{ dest_branch }}] Fetch all remote branches"
|
|
20
|
+
ansible.builtin.command:
|
|
21
|
+
cmd: git fetch origin --prune
|
|
22
|
+
chdir: "{{ work_dir }}"
|
|
23
|
+
changed_when: false
|
|
24
|
+
|
|
25
|
+
- name: "[{{ dest_branch }}] Does the source branch already exist on origin?"
|
|
26
|
+
ansible.builtin.command:
|
|
27
|
+
cmd: "git ls-remote --exit-code --heads origin {{ source_branch }}"
|
|
28
|
+
chdir: "{{ work_dir }}"
|
|
29
|
+
register: remote_src
|
|
30
|
+
failed_when: false
|
|
31
|
+
changed_when: false
|
|
32
|
+
|
|
33
|
+
# Base the working branch on its own remote head if it already exists (idempotent re-run),
|
|
34
|
+
# otherwise on the destination branch.
|
|
35
|
+
- name: "[{{ dest_branch }}] Check out the working branch"
|
|
36
|
+
ansible.builtin.command:
|
|
37
|
+
cmd: >-
|
|
38
|
+
git checkout -B {{ source_branch }}
|
|
39
|
+
{{ ('origin/' + source_branch) if remote_src.rc == 0 else ('origin/' + dest_branch) }}
|
|
40
|
+
chdir: "{{ work_dir }}"
|
|
41
|
+
|
|
42
|
+
# Required flags always passed; --color and --base_url are optional (blank => CLI defaults:
|
|
43
|
+
# $corp palette and the dev baseUrl). argv is built as a list so no shell quoting is involved.
|
|
44
|
+
- name: "[{{ dest_branch }}] Generate brand files via antelope-cli"
|
|
45
|
+
ansible.builtin.command:
|
|
46
|
+
argv: >-
|
|
47
|
+
{{ ['npx', 'antelope-cli@' ~ antelope_cli_version, 'onboarding-crm',
|
|
48
|
+
'--brand_id', antelope_id_norm,
|
|
49
|
+
'--brand_name', brand_name,
|
|
50
|
+
'--logo_url', logo_url,
|
|
51
|
+
'--favicon_url', favicon_url,
|
|
52
|
+
'--languages', languages_csv,
|
|
53
|
+
'--fcm_sender_id', (fcm_sender_id | string),
|
|
54
|
+
'--type', crm_type]
|
|
55
|
+
+ (['--color', color] if (color | default('') | length) > 0 else [])
|
|
56
|
+
+ (['--base_url', base_url] if (base_url | default('') | length) > 0 else []) }}
|
|
57
|
+
chdir: "{{ work_dir }}"
|
|
58
|
+
environment:
|
|
59
|
+
CI: "true"
|
|
60
|
+
changed_when: true
|
|
61
|
+
|
|
62
|
+
- name: "[{{ dest_branch }}] Stage changes"
|
|
63
|
+
ansible.builtin.command:
|
|
64
|
+
cmd: git add -A
|
|
65
|
+
chdir: "{{ work_dir }}"
|
|
66
|
+
changed_when: false
|
|
67
|
+
|
|
68
|
+
- name: "[{{ dest_branch }}] Detect staged changes"
|
|
69
|
+
ansible.builtin.command:
|
|
70
|
+
cmd: git diff --cached --quiet
|
|
71
|
+
chdir: "{{ work_dir }}"
|
|
72
|
+
register: staged
|
|
73
|
+
failed_when: false
|
|
74
|
+
changed_when: false
|
|
75
|
+
|
|
76
|
+
- name: "[{{ dest_branch }}] Commit"
|
|
77
|
+
ansible.builtin.command:
|
|
78
|
+
cmd: >-
|
|
79
|
+
git -c user.name="{{ git_user_name }}" -c user.email="{{ git_user_email }}"
|
|
80
|
+
commit -m "{{ jira_key_crm_branding }}: On-Boarding {{ brand_name }} CRM Branding"
|
|
81
|
+
chdir: "{{ work_dir }}"
|
|
82
|
+
when: staged.rc == 1
|
|
83
|
+
|
|
84
|
+
- name: "[{{ dest_branch }}] Push source branch"
|
|
85
|
+
ansible.builtin.command:
|
|
86
|
+
cmd: "git push -u origin {{ source_branch }}"
|
|
87
|
+
chdir: "{{ work_dir }}"
|
|
88
|
+
when: staged.rc == 1
|
|
89
|
+
|
|
90
|
+
- name: "[{{ dest_branch }}] Open pull request"
|
|
91
|
+
ansible.builtin.uri:
|
|
92
|
+
url: "{{ api_base }}/repositories/{{ workspace }}/{{ repo_slug }}/pullrequests"
|
|
93
|
+
method: POST
|
|
94
|
+
url_username: "{{ bitbucket_email }}"
|
|
95
|
+
url_password: "{{ bitbucket_token }}"
|
|
96
|
+
force_basic_auth: true
|
|
97
|
+
body_format: json
|
|
98
|
+
body:
|
|
99
|
+
title: "{{ jira_key_crm_branding }}: On-Boarding {{ brand_name }} CRM Branding"
|
|
100
|
+
description: "{{ jira_key_crm_branding }}: On-Boarding {{ brand_name }} CRM Branding"
|
|
101
|
+
source:
|
|
102
|
+
branch:
|
|
103
|
+
name: "{{ source_branch }}"
|
|
104
|
+
destination:
|
|
105
|
+
branch:
|
|
106
|
+
name: "{{ dest_branch }}"
|
|
107
|
+
reviewers: "{{ reviewers }}"
|
|
108
|
+
close_source_branch: true
|
|
109
|
+
return_content: true
|
|
110
|
+
status_code: [201, 400] # 400 tolerated: a PR for this source->dest already exists
|
|
111
|
+
register: pr_response
|
|
112
|
+
|
|
113
|
+
- name: "[{{ dest_branch }}] Record PR result"
|
|
114
|
+
ansible.builtin.set_fact:
|
|
115
|
+
pr_results: >-
|
|
116
|
+
{{ (pr_results | default([])) + [{
|
|
117
|
+
'destination': dest_branch,
|
|
118
|
+
'source': source_branch,
|
|
119
|
+
'status': pr_response.status,
|
|
120
|
+
'url': (pr_response.json.links.html.href | default('(already exists or not created)'))
|
|
121
|
+
}] }}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
# Constants — the target repository for CRM onboarding.
|
|
3
|
+
api_base: "https://api.bitbucket.org/2.0"
|
|
4
|
+
workspace: "xsitesinc"
|
|
5
|
+
repo_slug: "web-crm"
|
|
6
|
+
repo_ssh_url: "git@bitbucket.org:xsitesinc/web-crm.git"
|
|
7
|
+
|
|
8
|
+
# Consul (v2 cluster) — source of the release train used to derive destination branches.
|
|
9
|
+
consul_url: "https://consul.xsites.xyz"
|
package/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
const args = process.argv.slice(2);
|
|
3
|
-
|
|
4
|
-
if (args[0] === "onboarding") {
|
|
5
|
-
require('./onboarding');
|
|
6
|
-
} else if (args[0] === "onboarding-ca") {
|
|
7
|
-
require('./onboarding-ca');
|
|
8
|
-
} else if (args[0] === "onboarding-crm") {
|
|
9
|
-
require('./onboarding-crm');
|
|
10
|
-
} else {
|
|
11
|
-
console.log("Unknown command");
|
|
12
|
-
}
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const args = process.argv.slice(2);
|
|
3
|
+
|
|
4
|
+
if (args[0] === "onboarding") {
|
|
5
|
+
require('./onboarding');
|
|
6
|
+
} else if (args[0] === "onboarding-ca") {
|
|
7
|
+
require('./onboarding-ca');
|
|
8
|
+
} else if (args[0] === "onboarding-crm") {
|
|
9
|
+
require('./onboarding-crm');
|
|
10
|
+
} else {
|
|
11
|
+
console.log("Unknown command");
|
|
12
|
+
}
|
package/onboarding/brand.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
let brand = {
|
|
2
|
-
brandName: '',
|
|
3
|
-
kebabCaseName: '',
|
|
4
|
-
connectedBrandName: '',
|
|
5
|
-
color: '',
|
|
6
|
-
languages: null,
|
|
7
|
-
favicon: '',
|
|
8
|
-
type: '',
|
|
9
|
-
FCMSenderId: '',
|
|
10
|
-
logo: ''
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
function updateBrand(updatedBrand) {
|
|
14
|
-
brand = { ...brand, ...updatedBrand };
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function getBrand() {
|
|
18
|
-
return brand;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
module.exports = { updateBrand, getBrand };
|
|
1
|
+
let brand = {
|
|
2
|
+
brandName: '',
|
|
3
|
+
kebabCaseName: '',
|
|
4
|
+
connectedBrandName: '',
|
|
5
|
+
color: '',
|
|
6
|
+
languages: null,
|
|
7
|
+
favicon: '',
|
|
8
|
+
type: '',
|
|
9
|
+
FCMSenderId: '',
|
|
10
|
+
logo: ''
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
function updateBrand(updatedBrand) {
|
|
14
|
+
brand = { ...brand, ...updatedBrand };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function getBrand() {
|
|
18
|
+
return brand;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
module.exports = { updateBrand, getBrand };
|
|
@@ -1,71 +1,71 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const brandModule = require('./brand.js');
|
|
3
|
-
const chalk = require('chalk');
|
|
4
|
-
const configsFilePath = 'src/configs/configs.ts';
|
|
5
|
-
|
|
6
|
-
async function start(rl) {
|
|
7
|
-
try {
|
|
8
|
-
const configFile = configsFilePath;
|
|
9
|
-
// Get User FCMSenderId and type
|
|
10
|
-
let { FCMSenderId, type } = await promptForValues(rl);
|
|
11
|
-
// Making sure the type is all caps
|
|
12
|
-
type = type.toUpperCase();
|
|
13
|
-
// Update brand state
|
|
14
|
-
brandModule.updateBrand({ FCMSenderId, type });
|
|
15
|
-
// Generate new config with new values
|
|
16
|
-
const newConfigContent = updateConfigFile();
|
|
17
|
-
// Write to file
|
|
18
|
-
return new Promise((resolve, reject) => {
|
|
19
|
-
fs.writeFile(configFile, newConfigContent, 'utf8', (error) => {
|
|
20
|
-
if (error) {
|
|
21
|
-
reject(error);
|
|
22
|
-
} else {
|
|
23
|
-
console.log(chalk.cyan('configs.ts file updated successfully!'));
|
|
24
|
-
resolve(null);
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
} catch (e) {
|
|
29
|
-
console.error(e);
|
|
30
|
-
return start(rl);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const updateConfigFile = () => {
|
|
35
|
-
const brand = brandModule.getBrand();
|
|
36
|
-
return `export const configs: WebCrmConfig = {
|
|
37
|
-
baseUrl: 'https://dev-apicrm.antelopesystem.com/SignalsCRM/',
|
|
38
|
-
appId: 0,
|
|
39
|
-
type: '${brand.type}',
|
|
40
|
-
defaultLanguage: 'en',
|
|
41
|
-
gaTrackingID: 'UA-70456753-2',
|
|
42
|
-
colorTheme: 'theme-${brand.connectedBrandName}',
|
|
43
|
-
templateTheme: 'theme-template-${brand.connectedBrandName}',
|
|
44
|
-
title: '${brand.brandName}',
|
|
45
|
-
favicon: '${brand.favicon}',
|
|
46
|
-
affiliatesApiUrl: '',
|
|
47
|
-
FCMSenderId: '${brand.FCMSenderId}',
|
|
48
|
-
brandAssetsFolder: '${brand.connectedBrandName}',
|
|
49
|
-
};`;
|
|
50
|
-
};
|
|
51
|
-
const promptForValues = (rl) => {
|
|
52
|
-
return new Promise((resolve, reject) => {
|
|
53
|
-
try {
|
|
54
|
-
rl.question(
|
|
55
|
-
'Enter the FCMSenderId value (see https://xsites.atlassian.net/wiki/spaces/IKB/pages/777650347/Onboarding+Branding+Manual+for+devs#Firebase): ',
|
|
56
|
-
(FCMSenderId) => {
|
|
57
|
-
rl.question(
|
|
58
|
-
'Enter the type value (allowed values: CORP_FL, IB_FL, CORP_AFF_FL, CORP_AFF_IB_PORTAL, CORP_AFF_MSQ): ',
|
|
59
|
-
(type) => {
|
|
60
|
-
resolve({ FCMSenderId, type });
|
|
61
|
-
}
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
);
|
|
65
|
-
} catch (error) {
|
|
66
|
-
reject(error);
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
module.exports = { start };
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const brandModule = require('./brand.js');
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
const configsFilePath = 'src/configs/configs.ts';
|
|
5
|
+
|
|
6
|
+
async function start(rl) {
|
|
7
|
+
try {
|
|
8
|
+
const configFile = configsFilePath;
|
|
9
|
+
// Get User FCMSenderId and type
|
|
10
|
+
let { FCMSenderId, type } = await promptForValues(rl);
|
|
11
|
+
// Making sure the type is all caps
|
|
12
|
+
type = type.toUpperCase();
|
|
13
|
+
// Update brand state
|
|
14
|
+
brandModule.updateBrand({ FCMSenderId, type });
|
|
15
|
+
// Generate new config with new values
|
|
16
|
+
const newConfigContent = updateConfigFile();
|
|
17
|
+
// Write to file
|
|
18
|
+
return new Promise((resolve, reject) => {
|
|
19
|
+
fs.writeFile(configFile, newConfigContent, 'utf8', (error) => {
|
|
20
|
+
if (error) {
|
|
21
|
+
reject(error);
|
|
22
|
+
} else {
|
|
23
|
+
console.log(chalk.cyan('configs.ts file updated successfully!'));
|
|
24
|
+
resolve(null);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
} catch (e) {
|
|
29
|
+
console.error(e);
|
|
30
|
+
return start(rl);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const updateConfigFile = () => {
|
|
35
|
+
const brand = brandModule.getBrand();
|
|
36
|
+
return `export const configs: WebCrmConfig = {
|
|
37
|
+
baseUrl: 'https://dev-apicrm.antelopesystem.com/SignalsCRM/',
|
|
38
|
+
appId: 0,
|
|
39
|
+
type: '${brand.type}',
|
|
40
|
+
defaultLanguage: 'en',
|
|
41
|
+
gaTrackingID: 'UA-70456753-2',
|
|
42
|
+
colorTheme: 'theme-${brand.connectedBrandName}',
|
|
43
|
+
templateTheme: 'theme-template-${brand.connectedBrandName}',
|
|
44
|
+
title: '${brand.brandName}',
|
|
45
|
+
favicon: '${brand.favicon}',
|
|
46
|
+
affiliatesApiUrl: '',
|
|
47
|
+
FCMSenderId: '${brand.FCMSenderId}',
|
|
48
|
+
brandAssetsFolder: '${brand.connectedBrandName}',
|
|
49
|
+
};`;
|
|
50
|
+
};
|
|
51
|
+
const promptForValues = (rl) => {
|
|
52
|
+
return new Promise((resolve, reject) => {
|
|
53
|
+
try {
|
|
54
|
+
rl.question(
|
|
55
|
+
'Enter the FCMSenderId value (see https://xsites.atlassian.net/wiki/spaces/IKB/pages/777650347/Onboarding+Branding+Manual+for+devs#Firebase): ',
|
|
56
|
+
(FCMSenderId) => {
|
|
57
|
+
rl.question(
|
|
58
|
+
'Enter the type value (allowed values: CORP_FL, IB_FL, CORP_AFF_FL, CORP_AFF_IB_PORTAL, CORP_AFF_MSQ): ',
|
|
59
|
+
(type) => {
|
|
60
|
+
resolve({ FCMSenderId, type });
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
reject(error);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
module.exports = { start };
|