Skip to content

Commit f7d8de8

Browse files
committed
feat: evaluate service ctx reference
Signed-off-by: seven <zilisheng1996@gmail.com>
1 parent 782dc4e commit f7d8de8

File tree

4 files changed

+44
-41
lines changed

4 files changed

+44
-41
lines changed

src/common/iacHelper.ts

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import path from 'node:path';
22
import fs from 'node:fs';
33
import * as ros from '@alicloud/ros-cdk-core';
4-
import { ServerlessIac } from '../types';
4+
import { ActionContext } from '../types';
55

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

13-
export const replaceReference = <T>(value: T, stage: string): T => {
13+
const evalCtx = (value: string, ctx: ActionContext): string => {
14+
const containsStage = value.match(/\$\{ctx.\w+}/);
15+
16+
return containsStage ? value.replace(/\$\{ctx.stage}/g, ctx.stage) : value;
17+
};
18+
19+
export const replaceReference = <T>(value: T, ctx: ActionContext): T => {
1420
if (typeof value === 'string') {
1521
const matchVar = value.match(/^\$\{vars\.(\w+)}$/);
1622
const containsVar = value.match(/\$\{vars\.(\w+)}/);
1723
const matchMap = value.match(/^\$\{stages\.(\w+)}$/);
1824
const containsMap = value.match(/\$\{stages\.(\w+)}/);
1925
const matchFn = value.match(/^\$\{functions\.(\w+(\.\w+)?)}$/);
26+
if (value.match(/\$\{ctx.\w+}/)) {
27+
return evalCtx(value, ctx) as T;
28+
}
2029

2130
if (matchVar?.length) {
2231
return ros.Fn.ref(matchVar[1]) as T;
2332
}
2433
if (matchMap?.length) {
25-
return ros.Fn.findInMap('stages', stage, matchMap[1]) as T;
34+
return ros.Fn.findInMap('stages', ctx.stage, matchMap[1]) as T;
2635
}
2736

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

4554
if (Array.isArray(value)) {
46-
return value.map((item) => replaceReference(item, stage)) as T;
55+
return value.map((item) => replaceReference(item, ctx)) as T;
4756
}
4857

4958
if (typeof value === 'object' && value !== null) {
5059
return Object.fromEntries(
51-
Object.entries(value).map(([key, val]) => [key, replaceReference(val, stage)]),
60+
Object.entries(value).map(([key, val]) => [key, replaceReference(val, ctx)]),
5261
) as T;
5362
}
5463

5564
return value;
5665
};
57-
58-
export const evalRefValue = (value: string, iac: ServerlessIac, stage: string): string => {
59-
const containsStage = value.match(/\$\{stage}/);
60-
61-
return containsStage ? value.replace(/\$\{stage}/g, stage) : value;
62-
};

src/stack/iacStack.ts

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,26 @@ import { ActionContext, EventTypes, ServerlessIac } from '../types';
44
import * as fc from '@alicloud/ros-cdk-fc3';
55
import * as ram from '@alicloud/ros-cdk-ram';
66
import * as agw from '@alicloud/ros-cdk-apigateway';
7-
import { evalRefValue, replaceReference, resolveCode } from '../common';
7+
import { replaceReference, resolveCode } from '../common';
88

99
export class IacStack extends ros.Stack {
10-
private service: string;
10+
private readonly service: string;
1111

1212
constructor(scope: ros.Construct, iac: ServerlessIac, context: ActionContext) {
13-
super(scope, evalRefValue(iac.service, iac, context.stage), {
13+
super(scope, replaceReference(iac.service, context), {
1414
stackName: context.stackName,
1515
tags: iac.tags?.reduce((acc: { [key: string]: string }, tag) => {
16-
acc[tag.key] = replaceReference(tag.value, context.stage);
16+
acc[tag.key] = replaceReference(tag.value, context);
1717
return acc;
1818
}, {}),
1919
});
20-
this.service = evalRefValue(iac.service, iac, context.stage);
20+
this.service = replaceReference(iac.service, context);
2121

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

3333
// Define Mappings
3434
if (iac.stages) {
35-
new ros.RosMapping(this, 'stages', { mapping: replaceReference(iac.stages, context.stage) });
35+
new ros.RosMapping(this, 'stages', { mapping: replaceReference(iac.stages, context) });
3636
}
3737

3838
new ros.RosInfo(
3939
this,
4040
ros.RosInfo.description,
41-
replaceReference(`${this.service} stack`, context.stage),
41+
replaceReference(`${this.service} stack`, context),
4242
);
4343

4444
iac.functions.forEach((fnc) => {
4545
new fc.RosFunction(
4646
this,
4747
fnc.key,
4848
{
49-
functionName: replaceReference(fnc.name, context.stage),
50-
handler: replaceReference(fnc.handler, context.stage),
51-
runtime: replaceReference(fnc.runtime, context.stage),
52-
memorySize: replaceReference(fnc.memory, context.stage),
53-
timeout: replaceReference(fnc.timeout, context.stage),
54-
environmentVariables: replaceReference(fnc.environment, context.stage),
49+
functionName: replaceReference(fnc.name, context),
50+
handler: replaceReference(fnc.handler, context),
51+
runtime: replaceReference(fnc.runtime, context),
52+
memorySize: replaceReference(fnc.memory, context),
53+
timeout: replaceReference(fnc.timeout, context),
54+
environmentVariables: replaceReference(fnc.environment, context),
5555
code: {
5656
zipFile: resolveCode(fnc.code),
5757
},
@@ -64,10 +64,10 @@ export class IacStack extends ros.Stack {
6464
if (apiGateway?.length) {
6565
const gatewayAccessRole = new ram.RosRole(
6666
this,
67-
replaceReference(`${this.service}_role`, context.stage),
67+
replaceReference(`${this.service}_role`, context),
6868
{
69-
roleName: replaceReference(`${this.service}-gateway-access-role`, context.stage),
70-
description: replaceReference(`${this.service} role`, context.stage),
69+
roleName: replaceReference(`${this.service}-gateway-access-role`, context),
70+
description: replaceReference(`${this.service} role`, context),
7171
assumeRolePolicyDocument: {
7272
version: '1',
7373
statement: [
@@ -82,7 +82,7 @@ export class IacStack extends ros.Stack {
8282
},
8383
policies: [
8484
{
85-
policyName: replaceReference(`${this.service}-policy`, context.stage),
85+
policyName: replaceReference(`${this.service}-policy`, context),
8686
policyDocument: {
8787
version: '1',
8888
statement: [
@@ -102,10 +102,10 @@ export class IacStack extends ros.Stack {
102102

103103
const apiGatewayGroup = new agw.RosGroup(
104104
this,
105-
replaceReference(`${this.service}_apigroup`, context.stage),
105+
replaceReference(`${this.service}_apigroup`, context),
106106
{
107-
groupName: replaceReference(`${this.service}_apigroup`, context.stage),
108-
tags: replaceReference(iac.tags, context.stage),
107+
groupName: replaceReference(`${this.service}_apigroup`, context),
108+
tags: replaceReference(iac.tags, context),
109109
},
110110
true,
111111
);
@@ -129,29 +129,29 @@ export class IacStack extends ros.Stack {
129129

130130
const api = new agw.RosApi(
131131
this,
132-
replaceReference(`${event.key}_api_${key}`, context.stage),
132+
replaceReference(`${event.key}_api_${key}`, context),
133133
{
134-
apiName: replaceReference(`${event.name}_api_${key}`, context.stage),
134+
apiName: replaceReference(`${event.name}_api_${key}`, context),
135135
groupId: apiGatewayGroup.attrGroupId,
136136
visibility: 'PRIVATE',
137137
requestConfig: {
138138
requestProtocol: 'HTTP',
139-
requestHttpMethod: replaceReference(trigger.method, context.stage),
140-
requestPath: replaceReference(trigger.path, context.stage),
139+
requestHttpMethod: replaceReference(trigger.method, context),
140+
requestPath: replaceReference(trigger.path, context),
141141
requestMode: 'PASSTHROUGH',
142142
},
143143
serviceConfig: {
144144
serviceProtocol: 'FunctionCompute',
145145
functionComputeConfig: {
146146
fcRegionId: context.region,
147-
functionName: replaceReference(trigger.backend, context.stage),
147+
functionName: replaceReference(trigger.backend, context),
148148
roleArn: gatewayAccessRole.attrArn,
149149
fcVersion: '3.0',
150150
},
151151
},
152152
resultSample: 'ServerlessInsight resultSample',
153153
resultType: 'JSON',
154-
tags: replaceReference(iac.tags, context.stage),
154+
tags: replaceReference(iac.tags, context),
155155
},
156156
true,
157157
);

tests/fixtures/deployFixture.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ export const oneFcOneGatewayRos = {
143143
export const referredServiceIac = set(
144144
cloneDeep(oneFcOneGatewayIac),
145145
'service',
146-
'my-demo-service-${stage}',
146+
'my-demo-service-${ctx.stage}',
147147
);
148148

149149
export const referredServiceRos = {

tests/stack/deploy.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ describe('Unit tests for stack deployment', () => {
8989
options,
9090
);
9191
});
92-
it('should evaluate service name as pure string when it reference ${stage}', async () => {
92+
it('should evaluate service name as pure string when it reference ${ctx.stage}', async () => {
9393
const options = { stackName: 'my-demo-stack-fc-with-stage-1', stage: 'dev' };
9494
mockedRosStackDeploy.mockResolvedValueOnce(options.stackName);
9595

0 commit comments

Comments
 (0)