From 19acaf168119d8d26aa31a4691a47fb306d85ff7 Mon Sep 17 00:00:00 2001 From: Dylan Young <5227854+dylanyoung-dev@users.noreply.github.com> Date: Tue, 13 Sep 2022 15:22:44 -0400 Subject: [PATCH 1/2] Completed Web Templates + support for Yaml/yml config --- package-lock.json | 19 +++++ package.json | 4 +- src/utils/deploy/templates.ts | 144 +++++++++++++++++++--------------- 3 files changed, 104 insertions(+), 63 deletions(-) diff --git a/package-lock.json b/package-lock.json index ef6bffc..6e8c3c5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -65,6 +65,12 @@ "integrity": "sha512-GUvNiia85zTDDIx0iPrtF3pI8dwrQkfuokEqxqPDE55qxH0U5SZz4awVZjiJLWN2ZZRkXCUqgsMUbygXY+kytA==", "dev": true }, + "@types/js-yaml": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.5.tgz", + "integrity": "sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==", + "dev": true + }, "@types/json-diff": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/@types/json-diff/-/json-diff-0.7.0.tgz", @@ -119,6 +125,11 @@ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", "dev": true }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -467,6 +478,14 @@ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "requires": { + "argparse": "^2.0.1" + } + }, "json-diff": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/json-diff/-/json-diff-0.9.0.tgz", diff --git a/package.json b/package.json index 456b258..09c33db 100644 --- a/package.json +++ b/package.json @@ -33,12 +33,14 @@ "commander": "^9.4.0", "configstore": "6.0.0", "node-fetch": "3.2.10", - "json-diff": "0.9.0" + "json-diff": "0.9.0", + "js-yaml": "4.1.0" }, "devDependencies": { "@types/node": "18.6.3", "@types/configstore": "6.0.0", "@types/json-diff": "0.7.0", + "@types/js-yaml": "4.0.5", "nodemon": "^2.0.19", "ts-node": "^10.9.1", "typescript": "^4.7.4" diff --git a/src/utils/deploy/templates.ts b/src/utils/deploy/templates.ts index 5055b13..37eaa76 100644 --- a/src/utils/deploy/templates.ts +++ b/src/utils/deploy/templates.ts @@ -6,7 +6,7 @@ import fs from 'fs'; import { Template, TemplateElement } from '../../commands/api/templates/Template.interface.js'; import Configstore from 'configstore'; import { TemplateService } from '../../commands/api/templates/Template.service.js'; -import { stringify } from 'querystring'; +import yaml from 'js-yaml'; import { diffString } from 'json-diff'; const deployTemplates = async (artifactDirectory: string, config: Configstore) => { @@ -27,111 +27,131 @@ const deployTemplates = async (artifactDirectory: string, config: Configstore) = return; } - await deployDecisionTemplates(artifactDirectory, config); - await deployWebTemplates(artifactDirectory, config); + await deployTemplateTypes(artifactDirectory, 'DECISION', config); + await deployTemplateTypes(artifactDirectory, 'WEB', config); logline(chalk.greenBright(`Finished deploying templates`)); }; -const deployDecisionTemplates = async (artifactDirectory: string, config: Configstore): Promise => { +const deployTemplateTypes = async ( + artifactDirectory: string, + templateType: string, + config: Configstore +): Promise => { const templateService = TemplateService(config); - const decisionFolder = path.join(artifactDirectory, 'templates', 'decision'); + const templateFolder = path.join(artifactDirectory, 'templates', templateType); const clientKey: string = config.get('clientKey'); - logline(chalk.greenBright(`Starting to deploy decision templates`)); + logline(chalk.greenBright(`Starting to deploy ${templateType} templates`)); - if (!(await checkFolder(decisionFolder))) { - logline(chalk.red(`Decision templates folder doesn't exist - will not deploy`)); + if (!(await checkFolder(templateFolder))) { + logline(chalk.red(`${templateType} templates folder doesn't exist - will not deploy`)); return; } - const templatesToRun: string[] = await getFolders(decisionFolder); + const templatesToRun: string[] = await getFolders(templateFolder); if (templatesToRun.length === 0) { - logline(chalk.red(`No decision templates found - will not deploy`)); + logline(chalk.red(`No ${templateType} templates found - will not deploy`)); } await Promise.all( templatesToRun.map( async (templateToRun) => - await deployIndividualTemplates(templateToRun, decisionFolder, 'DECISION', templateService, clientKey) + await deployIndividualTemplates(templateToRun, templateFolder, templateType, templateService) ) ); - logline(chalk.greenBright(`Finished deploying decision templates`)); + logline(chalk.greenBright(`Finished deploying ${templateType} templates`)); }; -const deployWebTemplates = async (artifactDirectory: string, config: Configstore): Promise => { - const templateService = TemplateService(config); - const decisionFolder = path.join(artifactDirectory, 'templates', 'decision'); - const clientKey: string = config.get('clientKey'); - - logline(chalk.greenBright(`Starting to deploy decision templates`)); +const getConfigFile = async (startPath: string) => { + // Read File Sync by yml yaml or json from the file system + let extension = getExtensions(startPath, 'config'); - if (!(await checkFolder(decisionFolder))) { - logline(chalk.red(`Decision templates folder doesn't exist - will not deploy`)); - return; + if (extension === undefined) { + return null; } - const templatesToRun: string[] = await getFolders(decisionFolder); + let configContents: Template = yaml.load( + fs.readFileSync(path.join(startPath, `config.${extension}`), 'utf8') + ) as Template; - if (templatesToRun.length === 0) { - logline(chalk.red(`No decision templates found - will not deploy`)); + return configContents; +}; + +const getExtensions = (startDirectory: string, fileEntry: string): string | undefined => { + const files = fs.readdirSync(startDirectory); + + const filename: string | undefined = files.find((file) => { + // return the first files that include given entry + return file.includes(fileEntry); + }); + + if (filename === undefined) { + return undefined; } - await Promise.all( - templatesToRun.map( - async (templateToRun) => - await deployIndividualTemplates(templateToRun, decisionFolder, 'WEB', templateService, clientKey) - ) - ); + const extension = filename.split('.').pop(); - logline(chalk.greenBright(`Finished deploying decision templates`)); + return extension; }; -const deployIndividualTemplates = async ( - templateToRun: string, - folderPath: string, - templateType: string, - templateService: any, - clientKey: string -) => { - const templateFiles = await getFolderFiles(path.join(folderPath, templateToRun)); +const generateTemplateElements = (template: Template, startDirectory: string, templateType: string): Template => { + const files = fs.readdirSync(startDirectory); - // TODO: need a template validation function in the CLI to validate the template - let template: Template = JSON.parse( - fs.readFileSync(path.join(folderPath, templateToRun, 'config.json'), 'utf8') - ) as Template; + if (!files) { + return template; + } - if (template) { - // Need to make dynamic - const jsFileContents = await fs.promises.readFile(path.join(folderPath, templateToRun, 'file.js'), 'utf8'); + const filenames: string[] = files.filter((value) => value.match(/file.(js|html|css|ftl)/)); - if (!jsFileContents) { - logline(chalk.red(`Decision template file missing - Skip Deploy`)); - return; + if (filenames.length > 0) { + // If empty array, then initialize + if (template.templateElements == undefined || template.templateElements.length == 0) { + template.templateElements = []; } - // Check to see if this template already exists - let templateFromService: Template = await templateService.GetByFriendlyId(template.friendlyId); + filenames.forEach((file, item) => { + let fileContents = fs.readFileSync(path.join(startDirectory, file), 'utf8'); + let extension = file.split('.').pop(); - logline(chalk.greenBright(`Deploying decision template ${template.friendlyId}`)); + if (extension == 'ftl') { + extension = 'freemarker'; + } - // This needs to be refactored :-) - if (template.templateElements !== undefined && template.templateElements.length > 0) { - let objIndexTemplateElement = template.templateElements.findIndex((obj) => obj.id === 'js'); + if (fileContents && extension) { + let existingElement = template.templateElements.findIndex((element) => element.id == extension); - if (objIndexTemplateElement !== -1) { - template.templateElements[objIndexTemplateElement].template = jsFileContents; + if (existingElement > -1) { + template.templateElements[existingElement].template = fileContents; + } else { + template.templateElements.push({ id: extension, template: fileContents }); + } } else { - template.templateElements.push({ id: 'js', template: jsFileContents }); + logline(`There was an issue attaching file ${file} to ${template.name}`); } - } else { - template.templateElements = []; - template.templateElements.push({ id: 'js', template: jsFileContents }); - } + }); + } + return template; +}; + +const deployIndividualTemplates = async ( + templateToRun: string, + folderPath: string, + templateType: string, + templateService: any +) => { + let template: Template | null = await getConfigFile(path.join(folderPath, templateToRun)); + + if (template != null) { let result: Template | null = null; + + const templateFromService: Template = await templateService.GetByFriendlyId(template.friendlyId); + + template = generateTemplateElements(template, path.join(folderPath, templateToRun), templateType); + if (templateFromService) { logline(chalk.greenBright(`Template ${template.friendlyId} already exists in tenant - will update values`)); From a5f6297d63b9117f8acedeb5b075eeba812634d3 Mon Sep 17 00:00:00 2001 From: Dylan Young <5227854+dylanyoung-dev@users.noreply.github.com> Date: Tue, 13 Sep 2022 15:34:45 -0400 Subject: [PATCH 2/2] Uptick package version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 46a9981..2197e53 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sitecore-cdp-serializer", - "version": "0.1.2", + "version": "0.1.5", "description": "A Sitecore CDP/Personalize Serialization tool to abstract the APIs related to Tenant asset management and automated deployments from Source Control and/or physical files", "type": "module", "exports": "./lib/index.js",