import axios from "axios" ; import commander from "commander" ; import fs from "fs" ; import inquirer from "inquirer" ; import yaml from "js-yaml" ; import { Config , defaultConfigFile , loadConfiguration , saveConfiguration , } from "../config" ; import { build as buildCmd , exit as exitCmd } from "../lib/commandBuilder" ; import { build as buildError , log as logError } from "../lib/errorBuilder" ; import { errorStatusCode } from "../lib/errorStatusCode" ; import * as promptBuilder from "../lib/promptBuilder" ; import { deepClone } from "../lib/util" ; import { hasValue } from "../lib/validator" ; import { logger } from "../logger" ; import { ConfigYaml } from "../types" ; import decorator from "./init.decorator.json" ; interface CommandOptions { file : string | undefined ; interactive : boolean ; } interface Answer { azdo_org_name : string ; azdo_project_name : string ; azdo_pat : string ; toSetupIntrospectionConfig : boolean ; } param file export const handleFileConfig = ( file ) : void => { loadConfiguration ( file ) ; saveConfiguration ( file ) ; logger . info ( "Successfully initialized the bedrock tool!" ) ; } ; param curConfig return export const prompt = async ( curConfig ) : Promise < Answer > => { const questions = [ promptBuilder . azureOrgName ( curConfig . azure_devops ?. org ) , promptBuilder . azureProjectName ( curConfig . azure_devops ?. project ) , promptBuilder . azureAccessToken ( curConfig . azure_devops ?. access_token ) , promptBuilder . askToSetupIntrospectionConfig ( false ) , ] ; const answers = await inquirer . prompt ( questions ) ; return { azdo_org_name : answers . azdo_org_name as string , azdo_pat : answers . azdo_pat as string , azdo_project_name : answers . azdo_project_name as string , toSetupIntrospectionConfig : answers . toSetupIntrospectionConfig , } ; } ; /**
 * Returns Bedrock configuration. Empty azure devops values are returned
 * if config.yaml is absent.
 */ export const getConfig = ( ) : ConfigYaml => { try { loadConfiguration ( ) ; return Config ( ) ; } catch ( _ ) { logger . info ( "current config is not found." ) ; return { azure_devops : { access_token : "" , org : "" , project : "" , } , } ; } } ; param azure return export const validatePersonalAccessToken = async ( azure ) : Promise < boolean > => { if ( ! azure || ! azure . org || ! azure . project || ! azure . access_token ) { throw buildError ( errorStatusCode . ENV_SETTING_ERR , "init_cmd_unable_validate_pat" ) ; } try { const res = await axios . get ( `https://dev.azure.com/${ azure . org }/_apis/projects/${ azure . project }` , { auth : { password : azure . access_token as string , username : "" , } , } ) ; return res . status === 200 ; } catch ( _ ) { return false ; } } ; export const isIntrospectionAzureDefined = ( curConfig ) : boolean => { if ( ! curConfig . introspection ) { return false ; } const intro = curConfig . introspection ; return intro . azure !== undefined ; } ; export const handleIntrospectionInteractive = async ( curConfig ) : Promise < void > => { if ( ! isIntrospectionAzureDefined ( curConfig ) ) { curConfig . introspection = { azure : { } , } ; } const azure = curConfig . introspection ! . azure ! ; const ans = await inquirer . prompt ( [ promptBuilder . azureStorageAccountName ( azure . account_name ) , promptBuilder . azureStorageTableName ( azure . table_name ) , promptBuilder . azureStoragePartitionKey ( azure . partition_key ) , promptBuilder . azureStorageAccessKey ( azure . key ) , ] ) ; azure [ "account_name" ] = ans . azdo_storage_account_name ; azure [ "table_name" ] = ans . azdo_storage_table_name ; azure [ "partition_key" ] = ans . azdo_storage_partition_key ; azure . key = ans . azdo_storage_access_key ; } ; /**
 * Handles the interactive mode of the command.
 */ export const handleInteractiveMode = async ( ) : Promise < void > => { const conf = getConfig ( ) ; if ( conf . introspection && conf . introspection . azure ) { delete conf . introspection . azure . key ; } const curConfig = deepClone ( conf ) ; const answer = await prompt ( curConfig ) ; curConfig [ "azure_devops" ] = curConfig . azure_devops || { } ; curConfig . azure_devops . org = answer . azdo_org_name ; curConfig . azure_devops . project = answer . azdo_project_name ; curConfig . azure_devops [ "access_token" ] = answer . azdo_pat ; if ( answer . toSetupIntrospectionConfig ) { await handleIntrospectionInteractive ( curConfig ) ; } const data = yaml . safeDump ( curConfig ) ; fs . writeFileSync ( defaultConfigFile ( ) , data ) ; logger . info ( "Successfully constructed config.yaml file in .bedrock under the $HOME directory" ) ; const ok = await validatePersonalAccessToken ( curConfig . azure_devops ) ; if ( ok ) { logger . info ( "Organization name, project name and personal access token are verified." ) ; } else { logger . error ( "Unable to verify organization name, project name and personal access token." ) ; } } ; param opts param exitFn export const execute = async ( opts , exitFn ) : Promise < void > => { try { if ( ! hasValue ( opts . file ) && ! opts . interactive ) { throw buildError ( errorStatusCode . VALIDATION_ERR , "init_cmd_missing_opts" ) ; } if ( hasValue ( opts . file ) && opts . interactive ) { throw buildError ( errorStatusCode . VALIDATION_ERR , "init_cmd_both_opts_err" ) ; } if ( hasValue ( opts . file ) ) { handleFileConfig ( opts . file ) ; } else { await handleInteractiveMode ( ) ; } await exitFn ( 0 ) ; } catch ( err ) { logError ( buildError ( errorStatusCode . CMD_EXE_ERR , "init_cmd_failed" , err ) ) ; await exitFn ( 1 ) ; } } ; param command export const commandDecorator = ( command ) : void => { buildCmd ( command , decorator ) . action ( async ( opts ) => { await execute ( opts , async ( status ) => { await exitCmd ( logger , process . exit , status ) ; } ) ; } ) ; } ;