Skip to content

Commit

Permalink
feat: evaluate service ctx reference
Browse files Browse the repository at this point in the history
Signed-off-by: seven <[email protected]>
  • Loading branch information
Blankll committed Oct 29, 2024
1 parent 782dc4e commit f7d8de8
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 41 deletions.
25 changes: 14 additions & 11 deletions src/common/iacHelper.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import path from 'node:path';
import fs from 'node:fs';
import * as ros from '@alicloud/ros-cdk-core';
import { ServerlessIac } from '../types';
import { ActionContext } from '../types';

export const resolveCode = (location: string): string => {
const filePath = path.resolve(process.cwd(), location);
Expand All @@ -10,19 +10,28 @@ export const resolveCode = (location: string): string => {
return fileContent.toString('base64');
};

export const replaceReference = <T>(value: T, stage: string): T => {
const evalCtx = (value: string, ctx: ActionContext): string => {
const containsStage = value.match(/\$\{ctx.\w+}/);

return containsStage ? value.replace(/\$\{ctx.stage}/g, ctx.stage) : value;
};

export const replaceReference = <T>(value: T, ctx: ActionContext): 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+)}/);
const matchFn = value.match(/^\$\{functions\.(\w+(\.\w+)?)}$/);
if (value.match(/\$\{ctx.\w+}/)) {
return evalCtx(value, ctx) as T;
}

if (matchVar?.length) {
return ros.Fn.ref(matchVar[1]) as T;
}
if (matchMap?.length) {
return ros.Fn.findInMap('stages', stage, matchMap[1]) as T;
return ros.Fn.findInMap('stages', ctx.stage, matchMap[1]) as T;
}

if (matchFn?.length) {
Expand All @@ -43,20 +52,14 @@ export const replaceReference = <T>(value: T, stage: string): T => {
}

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

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

return value;
};

export const evalRefValue = (value: string, iac: ServerlessIac, stage: string): string => {
const containsStage = value.match(/\$\{stage}/);

return containsStage ? value.replace(/\$\{stage}/g, stage) : value;
};
56 changes: 28 additions & 28 deletions src/stack/iacStack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,26 @@ import { ActionContext, EventTypes, ServerlessIac } from '../types';
import * as fc from '@alicloud/ros-cdk-fc3';
import * as ram from '@alicloud/ros-cdk-ram';
import * as agw from '@alicloud/ros-cdk-apigateway';
import { evalRefValue, replaceReference, resolveCode } from '../common';
import { replaceReference, resolveCode } from '../common';

