Skip to content

Commit

Permalink
test: add more test and fix stackname not pass issue #5
Browse files Browse the repository at this point in the history
Signed-off-by: seven <[email protected]>
  • Loading branch information
Blankll committed Sep 23, 2024
1 parent bb533b0 commit 8ddcf77
Show file tree
Hide file tree
Showing 9 changed files with 351 additions and 94 deletions.
2 changes: 1 addition & 1 deletion src/commands/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export const deploy = async (
stackName: string,
options: { location: string; parameters: { [key: string]: string } },
) => {
const context = constructActionContext(options);
const context = constructActionContext({ ...options, stackName });
logger.info('Validating yaml...');
const iac = parseYaml(context.iacLocation);
logger.info('Yaml is valid! 🎉');
Expand Down
2 changes: 2 additions & 0 deletions src/common/actionContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ export const constructActionContext = (config?: {
location?: string;
parameters?: { [key: string]: string };
stage?: string;
stackName?: string;
}): ActionContext => {
return {
stage: config?.stage ?? 'default',
stackName: config?.stackName ?? '',
region:
config?.region ?? process.env.ROS_REGION_ID ?? process.env.ALIYUN_REGION ?? 'cn-hangzhou',
accessKeyId: config?.accessKeyId ?? (process.env.ALIYUN_ACCESS_KEY_ID as string),
Expand Down
49 changes: 49 additions & 0 deletions src/common/iacHelper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import path from 'node:path';
import fs from 'node:fs';
import * as ros from '@alicloud/ros-cdk-core';

export const resolveCode = (location: string): string => {
const filePath = path.resolve(process.cwd(), location);
const fileContent = fs.readFileSync(filePath);

return fileContent.toString('base64');
};

export const replaceVars = <T>(value: T, stage: string): T => {
if (typeof value === 'string') {
const matchVar = value.match(/^\$\{vars\.(\w+)}$/);
const containsVar = value.match(/\$\{vars\.(\w+)}/);
const matchMap = value.match(/^\$\{stages\.(\w+)}$/);
const containsMap = value.match(/\$\{stages\.(\w+)}/);
if (matchVar?.length) {
return ros.Fn.ref(matchVar[1]) as T;
}
if (matchMap?.length) {
return ros.Fn.findInMap('stages', '', matchMap[1]) as T;
}
if (containsMap?.length && containsVar?.length) {
return ros.Fn.sub(
value.replace(/\$\{stages\.(\w+)}/g, '${$1}').replace(/\$\{vars\.(\w+)}/g, '${$1}'),
) as T;
}
if (containsVar?.length) {
return ros.Fn.sub(value.replace(/\$\{vars\.(\w+)}/g, '${$1}')) as T;
}
if (containsMap?.length) {
return ros.Fn.sub(value.replace(/\$\{stages\.(\w+)}/g, '${$1}')) as T;
}
return value;
}

if (Array.isArray(value)) {
return value.map((item) => replaceVars(item, stage)) as T;
}

if (typeof value === 'object' && value !== null) {
return Object.fromEntries(
Object.entries(value).map(([key, val]) => [key, replaceVars(val, stage)]),
) as T;
}

return value;
};
1 change: 1 addition & 0 deletions src/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from './logger';
export * from './getVersion';
export * from './rosClient';
export * from './actionContext';
export * from './iacHelper';
8 changes: 1 addition & 7 deletions src/common/rosClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,7 @@ const updateStack = async (stackId: string, templateBody: unknown, context: Acti
parameterValue: Util.assertAsString(parameter.key),
}),
);
console.log(
'parameters:',
JSON.stringify({
parameters,
contextParam: context.parameters,
}),
);

const createStackRequest = new UpdateStackRequest({
regionId: context.region,
stackId,
Expand Down
122 changes: 37 additions & 85 deletions src/stack/iacStack.ts
Original file line number Diff line number Diff line change
@@ -1,61 +1,15 @@
import * as ros from '@alicloud/ros-cdk-core';
import { ActionContext, EventTypes, ServerlessIac } from '../types';
import { RosParameterType } from '@alicloud/ros-cdk-core';
import { ActionContext, EventTypes, ServerlessIac } from '../types';
import * as fc from '@alicloud/ros-cdk-fc';
import * as ram from '@alicloud/ros-cdk-ram';
import * as agw from '@alicloud/ros-cdk-apigateway';
import path from 'node:path';
import fs from 'node:fs';

const resolveCode = (location: string): string => {
const filePath = path.resolve(process.cwd(), location);
const fileContent = fs.readFileSync(filePath);

return fileContent.toString('base64');
};

const replaceVars = <T>(value: T, stage: string): T => {
if (typeof value === 'string') {
const matchVar = value.match(/^\$\{vars\.(\w+)}$/);
const containsVar = value.match(/\$\{vars\.(\w+)}/);
const matchMap = value.match(/^\$\{stages\.(\w+)}$/);
const containsMap = value.match(/\$\{stages\.(\w+)}/);
if (matchVar?.length) {
return ros.Fn.ref(matchVar[1]) as T;
}
if (matchMap?.length) {
return ros.Fn.findInMap('stages', '', matchMap[1]) as T;
}
if (containsMap?.length && containsVar?.length) {
return ros.Fn.sub(
value.replace(/\$\{stages\.(\w+)}/g, '${$1}').replace(/\$\{vars\.(\w+)}/g, '${$1}'),
) as T;
}
if (containsVar?.length) {
return ros.Fn.sub(value.replace(/\$\{vars\.(\w+)}/g, '${$1}')) as T;
}
if (containsMap?.length) {
return ros.Fn.sub(value.replace(/\$\{stages\.(\w+)}/g, '${$1}')) as T;
}
return value;
}

if (Array.isArray(value)) {
return value.map((item) => replaceVars(item, stage)) as T;
}

if (typeof value === 'object' && value !== null) {
return Object.fromEntries(
Object.entries(value).map(([key, val]) => [key, replaceVars(val, stage)]),
) as T;
}

return value;
};
import { replaceVars, resolveCode } from '../common';

export class IacStack extends ros.Stack {
constructor(scope: ros.Construct, iac: ServerlessIac, context: ActionContext) {
super(scope, iac.service, {
stackName: context.stackName,
tags: iac.tags.reduce((acc: { [key: string]: string }, tag) => {
acc[tag.key] = replaceVars(tag.value, context.stage);
return acc;
Expand All @@ -70,7 +24,7 @@ export class IacStack extends ros.Stack {
defaultValue: value,
}),
);
console.log('stages:', iac.stages);

// Define Mappings
new ros.RosMapping(this, 'stages', { mapping: replaceVars(iac.stages, context.stage) });

Expand Down Expand Up @@ -111,8 +65,8 @@ export class IacStack extends ros.Stack {
func.addDependsOn(service);
});

const apiGateway = iac.events.find((event) => event.type === EventTypes.API_GATEWAY);
if (apiGateway) {
const apiGateway = iac.events?.filter((event) => event.type === EventTypes.API_GATEWAY);
if (apiGateway?.length) {
const gatewayAccessRole = new ram.RosRole(
this,
replaceVars(`${iac.service}_role`, context.stage),
Expand Down Expand Up @@ -161,43 +115,41 @@ export class IacStack extends ros.Stack {
true,
);

iac.events
.filter((event) => event.type === EventTypes.API_GATEWAY)
.forEach((event) => {
event.triggers.forEach((trigger) => {
const key = `${trigger.method}_${trigger.path}`.toLowerCase().replace(/\//g, '_');
apiGateway.forEach((event) => {
event.triggers.forEach((trigger) => {
const key = `${trigger.method}_${trigger.path}`.toLowerCase().replace(/\//g, '_');

const api = new agw.RosApi(
this,
replaceVars(`${event.key}_api_${key}`, context.stage),
{
apiName: replaceVars(`${event.name}_api_${key}`, context.stage),
groupId: apiGatewayGroup.attrGroupId,
visibility: 'PRIVATE',
requestConfig: {
requestProtocol: 'HTTP',
requestHttpMethod: replaceVars(trigger.method, context.stage),
requestPath: replaceVars(trigger.path, context.stage),
requestMode: 'PASSTHROUGH',
},
serviceConfig: {
serviceProtocol: 'FunctionCompute',
functionComputeConfig: {
fcRegionId: context.region,
serviceName: service.serviceName,
functionName: trigger.backend,
roleArn: gatewayAccessRole.attrArn,
},
const api = new agw.RosApi(
this,
replaceVars(`${event.key}_api_${key}`, context.stage),
{
apiName: replaceVars(`${event.name}_api_${key}`, context.stage),
groupId: apiGatewayGroup.attrGroupId,
visibility: 'PRIVATE',
requestConfig: {
requestProtocol: 'HTTP',
requestHttpMethod: replaceVars(trigger.method, context.stage),
requestPath: replaceVars(trigger.path, context.stage),
requestMode: 'PASSTHROUGH',
},
serviceConfig: {
serviceProtocol: 'FunctionCompute',
functionComputeConfig: {
fcRegionId: context.region,
serviceName: service.serviceName,
functionName: trigger.backend,
roleArn: gatewayAccessRole.attrArn,
},
resultSample: 'ServerlessInsight resultSample',
resultType: 'JSON',
tags: replaceVars(iac.tags, context.stage),
},
true,
);
api.addDependsOn(apiGatewayGroup);
});
resultSample: 'ServerlessInsight resultSample',
resultType: 'JSON',
tags: replaceVars(iac.tags, context.stage),
},
true,
);
api.addDependsOn(apiGatewayGroup);
});
});
}
}
}
3 changes: 2 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,12 @@ export type ServerlessIac = {
service: string;
tags: Array<{ key: string; value: string }>;
functions: Array<IacFunction>;
events: Array<Event>;
events?: Array<Event>;
};

export type ActionContext = {
stage: string;
stackName: string;
region: string;
accessKeyId: string;
accessKeySecret: string;
Expand Down
Loading

0 comments on commit 8ddcf77

Please sign in to comment.