import commander from "commander" ; import fs from "fs" ; import path from "path" ; import { Bedrock , write } from "../../config" ; import * as bedrockYaml from "../../lib/bedrockYaml" ; import { build as buildCmd , exit as exitCmd } from "../../lib/commandBuilder" ; import { generateGitIgnoreFile , generateHldLifecyclePipelineYaml , getVersion , } from "../../lib/fileutils" ; import { exec } from "../../lib/shell" ; import { logger } from "../../logger" ; import { BedrockFile , MaintainersFile } from "../../types" ; import decorator from "./init.decorator.json" ; import { build as buildError , log as logError } from "../../lib/errorBuilder" ; import { errorStatusCode } from "../../lib/errorStatusCode" ; import { CLI_LOG_FILENAME } from "../../lib/constants" ; interface CommandOptions { defaultRing : string ; } param targetPath const generateBedrockFile = ( projectPath , defaultRings = [ ] ) : void => { const absProjectPath = path . resolve ( projectPath ) ; logger . info ( `Generating bedrock.yaml file in ${ absProjectPath }` ) ; const baseBedrockFile = { rings : defaultRings . reduce < { [ ring ] : { isDefault : boolean ; } ; } > ( ( defaults , ring ) => { defaults [ ring ] = { isDefault : true } ; return defaults ; } , { } ) , services : [ ] , version : getVersion ( ) , } ; const bedrockFilePath = path . join ( absProjectPath , "bedrock.yaml" ) ; if ( fs . existsSync ( bedrockFilePath ) ) { logger . warn ( `Existing bedrock.yaml found at ${ bedrockFilePath }, skipping generation` ) ; } else { bedrockYaml . create ( absProjectPath , baseBedrockFile ) ; } } ; param projectPath const generateMaintainersFile = async ( projectPath , packagePaths ) : Promise < void > => { const absProjectPath = path . resolve ( projectPath ) ; const absPackagePaths = packagePaths . map ( ( p ) => path . resolve ( p ) ) ; logger . info ( `Generating maintainers.yaml file in ${ absProjectPath }` ) ; const [ gitName , gitEmail ] = await Promise . all ( [ "name" , "email" ] . map ( async ( field ) => { try { const gitField = await exec ( "git" , [ "config" , `user.${ field }` ] ) ; return gitField ; } catch ( _ ) { logger . warn ( `Unable to parse git.${ field } from host. Leaving blank value in maintainers.yaml file` ) ; return "" ; } } ) ) ; const maintainersFile = absPackagePaths . reduce < MaintainersFile > ( ( file , absPackagePath ) => { const relPathToPackageFromRoot = path . relative ( absProjectPath , absPackagePath ) ; if ( relPathToPackageFromRoot !== "" ) { file . services [ "./" + relPathToPackageFromRoot ] = { maintainers : [ { email : "" , name : "" } ] , } ; } return file ; } , { services : { "./" : { maintainers : [ { email : gitEmail , name : gitName , } , ] , } , } , } ) ; const maintainersFilePath = path . join ( absProjectPath , "maintainers.yaml" ) ; logger . debug ( `Writing maintainers.yaml file to ${ maintainersFilePath }` ) ; if ( fs . existsSync ( maintainersFilePath ) ) { logger . warn ( `Existing maintainers.yaml found at ${ maintainersFilePath }, skipping generation` ) ; } else { write ( maintainersFile , absProjectPath ) ; } } ; param rootProjectPath param opts export const initialize = async ( rootProjectPath , opts ? ) : Promise < void > => { const absProjectRoot = path . resolve ( rootProjectPath ) ; logger . info ( `Initializing project Bedrock project ${ absProjectRoot }` ) ; const defaultRing = opts ? [ opts . defaultRing ] : [ ] ; generateBedrockFile ( absProjectRoot , defaultRing ) ; await generateMaintainersFile ( absProjectRoot , [ ] ) ; await generateHldLifecyclePipelineYaml ( absProjectRoot ) ; generateGitIgnoreFile ( absProjectRoot , [ CLI_LOG_FILENAME ] ) ; logger . info ( `Project initialization complete!` ) ; } ; export const execute = async ( opts , projectPath , exitFn ) : Promise < void > => { const defaultRing = opts . defaultRing ; try { Bedrock ( ) ; } catch ( err ) { logger . info ( err ) ; } try { await initialize ( projectPath , { defaultRing } ) ; await exitFn ( 0 ) ; } catch ( err ) { logError ( buildError ( errorStatusCode . EXE_FLOW_ERR , "project-init-cmd-failed" , err ) ) ; await exitFn ( 1 ) ; } } ; export const commandDecorator = ( command ) : void => { buildCmd ( command , decorator ) . action ( async ( opts ) => { await execute ( opts , process . cwd ( ) , async ( status ) => { await exitCmd ( logger , process . exit , status ) ; } ) ; } ) ; } ;