UNPKG

@sfdx-falcon/generator

Version:

Extends Yeoman's Generator class, adding customized support for SFDX-Falcon specific tools and capabilities. Part of the SFDX-Falcon Library.

647 lines (618 loc) 38.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); //─────────────────────────────────────────────────────────────────────────────────────────────────┐ /** * @author Vivek M. Chawla <@VivekMChawla> * @copyright 2019, Vivek M. Chawla / Salesforce. All rights reserved. * @license BSD-3-Clause For full license text, see the LICENSE file in the repo root or * `https://opensource.org/licenses/BSD-3-Clause` * @file packages/generator/src/project-generator.ts * @summary Exports `SfdxFalconProjectGenerator` for use with custom Yeoman generators that * focus on standing up local projects. * @description Exports an abstract class that extends the SFDX-Falcon Library's `SfdxFalconGenerator` * class, adding customized support for tools and capabilities that make it easier * to stand up a local git-based project. */ //─────────────────────────────────────────────────────────────────────────────────────────────────┘ // Import External Libraries, Modules, and Types //import chalk from 'chalk'; // Helps write colored text to the console. //import * as path from 'path'; // Library. Helps resolve local paths at runtime. const Generator = require("yeoman-generator"); // Class. Custom Generator classes must extend this. // Import SFDX-Falcon Libraries //import {GitUtil} from '@sfdx-falcon/util'; // Library. Git Helper functions specific to SFDX-Falcon. //import listrTasks from '@sfdx-falcon/util'; // Library. Helper functions that make using Listr with SFDX-Falcon easier. const validator_1 = require("@sfdx-falcon/validator"); // Library of Type Validation helper functions. // Import SFDX-Falcon Classes & Functions const debug_1 = require("@sfdx-falcon/debug"); // Class. Provides custom "debugging" services (ie. debug-style info to console.log()). const status_1 = require("@sfdx-falcon/status"); // Class. Implements a framework for creating results-driven, informational objects with a concept of heredity (child results) and the ability to "bubble up" both Errors (thrown exceptions) and application-defined "failures". const status_2 = require("@sfdx-falcon/status"); // Function. Prints a Styled Message to the console using Chalk. //import {SfdxFalconKeyValueTable} from '@sfdx-falcon/status'; // Class. Uses table creation code borrowed from the SFDX-Core UX library to make it easy to build "Key/Value" tables. const status_3 = require("@sfdx-falcon/status"); // Class. Status tracking object for use with Yeoman Generators. //import {InquirerChoices} from '@sfdx-falcon/types'; // Type. Represents a single "choice" option in an Inquirer multi-choice/multi-select question. //import {ListrContextFinalizeGit} from '@sfdx-falcon/types'; // Interface. Represents the Listr Context variables used by the "finalizeGit" task collection. //import {ListrTaskBundle} from '@sfdx-falcon/types'; // Interface. Represents the suite of information required to run a Listr Task Bundle. const types_1 = require("@sfdx-falcon/types"); // Enum. Represents the various types/states of a Status Message. // Set the File Local Debug Namespace const dbgNs = '@sfdx-falcon:project-generator'; debug_1.SfdxFalconDebug.msg(`${dbgNs}:`, `Debugging initialized for ${dbgNs}`); //─────────────────────────────────────────────────────────────────────────────────────────────────┐ /** * @class SfdxFalconGenerator * @extends Generator * @summary Abstract base class class for building Yeoman Generators for SFDX-Falcon commands. * @description Classes that extend `SfdxFalconGenerator` must provide a type parameter to * ensure that the "answers" family of member variables (`defaultAnswers`, * `userAnswers`, `metaAnswers`, and `finalAnswers`) has the appropriate interface * type which defines the answers that are relevant to a concrete child class. * @public @abstract */ //─────────────────────────────────────────────────────────────────────────────────────────────────┘ class SfdxFalconGenerator extends Generator { //───────────────────────────────────────────────────────────────────────────┐ /** * @constructs SfdxFalconGenerator * @param {string|string[]} args Required. Array of arguments that are * passed to this generator by Yeoman if the generator is being * invoked from the command line. Passed directly through to * the superclass constructor without modification. * @param {GeneratorOptions} opts Required. Object containing options * that help specify how a specific generator is run. These * options are set when external code uses a Yeoman Environment * to `run()` a Generator that's derived from this class. * @description Constructs an `SfdxFalconGenerator` object. * @public */ //───────────────────────────────────────────────────────────────────────────┘ constructor(args, opts, reqs) { // Define function-local debug namespace and debug incoming arguments. const funcName = `constructor`; const dbgNsLocal = `${dbgNs}:${funcName}`; debug_1.SfdxFalconDebug.obj(`${dbgNsLocal}:arguments:`, arguments); // Validate core options. validator_1.TypeValidator.throwOnEmptyNullInvalidObject(reqs, `${dbgNsLocal}`, `GeneratorRequirements`); validator_1.TypeValidator.throwOnEmptyNullInvalidObject(reqs.gitEnvReqs, `${dbgNsLocal}`, `GeneratorRequirements.gitEnvReqs`); validator_1.TypeValidator.throwOnEmptyNullInvalidObject(reqs.localEnvReqs, `${dbgNsLocal}`, `GeneratorRequirements.localEnvReqs`); validator_1.TypeValidator.throwOnEmptyNullInvalidObject(reqs.sfdxEnvReqs, `${dbgNsLocal}`, `GeneratorRequirements.sfdxEnvReqs`); validator_1.TypeValidator.throwOnEmptyNullInvalidObject(opts, `${dbgNsLocal}`, `GeneratorOptions`); validator_1.TypeValidator.throwOnEmptyNullInvalidString(opts.commandName, `${dbgNsLocal}`, `GeneratorOptions.commandName`); validator_1.TypeValidator.throwOnEmptyNullInvalidString(opts.generatorType, `${dbgNsLocal}`, `GeneratorOptions.generatorType`); validator_1.TypeValidator.throwOnEmptyNullInvalidString(opts.generatorPath, `${dbgNsLocal}`, `GeneratorOptions.generatorPath`); validator_1.TypeValidator.throwOnNullInvalidInstance(opts.generatorResult, status_1.SfdxFalconResult, `${dbgNsLocal}`, `GeneratorOptions.generatorType`); // Call the parent constructor to initialize the Yeoman Generator. super(args, opts); // Resolve Generator Requirements const generatorReqs = { sfdxEnvReqs: { standardOrgs: (reqs.sfdxEnvReqs.standardOrgs === true ? true : false), scratchOrgs: (reqs.sfdxEnvReqs.scratchOrgs === true ? true : false), devHubOrgs: (reqs.sfdxEnvReqs.devHubOrgs === true ? true : false), envHubOrgs: (reqs.sfdxEnvReqs.envHubOrgs === true ? true : false), managedPkgOrgs: (reqs.sfdxEnvReqs.managedPkgOrgs === true ? true : false), unmanagedPkgOrgs: (reqs.sfdxEnvReqs.unmanagedPkgOrgs === true ? true : false) }, gitEnvReqs: { // TODO: Implement once Git Environment is fleshed out. }, localEnvReqs: { // TODO: Implement once Local Environment is fleshed out. } }; // Determine the path to the package.json file for the currently running package. const pkgDotJsonPath = '../../../package.json'; // Attempt to pull the VERSION key from package.json. let pkgVersion = `??.??.??`; try { const { version } = require(pkgDotJsonPath); pkgVersion = validator_1.TypeValidator.isNotEmptyNullInvalidString(version) ? version : pkgVersion; } catch (pkgVersionJsonError) { debug_1.SfdxFalconDebug.obj(`${dbgNsLocal}:pkgVersionJsonError:`, pkgVersionJsonError); } debug_1.SfdxFalconDebug.str(`${dbgNsLocal}:pkgVersion:`, pkgVersion); // Attempt to pull the FALCON key from package.json. let pkgFalcon = {}; try { const { falcon } = require(pkgDotJsonPath); pkgFalcon = validator_1.TypeValidator.isNotNullInvalidObject(falcon) ? falcon : pkgFalcon; } catch (pkgFalconJsonError) { debug_1.SfdxFalconDebug.obj(`${dbgNsLocal}:pkgFalconJsonError:`, pkgFalconJsonError); } debug_1.SfdxFalconDebug.obj(`${dbgNsLocal}:pkgFalcon:`, pkgFalcon); // Initialize class members. this.commandName = opts.commandName; // Name of the command that's executing the Generator (eg. 'falcon:adk:clone'). this.generatorType = opts.generatorType; // Type (ie. file name minus the .ts extension) of the Generator being run. this.generatorResult = opts.generatorResult; // Used for activity tracking and communication back to the calling command. this.generatorReqs = generatorReqs; // Generator Requirements. Should be modified by the derived class. this.generatorStatus = new status_3.GeneratorStatus(); // Tracks status and build messages to the user. this.pluginVersion = pkgVersion; // Version of the plugin, taken from package.json. this.falcon = pkgFalcon; // Falcon global JsonMap, taken from package.json. this.sharedData = {}; // Special context for sharing data between Generator, Inquirer Questions, and Listr Tasks. // Initialize all Run-Loop Status booleans to `null`. // In practice, `null` will mean an unset value, `false` means failure, `true` means success. this.runLoopStatus = { initializingComplete: null, promptingComplete: null, configuringComplete: null, writingComplete: null, installComplete: null, endComplete: null }; // Initialize all Answer objects. this.answers = { default: {}, final: {}, user: {}, meta: {} }; // Set defaults for all Generator messages. this.generatorMessage = { opening: `SFDX-Falcon Powered Plugin\n${this.commandName}\nv${this.pluginVersion}`, confirmation: `Would you like to proceed based on the above settings?`, success: `${this.commandName} completed successfully`, failure: `${this.commandName} exited without completing the expected tasks`, warning: `${this.commandName} completed successfully, but with some warnings (see above)` }; // Start the GeneratorStatus object and add it to the detail of the GENERATOR Result. this.generatorStatus.start(); this.generatorResult.setDetail({ commandName: this.commandName, generatorType: this.generatorType, generatorPath: this.generatorPath, generatorReqs: this.generatorReqs, generatorMsgs: this.generatorMessage, interviewAnswers: this.answers, runLoopStatus: this.runLoopStatus, generatorStatus: this.generatorStatus }); this.generatorResult.debugResult(`After setting Detail in constructor`, `${dbgNsLocal}`); // Initialize Shared Data. this.sharedData['cliCommandName'] = this.commandName; // this.sharedData['generatorRequirements'] = this.generatorRequirements; this.sharedData['generatorStatus'] = this.generatorStatus; } //───────────────────────────────────────────────────────────────────────────┐ /** * @method initializing * @returns {Promise<void>} * @description STEP ONE in the Yeoman run-loop. Uses Yeoman's "initializing" * run-loop priority. This is a "default" implementation and * should work for most SFDX-Falcon use cases. It must be called * from inside the initializing() method of the child class. * @public @async */ //───────────────────────────────────────────────────────────────────────────┘ /* public async initializing():Promise<void> { // Do nothing if the Generator has been aborted. if (this.generatorStatus.aborted) { SfdxFalconDebug.msg(`${dbgNs}_default_initializing:`, `Generator has been aborted.`); return; } // Show the Yeoman to announce that the generator is running. this.log(yosay(this.generatorMessage.opening)); // Execute the initialization tasks for this generator try { await this._executeInitializationTasks(); } catch (initializationError) { SfdxFalconDebug.obj(`${dbgNs}default_initializing:`, initializationError, `initializationError: `); // Add an "abort" item to the Generator Status object. this.generatorStatus.abort({ type: StatusMessageType.ERROR, title: 'Initialization Error', message: `${this.commandName} command aborted because one or more initialization tasks failed` }); // Throw an Initialization Error. throw new SfdxFalconError( `Command initialization failed. ${initializationError.message}` , `InitializationError` , `${dbgNs}default_initializing` , SfdxFalconError.wrap(initializationError)); } // Add a line break to separate this section from the next in the console. console.log(''); }//*/ //───────────────────────────────────────────────────────────────────────────┐ /** * @method prompting * @param {StyledMessage} [preInterviewMessage] Optional. Message to * display to the user before the Interview starts. * @param {StyledMessage} [postInterviewMessage] Optional. Message to * display to the user after the Interview ends. * @returns {Promise<void>} * @description STEP TWO in the Yeoman run-loop. Interviews the User to get * information needed by the "writing" and "installing" phases. * This is a "default" implementation and should work for most * SFDX-Falcon use cases. It must be called from inside the * prompting() method of the child class. * @public @async */ //───────────────────────────────────────────────────────────────────────────┘ async prompting(preInterviewMessage, postInterviewMessage) { // Do nothing if the Generator has been aborted. if (this.generatorStatus.aborted) { debug_1.SfdxFalconDebug.msg(`${dbgNs}:prompting:`, `Generator has been aborted.`); return; } // Show the pre-interview message. status_2.printStyledMessage(preInterviewMessage); // Build the User Interview. this.userInterview = this._buildInterview(); // Start the User Interview. this.answers.final = await this.userInterview.start(); // Extract the "User Answers" from the Interview for inclusion in the GENERATOR Result's detail. this.generatorResult.detail['userAnswers'] = this.userInterview.userAnswers; // Check if the user aborted the Interview. if (this.userInterview.status.aborted) { this.generatorStatus.abort({ type: types_1.StatusMessageType.ERROR, title: 'Command Aborted', message: `${this.commandName} canceled by user. ${this.userInterview.status.reason}` }); } // Show the post-interview message. status_2.printStyledMessage(postInterviewMessage); // Done return; } //───────────────────────────────────────────────────────────────────────────┐ /** * @method configuring * @returns {void} * @description STEP THREE in the Yeoman run-loop. Perform any pre-install * configuration steps based on the answers provided by the User. * This is a "default" implementation and should work for most * SFDX-Falcon use cases. It must be called from inside the * configuring() method of the child class. * @protected */ //───────────────────────────────────────────────────────────────────────────┘ async configuring() { // Do nothing if the Generator has been aborted. if (this.generatorStatus.aborted) { debug_1.SfdxFalconDebug.msg(`${dbgNs}_default_configuring:`, `Generator has been aborted.`); return; } } //───────────────────────────────────────────────────────────────────────────┐ /** * @method writing * @returns {Promise<void>} * @description STEP FOUR in the Yeoman run-loop. Typically, this is where * you perform filesystem writes, git clone operations, etc. * This is a "default" implementation and should work for most * SFDX-Falcon use cases. It must be called from inside the * writing() method of the child class. * @public @async */ //───────────────────────────────────────────────────────────────────────────┘ async writing() { // Do nothing if the Generator has been aborted. if (this.generatorStatus.aborted) { debug_1.SfdxFalconDebug.msg(`${dbgNs}_default_writing:`, `Generator has been aborted.`); return; } } //───────────────────────────────────────────────────────────────────────────┐ /** * @method install * @returns {Promise<void>} * @description STEP FIVE in the Yeoman run-loop. Typically, this is where * you perform operations that must happen AFTER files are * written to disk. For example, if the "writing" step downloaded * an app to install, the "install" step would run the * installation. This is a "default" implementation and should * work for most SFDX-Falcon use cases. It must be called from * inside the install() method of the child class. * @public @async */ //───────────────────────────────────────────────────────────────────────────┘ async install() { // Do nothing if the Generator has been aborted. if (this.generatorStatus.aborted) { debug_1.SfdxFalconDebug.msg(`${dbgNs}_default_install:`, `Generator has been aborted.`); return; } } //───────────────────────────────────────────────────────────────────────────┐ /** * @method end * @returns {Promise<void>} * @description STEP SIX in the Yeoman run-loop. This is the FINAL step that * Yeoman runs and it gives us a chance to do any post-Yeoman * updates and/or cleanup. This is a "default" implementation * and should work for most SFDX-Falcon use cases. It must be * called from inside the end() method of the child class. * @public @async */ //───────────────────────────────────────────────────────────────────────────┘ async end() { // Check if the Yeoman interview/installation process was aborted. if (this.generatorStatus.aborted) { debug_1.SfdxFalconDebug.msg(`${dbgNs}end:`, `generatorStatus.aborted found as TRUE inside end()`); // Add a final error message this.generatorStatus.addMessage({ type: types_1.StatusMessageType.ERROR, title: 'Command Failed', message: `${this.generatorMessage.failure}\n` }); } else { // Generator completed successfully. Final message depends on presence of Generator Status Warnings. this.generatorStatus.complete([ { type: types_1.StatusMessageType.SUCCESS, title: 'Command Succeded', message: this.generatorStatus.hasWarning ? `${this.generatorMessage.warning}\n` : `${this.generatorMessage.success}\n` } ]); } // Print the final status table. this.generatorStatus.printStatusMessages(); return; } //───────────────────────────────────────────────────────────────────────────┐ /** * @method _cloneRepository * @returns {Promise<string>} Local path into which the Git Repository * was cloned. If the clone operation is unsuccessful, this * will return an empty string. * @description Clones a remote Git Repository per information specified * during by the command and/or during their interview. Returns * the local path to which the Git Repository was cloned, or * an empty string otherwise. * @protected @async */ //───────────────────────────────────────────────────────────────────────────┘ /* protected async _cloneRepository():Promise<string> { // Determine a number of Path/Git related strings required by this step. const targetDirectory = this.answers.final['targetDirectory'] as string; const gitRemoteUri = this['gitRemoteUri']; const gitCloneDirectory = this['gitCloneDirectory'] || GitUtil.getRepoNameFromUri(gitRemoteUri); const localProjectPath = path.join(targetDirectory, gitCloneDirectory); // Quick message saying we're going to start cloning. this.log(chalk`{yellow Cloning Project...}`); // Run a Listr Task that will clone the Remote Git Repo. return await listrTasks.cloneGitRemote.call(this, gitRemoteUri, targetDirectory, gitCloneDirectory).run() .then((_listrContext:unknown) => { // Add a message that the cloning was successful. this.generatorStatus.addMessage({ type: StatusMessageType.SUCCESS, title: `Project Cloned Successfully`, message: `Project cloned to ${localProjectPath}` }); return localProjectPath; }) .catch(gitCloneError => { this.generatorStatus.abort({ type: StatusMessageType.ERROR, title: `Git Clone Error`, message: gitCloneError.cause ? String(gitCloneError.cause.message).trim() : gitCloneError.message }); return ''; }); }//*/ //───────────────────────────────────────────────────────────────────────────┐ /** * @method _executeInitializationTasks * @returns {Promise<void>} * @description Runs a series of initialization tasks using the Listr UX/Task * Runner module. Listr provides a framework for executing tasks * while also providing an attractive, realtime display of task * status (running, successful, failed, etc.). * @protected @async */ //───────────────────────────────────────────────────────────────────────────┘ /* protected async _executeInitializationTasks():Promise<void> { // Define the first group of tasks (Git Initialization). const gitInitTasks = listrTasks.gitEnvironmentCheck.call(this, this.generatorRequirements.gitRemoteUri); // Define the second group of tasks (SFDX Initialization). const sfdxInitTasks = listrTasks.sfdxInitTasks.call(this); // Show a message to the User letting them know we're going to initialize this command. console.log(chalk`{yellow Initializing ${this.cliCommandName}...}`); // If required, run the Git Init Tasks. if (this.generatorRequirements.git || this.generatorRequirements.gitRemoteUri) { const gitInitResults = await gitInitTasks.run(); SfdxFalconDebug.obj(`${dbgNs}_executeInitializationTasks:`, gitInitResults, `gitInitResults: `); } // If required, run the SFDX Init Tasks. if ( this.generatorRequirements.standardOrgs === true || this.generatorRequirements.scratchOrgs === true || this.generatorRequirements.devHubOrgs === true || this.generatorRequirements.envHubOrgs === true || this.generatorRequirements.managedPkgOrgs === true || this.generatorRequirements.unmanagedPkgOrgs === true ) { const sfdxInitResults = await sfdxInitTasks.run(); SfdxFalconDebug.obj(`${dbgNs}_executeInitializationTasks:`, sfdxInitResults, `sfdxInitResults: `); } }//*/ //───────────────────────────────────────────────────────────────────────────┐ /** * @method _finalizeGitActions * @param {string} destinationRoot Required. * @param {boolean} isInitializingGit Required. * @param {string} gitRemoteUri Required. * @param {string} projectAlias Required. * @returns {Promise<void>} * @description Intended to run after _finalizeProjectCreation() during the * Yeoman "writing" phase. Initializes local Git repo, and will * even try to attach a Git remote if specified by the user. * @protected @async */ //───────────────────────────────────────────────────────────────────────────┘ /* protected async _finalizeGitActions(destinationRoot:string, isInitializingGit:boolean, gitRemoteUri:string, projectAlias:string):Promise<void> { // Make sure that the caller really WANTS to initialize Git. if (isInitializingGit !== true) { this.generatorStatus.addMessage({ type: StatusMessageType.SUCCESS, title: `Git Initialization`, message: `Skipped - Git initialization skipped at user's request` }); return; } // Tell the user that we are adding their project to Git this.log(chalk`{yellow Adding project to Git...}`); // Construct a Listr Task Object for the "Finalize Git" tasks. const finalizeGit = listrTasks.finalizeGit.call(this, destinationRoot, gitRemoteUri); // Try to run the "Finalize Git" tasks. Catch any errors so we can exit the broader Falcon command gracefully. let finalizeGitCtx = {} as ListrContextFinalizeGit; try { finalizeGitCtx = await finalizeGit.run() as ListrContextFinalizeGit; } catch (listrError) { SfdxFalconDebug.obj(`${dbgNs}_finalizeGitActions:listrError:`, listrError, `listrError: `); finalizeGitCtx = listrError.context; } // DEBUG SfdxFalconDebug.obj(`${dbgNs}_finalizeGitActions:finalizeGitCtx:`, finalizeGitCtx, `finalizeGitCtx: `); // Separate the end of the "Finalize Git" Listr tasks from following output. console.log(''); // Check if Git was installed in the local environment. if (finalizeGitCtx.gitInstalled !== true) { this.generatorStatus.addMessage({ type: StatusMessageType.WARNING, title: `Initializing Git`, message: `Warning - git executable not found in your environment - no Git operations attempted` }); // Skip the remaining checks and message builds. return; } // Check if the project was successfully initialized (ie. "git init" was run in the project directory). if (finalizeGitCtx.gitInitialized) { this.generatorStatus.addMessage({ type: StatusMessageType.SUCCESS, title: `Git Initialization`, message: `Success - Repository created successfully (${projectAlias})` }); } else { this.generatorStatus.addMessage({ type: StatusMessageType.WARNING, title: `Git Initialization`, message: `Warning - Git could not be initialized in your project folder` }); // Skip the remaining checks and message builds. return; } // Check if the files were staged and committed successfully. if (finalizeGitCtx.projectFilesStaged && finalizeGitCtx.projectFilesCommitted) { this.generatorStatus.addMessage({ type: StatusMessageType.SUCCESS, title: `Git Commit`, message: `Success - Staged all project files and executed the initial commit` }); } else { this.generatorStatus.addMessage({ type: StatusMessageType.WARNING, title: `Git Commit`, message: `Warning - Attempt to stage and commit project files failed - Nothing to commit` }); } // If the user specified a Git Remote, check for success there. if (gitRemoteUri) { // Check if the Git Remote is valid/reachable if (finalizeGitCtx.gitRemoteIsValid !== true) { this.generatorStatus.addMessage({ type: StatusMessageType.WARNING, title: `Git Remote`, message: `Warning - Could not add Git Remote - ${gitRemoteUri} is invalid/unreachable` }); } else { if (finalizeGitCtx.gitRemoteAdded) { this.generatorStatus.addMessage({ type: StatusMessageType.SUCCESS, title: `Git Remote`, message: `Success - Remote repository ${gitRemoteUri} added as "origin"` }); } else { this.generatorStatus.addMessage({ type: StatusMessageType.WARNING, title: `Git Remote`, message: `Warning - Could not add Git Remote - A remote named "origin" already exists` }); } } } // All done. return; }//*/ //───────────────────────────────────────────────────────────────────────────┐ /** * @method _finalizeProjectCloning * @returns {boolean} Returns FALSE if the project was aborted. * @description Intended to run after the Yeoman "writing" phase. Has logic * that ensures the Generator wasn't aborted, and then carries * out finalization tasks that are generic to "cloning" * Generators. Returns a boolean so the calling class can decide * whether or not to perform additional actions. * @protected */ //───────────────────────────────────────────────────────────────────────────┘ _finalizeProjectCloning() { // Check if we need to abort the Yeoman interview/installation process. if (this.generatorStatus.aborted) { debug_1.SfdxFalconDebug.msg(`${dbgNs}_finalizeProjectCloning:`, `generatorStatus.aborted found as TRUE inside install()`); return false; } // Make sure that a Destination Root was set. if (!this.destinationRoot()) { debug_1.SfdxFalconDebug.msg(`${dbgNs}_finalizeProjectCloning:`, `No value returned by this.destinationRoot(). Skipping finalization tasks.`); return false; } // If we get here, it means that a local SFDX-Falcon config file was likely created. this.generatorStatus.addMessage({ type: types_1.StatusMessageType.SUCCESS, title: `Local Config Created`, message: `.sfdx-falcon/sfdx-falcon-config.json created and customized successfully` }); // Add a line break to separate the end of the "writing" phase from any output in the "install" phase. console.log(''); // All done. return true; } //───────────────────────────────────────────────────────────────────────────┐ /** * @method _finalizeProjectCreation * @returns {boolean} Returns FALSE if the project was aborted. * @description Intended to run after the Yeoman "writing" phase. Has logic * that ensures the Generator wasn't aborted, and then carries * out finalization tasks that are generic to "creation" * Generators. Returns a boolean so the calling class can decide * whether or not to perform additional actions. * @protected */ //───────────────────────────────────────────────────────────────────────────┘ _finalizeProjectCreation() { // Check if we need to abort the Yeoman interview/installation process. if (this.generatorStatus.aborted) { debug_1.SfdxFalconDebug.msg(`${dbgNs}_finalizeProjectCreation:`, `generatorStatus.aborted found as TRUE inside install()`); return false; } // Make sure that a Destination Root was set. if (!this.destinationRoot()) { debug_1.SfdxFalconDebug.msg(`${dbgNs}_finalizeProjectCreation:`, `No value returned by this.destinationRoot(). Skipping finalization tasks.`); return false; } // Add a "project creation" success message to Generator Status. this.generatorStatus.addMessage({ type: types_1.StatusMessageType.SUCCESS, title: `Project Creation`, message: `Success - Project created at ${this.destinationRoot()}` }); // Add a line break to separate the end of the "writing" phase from any output in the "install" phase. console.log(''); // If we get this far, return TRUE so additional finalization code knows it should run. return true; } } exports.SfdxFalconGenerator = SfdxFalconGenerator; //# sourceMappingURL=project-generator.js.map