diff --git a/src/commands/deploy.ts b/src/commands/deploy.ts index 53c803d..468bc0e 100644 --- a/src/commands/deploy.ts +++ b/src/commands/deploy.ts @@ -8,7 +8,7 @@ export const deploy = async ( ) => { const context = constructActionContext({ ...options, stackName }); logger.info('Validating yaml...'); - const iac = parseYaml(context); + const iac = parseYaml(context.iacLocation); logger.info('Yaml is valid! πŸŽ‰'); logger.info('Deploying stack...'); diff --git a/src/commands/template.ts b/src/commands/template.ts index 50f2673..fbbe51f 100644 --- a/src/commands/template.ts +++ b/src/commands/template.ts @@ -1,15 +1,16 @@ import { TemplateFormat } from '../types'; import yaml from 'yaml'; import { generateStackTemplate } from '../stack/deploy'; -import { constructActionContext, logger } from '../common'; +import { constructActionContext, getIacLocation, logger } from '../common'; import { parseYaml } from '../parser'; export const template = ( stackName: string, options: { format: TemplateFormat; location: string; stage: string | undefined }, ) => { - const context = constructActionContext({ ...options, stackName }); - const iac = parseYaml(context); + const iac = parseYaml(getIacLocation(options.location)); + + const context = constructActionContext({ ...options, stackName, provider: iac.provider.name }); const { template } = generateStackTemplate(stackName, iac, context); if (typeof template === 'string') { diff --git a/src/commands/validate.ts b/src/commands/validate.ts index 1f12e89..ce33203 100644 --- a/src/commands/validate.ts +++ b/src/commands/validate.ts @@ -3,7 +3,6 @@ import { parseYaml } from '../parser'; export const validate = (location: string | undefined, stage: string | undefined) => { const context = constructActionContext({ location, stage }); - parseYaml(context); + parseYaml(context.iacLocation); logger.info('Yaml is valid! πŸŽ‰'); - logger.debug('Yaml is valid! debugπŸŽ‰'); }; diff --git a/src/common/actionContext.ts b/src/common/actionContext.ts index bf8d2db..395de1a 100644 --- a/src/common/actionContext.ts +++ b/src/common/actionContext.ts @@ -1,8 +1,20 @@ import { ActionContext } from '../types'; import path from 'node:path'; +import { ProviderEnum } from './providerEnum'; + +export const getIacLocation = (location?: string): string => { + const projectRoot = path.resolve(process.cwd()); + return location + ? path.resolve(projectRoot, location) + : path.resolve(projectRoot, 'serverlessinsight.yml') || + path.resolve(projectRoot, 'serverlessInsight.yml') || + path.resolve(projectRoot, 'ServerlessInsight.yml') || + path.resolve(projectRoot, 'serverless-insight.yml'); +}; export const constructActionContext = (config?: { region?: string; + provider?: string; account?: string; accessKeyId?: string; accessKeySecret?: string; @@ -20,15 +32,8 @@ export const constructActionContext = (config?: { accessKeyId: config?.accessKeyId ?? (process.env.ALIYUN_ACCESS_KEY_ID as string), accessKeySecret: config?.accessKeySecret ?? (process.env.ALIYUN_ACCESS_KEY_SECRET as string), securityToken: config?.securityToken ?? process.env.ALIYUN_SECURITY_TOKEN, - iacLocation: (() => { - const projectRoot = path.resolve(process.cwd()); - return config?.location - ? path.resolve(projectRoot, config.location) - : path.resolve(projectRoot, 'serverlessinsight.yml') || - path.resolve(projectRoot, 'serverlessInsight.yml') || - path.resolve(projectRoot, 'ServerlessInsight.yml') || - path.resolve(projectRoot, 'serverless-insight.yml'); - })(), + iacLocation: getIacLocation(config?.location), parameters: Object.entries(config?.parameters ?? {}).map(([key, value]) => ({ key, value })), + provider: config?.provider as ProviderEnum, }; }; diff --git a/src/common/index.ts b/src/common/index.ts index c46770f..af3dea1 100644 --- a/src/common/index.ts +++ b/src/common/index.ts @@ -1,4 +1,4 @@ -export * from './provider'; +export * from './providerEnum'; export * from './logger'; export * from './getVersion'; export * from './rosClient'; diff --git a/src/common/provider.ts b/src/common/providerEnum.ts similarity index 80% rename from src/common/provider.ts rename to src/common/providerEnum.ts index 67af4b2..304d35a 100644 --- a/src/common/provider.ts +++ b/src/common/providerEnum.ts @@ -1,4 +1,4 @@ -export enum Provider { +export enum ProviderEnum { HUAWEI = 'huawei', ALIYUN = 'aliyun', // TENCENT = 'TENCENT', diff --git a/src/parser/index.ts b/src/parser/index.ts index 9e9cd65..106be5c 100644 --- a/src/parser/index.ts +++ b/src/parser/index.ts @@ -1,12 +1,11 @@ import { existsSync, readFileSync } from 'node:fs'; -import { ActionContext, ServerlessIac, ServerlessIacRaw } from '../types'; +import { ServerlessIac, ServerlessIacRaw } from '../types'; import { parseFunction } from './functionParser'; import { parseEvent } from './eventParser'; import { parseDatabase } from './databaseParser'; import { parseTag } from './tagParser'; import { parse } from 'yaml'; import { validateYaml } from '../validator'; -import { Provider } from '../common'; const validateExistence = (path: string) => { if (!existsSync(path)) { @@ -18,7 +17,7 @@ const transformYaml = (iacJson: ServerlessIacRaw): ServerlessIac => { return { service: iacJson.service, version: iacJson.version, - provider: iacJson.provider as Provider, + provider: iacJson.provider, vars: iacJson.vars, stages: iacJson.stages, functions: parseFunction(iacJson.functions), @@ -28,10 +27,10 @@ const transformYaml = (iacJson: ServerlessIacRaw): ServerlessIac => { }; }; -export const parseYaml = (context: ActionContext): ServerlessIac => { - validateExistence(context.iacLocation); +export const parseYaml = (iacLocation: string): ServerlessIac => { + validateExistence(iacLocation); - const yamlContent = readFileSync(context.iacLocation, 'utf8'); + const yamlContent = readFileSync(iacLocation, 'utf8'); const iacJson = parse(yamlContent) as ServerlessIacRaw; validateYaml(iacJson); diff --git a/src/stack/deploy.ts b/src/stack/deploy.ts index 93f8d3c..05b5d77 100644 --- a/src/stack/deploy.ts +++ b/src/stack/deploy.ts @@ -1,7 +1,7 @@ import * as ros from '@alicloud/ros-cdk-core'; import { ActionContext, ServerlessIac } from '../types'; -import { logger, Provider, rosStackDeploy } from '../common'; +import { logger, ProviderEnum, rosStackDeploy } from '../common'; import { RosStack } from './rosStack'; import { RfsStack } from './rfsStack'; @@ -48,9 +48,9 @@ export const generateStackTemplate = ( iac: ServerlessIac, context: ActionContext, ): { template: unknown } => { - if (iac.provider === Provider.ALIYUN) { + if (iac.provider.name === ProviderEnum.ALIYUN) { return generateRosStackTemplate(stackName, iac, context); - } else if (iac.provider === Provider.HUAWEI) { + } else if (iac.provider.name === ProviderEnum.HUAWEI) { return generateRfsStackTemplate(stackName, iac, context); } return { template: '' }; diff --git a/src/types/domains/context.ts b/src/types/domains/context.ts index 1d2774c..eb19a90 100644 --- a/src/types/domains/context.ts +++ b/src/types/domains/context.ts @@ -1,7 +1,10 @@ +import { ProviderEnum } from '../../common'; + export type ActionContext = { - stage: string; - stackName: string; region: string; + provider: ProviderEnum; + stackName: string; + stage: string; accessKeyId: string; accessKeySecret: string; securityToken?: string; diff --git a/src/types/domains/provider.ts b/src/types/domains/provider.ts new file mode 100644 index 0000000..57b5870 --- /dev/null +++ b/src/types/domains/provider.ts @@ -0,0 +1,6 @@ +import { ProviderEnum } from '../../common'; + +export type Provider = { + name: ProviderEnum; + region: string; +}; diff --git a/src/types/index.ts b/src/types/index.ts index 504c7e7..c3c2886 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -3,7 +3,7 @@ import { Tags } from './domains/tag'; import { EventDomain, EventRaw } from './domains/event'; import { DatabaseDomain, DatabaseRaw } from './domains/database'; import { FunctionDomain, FunctionRaw } from './domains/function'; -import { Provider } from '../common'; +import { Provider } from './domains/provider'; export * from './domains/database'; export * from './domains/event'; diff --git a/src/validator/rootSchema.ts b/src/validator/rootSchema.ts index 7aa6757..5d3e876 100644 --- a/src/validator/rootSchema.ts +++ b/src/validator/rootSchema.ts @@ -3,7 +3,13 @@ export const rootSchema = { type: 'object', properties: { version: { type: 'string', enum: ['0.0.0', '0.0.1'] }, - provider: { type: 'string', enum: ['aliyun', 'huawei'] }, + provider: { + type: 'object', + properties: { + name: { type: 'string', enum: ['huawei', 'aliyun'] }, + region: { type: 'string' }, + }, + }, service: { type: 'string' }, vars: { type: 'object', diff --git a/tests/fixtures/contextFixture.ts b/tests/fixtures/contextFixture.ts index b6d040e..0a50b67 100644 --- a/tests/fixtures/contextFixture.ts +++ b/tests/fixtures/contextFixture.ts @@ -1,8 +1,10 @@ import { ActionContext } from '../../src/types'; +import { ProviderEnum } from '../../src/common'; export const context: ActionContext = { stage: 'test', stackName: 'testStack', + provider: ProviderEnum.ALIYUN, region: 'cn-hangzhou', accessKeyId: 'testAccessKeyId', accessKeySecret: 'testAccessKeySecret', diff --git a/tests/fixtures/deployFixture.ts b/tests/fixtures/deployFixture.ts index 7cfdbeb..9183fe0 100644 --- a/tests/fixtures/deployFixture.ts +++ b/tests/fixtures/deployFixture.ts @@ -1,13 +1,15 @@ import { DatabaseEnum, ServerlessIac } from '../../src/types'; import { cloneDeep, set } from 'lodash'; -import { Provider } from '../../src/common'; +import { ProviderEnum } from '../../src/common'; export const oneFcOneGatewayIac = { service: 'my-demo-service', version: '0.0.1', - provider: 'aliyun' as Provider, + provider: { + name: 'aliyun' as ProviderEnum, + region: "cn-hangzhou'", + }, vars: { - region: 'cn-hangzhou', account_id: 1234567890, }, stages: { @@ -65,7 +67,6 @@ export const oneFcOneGatewayRos = { Metadata: { 'ALIYUN::ROS::Interface': { TemplateTags: ['Create by ROS CDK'] } }, Parameters: { account_id: { Default: 1234567890, Type: 'String' }, - region: { Default: 'cn-hangzhou', Type: 'String' }, }, ROSTemplateFormatVersion: '2015-09-01', Resources: { @@ -160,7 +161,6 @@ export const referredServiceRos = { Metadata: { 'ALIYUN::ROS::Interface': { TemplateTags: ['Create by ROS CDK'] } }, Parameters: { account_id: { Default: 1234567890, Type: 'String' }, - region: { Default: 'cn-hangzhou', Type: 'String' }, }, ROSTemplateFormatVersion: '2015-09-01', Resources: { @@ -240,7 +240,10 @@ export const referredServiceRos = { export const minimumIac = { service: 'my-demo-minimum-service', version: '0.0.1', - provider: 'aliyun' as Provider, + provider: { + name: 'aliyun' as ProviderEnum, + region: 'cn-hangzhou', + }, functions: [ { @@ -273,9 +276,11 @@ export const minimumRos = { export const oneFcIac = { service: 'my-demo-service', version: '0.0.1', - provider: 'aliyun' as Provider, - vars: { + provider: { + name: 'aliyun' as ProviderEnum, region: 'cn-hangzhou', + }, + vars: { account_id: 1234567890, }, stages: { @@ -319,7 +324,6 @@ export const oneFcRos = { Metadata: { 'ALIYUN::ROS::Interface': { TemplateTags: ['Create by ROS CDK'] } }, Parameters: { account_id: { Default: 1234567890, Type: 'String' }, - region: { Default: 'cn-hangzhou', Type: 'String' }, }, ROSTemplateFormatVersion: '2015-09-01', Resources: { @@ -341,9 +345,11 @@ export const oneFcRos = { export const oneFcIacWithStage = { service: 'my-demo-service', version: '0.0.1', - provider: 'aliyun' as Provider, - vars: { + provider: { + name: 'aliyun', region: 'cn-hangzhou', + }, + vars: { account_id: 1234567890, }, stages: { @@ -395,7 +401,6 @@ export const oneFcWithStageRos = { Metadata: { 'ALIYUN::ROS::Interface': { TemplateTags: ['Create by ROS CDK'] } }, Parameters: { account_id: { Default: 1234567890, Type: 'String' }, - region: { Default: 'cn-hangzhou', Type: 'String' }, }, ROSTemplateFormatVersion: '2015-09-01', Resources: { @@ -437,10 +442,6 @@ export const largeCodeRos = { Default: 1234567890, Type: 'String', }, - region: { - Default: 'cn-hangzhou', - Type: 'String', - }, }, ROSTemplateFormatVersion: '2015-09-01', Resources: { @@ -752,7 +753,10 @@ export const defaultContext = { export const esServerlessMinimumIac: ServerlessIac = { service: 'my-demo-es-serverless-service', version: '0.0.1', - provider: 'aliyun' as Provider as Provider, + provider: { + name: 'aliyun' as ProviderEnum, + region: 'cn-hangzhou', + }, databases: [ { key: 'insight_es_db_test', diff --git a/tests/fixtures/serverless-insight-es.yml b/tests/fixtures/serverless-insight-es.yml index 61a7043..3d3c701 100644 --- a/tests/fixtures/serverless-insight-es.yml +++ b/tests/fixtures/serverless-insight-es.yml @@ -1,5 +1,8 @@ version: 0.0.1 -provider: aliyun + +provider: + name: aliyun + region: cn-chengdu service: insight-es-poc diff --git a/tests/fixtures/serverless-insight-huawei.yml b/tests/fixtures/serverless-insight-huawei.yml index 7dc6d08..fc4c596 100644 --- a/tests/fixtures/serverless-insight-huawei.yml +++ b/tests/fixtures/serverless-insight-huawei.yml @@ -1,21 +1,20 @@ version: 0.0.1 -provider: huawei +provider: + name: huawei + region: cn-north-4 vars: - region: cn-hangzhou testv: testVarValue handler: index.handler stages: default: - region: ${vars.region} node_env: default dev: region: ${vars.region} node_env: development prod: - region: cn-shanghai - + node_env: prod service: insight-poc tags: diff --git a/tests/fixtures/serverless-insight.yml b/tests/fixtures/serverless-insight.yml index faa5fbb..5ad9b04 100644 --- a/tests/fixtures/serverless-insight.yml +++ b/tests/fixtures/serverless-insight.yml @@ -1,5 +1,7 @@ version: 0.0.1 -provider: aliyun +provider: + name: aliyun + region: cn-chengdu vars: region: cn-hangzhou diff --git a/tests/parser/parse.test.ts b/tests/parser/parse.test.ts index b64651c..d28c08a 100644 --- a/tests/parser/parse.test.ts +++ b/tests/parser/parse.test.ts @@ -3,20 +3,17 @@ import { parseYaml } from '../../src/parser'; describe('unit test for parse', () => { describe('domain - databases', () => { - const defaultContext = { - iacLocation: path.resolve(__dirname, '../fixtures/serverless-insight-es.yml'), - accessKeyId: 'xxx', - accessKeySecret: 'xxx', - region: 'cn-chengdu', - stackName: 'insight-es-poc-test', - stage: 'test', - }; + const iacLocation = path.resolve(__dirname, '../fixtures/serverless-insight-es.yml'); + it('should pass databases from yaml to domain instance when the yaml is valid', () => { - const databaseDomain = parseYaml(defaultContext); + const databaseDomain = parseYaml(iacLocation); expect(databaseDomain).toEqual({ service: 'insight-es-poc', version: '0.0.1', - provider: 'aliyun', + provider: { + name: 'aliyun', + region: 'cn-chengdu', + }, tags: [ { key: 'iac-provider', value: 'ServerlessInsight' }, { key: 'owner', value: 'geek-fun' },