export class IacStack extends ros.Stack {
private service: string;
private readonly service: string;

constructor(scope: ros.Construct, iac: ServerlessIac, context: ActionContext) {
super(scope, evalRefValue(iac.service, iac, context.stage), {
super(scope, replaceReference(iac.service, context), {
stackName: context.stackName,
tags: iac.tags?.reduce((acc: { [key: string]: string }, tag) => {
acc[tag.key] = replaceReference(tag.value, context.stage);
acc[tag.key] = replaceReference(tag.value, context);
return acc;
}, {}),
});
this.service = evalRefValue(iac.service, iac, context.stage);
this.service = replaceReference(iac.service, context);

// Define Parameters
if (iac.vars) {
Object.entries(iac.vars).map(
([key, value]) =>
new ros.RosParameter(this, key, {
([id, value]) =>
new ros.RosParameter(this, id, {
type: RosParameterType.STRING,
defaultValue: value,
}),
Expand All @@ -32,26 +32,26 @@ export class IacStack extends ros.Stack {

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

new ros.RosInfo(
this,
ros.RosInfo.description,
replaceReference(`${this.service} stack`, context.stage),
replaceReference(`${this.service} stack`, context),
);

iac.functions.forEach((fnc) => {
new fc.RosFunction(
this,
fnc.key,
{
functionName: replaceReference(fnc.name, context.stage),
handler: replaceReference(fnc.handler, context.stage),
runtime: replaceReference(fnc.runtime, context.stage),
memorySize: replaceReference(fnc.memory, context.stage),
timeout: replaceReference(fnc.timeout, context.stage),
environmentVariables: replaceReference(fnc.environment, context.stage),
functionName: replaceReference(fnc.name, context),
handler: replaceReference(fnc.handler, context),
runtime: replaceReference(fnc.runtime, context),
memorySize: replaceReference(fnc.memory, context),
timeout: replaceReference(fnc.timeout, context),
environmentVariables: replaceReference(fnc.environment, context),
code: {
zipFile: resolveCode(fnc.code),
},
Expand All @@ -64,10 +64,10 @@ export class IacStack extends ros.Stack {
if (apiGateway?.length) {
const gatewayAccessRole = new ram.RosRole(
this,
replaceReference(`${this.service}_role`, context.stage),
replaceReference(`${this.service}_role`, context),
{
roleName: replaceReference(`${this.service}-gateway-access-role`, context.stage),
description: replaceReference(`${this.service} role`, context.stage),
roleName: replaceReference(`${this.service}-gateway-access-role`, context),
description: replaceReference(`${this.service} role`, context),
assumeRolePolicyDocument: {
version: '1',
statement: [
Expand All @@ -82,7 +82,7 @@ export class IacStack extends ros.Stack {
},
policies: [
{
policyName: replaceReference(`${this.service}-policy`, context.stage),
policyName: replaceReference(`${this.service}-policy`, context),
policyDocument: {
version: '1',
statement: [
Expand All @@ -102,10 +102,10 @@ export class IacStack extends ros.Stack {

const apiGatewayGroup = new agw.RosGroup(
this,
replaceReference(`${this.service}_apigroup`, context.stage),
replaceReference(`${this.service}_apigroup`, context),
{
groupName: replaceReference(`${this.service}_apigroup`, context.stage),
tags: replaceReference(iac.tags, context.stage),
groupName: replaceReference(`${this.service}_apigroup`, context),
tags: replaceReference(iac.tags, context),
},
true,
);
Expand All @@ -129,29 +129,29 @@ export class IacStack extends ros.Stack {

const api = new agw.RosApi(
this,
replaceReference(`${event.key}_api_${key}`, context.stage),
replaceReference(`${event.key}_api_${key}`, context),
{
apiName: replaceReference(`${event.name}_api_${key}`, context.stage),
apiName: replaceReference(`${event.name}_api_${key}`, context),
groupId: apiGatewayGroup.attrGroupId,
visibility: 'PRIVATE',
requestConfig: {
requestProtocol: 'HTTP',
requestHttpMethod: replaceReference(trigger.method, context.stage),
requestPath: replaceReference(trigger.path, context.stage),
requestHttpMethod: replaceReference(trigger.method, context),
requestPath: replaceReference(trigger.path, context),
requestMode: 'PASSTHROUGH',
},
serviceConfig: {
serviceProtocol: 'FunctionCompute',
functionComputeConfig: {
fcRegionId: context.region,
functionName: replaceReference(trigger.backend, context.stage),
functionName: replaceReference(trigger.backend, context),
roleArn: gatewayAccessRole.attrArn,
fcVersion: '3.0',
},
},
resultSample: 'ServerlessInsight resultSample',
resultType: 'JSON',
tags: replaceReference(iac.tags, context.stage),
tags: replaceReference(iac.tags, context),
},
true,
);
Expand Down
2 changes: 1 addition & 1 deletion tests/fixtures/deployFixture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ export const oneFcOneGatewayRos = {
export const referredServiceIac = set(
cloneDeep(oneFcOneGatewayIac),
'service',
'my-demo-service-${stage}',
'my-demo-service-${ctx.stage}',
);

export const referredServiceRos = {
Expand Down
2 changes: 1 addition & 1 deletion tests/stack/deploy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ describe('Unit tests for stack deployment', () => {
options,
);
});
it('should evaluate service name as pure string when it reference ${stage}', async () => {
it('should evaluate service name as pure string when it reference ${ctx.stage}', async () => {
const options = { stackName: 'my-demo-stack-fc-with-stage-1', stage: 'dev' };
mockedRosStackDeploy.mockResolvedValueOnce(options.stackName);

Expand Down

0 comments on commit f7d8de8

Please sign in to comment.