@docupace/pipeline 1.0.3 โ†’ 1.0.4-1.haproxysync.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,10 +2,11 @@ import fs from 'fs';
2
2
  import path from 'path';
3
3
  import yaml from 'js-yaml';
4
4
  import { $ } from 'zx';
5
-
6
- const REPO_NAME = 'gitops-dev';
7
- const REPO_URL = `https://x-token-auth:${process.env.GITOPS_DEV_REP_TOKEN}@bitbucket.org/dp-cloud/${REPO_NAME}.git`;
8
- const GITOPS_BRANCH = 'master';
5
+ import lodash from 'lodash';
6
+ import { appInfo, environmentConfig, getRepUrl } from './config.js';
7
+ import { copy2 } from './copy.js';
8
+ import axios from 'axios';
9
+ import { deployCore, deployConnect } from './jenkins.js';
9
10
 
10
11
  /**
11
12
  * Clone the repository, read the YAML file, and return the parsed data and file paths.
@@ -13,24 +14,180 @@ const GITOPS_BRANCH = 'master';
13
14
  * @param {string} site - The site name.
14
15
  * @returns {object} - The repository path, file path, and YAML data.
15
16
  */
16
- export async function readDeployConfig(application, site) {
17
- const repoPath = path.join(process.cwd(), REPO_NAME);
18
- const deployConfigFilePath = path.join(repoPath, `dp/${site}/${application}.values.yaml`);
19
17
 
20
- console.log(`Cloning repository: ${REPO_NAME}`);
21
- await $`git clone ${REPO_URL}`;
22
- console.log(`Repository cloned to: ${repoPath}`);
18
+ function getRepoLocalPath(env) {
19
+ const repoName = `gitops-${env}`;
20
+ const repoPath = path.join(process.cwd(), repoName);
21
+ return { repoPath, repoName };
22
+ }
23
+
24
+ async function updateAndCommitConnectVersion(
25
+ toEnv,
26
+ toSite,
27
+ getComparedVersion,
28
+ connectDeployPath,
29
+ ) {
30
+ const connectToEnv = toEnv == 'qa' ? 'preprod' : toEnv;
31
+ const filePath = path.join(
32
+ connectDeployPath,
33
+ 'envs',
34
+ connectToEnv,
35
+ toSite,
36
+ 'dock.sh',
37
+ );
38
+
39
+ try {
40
+ let content = fs.readFileSync(filePath, 'utf8');
41
+ content = content.replace(
42
+ /IMAGE_VERSION=.*/,
43
+ `IMAGE_VERSION=git-commit-${getComparedVersion}`,
44
+ );
45
+ fs.writeFileSync(filePath, content, 'utf8');
46
+
47
+ // Git commands to stage, commit and push changes
48
+ await $`cd ${connectDeployPath} && git config user.email "gitops@docupace.com"`;
49
+ await $`cd ${connectDeployPath} && git add .`;
50
+ await $`cd ${connectDeployPath} && git commit -m "Update Connect version for ${toSite} in ${toEnv} to ${getComparedVersion}" || echo "No changes to commit"`;
51
+ await $`cd ${connectDeployPath} && git push`;
52
+
53
+ console.log('๐Ÿงน Cleaning up...');
54
+ await $`rm -rf ${connectDeployPath}`;
55
+ console.log('โœ… Cleanup complete.');
56
+ } catch (error) {
57
+ console.error('Error updating Connect version:', error);
58
+ throw error;
59
+ }
60
+ }
61
+
62
+ async function fetchLoginFooter(env, site, isNewUrl) {
63
+ const url = isNewUrl
64
+ ? environmentConfig[env].newUrl(site)
65
+ : environmentConfig[env].oldUrl(site);
66
+ const endpoint = isNewUrl ? '/connect/loginFooter' : '_ui/loginFooter';
67
+ return await axios.get(`${url}${endpoint}`);
68
+ }
69
+
70
+ async function compareGetConnectSiteVersions(fromEnv, fromSite, toEnv, toSite) {
71
+ try {
72
+ let fromResponse, toResponse;
73
+ try {
74
+ fromResponse = await fetchLoginFooter(fromEnv, fromSite, true);
75
+ } catch {
76
+ fromResponse = await fetchLoginFooter(fromEnv, fromSite, false);
77
+ }
23
78
 
24
- let deployConfig;
25
79
  try {
26
- deployConfig = yaml.load(fs.readFileSync(deployConfigFilePath, 'utf8'));
27
- console.log(`YAML file loaded from: ${deployConfigFilePath}`);
28
- } catch (error) {
29
- console.error(`Error reading YAML file: ${error.message}`);
30
- process.exit(1);
80
+ toResponse = await fetchLoginFooter(toEnv, toSite, true);
81
+ } catch {
82
+ toResponse = await fetchLoginFooter(toEnv, toSite, false);
83
+ }
84
+
85
+ const fromMatch = fromResponse.data.match(/UI Build: ([a-f0-9]*)/);
86
+ const toMatch = toResponse.data.match(/UI Build: ([a-f0-9]*)/);
87
+
88
+ if (fromMatch && fromMatch[1] && toMatch && toMatch[1]) {
89
+ if (fromMatch[1] !== toMatch[1]) {
90
+ return fromMatch[1];
91
+ }
31
92
  }
93
+ return false;
94
+ } catch (error) {
95
+ console.error('Error fetching Connect versions:', error);
96
+ throw error;
97
+ }
98
+ }
99
+ function getRepoLocalPathByRepoSlug(repoSlug) {
100
+ const repoName = `${repoSlug}`;
101
+ const repoPath = path.join(process.cwd(), repoName);
102
+ return { repoPath, repoName };
103
+ }
104
+
105
+ function cleanUpRepoPath(repoPath) {
106
+ // Check and handle repo directory
107
+ if (fs.existsSync(repoPath)) {
108
+ console.log(`${repoPath} directory exists. Removing it...`);
109
+ fs.rmSync(repoPath, {
110
+ recursive: true,
111
+ force: true,
112
+ });
113
+ }
114
+ }
32
115
 
33
- return { repoPath, deployConfigFilePath, deployConfig };
116
+ export async function cloneEnvRepository(env) {
117
+ const { repoPath, repoName } = getRepoLocalPath(env);
118
+ const repoUrl = getRepUrl(repoName);
119
+ console.log(`Cloning repository: ${repoName}`);
120
+ await cleanUpRepoPath(repoPath);
121
+ await $`git clone --depth 1 ${repoUrl}`;
122
+ console.log(`Repository cloned to: ${repoPath}`);
123
+ return repoPath;
124
+ }
125
+
126
+ export async function cloneRepository(repoSlug) {
127
+ const { repoPath, repoName } = getRepoLocalPathByRepoSlug(repoSlug);
128
+ const repoUrl = getRepUrl(repoName);
129
+
130
+ await cleanUpRepoPath(repoPath);
131
+
132
+ console.log(`Cloning repository: ${repoName}`);
133
+ await $`git clone --depth 1 ${repoUrl}`;
134
+ console.log(`Repository cloned to: ${repoPath}`);
135
+ return repoPath;
136
+ }
137
+
138
+ function getConfigPath(application, env, site, name) {
139
+ const { repoPath } = getRepoLocalPath(env);
140
+ const deployConfigFilePath = path.join(
141
+ repoPath,
142
+ `dp/${site}/${application}.${name}.yaml`,
143
+ );
144
+
145
+ return { repoPath, deployConfigFilePath };
146
+ }
147
+
148
+ function getAppTypesFromRepo(env, site) {
149
+ const { repoPath } = getRepoLocalPath(env);
150
+ const deployConfigFilePath = path.join(repoPath, `dp/${site}`);
151
+ const applications = [];
152
+ if (fs.existsSync(deployConfigFilePath)) {
153
+ const files = fs.readdirSync(deployConfigFilePath);
154
+ files.forEach((file) => {
155
+ if (file.includes('.values.yaml')) {
156
+ const appName = file.split('.')[0];
157
+ applications.push(appName);
158
+ }
159
+ });
160
+ }
161
+
162
+ return { applications };
163
+ }
164
+
165
+ export async function readDeployConfig(application, env, site, name) {
166
+ const { deployConfigFilePath } = getConfigPath(application, env, site, name);
167
+
168
+ let deployConfig;
169
+ try {
170
+ deployConfig = yaml.load(fs.readFileSync(deployConfigFilePath, 'utf8'));
171
+ console.log(`YAML file loaded from: ${deployConfigFilePath}`);
172
+ } catch (error) {
173
+ console.error(`Error reading YAML file: ${error.message}`);
174
+ process.exit(1);
175
+ }
176
+
177
+ return { deployConfig, deployConfigFilePath };
178
+ }
179
+
180
+ export async function cloneAndReadDeployConfig(application, env, site) {
181
+ const repoPath = await cloneEnvRepository(env);
182
+
183
+ const { deployConfig, deployConfigFilePath } = await readDeployConfig(
184
+ application,
185
+ env,
186
+ site,
187
+ 'values',
188
+ );
189
+
190
+ return { repoPath, deployConfigFilePath, deployConfig };
34
191
  }
35
192
 
36
193
  /**
@@ -40,15 +197,15 @@ export async function readDeployConfig(application, site) {
40
197
  * @returns {object} - The updated YAML data.
41
198
  */
42
199
  export function setTag(deployConfig, tag) {
43
- if (deployConfig.image && deployConfig.image.tag) {
44
- console.log(`Current image tag: ${deployConfig.image.tag}`);
45
- deployConfig.image.tag = tag;
46
- console.log(`Updated image tag to: ${deployConfig.image.tag}`);
47
- } else {
48
- console.error('No "image.tag" field found in the YAML file.');
49
- process.exit(1);
50
- }
51
- return deployConfig;
200
+ if (deployConfig.image && deployConfig.image.tag) {
201
+ console.log(`Current image tag: ${deployConfig.image.tag}`);
202
+ deployConfig.image.tag = tag;
203
+ console.log(`Updated image tag to: ${deployConfig.image.tag}`);
204
+ } else {
205
+ console.error('No "image.tag" field found in the YAML file.');
206
+ process.exit(1);
207
+ }
208
+ return deployConfig;
52
209
  }
53
210
 
54
211
  /**
@@ -57,35 +214,50 @@ export function setTag(deployConfig, tag) {
57
214
  * @param {string} deployConfigFilePath - The path to the YAML file.
58
215
  * @param {object} deployConfig - The updated YAML data.
59
216
  */
60
- export async function writeDeployConfig(repoPath, deployConfigFilePath, deployConfig) {
61
- try {
62
- fs.writeFileSync(deployConfigFilePath, yaml.dump(deployConfig), 'utf8');
63
- console.log(`โœ… Updated YAML file saved at: ${deployConfigFilePath}`);
64
- } catch (error) {
65
- console.error(`โŒ Error writing YAML file: ${error.message}`);
66
- process.exit(1);
67
- }
68
217
 
69
- console.log('๐Ÿ“Œ Checking for updates to commit...');
70
- // Check if there are any changes to commit
71
- const status = (await $`cd ${repoPath} && git status --porcelain`).stdout.trim();
72
- if (!status) {
73
- console.log('โœ… No changes to commit. Exiting.');
74
- await $`rm -rf ${repoPath}`;
75
- console.log('๐Ÿงน Cleanup complete.');
76
- return;
77
- }
218
+ export async function pushDeployConfig(repoPath, commitMessage) {
219
+ console.log('๐Ÿ“Œ Checking for updates to commit...');
220
+ // Check if there are any changes to commit
221
+ const status = (
222
+ await $`cd ${repoPath} && git status --porcelain`
223
+ ).stdout.trim();
224
+ if (!status) {
225
+ console.log('โœ… No changes to commit. Exiting.');
226
+ await $`rm -rf ${repoPath}`;
227
+ console.log('๐Ÿงน Cleanup complete.');
228
+ return;
229
+ }
78
230
 
79
- console.log('๐Ÿ“Œ Committing changes to the repository...');
80
- await $`cd ${repoPath} && git config user.email "gitops@docupace.com"`;
81
- await $`cd ${repoPath} && git add ${deployConfigFilePath}`;
82
- await $`cd ${repoPath} && git commit -m "Update image tag to ${deployConfig.image.tag}"`;
83
- await $`cd ${repoPath} && git push origin ${GITOPS_BRANCH}`;
84
- console.log('โœ… Changes pushed to the remote repository.');
231
+ console.log('๐Ÿ“Œ Committing changes to the repository...');
232
+ await $`cd ${repoPath} && git config user.email "gitops@docupace.com"`;
233
+ await $`cd ${repoPath} && git add .`;
234
+ await $`cd ${repoPath} && git commit -m ${commitMessage}`;
235
+ await $`cd ${repoPath} && git push`;
236
+ console.log('โœ… Changes pushed to the remote repository.');
85
237
 
86
- console.log('๐Ÿงน Cleaning up...');
87
- await $`rm -rf ${repoPath}`;
88
- console.log('โœ… Cleanup complete.');
238
+ console.log('๐Ÿงน Cleaning up...');
239
+ await $`rm -rf ${repoPath}`;
240
+ console.log('โœ… Cleanup complete.');
241
+ }
242
+
243
+ function writeDeployConfig(deployConfigFilePath, deployConfig) {
244
+ try {
245
+ fs.writeFileSync(deployConfigFilePath, yaml.dump(deployConfig), 'utf8');
246
+ console.log(`โœ… Updated YAML file saved at: ${deployConfigFilePath}`);
247
+ } catch (error) {
248
+ console.error(`โŒ Error writing YAML file: ${error.message}`);
249
+ process.exit(1);
250
+ }
251
+ }
252
+
253
+ export async function writeAndPushDeployConfig(
254
+ repoPath,
255
+ deployConfigFilePath,
256
+ deployConfig,
257
+ commitMessage,
258
+ ) {
259
+ writeDeployConfig(deployConfigFilePath, deployConfig);
260
+ await pushDeployConfig(repoPath, commitMessage);
89
261
  }
90
262
 
91
263
  /**
@@ -94,35 +266,275 @@ export async function writeDeployConfig(repoPath, deployConfigFilePath, deployCo
94
266
  * @param {string} site - The site name.
95
267
  */
96
268
 
97
- async function getDeployTag() {
98
- const gitTag = (await $`git tag --points-at HEAD | grep '^v' | head -n 1`).stdout.trim()
99
- const deployTag = gitTag || `build-${process.env.BITBUCKET_BUILD_NUMBER}`;
100
- return deployTag;
269
+ export async function getDeployTag() {
270
+ const gitTag = (
271
+ await $`git tag --points-at HEAD | grep '^v' | head -n 1`
272
+ ).stdout.trim();
273
+ const deployTag = gitTag || `build-${process.env.BITBUCKET_BUILD_NUMBER}`;
274
+ return deployTag;
275
+ }
276
+
277
+ export async function getDefaultDeploySite(deployTag) {
278
+ const env = deployTag.includes('alpha') ? 'dev' : 'qa';
279
+ const site = env === 'dev' ? 'financialdev' : 'qa';
280
+ return { env, site };
281
+ }
282
+
283
+ export async function deployTemplate(env, site, deployTag) {
284
+ console.log(`Deploying standard template for site: ${site}`);
285
+ console.log(`Using deployment tag: ${deployTag}`);
286
+ const { repoPath, deployConfigFilePath, deployConfig } =
287
+ await cloneAndReadDeployConfig('graphql-server', env, site);
288
+
289
+ deployConfig.graphqlServer.standardConfigRemoteBranch = deployTag;
290
+
291
+ await writeAndPushDeployConfig(
292
+ repoPath,
293
+ deployConfigFilePath,
294
+ deployConfig,
295
+ `Update template to ${deployConfig.graphqlServer.standardConfigRemoteBranch}`,
296
+ );
297
+ console.log('Deployment completed successfully.');
298
+ }
299
+
300
+ export async function deployAppWithTag(application, env, site, deployTag) {
301
+ console.log(`Deploying application: ${application} for site: ${site}`);
302
+ console.log(`Using deployment tag: ${deployTag}`);
303
+
304
+ if (env !== 'dev') {
305
+ const appDetails = appInfo[application];
306
+ await copy2(appDetails.repositoryName, 'dev', env, deployTag);
307
+ }
308
+
309
+ const { repoPath, deployConfigFilePath, deployConfig } =
310
+ await cloneAndReadDeployConfig(application, env, site);
311
+ const updatedConfigData = setTag(deployConfig, deployTag);
312
+ await writeAndPushDeployConfig(
313
+ repoPath,
314
+ deployConfigFilePath,
315
+ updatedConfigData,
316
+ `Update image tag to ${deployConfig.image.tag}`,
317
+ );
318
+
319
+ console.log('Deployment completed successfully.');
320
+ }
321
+
322
+ async function getAppInfo(coreUrl) {
323
+ const url = `${coreUrl}/b2b/rest/v1/appinfo`;
324
+ return await axios.get(url);
325
+ }
326
+
327
+ function getBranchNameFromVersion(version) {
328
+ const match = version.match(/(\d+\.\d+\.[^\-]+)(?:-(\d+)-g([a-f0-9]+))?/);
329
+
330
+ if (!match) {
331
+ throw new Error(`Invalid version format: ${version}`);
332
+ }
333
+
334
+ const fullVersion = match[1]; // e.g., 24.19.19, 24.20.alpha3, etc.
335
+ const customBranch = match[2]; // e.g., 4, 58, or 0
336
+ const commitHash = match[3]; // e.g., 668edef58e, 634cf6c904, etc.
337
+
338
+ // If "alpha" is in the version or customBranch is non-zero, use the commit hash
339
+ if (fullVersion.includes('alpha') || (customBranch && customBranch !== '0')) {
340
+ return commitHash;
341
+ }
342
+
343
+ // Otherwise, use the full version
344
+ return 'v' + fullVersion;
101
345
  }
102
346
 
103
- export async function deployTemplate(site) {
104
- const deployTag = await getDeployTag();
105
- console.log(`Deploying standard template for site: ${site}`);
106
- console.log(`Using deployment tag: ${deployTag}`);
107
- const { repoPath, deployConfigFilePath, deployConfig } = await readDeployConfig('graphql-server', site);
347
+ async function getCoreBranchName(fromEnv, fromSite) {
348
+ const envConfig = environmentConfig[fromEnv];
349
+ const oldUrl = envConfig.oldUrl(fromSite);
350
+ const newUrl = envConfig.newUrl(fromSite) + '/core';
108
351
 
109
- deployConfig.graphqlServer.standardConfigRemoteBranch = deployTag;
352
+ let appinfo;
353
+ try {
354
+ appinfo = await getAppInfo(oldUrl);
355
+ } catch {
356
+ try {
357
+ appinfo = await getAppInfo(newUrl);
358
+ } catch {
359
+ throw new Error('Cannot get app info');
360
+ }
361
+ }
362
+
363
+ const coreVersion = appinfo.data.core.version;
364
+ const branchName = getBranchNameFromVersion(coreVersion);
365
+ return branchName;
366
+ }
367
+
368
+ export async function deployApp(
369
+ application,
370
+ appDetails,
371
+ fromEnv,
372
+ fromSite,
373
+ toEnv,
374
+ toSite,
375
+ ) {
376
+ let changesMade = false;
377
+ console.log(`Processing application: ${application}`);
378
+
379
+ // Read the deployment configuration for the source environment and site
380
+ const { deployConfig: fromDeployConfig } = await readDeployConfig(
381
+ application,
382
+ fromEnv,
383
+ fromSite,
384
+ 'values',
385
+ );
386
+
387
+ if (fromEnv !== toEnv) {
388
+ await copy2(
389
+ appDetails.repositoryName,
390
+ fromEnv,
391
+ toEnv,
392
+ fromDeployConfig.image.tag,
393
+ );
394
+ }
395
+
396
+ // Read the deployment configuration for the target environment and site
397
+ const {
398
+ deployConfig: toDeployConfig,
399
+ deployConfigFilePath: toDeployConfigFilePath,
400
+ } = await readDeployConfig(application, toEnv, toSite, 'values');
401
+
402
+ // Update target configuration using attributes specified in appInfo
403
+ for (const attribute of appDetails.deployAttributes) {
404
+ const sourceValue = lodash.get(fromDeployConfig, attribute);
405
+
406
+ if (sourceValue !== undefined) {
407
+ // Update the target configuration with the source value
408
+ lodash.set(toDeployConfig, attribute, sourceValue);
409
+ changesMade = true;
410
+ }
411
+ }
412
+
413
+ const {
414
+ deployConfig: toDeployAppConfig,
415
+ deployConfigFilePath: toDeployAppConfigFilePath,
416
+ } = await readDeployConfig(application, toEnv, toSite, 'app');
110
417
 
111
- await writeDeployConfig(repoPath, deployConfigFilePath, deployConfig);
112
- console.log('Deployment completed successfully.');
418
+ toDeployAppConfig.revision = fromDeployConfig.image.tag;
113
419
 
420
+ // Write updated configuration to the target YAML file
421
+ writeDeployConfig(toDeployConfigFilePath, toDeployConfig);
422
+
423
+ writeDeployConfig(toDeployAppConfigFilePath, toDeployAppConfig);
424
+ return changesMade;
114
425
  }
115
426
 
427
+ export async function deployFromSite(
428
+ fromEnv,
429
+ fromSite,
430
+ toEnv,
431
+ toSite,
432
+ isDeployCore,
433
+ isDeployConnect,
434
+ ) {
435
+ if (isDeployCore === 'true') {
436
+ const branchName = await getCoreBranchName(fromEnv, fromSite);
437
+
438
+ const coreEnv = toEnv == 'qa' ? 'preprod' : toEnv;
439
+ await deployCore(coreEnv, toSite, 'true', branchName);
440
+
441
+ // To be added back when splitting between on prem and in cloud
442
+ /*await runPipeline('site-deploy', 'deploy-core', 'main', {
443
+ ENV: toEnv,
444
+ SITE: toSite,
445
+ LIQUIBASE: 'true',
446
+ BRANCH: branchName,
447
+ });*/
448
+ }
449
+
450
+ if (isDeployConnect === 'true') {
451
+ const branch = '';
452
+ const getComparedVersion = await compareGetConnectSiteVersions(
453
+ fromEnv,
454
+ fromSite,
455
+ toEnv,
456
+ toSite,
457
+ );
458
+ if (getComparedVersion) {
459
+ console.log('Version to deploy is: ', getComparedVersion);
460
+ const connectDeployPath = await cloneRepository('connect-deploy');
461
+ // update target version set to git-commit-${getCommparedVersion}}
462
+ await updateAndCommitConnectVersion(
463
+ toEnv,
464
+ toSite,
465
+ getComparedVersion,
466
+ connectDeployPath,
467
+ );
468
+ // save and deploy
469
+ const runLiquibase = true;
470
+ await deployConnect(toEnv, toSite, runLiquibase, branch);
471
+ }
472
+ }
473
+
474
+ // Clone repositories for source and target environments
475
+ const fromRepoPath = await cloneEnvRepository(fromEnv);
476
+ const toRepoPath =
477
+ toEnv === fromEnv ? fromRepoPath : await cloneEnvRepository(toEnv);
116
478
 
117
- export async function deploy(application, site) {
118
- const deployTag = getDeployTag();
479
+ // Initialize a flag to track changes
480
+ let changesMade = false;
481
+ const applications = await getAppTypesFromRepo(toEnv, toSite);
482
+ console.log(applications);
483
+ // Iterate over applications in appInfo
119
484
 
120
- console.log(`Deploying application: ${application} for site: ${site}`);
121
- console.log(`Using deployment tag: ${deployTag}`);
485
+ let appInfoLocal = Object.fromEntries(
486
+ applications.applications
487
+ .filter((application) =>
488
+ Object.prototype.hasOwnProperty.call(appInfo, application),
489
+ )
490
+ .map((application) => [application, appInfo[application]]),
491
+ );
122
492
 
123
- const { repoPath, deployConfigFilePath, deployConfig } = await readDeployConfig(application, site);
124
- const updatedConfigData = setTag(deployConfig, deployTag);
125
- await writeDeployConfig(repoPath, deployConfigFilePath, updatedConfigData);
493
+ // let appInfoLocal = {};
494
+ // for (const application of applications.applications) {
495
+ // if (Object.prototype.hasOwnProperty.call(appInfo, application)) {
496
+ // appInfoLocal[application] = appInfo[application];
497
+ // }
498
+ // }
499
+
500
+ if (Object.keys(appInfoLocal).length === 0) {
501
+ const { deployConfig: toDeployAppConfig } = await readDeployConfig(
502
+ fromSite,
503
+ toEnv,
504
+ toSite,
505
+ 'app',
506
+ );
507
+
508
+ appInfoLocal[fromSite] = {
509
+ repositoryName: toDeployAppConfig.repo,
510
+ deployAttributes: ['image.tag'],
511
+ };
512
+ }
513
+
514
+ console.log('appinfoLocal', appInfoLocal);
515
+
516
+ for (const [application, appDetails] of Object.entries(appInfoLocal)) {
517
+ let cm = await deployApp(
518
+ application,
519
+ appDetails,
520
+ fromEnv,
521
+ fromSite,
522
+ toEnv,
523
+ toSite,
524
+ );
525
+ if (cm) {
526
+ changesMade = true;
527
+ }
528
+ }
126
529
 
127
- console.log('Deployment completed successfully.');
530
+ // Push all changes if any updates were made
531
+ if (changesMade) {
532
+ await pushDeployConfig(
533
+ toRepoPath,
534
+ `Updated deployment configurations from ${fromEnv}/${fromSite} to ${toEnv}/${toSite}`,
535
+ );
536
+ console.log('โœ… All configurations updated and pushed successfully.');
537
+ } else {
538
+ console.log('โœ… No changes detected. Nothing to push.');
539
+ }
128
540
  }
@@ -0,0 +1,67 @@
1
+ import { $ } from 'zx';
2
+ import fs from 'fs-extra';
3
+ import path from 'path';
4
+
5
+ export async function haproxySync() {
6
+ const cluster = process.env.HAPROXY_CLUSTER;
7
+ if (cluster !== 'preprod' && cluster !== 'stage') {
8
+ console.log('Error: Cluster must be preprod or stage');
9
+ process.exit(1);
10
+ }
11
+
12
+ const repoPath = '/root/repo/docupace-ansible';
13
+ const inventory = path.join(repoPath, `inventories/${cluster}/inventory`);
14
+
15
+ // Create haproxy.sh
16
+ const cluserHostMap = {
17
+ preprod: {
18
+ host: '10.10.28.198',
19
+ branch: 'master',
20
+ },
21
+ stage: {
22
+ host: '10.12.28.10',
23
+ branch: 'INFP-6565-haproxy-prod-implementation',
24
+ },
25
+ };
26
+
27
+ const scriptContent = `
28
+ #!/bin/bash
29
+
30
+ [[ ! -f ${inventory} ]] && ( echo "Alert: no inventory file: ${inventory}" ; exit 1 )
31
+ cd ${repoPath}
32
+ pwd
33
+ git stash
34
+ git fetch --all
35
+ git pull origin master
36
+ git checkout ${cluserHostMap[cluster].branch}
37
+ git submodule update --remote
38
+ git submodule foreach --recursive git checkout master
39
+ git submodule foreach --recursive git pull origin master
40
+
41
+ ansible-playbook -i inventories/${cluster}/inventory haproxy.yml -e "cluster=${cluster}"
42
+
43
+ echo "proceeding"
44
+ echo "committing changes"
45
+ git add ${cluster}-haproxy.cfg
46
+ git commit -m "Sync haproxy"
47
+ git push origin master
48
+ `;
49
+
50
+ await fs.writeFile('haproxy.sh', scriptContent);
51
+
52
+ // Private key
53
+ const haproxyPrivateKey = process.env.HAPROXY_PRIVATE_KEY;
54
+ if (!haproxyPrivateKey) {
55
+ console.log('Error: HAPROXY_PRIVATE_KEY not set.');
56
+ process.exit(1);
57
+ }
58
+
59
+ await fs.writeFile('private.key', Buffer.from(haproxyPrivateKey, 'base64'));
60
+ await fs.chmod('private.key', 0o600);
61
+
62
+ // Copy script to remote
63
+ await $`scp -i private.key -o StrictHostKeyChecking=no haproxy.sh root@${cluserHostMap[cluster].host}:/tmp/haproxy.sh`;
64
+
65
+ // Execute script on remote
66
+ await $`ssh -i private.key -o StrictHostKeyChecking=no root@${cluserHostMap[cluster].host} "bash /tmp/haproxy.sh"`;
67
+ }