UNPKG

sfdx-hardis

Version:

Swiss-army-knife Toolbox for Salesforce. Allows you to define a complete CD/CD Pipeline. Orchestrate base commands and assist users with interactive wizards

219 lines (217 loc) 10.2 kB
/* jscpd:ignore-start */ import { SfCommand, Flags } from '@salesforce/sf-plugins-core'; import { Messages, SfError } from '@salesforce/core'; import c from 'chalk'; import fs from 'fs-extra'; import pascalcase from 'pascalcase'; import * as path from 'path'; import { uxLog } from '../../../../common/utils/index.js'; import { dataFolderRoot } from '../../../../common/utils/dataUtils.js'; import { prompts } from '../../../../common/utils/prompts.js'; import { WebSocketClient } from '../../../../common/websocketClient.js'; import { getConfig, setConfig } from '../../../../config/index.js'; import { PACKAGE_ROOT_DIR } from '../../../../settings.js'; Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const messages = Messages.loadMessages('sfdx-hardis', 'org'); export default class ConfigureData extends SfCommand { static title = 'Configure Data project'; static description = `Configure Data Export/Import with a [SFDX Data Loader](https://help.sfdmu.com/) Project See article: [![How to detect bad words in Salesforce records using SFDX Data Loader and sfdx-hardis](https://github.com/hardisgroupcom/sfdx-hardis/raw/main/docs/assets/images/article-badwords.jpg)](https://nicolas.vuillamy.fr/how-to-detect-bad-words-in-salesforce-records-using-sfdx-data-loader-and-sfdx-hardis-171db40a9bac) `; static examples = ['$ sf hardis:org:configure:data']; static flags = { debug: Flags.boolean({ char: 'd', default: false, description: messages.getMessage('debugMode'), }), websocket: Flags.string({ description: messages.getMessage('websocket'), }), skipauth: Flags.boolean({ description: 'Skip authentication check when a default username is required', }), }; // Set this to true if your command requires a project workspace; 'requiresProject' is false by default static requiresProject = false; // List required plugins, their presence will be tested before running the command static requiresSfdxPlugins = ['sfdmu']; additionalFiles = []; dataPath; sfdmuConfig; importInScratchOrgs; /* jscpd:ignore-end */ async run() { const template = await this.selectTemplate(); if (template === 'blank') { // Request info to build sfdmu workspace await this.buildExportJsonInfo(); } else { await this.buildExportJsonInfoFromTemplate(template); } // Check if not already existing const { exportJsonFile, sfdmuProjectFolder } = await this.generateConfigurationFiles(); await this.promptImportInScratchOrgs(sfdmuProjectFolder); // Set bac initial cwd const message = c.cyan(`Successfully initialized sfdmu project ${c.green(sfdmuProjectFolder)}, with ${c.green('export.json')} file. You can now configure it using SFDMU documentation: https://help.sfdmu.com/plugin-basics/basic-usage/minimal-configuration If you don't have unique field to identify an object, use composite external ids: https://help.sfdmu.com/full-documentation/advanced-features/composite-external-id-keys `); uxLog(this, message); // Trigger command to open SFDMU config file in VsCode extension WebSocketClient.requestOpenFile(exportJsonFile); return { outputString: message }; } async generateConfigurationFiles() { const sfdmuProjectFolder = path.join(dataFolderRoot, this.dataPath); if (fs.existsSync(sfdmuProjectFolder)) { throw new SfError(`[sfdx-hardis]${c.red(`Folder ${c.bold(sfdmuProjectFolder)} already exists`)}`); } // Create folder & export.json await fs.ensureDir(sfdmuProjectFolder); const exportJsonFile = path.join(sfdmuProjectFolder, 'export.json'); await fs.writeFile(exportJsonFile, JSON.stringify(this.sfdmuConfig, null, 2)); uxLog(this, 'Generated SFDMU config file ' + exportJsonFile); for (const additionalFile of this.additionalFiles) { const additionalFileFull = path.join(sfdmuProjectFolder, additionalFile.path); await fs.writeFile(additionalFileFull, additionalFile.text); uxLog(this, c.cyan(additionalFile.message + ': ') + c.yellow(additionalFileFull)); WebSocketClient.requestOpenFile(additionalFileFull); } return { exportJsonFile, sfdmuProjectFolder }; } async buildExportJsonInfo() { const resp = await this.promptExportInfo(); // Collect / reformat data this.dataPath = pascalcase(resp.dataPath); const sfdxHardisLabel = resp.sfdxHardisLabel; const sfdxHardisDescription = resp.sfdxHardisDescription; const additionalConfig = resp.additional || []; this.sfdmuConfig = { sfdxHardisLabel: sfdxHardisLabel, sfdxHardisDescription: sfdxHardisDescription, objects: [ { query: "SELECT all FROM Account WHERE Name='sfdx-hardis'", operation: 'Upsert', externalId: 'Name', }, ], }; // Manage badwords filter option if (additionalConfig.includes('badwordsFilter')) { const badwordsFileName = 'badwords.json'; this.sfdmuConfig.objects[0] = [ { query: 'SELECT all FROM Lead', operation: 'Readonly', targetRecordsFilter: 'core:DetectBadwords', filterRecordsAddons: [ { module: 'core:RecordsFilter', args: { filterType: 'BadWords', settings: { badwordsFile: badwordsFileName, detectFields: ['Description'], highlightWords: true, outputMatches: false, }, }, }, ], }, ]; if (!fs.existsSync('badwords.json')) { const badwordsSample = { badwords: ['write', 'your', 'bad', 'words', 'and expressions', 'here'], }; this.additionalFiles.push({ path: badwordsFileName, text: JSON.stringify(badwordsSample, null, 2), message: 'Sample badwords file has been generated and needs to be updated', }); } } } async promptExportInfo() { return await prompts([ { type: 'text', name: 'dataPath', message: c.cyanBright('Please input the SFDMU folder name (PascalCase format). Ex: "ProductsActive"'), }, { type: 'text', name: 'sfdxHardisLabel', message: c.cyanBright('Please input the SFDMU config label. Ex: "Active Products"'), }, { type: 'text', name: 'sfdxHardisDescription', message: c.cyanBright('Please input the SFDMU config description. Ex: "Active products are used for scratch org initialization and in deployments"'), }, { type: 'multiselect', name: 'additional', message: c.cyanBright('Please select additional options if you need them. If not, just select nothing and continue'), choices: [ { title: 'Bad words detector', description: 'Can detect a list of bad words in records', value: 'badwordsFilter', }, ], }, ]); } async selectTemplate() { const templateChoices = []; const templatesFolder = path.join(PACKAGE_ROOT_DIR, 'defaults/templates/sfdmu'); const templateFiles = fs.readdirSync(templatesFolder); for (const templateFile of templateFiles) { const templateName = path.basename(templateFile).replace('.json', ''); templateChoices.push({ title: `📝 ${templateName}`, value: path.join(templatesFolder, templateFile), description: `sfdx-hardis template for ${templateName}`, }); } const defaultTemplateChoice = { title: '📄 Blank template', value: 'blank', description: 'Configure your data import/export from scratch :)', }; const templateResp = await prompts({ type: 'select', name: 'template', message: c.cyanBright('Please select a SFDMU template, or the blank one'), choices: [...[defaultTemplateChoice], ...templateChoices], }); return templateResp.template; } async buildExportJsonInfoFromTemplate(templateFile) { const templateName = path.basename(templateFile).replace('.json', ''); this.dataPath = pascalcase(templateName); this.sfdmuConfig = JSON.parse(fs.readFileSync(templateFile, 'utf-8')); } async promptImportInScratchOrgs(sfdmuProjectFolder) { const importResp = await prompts({ type: 'confirm', name: 'importInScratchOrgs', message: c.cyanBright('Do you want this SFDMU config to be used to import data when initializing a new scratch org ?'), default: false, }); this.importInScratchOrgs = importResp.importInScratchOrgs === true; // Manage dataPackages if importInScratchOrgs is true if (this.importInScratchOrgs === true) { const config = await getConfig('project'); const dataPackages = config.dataPackages || []; dataPackages.push({ dataPath: sfdmuProjectFolder.replace(/\\/g, '/'), importInScratchOrgs: true }); await setConfig('project', { dataPackages: dataPackages }); } } } //# sourceMappingURL=data.js.map