import dotenv from "dotenv" ; import fs from "fs" ; import yaml from "js-yaml" ; import * as os from "os" ; import path from "path" ; import { build as buildError } from "./lib/errorBuilder" ; import { errorStatusCode } from "./lib/errorStatusCode" ; import { writeVersion } from "./lib/fileutils" ; import { logger } from "./logger" ; import { AzurePipelinesYaml , ConfigYaml , MaintainersFile , BedrockFile , } from "./types" ; import * as bedrockYaml from "./lib/bedrockYaml" ; let bedrockConfig = { } ; let hasWarnedAboutUninitializedConfig = false ; throws param filepath export const readYaml = < T > ( filepath ) : T => { if ( fs . existsSync ( filepath ) ) { const contents = fs . readFileSync ( filepath , "utf8" ) ; return yaml . safeLoad ( contents ) as T ; } throw buildError ( errorStatusCode . FILE_IO_ERR , { errorKey : "bedrock-config-yaml-err-readyaml" , values : [ filepath ] , } ) ; } ; param value export const updateVariableWithLocalEnv = ( value ) : string => { const regexp = /\${env:([a-zA-Z_$][a-zA-Z_$0-9]+)}/ ; let matches = regexp . exec ( value ) ; while ( matches ) { if ( matches . length > 1 ) { if ( process . env [ matches [ 1 ] ] ) { value = value . replace ( matches [ 0 ] , process . env [ matches [ 1 ] ] as string ) ; } else { throw buildError ( errorStatusCode . ENV_SETTING_ERR , { errorKey : "bedrock-config-yaml-var-undefined" , values : [ matches [ 1 ] ] , } ) ; } matches = regexp . exec ( value ) ; } } return value ; } ; param configYaml returns export const loadConfigurationFromLocalEnv = < T > ( configObj ) : T => { const iterate = ( obj ) : void => { if ( obj !== null && obj !== undefined ) { for ( const [ key , value ] of Object . entries ( obj ) ) { obj [ key ] = updateVariableWithLocalEnv ( value as string ) ; if ( typeof obj [ key ] === "object" ) { iterate ( obj [ key ] ) ; } } } } ; iterate ( configObj ) ; return configObj ; } ; /**
 * Fetches the absolute default directory of the bedrock global config
 */ export const defaultConfigDir = ( ) : string => { const dir = path . join ( os . homedir ( ) , ".bedrock" ) ; if ( ! fs . existsSync ( dir ) ) { fs . mkdirSync ( dir ) ; } return dir ; } ; /**
 * Fetches the absolute default path of the bedrock global config
 */ export const defaultConfigFile = ( ) : string => path . join ( defaultConfigDir ( ) , "config.yaml" ) ; param filepath export const loadConfiguration = ( filepath = defaultConfigFile ( ) ) : void => { try { fs . statSync ( filepath ) ; dotenv . config ( ) ; const data = readYaml < ConfigYaml > ( filepath ) ; bedrockConfig = loadConfigurationFromLocalEnv ( data || { } ) ; } catch ( err ) { throw buildError ( errorStatusCode . FILE_IO_ERR , "bedrock-config-yaml-load-err" , err ) ; } } ; /**
 * Returns the global bedrock-config from the host user
 */ export const Config = ( ) : ConfigYaml => { if ( Object . keys ( bedrockConfig ) . length === 0 ) { try { loadConfiguration ( ) ; } catch ( err ) { logger . verbose ( err ) ; if ( ! hasWarnedAboutUninitializedConfig ) { logger . info ( `Unable to load Bedrock configuration file; run \`bedrock init\` to initialize your global configuration or ensure you have passed all required parameters to the called function.` ) ; hasWarnedAboutUninitializedConfig = true ; } } } return bedrockConfig ; } ; param fileDirectory export const Bedrock = ( fileDirectory = process . cwd ( ) ) : BedrockFile => { const bedrockYamlPath = path . join ( fileDirectory , "bedrock.yaml" ) ; const bedrock = bedrockYaml . read ( fileDirectory ) ; const { services } = bedrock ; const helmErrors = Object . entries ( services ) . map ( ( [ servicePath , serviceConfig ] ) => { const { chart } = serviceConfig . helm ; const isGitBased = "git" in chart && "path" in chart && ( "branch" in chart || "sha" in chart ) ; const isHelmBased = "repository" in chart && "chart" in chart ; if ( ! isGitBased && ! isHelmBased ) { const requiredGitValues = [ "git" , "path" , "branch|sha" ] ; const requiredHelmValues = [ "repository" , "chart" ] ; return Error ( `invalid helm configuration found in service ${ servicePath }, helm configuration expects a set of keys matching ${ JSON . stringify ( requiredGitValues ) } or ${ JSON . stringify ( requiredHelmValues ) }; found: ${ JSON . stringify ( chart ) }` ) ; } } ) . filter ( ( e ) => ! ! e ) as Error [ ] ; if ( helmErrors . length > 0 ) { for ( const error of helmErrors ) { logger . error ( error ) ; } throw buildError ( errorStatusCode . ENV_SETTING_ERR , { errorKey : "bedrock-config-invalid" , values : [ bedrockYamlPath ] , } ) ; } return { ... bedrock } ; } ; param fileDirectory export const BedrockAsync = async ( fileDirectory = process . cwd ( ) ) : Promise < BedrockFile > => Bedrock ( fileDirectory ) ; /**
 * Returns the current maintainers.yaml file for the project
 */ export const Maintainers = ( fileDirectory = process . cwd ( ) ) : MaintainersFile => readYaml < MaintainersFile > ( path . join ( fileDirectory , "maintainers.yaml" ) ) ; param fileDirectory export const MaintainersAsync = async ( fileDirectory = process . cwd ( ) ) : Promise < MaintainersFile > => Maintainers ( fileDirectory ) ; param file export const write = ( file , targetDirectory = process . cwd ( ) , fileName ? ) : void => { const asYaml = yaml . safeDump ( file , { lineWidth : Number . MAX_SAFE_INTEGER } ) ; if ( "services" in file ) { fileName = "maintainers.yaml" ; writeVersion ( path . join ( targetDirectory , fileName ) ) ; return fs . appendFileSync ( path . join ( targetDirectory , fileName ) , asYaml ) ; } else { if ( typeof fileName === "undefined" ) { throw buildError ( errorStatusCode . EXE_FLOW_ERR , "config-file-not-defined" ) ; } writeVersion ( path . join ( targetDirectory , fileName ) ) ; return fs . appendFileSync ( path . join ( targetDirectory , fileName ) , asYaml ) ; } } ; param sourceFilePath param targetDir export const saveConfiguration = ( sourceFilePath , targetDir = defaultConfigDir ( ) ) : void => { try { logger . info ( "Generating config.yaml from yaml file input." ) ; const data = yaml . safeDump ( readYaml < ConfigYaml > ( sourceFilePath ) , { lineWidth : Number . MAX_SAFE_INTEGER , } ) ; const targetFile = path . join ( targetDir , "config.yaml" ) ; fs . writeFileSync ( targetFile , data ) ; logger . info ( `config.yaml was generated and located at ${ targetFile }.` ) ; } catch ( err ) { logger . error ( `Error occurred while writing config to default location ${ err }` ) ; } } ;