From a2437633460b35125d4a45739ec9888c63da9eab Mon Sep 17 00:00:00 2001 From: Sergio Gimenez <36163163+sgimama@users.noreply.github.com> Date: Mon, 28 Oct 2024 08:45:10 +1000 Subject: [PATCH 1/4] feat: add global-config-scripts --- package.json | 1 + .../commands/global-configs/config-tenants.ts | 134 ++++++++++++++++++ .../commands/global-configs/config-tokens.ts | 103 ++++++++++++++ .../global-configs/generate-tokens.ts | 28 ++++ packages/gdu/commands/global-configs/index.ts | 10 ++ packages/gdu/commands/index.ts | 4 + packages/gdu/lib/globalConfigs.ts | 15 ++ yarn.lock | 8 ++ 8 files changed, 303 insertions(+) create mode 100644 packages/gdu/commands/global-configs/config-tenants.ts create mode 100644 packages/gdu/commands/global-configs/config-tokens.ts create mode 100644 packages/gdu/commands/global-configs/generate-tokens.ts create mode 100644 packages/gdu/commands/global-configs/index.ts create mode 100644 packages/gdu/lib/globalConfigs.ts diff --git a/package.json b/package.json index 206f763..0ac6ba5 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "@manypkg/cli": "^0.21.4", "@types/node": "^16.4.13", "browserslist-config-autoguru": "*", + "dotenv": "^16.4.5", "eslint": "^7.28.0", "eslint-plugin-jest": "^24.3.6", "glob": "^7.1.6", diff --git a/packages/gdu/commands/global-configs/config-tenants.ts b/packages/gdu/commands/global-configs/config-tenants.ts new file mode 100644 index 0000000..8ead927 --- /dev/null +++ b/packages/gdu/commands/global-configs/config-tenants.ts @@ -0,0 +1,134 @@ +import * as fs from 'fs'; +import * as path from 'path'; + +import * as dotenv from 'dotenv'; + +import { getTokens } from '../../lib/globalConfigs'; + +const envs = ['uat', 'preprod', 'dev', 'prod', 'test', 'tokens']; +const tenants = ['au', 'nz', 'au-legacy']; +type ENV = (typeof envs)[number]; +type TENANT = (typeof tenants)[number] ; + +export default async () => { + console.log('Global config tenants started'); + const TOKENS = await getTokens(); + + const mfeListFile = path.resolve( + process.cwd(), + '.mfe-data', + 'mfe-list.json', + ); + const mfeList = JSON.parse(fs.readFileSync(mfeListFile, 'utf-8')); + let mfeProjects = []; + + for (const category in mfeList) { + const categoryKeys = Object.keys(mfeList[category]); + mfeProjects = mfeProjects.concat(categoryKeys); + } + + const destinationFolder = path.join( + process.cwd(), + '.mfe-data', + 'app-configs', + ); + + const copyTokens = (mfe) => { + const prodFile = path.join( + process.cwd(), + 'apps', + mfe, + '.gdu_app_config', + '.env.prod', + ); + if (fs.existsSync(prodFile)) { + const tokensFile = path.join( + process.cwd(), + 'apps', + mfe, + '.gdu_app_config', + '.env.tokens', + ); + + // Extract text from prod file + const prodText = fs.readFileSync(prodFile, 'utf8'); + // replace #{*****} with "#{*****}" where ***** can be any value with any length + const tokensText = prodText.replace(/#{(.*?)}/g, '"#{$1}"'); + + // Write the tokens file + fs.writeFileSync( + tokensFile, + `# This file automatically generated from .env.prod file. \r${tokensText}`, + ); + } + }; + +// force delete destination folder if it exists + if (fs.existsSync(destinationFolder)) { + fs.rmSync(destinationFolder, { recursive: true }); + } +// create destination folder + if (!fs.existsSync(destinationFolder)) { + fs.mkdirSync(destinationFolder, { recursive: true }); + } + const getEnvFile = (mfe, env: ENV, tenant?: TENANT) => + path.join( + process.cwd(), + 'apps', + mfe, + '.gdu_app_config', + tenant ? `.env.${env}_${tenant}` : `.env.${env}`, + ); + + const generateTokens = (envFile, mfe, env: ENV, tenant?: TENANT) => { + const fileStats = fs.statSync(envFile); + const dirPathMfeApp = path.join(destinationFolder, `${mfe}`); + if (!fs.existsSync(dirPathMfeApp)) { + fs.mkdirSync(dirPathMfeApp); + } + let data = ''; + + // Check if the file is empty + if (fileStats.size > 0) { + dotenv.config({ path: envFile, override: true }); + + const fileContent = fs.readFileSync(envFile, 'utf8'); + const FILTERED_TOKENS = Object.keys(TOKENS).reduce((acc, key) => { + if (fileContent.includes(key)) { + acc[key] = process.env[key]; + } + return acc; + }, {}); + + data = JSON.stringify(FILTERED_TOKENS, null, 2); + } + + fs.writeFileSync( + path.join( + dirPathMfeApp, + tenant ? `${env}_${tenant}.json` : `${env}.json`, + ), + data, + ); + }; + + mfeProjects.forEach((mfe) => { + envs.forEach((env) => { + if (env === 'tokens') { + const envFile = getEnvFile(mfe, env); + copyTokens(mfe); + if (fs.existsSync(envFile)) { + generateTokens(envFile, mfe, env); + } + } + tenants.forEach((tenant) => { + const envFile = getEnvFile(mfe, env, tenant); + if (fs.existsSync(envFile)) { + generateTokens(envFile, mfe, env, tenant); + } + }); + }); + }); + console.log('Global config tokens finished'); + +} diff --git a/packages/gdu/commands/global-configs/config-tokens.ts b/packages/gdu/commands/global-configs/config-tokens.ts new file mode 100644 index 0000000..364fc08 --- /dev/null +++ b/packages/gdu/commands/global-configs/config-tokens.ts @@ -0,0 +1,103 @@ +import * as fs from 'fs'; +import * as path from 'path'; + +import * as dotenv from 'dotenv'; + +import { getTokens } from '../../lib/globalConfigs'; + +const envs = ['uat', 'preprod', 'dev', 'prod_build', 'test', 'tokens']; +const tenants = ['au', 'nz', 'au-legacy']; +type ENV = (typeof envs)[number]; +type TENANT = (typeof tenants)[number] ; + + +export default async () => { + console.log('Global config tokens started'); + const TOKENS = await getTokens(); + + // eslint-disable-next-line unicorn/consistent-function-scoping + const getFileName = (env: ENV) => { + switch (env) { + case 'prod_build': + return 'prod'; + default: + return env; + } + }; + + const defaultsFile = path.join( + process.cwd(), + '.gdu_config', + '.env.defaults', + ); + + const destinationFolder = path.join( + process.cwd(), + '.mfe-data', + 'env-configs', + ); + + const copyTokens = () => { + const prodFile = path.join( + process.cwd(), + '.gdu_config', + '.env.prod', + ); + const tokensFile = path.join( + process.cwd(), + '.gdu_config', + '.env.tokens', + ); + + // Extract text from prod file + const prodText = fs.readFileSync(prodFile, 'utf8'); + // replace #{*****} with "#{*****}" where ***** can be any value with any length + const tokensText = prodText.replace(/#{(.*?)}/g, '"#{$1}"'); + // Write the tokens file + fs.writeFileSync( + tokensFile, + `# This file automatically generated from .env.prod file. \r${tokensText}`, + ); + }; + + const generateTokens = (env: ENV, tenant?: TENANT) => { + if (env === 'tokens') { + copyTokens(); + } + const envFile = path.join( + process.cwd(), + '.gdu_config', + tenant ? `.env.${env}_${tenant}` : `.env.${env}`, + ); + dotenv.config({ path: [defaultsFile, envFile], override: true }); + + const FILTERED_TOKENS = Object.keys(TOKENS).reduce((acc, key) => { + if (process.env[key]) + acc[key] = process.env[key]; + return acc; + }, {}); + + const json = JSON.stringify(FILTERED_TOKENS, null, 2); + + fs.writeFileSync( + path.join( + destinationFolder, + tenant + ? `${getFileName(env)}_${tenant}.json` + : `${getFileName(env)}.json`, + ), + json, + ); + }; + + envs.forEach((env: ENV) => { + if (env !== 'tokens') { + tenants.forEach((tenant: TENANT) => { + generateTokens(env, tenant); + }); + } + generateTokens(env); + }); + console.log('Global config tokens finished'); + +} diff --git a/packages/gdu/commands/global-configs/generate-tokens.ts b/packages/gdu/commands/global-configs/generate-tokens.ts new file mode 100644 index 0000000..7662c81 --- /dev/null +++ b/packages/gdu/commands/global-configs/generate-tokens.ts @@ -0,0 +1,28 @@ +import * as fs from 'fs'; +import * as path from 'path'; +export default async () => { + console.log('Global config generate tokens started'); + + const typeFilePath = path.resolve( 'packages', 'global-configs', 'processEnvs.d.ts'); + const fileContent: string = fs.readFileSync(typeFilePath, 'utf-8'); + type ProcessEnvs = any; + + const regex = /readonly\s+(\w+):/g; + let match: RegExpExecArray | null; + const keys: (keyof ProcessEnvs)[] = []; + + while ((match = regex.exec(fileContent)) !== null) { + keys.push(match[1] as keyof ProcessEnvs); + } + + const TOKENS: Record = keys.reduce((acc, key) => { + acc[key] = `process.env.${key.toString()}`; + return acc; + }, {} as Record); + + const tokensContent: string = `export const TOKENS = ${JSON.stringify(TOKENS, null, 2).replace(/"process\.env\.(\w+)"/g, 'process.env.$1')};\n`; + const tokensFilePath = path.resolve('packages', 'global-configs', '__generated__', 'tokens.ts'); + fs.writeFileSync(tokensFilePath, tokensContent); + + console.log('tokens.ts has been created with the TOKENS object.'); +} diff --git a/packages/gdu/commands/global-configs/index.ts b/packages/gdu/commands/global-configs/index.ts new file mode 100644 index 0000000..ae082d8 --- /dev/null +++ b/packages/gdu/commands/global-configs/index.ts @@ -0,0 +1,10 @@ + +import configTenants from './config-tenants'; +import configTokents from './config-tokens'; +import configGenerateTokens from './generate-tokens'; + +export default async () => { + await configGenerateTokens(); + await configTokents(); + await configTenants(); +}; diff --git a/packages/gdu/commands/index.ts b/packages/gdu/commands/index.ts index fc294a4..0867209 100644 --- a/packages/gdu/commands/index.ts +++ b/packages/gdu/commands/index.ts @@ -113,6 +113,10 @@ export default (app: Sade) => { app.command('gh-actions') .describe('A command to create GitHub actions things') .action(deferredAction(async () => import('./gh-actions'))); + + app.command('generate-global-configs') + .describe('Generate global configs') + .action(deferredAction(async () => import('./global-configs'), IS_NOT_ROOT)); }; const NOT_READY = wrapAction(() => { diff --git a/packages/gdu/lib/globalConfigs.ts b/packages/gdu/lib/globalConfigs.ts new file mode 100644 index 0000000..21e26c5 --- /dev/null +++ b/packages/gdu/lib/globalConfigs.ts @@ -0,0 +1,15 @@ +import { join } from 'path'; + +import { register } from 'ts-node'; + +import { PROJECT_ROOT } from './roots'; + + +export const getTokens = async () => { + register(); + + const tokensFile = join(PROJECT_ROOT, 'packages/global-configs/__generated__/tokens.ts'); + const fileTokens = await import(tokensFile); + return fileTokens.TOKENS + +}; diff --git a/yarn.lock b/yarn.lock index c28cd37..6a0cdaa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8487,6 +8487,13 @@ __metadata: languageName: node linkType: hard +"dotenv@npm:^16.4.5": + version: 16.4.5 + resolution: "dotenv@npm:16.4.5" + checksum: 301a12c3d44fd49888b74eb9ccf9f07a1f5df43f489e7fcb89647a2edcd84c42d6bc349dc8df099cd18f07c35c7b04685c1a4f3e6a6a9e6b30f8d48c15b7f49c + languageName: node + linkType: hard + "dotenv@npm:^8.2.0": version: 8.6.0 resolution: "dotenv@npm:8.6.0" @@ -15124,6 +15131,7 @@ __metadata: "@manypkg/cli": ^0.21.4 "@types/node": ^16.4.13 browserslist-config-autoguru: "*" + dotenv: ^16.4.5 eslint: ^7.28.0 eslint-plugin-jest: ^24.3.6 glob: ^7.1.6 From d52d12b30b03d40eb55068d1f90615a5668c3827 Mon Sep 17 00:00:00 2001 From: Sergio Gimenez <36163163+sgimama@users.noreply.github.com> Date: Mon, 28 Oct 2024 09:45:24 +1000 Subject: [PATCH 2/4] feat: add global-config-scripts --- packages/gdu/commands/global-configs/config-tokens.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/gdu/commands/global-configs/config-tokens.ts b/packages/gdu/commands/global-configs/config-tokens.ts index 364fc08..92f89ac 100644 --- a/packages/gdu/commands/global-configs/config-tokens.ts +++ b/packages/gdu/commands/global-configs/config-tokens.ts @@ -77,7 +77,7 @@ export default async () => { return acc; }, {}); - const json = JSON.stringify(FILTERED_TOKENS, null, 2); + const data = JSON.stringify(FILTERED_TOKENS, null, 2); fs.writeFileSync( path.join( @@ -86,7 +86,7 @@ export default async () => { ? `${getFileName(env)}_${tenant}.json` : `${getFileName(env)}.json`, ), - json, + data, ); }; From 095fc3a0359ba2c9f0faa2a759cfae7981badb5e Mon Sep 17 00:00:00 2001 From: Sergio Gimenez <36163163+sgimama@users.noreply.github.com> Date: Mon, 28 Oct 2024 10:09:11 +1000 Subject: [PATCH 3/4] feat: increase version --- .changeset/blue-pumas-run.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/blue-pumas-run.md diff --git a/.changeset/blue-pumas-run.md b/.changeset/blue-pumas-run.md new file mode 100644 index 0000000..6480754 --- /dev/null +++ b/.changeset/blue-pumas-run.md @@ -0,0 +1,5 @@ +--- +'gdu': major +--- + +Add scripts for tokens mfe From 83e333f8947e3dd917c9df3d0ddf6775bc0eb61d Mon Sep 17 00:00:00 2001 From: Sergio Gimenez <36163163+sgimama@users.noreply.github.com> Date: Mon, 28 Oct 2024 10:14:56 +1000 Subject: [PATCH 4/4] feat: increase version --- .changeset/{blue-pumas-run.md => new-seas-check.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename .changeset/{blue-pumas-run.md => new-seas-check.md} (73%) diff --git a/.changeset/blue-pumas-run.md b/.changeset/new-seas-check.md similarity index 73% rename from .changeset/blue-pumas-run.md rename to .changeset/new-seas-check.md index 6480754..f87df83 100644 --- a/.changeset/blue-pumas-run.md +++ b/.changeset/new-seas-check.md @@ -1,5 +1,5 @@ --- -'gdu': major +'gdu': minor --- Add scripts for tokens mfe