UNPKG

mira

Version:

NearForm Accelerator for Cloud Native Serverless AWS

276 lines (238 loc) 8.05 kB
import configModule from 'config' import { pascalCase } from 'change-case' import parseGitUrl from 'git-url-parse' /** @ignore - Excluded from documentation generation. */ // eslint-disable-next-line const minimist = require('minimist') /** @ignore - Excluded from documentation generation. */ const args = minimist(process.argv) export interface Config { app: App dev: Dev accounts: { [x: string]: Account } cicd?: CicdConfig domain?: DomainConfig } interface App { prefix: string name: string } interface Dev { target: string } export interface AccountEnvData { account: string region: string } type EnvironmentVariable = { name: string value: string } export interface Account { readonly name: string readonly profile?: string readonly env: AccountEnvData } export interface Stage { readonly target: string readonly withDomain?: boolean readonly requireManualApproval: boolean readonly privileged: boolean } export interface CiProps { readonly target: string readonly withDomain?: string readonly requireManualApproval?: boolean readonly privileged?: boolean readonly account: Account } interface CicdConfig { readonly account: Account readonly permissionsFile: string readonly provider: string readonly repositoryUrl: string readonly branchName: string readonly gitHubTokenSecretArn?: string readonly codeCommitUserPublicKey?: string readonly buildspecFile: string readonly accounts: string[] readonly repositoryOwner?: string readonly repositoryName?: string } export interface DomainConfig { readonly hostedZoneId?: string readonly accounts: string[] } /** * A mapping of configuration properties and their expected keys within the JSON config. */ enum CONFIG_KEYS { CICD = 'cicd', ACCOUNTS = 'accounts', DEV = 'dev', STAGES = 'stages', TARGET = 'target', COST_CENTER = 'costCenter' } /** * Command line arguments that do not require a configuration file to run. * @internal * @ignore - Excluded from documentation generation. */ const whitelistedArgs: string[] = ['docs', 'init'] /** * This class represents the loaded Mira Configuration as defined by default.json * and its overrides (dev.json). * * @class MiraConfigClass */ class MiraConfigClass { /** * The project name comes from the `app.name` property of the default.json configuration file. * It represents the name of the application being deployed. */ public readonly projectName: string /** * The project prefix comes from the `app.prefix` property of the default.json configuration file. * It represents a prefix added to the application name (eg prefix-name) during deployment. */ public readonly projectPrefix: string constructor () { try { this.projectName = pascalCase(configModule.get('app.name')) this.projectPrefix = pascalCase(configModule.get('app.prefix')) } catch (err) { if (!whitelistedArgs.includes(args._[2])) { console.warn(`${err.message}, you will not be able to deploy your app yet. `) throw err } } } /** * Stores a reference to the environment name we will be deploying to. * The name should be one of the accounts listed in the configuration file * `accounts` object. */ public defaultEnvironmentName: string public setDefaultEnvironmentName (name: string): void { this.defaultEnvironmentName = name } public getEnvironment (name?: string): Account { name = this.getTargetName(name) const output = this.getFullAccountProps(name) if (!output) { throw new Error(`Cannot find environment ${name}`) } return output } public getEnvironmentWithCiProps (name?: string): CiProps { name = this.getTargetName(name) const output = this.getFullAccountProps(name) if (!output) { throw new Error(`Cannot find environment ${name}`) } const cicdKey = `${CONFIG_KEYS.CICD}.${CONFIG_KEYS.STAGES}` const ciOutput = (configModule .get(cicdKey) as CiProps[]) .find((ciProps: CiProps) => ciProps.target === name) if (!output) { throw new Error(`Cannot find environment ${name}`) } return Object.assign({}, { account: output }, ciOutput) } public getBaseStackName (suffix = ''): string { let output = `${this.projectPrefix}-${this.projectName}` if (suffix) { output += `-${suffix}` } return output } public calculateCertificateStackName (): string { return this.getBaseStackName('Domain') } public calculateRepositoryName (): string { return this.getBaseStackName('Repository') } public getCICDAccounts (): Account[] { let output = [] as Account[] const accountsPath = `${CONFIG_KEYS.CICD}.${CONFIG_KEYS.STAGES}` if (configModule.has(accountsPath)) { output = ((configModule.get(accountsPath) || []) as Stage[]) .map((stage: Stage) => this.getEnvironment(stage.target)) } return output } public getPermissionsFilePath (): string { return args.file || args.f || this.getCICDConfig().permissionsFile } public getCICDConfig (): CicdConfig { const output = this.getFullCiProps(CONFIG_KEYS.CICD) const githubValues: { repositoryName?: string, repositoryOwner?: string } = {} if (output.provider !== 'codecommit') { const { name, owner } = parseGitUrl(output.repositoryUrl) githubValues.repositoryName = name githubValues.repositoryOwner = owner } return { ...output, ...githubValues } } public getDomainConfig (): DomainConfig { if (configModule.has('domain')) { return configModule.get('domain') as DomainConfig } throw new Error('Cannot find Domain configuration.') } public getDomainAllowedPrincipals (): Account[] { let output = [] as Account[] if (configModule.has('domain.accounts')) { output = ((configModule.get('domain.accounts') || []) as string[]) .map((accountName) => this.getEnvironment(accountName)) } return output } public calculateSharedResourceName (resource: string): string { const env = this.getEnvironment() const prefix = this.getBaseStackName() return `${prefix}-${env.name}-${resource}` } private getFullCiProps (name: string): CicdConfig { if (!configModule.has(name)) throw new Error(`Missing ${name} in the top level of config.`) if (!configModule.has(`${name}.${CONFIG_KEYS.TARGET}`)) throw new Error(`Missing ${CONFIG_KEYS.TARGET} name in the ${name} configuration.`) const envKey: string = configModule.get(`${name}.${CONFIG_KEYS.TARGET}`) if (!configModule.has(`${CONFIG_KEYS.ACCOUNTS}.${envKey}`)) { throw new Error(`Target named: ${envKey} is not defined in the accounts section of the configuration file. Check if you did not override accounts in dev.json file.`) } const account: Account = configModule.get(`${CONFIG_KEYS.ACCOUNTS}.${envKey}`) return Object.assign({}, configModule.get(name), { account }) as CicdConfig } private getFullAccountProps (name: string): Account { const accountsKey = CONFIG_KEYS.ACCOUNTS if (!configModule.has(accountsKey)) throw new Error(`Missing ${accountsKey} section in your configuration file`) if (!configModule.has(`${accountsKey}.${name}`)) throw new Error(`Missing ${accountsKey}.${name} section in your configuration file`) return Object.assign({}, configModule.get(`${accountsKey}.${name}`), { name }) as Account } private getTargetName (name?: string): string { const devTargetPath = `${CONFIG_KEYS.DEV}.${CONFIG_KEYS.TARGET}` if (!name) { if (!configModule.has(devTargetPath)) { throw new Error(`Missing ${devTargetPath} in your config file.`) } name = configModule.get(devTargetPath) || '' } return name } public getCostCenter (): string { if (configModule.has(CONFIG_KEYS.COST_CENTER)) { return configModule.get(CONFIG_KEYS.COST_CENTER) } return '' } } export const MiraConfig = new MiraConfigClass()