From 729080aaa21892b77a1edf9846b599e67cc87eac Mon Sep 17 00:00:00 2001 From: manushak Date: Thu, 1 Aug 2024 10:17:00 +0400 Subject: [PATCH 01/23] fix(util): improve `isDirectoryExists` function in the fs.ts --- src/common/util/fs.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/common/util/fs.ts b/src/common/util/fs.ts index bf10af9ba..dbd6d2dcb 100644 --- a/src/common/util/fs.ts +++ b/src/common/util/fs.ts @@ -18,8 +18,8 @@ export const isFileExists = async (filePath: string) => { */ export const isDirectoryExists = async (directoryPath: string) => { try { - await fs.access(directoryPath); - return true; + const stat = await fs.lstat(directoryPath); + return stat.isDirectory(); } catch (error) { return false; } @@ -35,9 +35,9 @@ export const getYamlFiles = async (directory: string) => { for (const file of files) { const fullPath = path.join(directory, file); - const stat = await fs.lstat(fullPath); + const isDirExists = await isDirectoryExists(fullPath); - if (stat.isDirectory()) { + if (isDirExists) { yamlFiles = yamlFiles.concat(await getYamlFiles(fullPath)); } else { if (file.endsWith('.yml') || file.endsWith('.yaml')) { From b5222efc8290b8c9cc548e3d9b3ca42abfa1019f Mon Sep 17 00:00:00 2001 From: manushak Date: Thu, 1 Aug 2024 10:20:11 +0400 Subject: [PATCH 02/23] test(mocks): update fs.ts mocks --- src/__mocks__/fs/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/__mocks__/fs/index.ts b/src/__mocks__/fs/index.ts index 0f37a4291..927509cba 100644 --- a/src/__mocks__/fs/index.ts +++ b/src/__mocks__/fs/index.ts @@ -151,7 +151,8 @@ export const readdir = (directoryPath: string) => { export const lstat = (filePath: string) => { if ( filePath.includes('mock-directory') || - filePath.includes('mock-sub-directory/subdir') + filePath.includes('mock-sub-directory/subdir') || + filePath === 'true' ) { return { isDirectory: () => true, From c52ae5a006ce4cdcb4f6539b62e55db43c265a6a Mon Sep 17 00:00:00 2001 From: manushak Date: Thu, 1 Aug 2024 10:27:35 +0400 Subject: [PATCH 03/23] fix(config): move `DIRECTORY_NOT_FOUND` from if-check into common config --- src/common/config/strings.ts | 1 + src/if-check/config/strings.ts | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/config/strings.ts b/src/common/config/strings.ts index b68d5ce7c..82592463f 100644 --- a/src/common/config/strings.ts +++ b/src/common/config/strings.ts @@ -9,4 +9,5 @@ Incubation projects are experimental, offer no support guarantee, have minimal g MANIFEST_NOT_FOUND: 'Manifest file not found.', SUCCESS_MESSAGE: 'The environment is successfully setup!', MANIFEST_IS_MISSING: 'Manifest is missing.', + DIRECTORY_NOT_FOUND: 'Directory not found.', }; diff --git a/src/if-check/config/strings.ts b/src/if-check/config/strings.ts index 1b6f1c3ef..024d57134 100644 --- a/src/if-check/config/strings.ts +++ b/src/if-check/config/strings.ts @@ -2,7 +2,6 @@ export const STRINGS = { CHECKING: 'Checking...', IF_CHECK_FLAGS_MISSING: 'Either the `--manifest` or `--directory` command should be provided with a path', - DIRECTORY_NOT_FOUND: 'Directory not found.', DIRECTORY_YAML_FILES_NOT_FOUND: 'The directory does not contain any YAML/YML files.\n', IF_CHECK_EXECUTING: (filename: string) => `Executing \`${filename}\``, From 431b30a4ba1e821a59b549bb83d2508371369222 Mon Sep 17 00:00:00 2001 From: manushak Date: Thu, 1 Aug 2024 10:29:10 +0400 Subject: [PATCH 04/23] fix(util): move `DIRECTORY_NOT_FOUND` from if-check into common config --- src/if-check/util/args.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/if-check/util/args.ts b/src/if-check/util/args.ts index ab6e3fd93..8b60f6f15 100644 --- a/src/if-check/util/args.ts +++ b/src/if-check/util/args.ts @@ -19,8 +19,9 @@ const { const {ARGS, HELP} = CONFIG; -const {IF_CHECK_FLAGS_MISSING, DIRECTORY_NOT_FOUND} = STRINGS; -const {MANIFEST_NOT_FOUND, SOURCE_IS_NOT_YAML} = COMMON_STRINGS; +const {IF_CHECK_FLAGS_MISSING} = STRINGS; +const {MANIFEST_NOT_FOUND, SOURCE_IS_NOT_YAML, DIRECTORY_NOT_FOUND} = + COMMON_STRINGS; /** * Parses `if-check` process arguments. From d02cf9c39e04ff93d622f0ac35abdad4460fc736 Mon Sep 17 00:00:00 2001 From: manushak Date: Thu, 1 Aug 2024 10:36:32 +0400 Subject: [PATCH 05/23] fix(config): remove `optional: false` from if-csv to allow the lib to handle error --- src/if-csv/config/config.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/if-csv/config/config.ts b/src/if-csv/config/config.ts index 8be9dba75..255776542 100644 --- a/src/if-csv/config/config.ts +++ b/src/if-csv/config/config.ts @@ -22,7 +22,6 @@ export const CONFIG = { }, params: { type: String, - optional: false, alias: 'p', description: '[parameter to export]', }, From 0ebccdf77fca548852b7a3bc508e06bf2e82b4d3 Mon Sep 17 00:00:00 2001 From: manushak Date: Thu, 1 Aug 2024 10:49:25 +0400 Subject: [PATCH 06/23] fix(config): remove `PARAMS_NOT_PRESENT` unneseccary string from if-csv --- src/if-csv/config/strings.ts | 1 - src/if-csv/util/args.ts | 7 +------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/if-csv/config/strings.ts b/src/if-csv/config/strings.ts index 717461c1b..c104a19a3 100644 --- a/src/if-csv/config/strings.ts +++ b/src/if-csv/config/strings.ts @@ -1,4 +1,3 @@ export const STRINGS = { - PARAMS_NOT_PRESENT: 'Parameter not provided.', FAILURE_MESSAGE_OUTPUTS: 'Manifest outputs are not available!', }; diff --git a/src/if-csv/util/args.ts b/src/if-csv/util/args.ts index 4b9674882..fc4117460 100644 --- a/src/if-csv/util/args.ts +++ b/src/if-csv/util/args.ts @@ -4,7 +4,7 @@ import {ERRORS} from '@grnsft/if-core/utils'; import {checkIfFileIsYaml} from '../../common/util/yaml'; import {prependFullFilePath} from '../../common/util/helpers'; -import {CONFIG, STRINGS} from '../config'; +import {CONFIG} from '../config'; import {STRINGS as COMMON_STRINGS} from '../../common/config'; import {IFCsvArgs} from '../types/process-args'; @@ -13,7 +13,6 @@ import {isFileExists} from '../../common/util/fs'; const {ParseCliParamsError, CliSourceFileError} = ERRORS; const {ARGS, HELP} = CONFIG; -const {PARAMS_NOT_PRESENT} = STRINGS; const {SOURCE_IS_NOT_YAML, MANIFEST_NOT_FOUND} = COMMON_STRINGS; /** @@ -37,10 +36,6 @@ const validateAndParseIfCsvArgs = () => { export const parseIfCsvArgs = async () => { const {manifest, output, params} = validateAndParseIfCsvArgs(); - if (!params) { - throw new ParseCliParamsError(PARAMS_NOT_PRESENT); - } - if (manifest) { const response = prependFullFilePath(manifest); const isManifestFileExists = await isFileExists(response); From 0dafebd93b9b02e9555a4095f421a487651e81e8 Mon Sep 17 00:00:00 2001 From: manushak Date: Thu, 1 Aug 2024 10:51:33 +0400 Subject: [PATCH 07/23] test(util): update if-check test related to changes --- src/__tests__/if-check/util/args.test.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/__tests__/if-check/util/args.test.ts b/src/__tests__/if-check/util/args.test.ts index de0f2a045..63a87d9d2 100644 --- a/src/__tests__/if-check/util/args.test.ts +++ b/src/__tests__/if-check/util/args.test.ts @@ -72,8 +72,9 @@ const { CliSourceFileError, ParseCliParamsError, } = ERRORS; -const {DIRECTORY_NOT_FOUND, IF_CHECK_FLAGS_MISSING} = STRINGS; -const {SOURCE_IS_NOT_YAML, MANIFEST_NOT_FOUND} = COMMON_STRINGS; +const {IF_CHECK_FLAGS_MISSING} = STRINGS; +const {SOURCE_IS_NOT_YAML, MANIFEST_NOT_FOUND, DIRECTORY_NOT_FOUND} = + COMMON_STRINGS; describe('if-check/util: ', () => { const originalEnv = process.env; From addd01b287412ff717e230bb64ceb77f12a76863 Mon Sep 17 00:00:00 2001 From: manushak Date: Thu, 1 Aug 2024 10:53:15 +0400 Subject: [PATCH 08/23] feat(config): add config and string for if-merge --- src/if-merge/config/config.ts | 41 ++++++++++++++++++++++++++++++++++ src/if-merge/config/index.ts | 2 ++ src/if-merge/config/strings.ts | 6 +++++ 3 files changed, 49 insertions(+) create mode 100644 src/if-merge/config/config.ts create mode 100644 src/if-merge/config/index.ts create mode 100644 src/if-merge/config/strings.ts diff --git a/src/if-merge/config/config.ts b/src/if-merge/config/config.ts new file mode 100644 index 000000000..d4c3059ad --- /dev/null +++ b/src/if-merge/config/config.ts @@ -0,0 +1,41 @@ +import {ArgumentConfig, ParseOptions} from 'ts-command-line-args'; + +import {STRINGS} from '../../common/config'; + +import {IFMergeArgs} from '../types/process-args'; + +const {DISCLAIMER_MESSAGE} = STRINGS; + +export const CONFIG = { + IF_MERGE: { + ARGS: { + manifests: { + type: String, + multiple: true, + alias: 'm', + description: '[path to the manifests files]', + }, + name: { + type: String, + optional: true, + alias: 'n', + description: '[name of the merged manifest]', + }, + description: { + type: String, + optional: true, + alias: 'd', + description: '[decription of the merged manifest]', + }, + } as unknown as ArgumentConfig, + HELP: { + helpArg: 'help', + headerContentSections: [ + {header: 'Impact Framework', content: 'IF-Merge Helpful keywords:'}, + ], + footerContentSections: [ + {header: 'Green Software Foundation', content: DISCLAIMER_MESSAGE}, + ], + } as ParseOptions, + }, +}; diff --git a/src/if-merge/config/index.ts b/src/if-merge/config/index.ts new file mode 100644 index 000000000..4972b390b --- /dev/null +++ b/src/if-merge/config/index.ts @@ -0,0 +1,2 @@ +export {CONFIG} from './config'; +export {STRINGS} from './strings'; diff --git a/src/if-merge/config/strings.ts b/src/if-merge/config/strings.ts new file mode 100644 index 000000000..aa224b0ba --- /dev/null +++ b/src/if-merge/config/strings.ts @@ -0,0 +1,6 @@ +export const STRINGS = { + MERGING: 'Merging...', + SUCCESS_MESSAGE: 'Manifests are merged successfully!', + MANIFEST_IS_NOT_YAML: (path: string) => + `The \`${path}\` is not in yaml format.`, +}; From 875c86301bfd15beab23b7c30c99f6aa282a1825 Mon Sep 17 00:00:00 2001 From: manushak Date: Thu, 1 Aug 2024 10:55:39 +0400 Subject: [PATCH 09/23] feat(types): add `IFMergeArgs` type --- src/if-merge/types/process-args.ts | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/if-merge/types/process-args.ts diff --git a/src/if-merge/types/process-args.ts b/src/if-merge/types/process-args.ts new file mode 100644 index 000000000..f34b65e8b --- /dev/null +++ b/src/if-merge/types/process-args.ts @@ -0,0 +1,5 @@ +export interface IFMergeArgs { + manifests: string[]; + name?: string; + description?: string; +} From a11de2e9864a07d3dc7c6176358deadd66920bca Mon Sep 17 00:00:00 2001 From: manushak Date: Thu, 1 Aug 2024 10:56:39 +0400 Subject: [PATCH 10/23] feat(util): add args.ts for if-merge --- src/if-merge/util/args.ts | 69 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 src/if-merge/util/args.ts diff --git a/src/if-merge/util/args.ts b/src/if-merge/util/args.ts new file mode 100644 index 000000000..98e28738f --- /dev/null +++ b/src/if-merge/util/args.ts @@ -0,0 +1,69 @@ +import {parse} from 'ts-command-line-args'; +import {ERRORS} from '@grnsft/if-core/utils'; + +import {isFileExists, isDirectoryExists} from '../../common/util/fs'; +import {prependFullFilePath} from '../../common/util/helpers'; +import {checkIfFileIsYaml} from '../../common/util/yaml'; + +import {STRINGS as COMMON_STRINGS} from '../../common/config'; + +import {IFMergeArgs} from '../types/process-args'; + +import {CONFIG, STRINGS} from '../config'; + +const {ParseCliParamsError, InvalidDirectoryError, CliSourceFileError} = ERRORS; +const {IF_MERGE} = CONFIG; +const {MANIFEST_IS_NOT_YAML} = STRINGS; +const {MANIFEST_NOT_FOUND, DIRECTORY_NOT_FOUND} = COMMON_STRINGS; + +/** + * Parses `if-merge` process arguments. + */ +const validateAndParseIfMergeArgs = () => { + try { + return parse(IF_MERGE.ARGS, IF_MERGE.HELP); + } catch (error) { + if (error instanceof Error) { + throw new ParseCliParamsError(error.message); + } + + throw error; + } +}; + +/** + * Checks if the `manifests` command is provided and they are valid manifests files or a folder. + */ +export const parseIfMergeArgs = async () => { + const {manifests, name, description} = validateAndParseIfMergeArgs(); + + const manifestsWithFullPath = []; + + if (manifests.length === 1) { + const isDirectory = await isDirectoryExists(manifests[0]); + if (!isDirectory) { + throw new InvalidDirectoryError(DIRECTORY_NOT_FOUND); + } + + return {manifests, name, description}; + } + + for await (const manifest of manifests) { + const response = prependFullFilePath(manifest); + const isManifestFileExists = await isFileExists(response); + const isYamlFile = checkIfFileIsYaml(response); + + if (!isManifestFileExists) { + throw new ParseCliParamsError(`${manifest} ${MANIFEST_NOT_FOUND}`); + } + + if (!isYamlFile) { + throw new CliSourceFileError(MANIFEST_IS_NOT_YAML(manifest)); + } + + if (checkIfFileIsYaml(manifest)) { + manifestsWithFullPath.push(response); + } + } + return {manifests: manifestsWithFullPath, name, description}; +}; From 0b680ee28a745e3df01c680b6adb8692eb0d8722 Mon Sep 17 00:00:00 2001 From: manushak Date: Thu, 1 Aug 2024 10:58:11 +0400 Subject: [PATCH 11/23] feat(util): add helpers functions for if-merge --- src/if-merge/util/helpers.ts | 67 ++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 src/if-merge/util/helpers.ts diff --git a/src/if-merge/util/helpers.ts b/src/if-merge/util/helpers.ts new file mode 100644 index 000000000..33123c828 --- /dev/null +++ b/src/if-merge/util/helpers.ts @@ -0,0 +1,67 @@ +import * as path from 'path'; + +import {getFileName, getYamlFiles} from '../../common/util/fs'; +import {load} from '../../common/lib/load'; +import {Context} from '../../common/types/manifest'; + +import {ExportYaml} from '../../if-run/builtins/export-yaml'; + +import {IFMergeArgs} from '../types/process-args'; + +/** + * Merges the given manifests in the one file. + */ +export const mergeManifests = async (commandArgs: IFMergeArgs) => { + const {manifests: commandManifests, name, description} = commandArgs; + let manifests = commandManifests; + let manifestPath = process.env.CURRENT_DIR || process.cwd(); + + if (commandManifests.length === 1) { + manifests = await getYamlFiles(commandManifests[0]); + manifestPath = commandManifests[0]; + } + + const context = { + name: name || 'if-merge', + description: description || 'merged manifest', + tags: null, + initialize: {plugins: {}}, + }; + const tree: any = {children: {}}; + + for await (const manifest of manifests) { + const manifestName = getFileName(manifest); + const {rawManifest} = await load(manifest); + + context.tags = Object.assign({}, context.tags, rawManifest.tags); + context.initialize.plugins = { + ...context.initialize.plugins, + ...rawManifest.initialize.plugins, + }; + + Object.keys(rawManifest.tree.children).forEach(child => { + tree.children[`${child}-${manifestName}`] = { + ...rawManifest.tree.children[child], + }; + }); + } + const manifestName = name + ? `${name.replace(' ', '-')}.yaml` + : 'merged-manifest.yaml'; + const outputPath = path.join(manifestPath, manifestName); + + await saveMergedManifest(tree, context, outputPath); +}; + +/** + * Saves the merged manifest in the `merged-manifest.yaml` file. + */ +const saveMergedManifest = async ( + tree: any, + context: Context, + outputPath: string +) => { + const exportYaml = ExportYaml(); + + await exportYaml.execute(tree, context, outputPath); +}; From ac575eff8df29473393116bb626215c61a879522 Mon Sep 17 00:00:00 2001 From: manushak Date: Thu, 1 Aug 2024 10:59:15 +0400 Subject: [PATCH 12/23] test(util): add tests for args.ts and helpers.ts --- src/__tests__/if-merge/util/args.test.ts | 163 +++++++++++++++++++ src/__tests__/if-merge/util/helpers.test.ts | 167 ++++++++++++++++++++ src/if-merge/util/helpers.ts | 2 +- 3 files changed, 331 insertions(+), 1 deletion(-) create mode 100644 src/__tests__/if-merge/util/args.test.ts create mode 100644 src/__tests__/if-merge/util/helpers.test.ts diff --git a/src/__tests__/if-merge/util/args.test.ts b/src/__tests__/if-merge/util/args.test.ts new file mode 100644 index 000000000..904c7e317 --- /dev/null +++ b/src/__tests__/if-merge/util/args.test.ts @@ -0,0 +1,163 @@ +import * as path from 'path'; + +jest.mock('../../../common/util/fs', () => ({ + isFileExists: () => { + if (process.env.fileExists === 'true') { + return true; + } + return false; + }, + isDirectoryExists: () => { + if (process.env.directoryExists === 'true') { + return true; + } + return false; + }, +})); + +jest.mock('ts-command-line-args', () => ({ + __esModule: true, + parse: () => { + switch (process.env.result) { + case 'manifests-are-provided': + return {manifests: ['mock-manifest1.yaml', 'mock-manifest2.yaml']}; + case 'directory-is-provided': + return {manifests: ['/mock-directory']}; + case 'flags-are-not-provided': + return {manifests: undefined, name: undefined, description: undefined}; + case 'manifest-is-not-yaml': + return {manifests: ['mock-manifest1.yaml', './mock-manifest2']}; + case 'env-throw-error': + throw new Error('mock-error'); + case 'env-throw': + throw 'mock-error'; + default: + return { + manifests: ['mock-manifest1.yaml', 'mock-manifest2.yaml'], + output: 'mock-output', + }; + } + }, +})); + +import {ERRORS} from '@grnsft/if-core/utils'; + +import {parseIfMergeArgs} from '../../../if-merge/util/args'; + +import {STRINGS as COMMON_STRINGS} from '../../../common/config'; + +import {STRINGS} from '../../../if-merge/config'; + +const {InvalidDirectoryError, CliSourceFileError, ParseCliParamsError} = ERRORS; + +const {DIRECTORY_NOT_FOUND, MANIFEST_NOT_FOUND} = COMMON_STRINGS; +const {MANIFEST_IS_NOT_YAML} = STRINGS; + +describe('if-merge/util/args: ', () => { + const originalEnv = process.env; + + describe('parseIfMergeArgs(): ', () => { + const manifests = [ + path.join(process.cwd(), 'mock-manifest1.yaml'), + path.join(process.cwd(), 'mock-manifest2.yaml'), + ]; + it('executes when `manifest` is provided.', async () => { + process.env.fileExists = 'true'; + process.env.result = 'manifests-are-provided'; + const response = await parseIfMergeArgs(); + + expect.assertions(1); + + expect(response).toEqual({ + name: undefined, + description: undefined, + manifests, + }); + }); + + it('executes when the directory is provided.', async () => { + process.env.directoryExists = 'true'; + process.env.result = 'directory-is-provided'; + + const response = await parseIfMergeArgs(); + + expect.assertions(1); + + expect(response).toEqual({ + name: undefined, + description: undefined, + manifests: ['/mock-directory'], + }); + }); + + it('throws an error when the directory does not exist.', async () => { + process.env.directoryExists = 'false'; + process.env.result = 'directory-is-provided'; + expect.assertions(1); + + try { + await parseIfMergeArgs(); + } catch (error) { + expect(error).toEqual(new InvalidDirectoryError(DIRECTORY_NOT_FOUND)); + } + }); + + it('throws an error if one of manifests is not a yaml.', async () => { + process.env.fileExists = 'true'; + process.env.result = 'manifest-is-not-yaml'; + expect.assertions(1); + + try { + await parseIfMergeArgs(); + } catch (error) { + if (error instanceof Error) { + expect(error).toEqual( + new CliSourceFileError(MANIFEST_IS_NOT_YAML('./mock-manifest2')) + ); + } + } + }); + + it('throws an error if `manifest` path is invalid.', async () => { + process.env.fileExists = 'false'; + process.env.result = 'manifest-is-not-yaml'; + expect.assertions(1); + + try { + await parseIfMergeArgs(); + } catch (error) { + if (error instanceof Error) { + expect(error).toEqual( + new ParseCliParamsError(`mock-manifest1.yaml ${MANIFEST_NOT_FOUND}`) + ); + } + } + }); + + it('throws an error if parsing failed.', async () => { + process.env.result = 'env-throw-error'; + expect.assertions(1); + + try { + await parseIfMergeArgs(); + } catch (error) { + if (error instanceof Error) { + expect(error).toEqual(new ParseCliParamsError('mock-error')); + } + } + }); + + it('throws error if parsing failed (not instance of error).', async () => { + process.env.result = 'env-throw'; + expect.assertions(1); + + try { + await parseIfMergeArgs(); + } catch (error) { + expect(error).toEqual('mock-error'); + } + }); + }); + + process.env = originalEnv; +}); diff --git a/src/__tests__/if-merge/util/helpers.test.ts b/src/__tests__/if-merge/util/helpers.test.ts new file mode 100644 index 000000000..f69ddd27c --- /dev/null +++ b/src/__tests__/if-merge/util/helpers.test.ts @@ -0,0 +1,167 @@ +import {mergeManifests} from '../../../if-merge/util/helpers'; +import {getFileName, getYamlFiles} from '../../../common/util/fs'; + +import {load} from '../../../common/lib/load'; + +jest.mock('../../../common/util/fs', () => ({ + getYamlFiles: jest.fn(), + getFileName: jest.fn(), + load: jest.fn(), +})); + +jest.mock('../../../common/lib/load', () => ({ + load: jest.fn(), +})); + +jest.mock('../../../if-run/builtins/export-yaml', () => ({ + ExportYaml: jest.fn().mockImplementation(() => ({ + // @ts-ignore + execute: (tree, context, outputPath) => { + const expectedContext = { + name: 'if-merge', + description: 'merged manifest', + tags: {}, + initialize: { + plugins: { + multiply: { + path: 'builtin', + method: 'Multiply', + 'global-config': { + 'input-parameters': ['cpu/utilization', 'duration'], + 'output-parameter': 'cpu-times-duration', + }, + }, + }, + }, + }; + + if (process.env.CONTEXT !== 'default-name-description') { + expectedContext.name = 'mock name'; + expectedContext.description = 'mock description'; + expect(outputPath).toBe('mock-dir/mock-name.yaml'); + } else { + expect(outputPath).toBe('mock-dir/merged-manifest.yaml'); + } + + expect(context).toEqual(expectedContext); + }, + })), +})); + +describe('if-merge/util/helpers: ', () => { + describe('mergeManifests(): ', () => { + const mockCommandArgs = { + manifests: ['manifest1.yaml', 'manifest2.yaml'], + name: 'mock name', + description: 'mock description', + }; + + const tree = { + children: { + 'child-0': { + defaults: { + 'cpu/thermal-design-power': 100, + }, + pipeline: ['sum'], + inputs: [ + { + timestamp: '2023-07-06T00:00', + duration: 1, + 'cpu/utilization': 20, + 'cpu/energy': 20, + 'network/energy': 30, + }, + ], + outputs: [ + { + timestamp: '2023-07-06T00:00', + duration: 1, + 'cpu/utilization': 20, + 'cpu/energy': 20, + 'network/energy': 30, + 'cpu/thermal-design-power': 100, + 'energy-sum': 50, + }, + ], + }, + }, + }; + const context = { + name: 'mock name', + description: 'mock description', + tags: null, + initialize: { + plugins: { + multiply: { + path: 'builtin', + method: 'Multiply', + 'global-config': { + 'input-parameters': ['cpu/utilization', 'duration'], + 'output-parameter': 'cpu-times-duration', + }, + }, + }, + }, + }; + const mockRawManifest = { + ...context, + tree, + }; + + beforeEach(() => { + jest.clearAllMocks(); + process.env.CURRENT_DIR = 'mock-dir'; + }); + + it('merges manifests correctly when there is more than one manifest.', async () => { + (getFileName as jest.Mock).mockImplementation(file => + file.replace('.yaml', '') + ); + (load as jest.Mock).mockResolvedValue({rawManifest: mockRawManifest}); + + await mergeManifests(mockCommandArgs); + + expect.assertions(4); + + expect(getFileName).toHaveBeenCalledTimes(2); + expect(load).toHaveBeenCalledTimes(2); + }); + + it('gets YAML files when there is only one manifest.', async () => { + const singleManifestArgs = { + manifests: ['mock-dir'], + name: 'mock name', + description: 'mock description', + }; + (getYamlFiles as jest.Mock).mockResolvedValue([ + 'manifest1.yaml', + 'manifest2.yaml', + ]); + (getFileName as jest.Mock).mockImplementation(file => + file.replace('.yaml', '') + ); + (load as jest.Mock).mockResolvedValue({rawManifest: mockRawManifest}); + + await mergeManifests(singleManifestArgs); + + expect.assertions(4); + expect(getYamlFiles).toHaveBeenCalledWith('mock-dir'); + expect(load).toHaveBeenCalledTimes(2); + }); + + it('uses default values for name and description if not provided.', async () => { + process.env.CONTEXT = 'default-name-description'; + + const defaultArgs = {manifests: ['manifest1.yaml', 'manifest2.yaml']}; + + (getFileName as jest.Mock).mockImplementation(file => + file.replace('.yaml', '') + ); + (load as jest.Mock).mockResolvedValue({rawManifest: mockRawManifest}); + + await mergeManifests(defaultArgs); + + expect.assertions(2); + }); + }); +}); diff --git a/src/if-merge/util/helpers.ts b/src/if-merge/util/helpers.ts index 33123c828..61fb3d59d 100644 --- a/src/if-merge/util/helpers.ts +++ b/src/if-merge/util/helpers.ts @@ -1,8 +1,8 @@ import * as path from 'path'; import {getFileName, getYamlFiles} from '../../common/util/fs'; -import {load} from '../../common/lib/load'; import {Context} from '../../common/types/manifest'; +import {load} from '../../common/lib/load'; import {ExportYaml} from '../../if-run/builtins/export-yaml'; From 54a46d90853f630c1e1e479c09cdb69d4c387360 Mon Sep 17 00:00:00 2001 From: manushak Date: Thu, 1 Aug 2024 11:00:32 +0400 Subject: [PATCH 13/23] feat(src): add if-merge logic --- src/if-merge/index.ts | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/if-merge/index.ts diff --git a/src/if-merge/index.ts b/src/if-merge/index.ts new file mode 100644 index 000000000..d9d93bb0d --- /dev/null +++ b/src/if-merge/index.ts @@ -0,0 +1,33 @@ +#!/usr/bin/env node +/* eslint-disable no-process-exit */ +import {debugLogger} from '../common/util/debug-logger'; +import {logger} from '../common/util/logger'; + +import {parseIfMergeArgs} from './util/args'; +import {mergeManifests} from './util/helpers'; + +import {STRINGS} from './config'; + +const {MERGING, SUCCESS_MESSAGE} = STRINGS; + +const IfMerge = async () => { + // Call this function with false parameter to prevent log debug messages. + debugLogger.overrideConsoleMethods(false); + + const commandArgs = await parseIfMergeArgs(); + + console.log(`${MERGING}\n`); + + await mergeManifests(commandArgs); + + console.log(SUCCESS_MESSAGE); + + process.exit(0); +}; + +IfMerge().catch(error => { + if (error instanceof Error) { + logger.error(error); + process.exit(2); + } +}); From 1fa432660f9b10d2ba50366d4810f05cd78d415b Mon Sep 17 00:00:00 2001 From: manushak Date: Thu, 1 Aug 2024 11:05:46 +0400 Subject: [PATCH 14/23] feat(package): add `if-merge` command tool into package.json --- package-lock.json | 5 +++-- package.json | 8 +++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index df1de316d..03650a619 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "@grnsft/if", + "name": "if-environment", "version": "0.5.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "@grnsft/if", + "name": "if-environment", "version": "0.5.0", "license": "MIT", "dependencies": { @@ -28,6 +28,7 @@ "if-csv": "build/if-csv/index.js", "if-diff": "build/if-diff/index.js", "if-env": "build/if-env/index.js", + "if-merge": "build/if-merge/index.js", "if-run": "build/if-run/index.js" }, "devDependencies": { diff --git a/package.json b/package.json index f8df2255f..0d5d9e821 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "@grnsft/if", + "name": "if-environment", "description": "Impact Framework", "version": "0.5.0", "author": { @@ -11,7 +11,8 @@ "if-run": "./build/if-run/index.js", "if-env": "./build/if-env/index.js", "if-check": "./build/if-check/index.js", - "if-csv": "./build/if-csv/index.js" + "if-csv": "./build/if-csv/index.js", + "if-merge": "./build/if-merge/index.js" }, "bugs": { "url": "https://github.com/Green-Software-Foundation/if/issues/new?assignees=&labels=feedback&projects=&template=feedback.md&title=Feedback+-+" @@ -80,6 +81,7 @@ "if-csv": "cross-env CURRENT_DIR=$(node -p \"process.env.INIT_CWD\") npx ts-node src/if-csv/index.ts", "if-diff": "npx ts-node src/if-diff/index.ts", "if-env": "cross-env CURRENT_DIR=$(node -p \"process.env.INIT_CWD\") npx ts-node src/if-env/index.ts", + "if-merge": "cross-env CURRENT_DIR=$(node -p \"process.env.INIT_CWD\") npx ts-node src/if-merge/index.ts", "if-run": "npx ts-node src/if-run/index.ts", "lint": "gts lint", "pre-commit": "lint-staged", @@ -89,4 +91,4 @@ "test": "jest --verbose --testPathPattern=src/__tests__/" }, "stability": "stable" -} +} \ No newline at end of file From 81961699f941e7da2f5c71416ecb67a696126def Mon Sep 17 00:00:00 2001 From: Manushak Keramyan Date: Thu, 1 Aug 2024 13:21:37 +0400 Subject: [PATCH 15/23] Update package.json Co-authored-by: Narek Hovhannisyan Signed-off-by: Manushak Keramyan --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0d5d9e821..96e57f8e5 100644 --- a/package.json +++ b/package.json @@ -91,4 +91,4 @@ "test": "jest --verbose --testPathPattern=src/__tests__/" }, "stability": "stable" -} \ No newline at end of file +} From 49b2b5bb665c1a10e8b438091788ca46f149df87 Mon Sep 17 00:00:00 2001 From: manushak Date: Thu, 1 Aug 2024 13:23:19 +0400 Subject: [PATCH 16/23] fix(package): revert package name to correct one --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 03650a619..256cca7e0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "if-environment", + "name": "@grnsft/if", "version": "0.5.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "if-environment", + "name": "@grnsft/if", "version": "0.5.0", "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 96e57f8e5..a5e2a8083 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "if-environment", + "name": "@grnsft/if", "description": "Impact Framework", "version": "0.5.0", "author": { From 6f99d7fa1f8df04718baf74b6c1b4071b3ab412c Mon Sep 17 00:00:00 2001 From: manushak Date: Thu, 1 Aug 2024 13:58:04 +0400 Subject: [PATCH 17/23] test(util): add eslint comment --- src/__tests__/if-merge/util/helpers.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/__tests__/if-merge/util/helpers.test.ts b/src/__tests__/if-merge/util/helpers.test.ts index f69ddd27c..db52a2a84 100644 --- a/src/__tests__/if-merge/util/helpers.test.ts +++ b/src/__tests__/if-merge/util/helpers.test.ts @@ -15,6 +15,7 @@ jest.mock('../../../common/lib/load', () => ({ jest.mock('../../../if-run/builtins/export-yaml', () => ({ ExportYaml: jest.fn().mockImplementation(() => ({ + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore execute: (tree, context, outputPath) => { const expectedContext = { From a828eb35730b33b56df362971cec02ff9180f84f Mon Sep 17 00:00:00 2001 From: manushak Date: Thu, 1 Aug 2024 14:02:48 +0400 Subject: [PATCH 18/23] feat(util): imporve `mergeManifests` helper function --- src/if-merge/util/helpers.ts | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/if-merge/util/helpers.ts b/src/if-merge/util/helpers.ts index 61fb3d59d..362791a6f 100644 --- a/src/if-merge/util/helpers.ts +++ b/src/if-merge/util/helpers.ts @@ -11,8 +11,8 @@ import {IFMergeArgs} from '../types/process-args'; /** * Merges the given manifests in the one file. */ -export const mergeManifests = async (commandArgs: IFMergeArgs) => { - const {manifests: commandManifests, name, description} = commandArgs; +export const mergeManifests = async (mergeArgs: IFMergeArgs) => { + const {manifests: commandManifests, name, description} = mergeArgs; let manifests = commandManifests; let manifestPath = process.env.CURRENT_DIR || process.cwd(); @@ -20,13 +20,22 @@ export const mergeManifests = async (commandArgs: IFMergeArgs) => { manifests = await getYamlFiles(commandManifests[0]); manifestPath = commandManifests[0]; } - const context = { name: name || 'if-merge', description: description || 'merged manifest', tags: null, initialize: {plugins: {}}, }; + const tree = await mergeManifestsData(manifests, context); + const outputPath = getOutputPath(name, manifestPath); + + await saveMergedManifest(tree, context, outputPath); +}; + +/** + * Merges manifests data. + */ +const mergeManifestsData = async (manifests: string[], context: Context) => { const tree: any = {children: {}}; for await (const manifest of manifests) { @@ -45,12 +54,17 @@ export const mergeManifests = async (commandArgs: IFMergeArgs) => { }; }); } - const manifestName = name - ? `${name.replace(' ', '-')}.yaml` - : 'merged-manifest.yaml'; - const outputPath = path.join(manifestPath, manifestName); - await saveMergedManifest(tree, context, outputPath); + return tree; +}; + +/** + * Gets output path. + */ +const getOutputPath = (name: string | undefined, manifestPath: string) => { + const manifestName = `${(name || 'merged-manifest').replace(' ', '-')}.yaml`; + + return path.join(manifestPath, manifestName); }; /** From 5729b2b1f80103b0410435b8fe6bb2dbc4ebb7aa Mon Sep 17 00:00:00 2001 From: manushak Date: Thu, 8 Aug 2024 11:26:39 +0400 Subject: [PATCH 19/23] fix(config): add `output` flag --- src/if-merge/config/config.ts | 66 ++++++++++++++++++---------------- src/if-merge/config/strings.ts | 2 +- 2 files changed, 36 insertions(+), 32 deletions(-) diff --git a/src/if-merge/config/config.ts b/src/if-merge/config/config.ts index d4c3059ad..81ee6baff 100644 --- a/src/if-merge/config/config.ts +++ b/src/if-merge/config/config.ts @@ -7,35 +7,39 @@ import {IFMergeArgs} from '../types/process-args'; const {DISCLAIMER_MESSAGE} = STRINGS; export const CONFIG = { - IF_MERGE: { - ARGS: { - manifests: { - type: String, - multiple: true, - alias: 'm', - description: '[path to the manifests files]', - }, - name: { - type: String, - optional: true, - alias: 'n', - description: '[name of the merged manifest]', - }, - description: { - type: String, - optional: true, - alias: 'd', - description: '[decription of the merged manifest]', - }, - } as unknown as ArgumentConfig, - HELP: { - helpArg: 'help', - headerContentSections: [ - {header: 'Impact Framework', content: 'IF-Merge Helpful keywords:'}, - ], - footerContentSections: [ - {header: 'Green Software Foundation', content: DISCLAIMER_MESSAGE}, - ], - } as ParseOptions, - }, + ARGS: { + manifests: { + type: String, + multiple: true, + alias: 'm', + description: '[path to the manifests files]', + }, + output: { + type: String, + optional: true, + alias: 'o', + description: '[path to the merged output file]', + }, + name: { + type: String, + optional: true, + alias: 'n', + description: '[name of the merged manifest]', + }, + description: { + type: String, + optional: true, + alias: 'd', + description: '[decription of the merged manifest]', + }, + } as unknown as ArgumentConfig, + HELP: { + helpArg: 'help', + headerContentSections: [ + {header: 'Impact Framework', content: 'IF-Merge Helpful keywords:'}, + ], + footerContentSections: [ + {header: 'Green Software Foundation', content: DISCLAIMER_MESSAGE}, + ], + } as ParseOptions, }; diff --git a/src/if-merge/config/strings.ts b/src/if-merge/config/strings.ts index aa224b0ba..ed3e824fb 100644 --- a/src/if-merge/config/strings.ts +++ b/src/if-merge/config/strings.ts @@ -1,6 +1,6 @@ export const STRINGS = { MERGING: 'Merging...', - SUCCESS_MESSAGE: 'Manifests are merged successfully!', + SUCCESS_MESSAGE: '\nManifests are merged successfully!', MANIFEST_IS_NOT_YAML: (path: string) => `The \`${path}\` is not in yaml format.`, }; From 902a810177fd0b4d0e36a6370644240025f64ed9 Mon Sep 17 00:00:00 2001 From: manushak Date: Thu, 8 Aug 2024 11:27:43 +0400 Subject: [PATCH 20/23] fix(types): add `output` into IFMergeArgs type --- src/if-merge/types/process-args.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/if-merge/types/process-args.ts b/src/if-merge/types/process-args.ts index f34b65e8b..8fa28e365 100644 --- a/src/if-merge/types/process-args.ts +++ b/src/if-merge/types/process-args.ts @@ -1,5 +1,6 @@ export interface IFMergeArgs { manifests: string[]; + output?: string; name?: string; description?: string; } From 7efa83702cb5a8fcae606999e382e3088fa61de1 Mon Sep 17 00:00:00 2001 From: manushak Date: Thu, 8 Aug 2024 11:35:41 +0400 Subject: [PATCH 21/23] fix(util): update logic to print result if the `output` is not provided --- src/if-merge/util/args.ts | 11 ++++++----- src/if-merge/util/helpers.ts | 31 +++++++++---------------------- 2 files changed, 15 insertions(+), 27 deletions(-) diff --git a/src/if-merge/util/args.ts b/src/if-merge/util/args.ts index 98e28738f..9aba9d21c 100644 --- a/src/if-merge/util/args.ts +++ b/src/if-merge/util/args.ts @@ -12,7 +12,7 @@ import {IFMergeArgs} from '../types/process-args'; import {CONFIG, STRINGS} from '../config'; const {ParseCliParamsError, InvalidDirectoryError, CliSourceFileError} = ERRORS; -const {IF_MERGE} = CONFIG; +const {ARGS, HELP} = CONFIG; const {MANIFEST_IS_NOT_YAML} = STRINGS; const {MANIFEST_NOT_FOUND, DIRECTORY_NOT_FOUND} = COMMON_STRINGS; @@ -21,7 +21,7 @@ const {MANIFEST_NOT_FOUND, DIRECTORY_NOT_FOUND} = COMMON_STRINGS; */ const validateAndParseIfMergeArgs = () => { try { - return parse(IF_MERGE.ARGS, IF_MERGE.HELP); + return parse(ARGS, HELP); } catch (error) { if (error instanceof Error) { throw new ParseCliParamsError(error.message); @@ -35,7 +35,7 @@ const validateAndParseIfMergeArgs = () => { * Checks if the `manifests` command is provided and they are valid manifests files or a folder. */ export const parseIfMergeArgs = async () => { - const {manifests, name, description} = validateAndParseIfMergeArgs(); + const {manifests, output, name, description} = validateAndParseIfMergeArgs(); const manifestsWithFullPath = []; @@ -45,7 +45,7 @@ export const parseIfMergeArgs = async () => { throw new InvalidDirectoryError(DIRECTORY_NOT_FOUND); } - return {manifests, name, description}; + return {manifests, output, name, description}; } for await (const manifest of manifests) { @@ -65,5 +65,6 @@ export const parseIfMergeArgs = async () => { manifestsWithFullPath.push(response); } } - return {manifests: manifestsWithFullPath, name, description}; + + return {manifests: manifestsWithFullPath, output, name, description}; }; diff --git a/src/if-merge/util/helpers.ts b/src/if-merge/util/helpers.ts index 362791a6f..bd2d46d36 100644 --- a/src/if-merge/util/helpers.ts +++ b/src/if-merge/util/helpers.ts @@ -1,24 +1,19 @@ -import * as path from 'path'; - import {getFileName, getYamlFiles} from '../../common/util/fs'; import {Context} from '../../common/types/manifest'; import {load} from '../../common/lib/load'; -import {ExportYaml} from '../../if-run/builtins/export-yaml'; - +import {exhaust} from '../../if-run/lib/exhaust'; import {IFMergeArgs} from '../types/process-args'; /** * Merges the given manifests in the one file. */ export const mergeManifests = async (mergeArgs: IFMergeArgs) => { - const {manifests: commandManifests, name, description} = mergeArgs; + const {manifests: commandManifests, output, name, description} = mergeArgs; let manifests = commandManifests; - let manifestPath = process.env.CURRENT_DIR || process.cwd(); if (commandManifests.length === 1) { manifests = await getYamlFiles(commandManifests[0]); - manifestPath = commandManifests[0]; } const context = { name: name || 'if-merge', @@ -27,9 +22,8 @@ export const mergeManifests = async (mergeArgs: IFMergeArgs) => { initialize: {plugins: {}}, }; const tree = await mergeManifestsData(manifests, context); - const outputPath = getOutputPath(name, manifestPath); - await saveMergedManifest(tree, context, outputPath); + await saveMergedManifest(tree, context, output); }; /** @@ -58,24 +52,17 @@ const mergeManifestsData = async (manifests: string[], context: Context) => { return tree; }; -/** - * Gets output path. - */ -const getOutputPath = (name: string | undefined, manifestPath: string) => { - const manifestName = `${(name || 'merged-manifest').replace(' ', '-')}.yaml`; - - return path.join(manifestPath, manifestName); -}; - /** * Saves the merged manifest in the `merged-manifest.yaml` file. */ const saveMergedManifest = async ( tree: any, context: Context, - outputPath: string + outputPath: string | undefined ) => { - const exportYaml = ExportYaml(); - - await exportYaml.execute(tree, context, outputPath); + const output = { + outputPath, + noOutput: false, + }; + await exhaust(tree, context, output); }; From ec1693b97db312193c4b68f7fc657f7ac5bde01e Mon Sep 17 00:00:00 2001 From: manushak Date: Thu, 8 Aug 2024 11:37:28 +0400 Subject: [PATCH 22/23] test(util): update tests --- src/__tests__/if-merge/util/helpers.test.ts | 34 +++++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/src/__tests__/if-merge/util/helpers.test.ts b/src/__tests__/if-merge/util/helpers.test.ts index db52a2a84..1f4c0609f 100644 --- a/src/__tests__/if-merge/util/helpers.test.ts +++ b/src/__tests__/if-merge/util/helpers.test.ts @@ -39,9 +39,9 @@ jest.mock('../../../if-run/builtins/export-yaml', () => ({ if (process.env.CONTEXT !== 'default-name-description') { expectedContext.name = 'mock name'; expectedContext.description = 'mock description'; - expect(outputPath).toBe('mock-dir/mock-name.yaml'); + expect(outputPath).toBe('mock-outputPath'); } else { - expect(outputPath).toBe('mock-dir/merged-manifest.yaml'); + expect(outputPath).toBe('mock-outputPath'); } expect(context).toEqual(expectedContext); @@ -50,9 +50,16 @@ jest.mock('../../../if-run/builtins/export-yaml', () => ({ })); describe('if-merge/util/helpers: ', () => { + const consopleSpy = jest.spyOn(global.console, 'log'); + + beforeEach(() => { + consopleSpy.mockReset(); + }); + describe('mergeManifests(): ', () => { const mockCommandArgs = { manifests: ['manifest1.yaml', 'manifest2.yaml'], + output: 'mock-outputPath', name: 'mock name', description: 'mock description', }; @@ -128,9 +135,27 @@ describe('if-merge/util/helpers: ', () => { expect(load).toHaveBeenCalledTimes(2); }); + it('successfully prints merged manifests when the `output` is not provided.', async () => { + (getFileName as jest.Mock).mockImplementation(file => + file.replace('.yaml', '') + ); + (load as jest.Mock).mockResolvedValue({rawManifest: mockRawManifest}); + + const mockCommandArgs = { + manifests: ['manifest1.yaml', 'manifest2.yaml'], + name: 'mock name', + description: 'mock description', + }; + await mergeManifests(mockCommandArgs); + + expect.assertions(1); + expect(consopleSpy).toHaveBeenCalledTimes(1); + }); + it('gets YAML files when there is only one manifest.', async () => { const singleManifestArgs = { manifests: ['mock-dir'], + output: 'mock-outputPath', name: 'mock name', description: 'mock description', }; @@ -153,7 +178,10 @@ describe('if-merge/util/helpers: ', () => { it('uses default values for name and description if not provided.', async () => { process.env.CONTEXT = 'default-name-description'; - const defaultArgs = {manifests: ['manifest1.yaml', 'manifest2.yaml']}; + const defaultArgs = { + manifests: ['manifest1.yaml', 'manifest2.yaml'], + output: 'mock-outputPath', + }; (getFileName as jest.Mock).mockImplementation(file => file.replace('.yaml', '') From dd24689b7949eb7c327eae2c9cd15cbd1b606b91 Mon Sep 17 00:00:00 2001 From: manushak Date: Thu, 8 Aug 2024 14:49:32 +0400 Subject: [PATCH 23/23] fix(util): compose unique name for tree children --- src/if-merge/util/helpers.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/if-merge/util/helpers.ts b/src/if-merge/util/helpers.ts index bd2d46d36..db713974d 100644 --- a/src/if-merge/util/helpers.ts +++ b/src/if-merge/util/helpers.ts @@ -1,3 +1,5 @@ +import * as path from 'path'; + import {getFileName, getYamlFiles} from '../../common/util/fs'; import {Context} from '../../common/types/manifest'; import {load} from '../../common/lib/load'; @@ -35,6 +37,8 @@ const mergeManifestsData = async (manifests: string[], context: Context) => { for await (const manifest of manifests) { const manifestName = getFileName(manifest); const {rawManifest} = await load(manifest); + const parentDir = path.basename(path.dirname(manifest)); + const uniqueName = `${parentDir}-${manifestName}`; context.tags = Object.assign({}, context.tags, rawManifest.tags); context.initialize.plugins = { @@ -43,7 +47,7 @@ const mergeManifestsData = async (manifests: string[], context: Context) => { }; Object.keys(rawManifest.tree.children).forEach(child => { - tree.children[`${child}-${manifestName}`] = { + tree.children[`${child}-${uniqueName}`] = { ...rawManifest.tree.children[child], }; });