Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add global-config-scripts #270

Merged
merged 4 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/new-seas-check.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'gdu': minor
---

Add scripts for tokens mfe
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
134 changes: 134 additions & 0 deletions packages/gdu/commands/global-configs/config-tenants.ts
Original file line number Diff line number Diff line change
@@ -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');

}
103 changes: 103 additions & 0 deletions packages/gdu/commands/global-configs/config-tokens.ts
Original file line number Diff line number Diff line change
@@ -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 data = JSON.stringify(FILTERED_TOKENS, null, 2);

fs.writeFileSync(
path.join(
destinationFolder,
tenant
? `${getFileName(env)}_${tenant}.json`
: `${getFileName(env)}.json`,
),
data,
);
};

envs.forEach((env: ENV) => {
if (env !== 'tokens') {
tenants.forEach((tenant: TENANT) => {
generateTokens(env, tenant);
});
}
generateTokens(env);
});
console.log('Global config tokens finished');

}
28 changes: 28 additions & 0 deletions packages/gdu/commands/global-configs/generate-tokens.ts
Original file line number Diff line number Diff line change
@@ -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<keyof ProcessEnvs, string | undefined> = keys.reduce((acc, key) => {
acc[key] = `process.env.${key.toString()}`;
return acc;
}, {} as Record<keyof ProcessEnvs, string | undefined>);

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.');
}
10 changes: 10 additions & 0 deletions packages/gdu/commands/global-configs/index.ts
Original file line number Diff line number Diff line change
@@ -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();
};
4 changes: 4 additions & 0 deletions packages/gdu/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(() => {
Expand Down
15 changes: 15 additions & 0 deletions packages/gdu/lib/globalConfigs.ts
Original file line number Diff line number Diff line change
@@ -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

};
8 changes: 8 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down
Loading