@geek-fun/serverlessinsight 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geek-fun/serverlessinsight",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Full life cycle cross providers serverless application management for your fast-growing business.",
5
5
  "homepage": "https://serverlessinsight.geekfun.club",
6
6
  "main": "dist/src/index.js",
@@ -49,51 +49,52 @@
49
49
  "function"
50
50
  ],
51
51
  "dependencies": {
52
- "@alicloud/ims20190815": "^2.1.4",
53
- "@alicloud/openapi-client": "^0.4.12",
54
- "@alicloud/ros-cdk-apigateway": "^1.6.0",
55
- "@alicloud/ros-cdk-core": "^1.6.0",
56
- "@alicloud/ros-cdk-dns": "^1.6.0",
57
- "@alicloud/ros-cdk-ecs": "^1.6.0",
58
- "@alicloud/ros-cdk-elasticsearchserverless": "^1.6.0",
59
- "@alicloud/ros-cdk-fc3": "^1.6.0",
60
- "@alicloud/ros-cdk-nas": "^1.6.0",
61
- "@alicloud/ros-cdk-oss": "^1.6.0",
62
- "@alicloud/ros-cdk-ossdeployment": "^1.6.0",
63
- "@alicloud/ros-cdk-ram": "^1.6.0",
64
- "@alicloud/ros-cdk-rds": "^1.6.0",
65
- "@alicloud/ros-cdk-sls": "^1.6.0",
66
- "@alicloud/ros20190910": "^3.5.2",
52
+ "@alicloud/ims20190815": "^2.2.0",
53
+ "@alicloud/openapi-client": "^0.4.14",
54
+ "@alicloud/ros-cdk-apigateway": "^1.8.0",
55
+ "@alicloud/ros-cdk-core": "^1.8.0",
56
+ "@alicloud/ros-cdk-dns": "^1.8.0",
57
+ "@alicloud/ros-cdk-ecs": "^1.8.0",
58
+ "@alicloud/ros-cdk-elasticsearchserverless": "^1.8.0",
59
+ "@alicloud/ros-cdk-fc3": "^1.8.0",
60
+ "@alicloud/ros-cdk-nas": "^1.8.0",
61
+ "@alicloud/ros-cdk-oss": "^1.8.0",
62
+ "@alicloud/ros-cdk-ossdeployment": "^1.8.0",
63
+ "@alicloud/ros-cdk-ram": "^1.8.0",
64
+ "@alicloud/ros-cdk-rds": "^1.8.0",
65
+ "@alicloud/ros-cdk-sls": "^1.8.0",
66
+ "@alicloud/ros-cdk-vpc": "^1.8.0",
67
+ "@alicloud/ros20190910": "^3.5.6",
67
68
  "ajv": "^8.17.1",
68
69
  "ali-oss": "^6.22.0",
69
70
  "chalk": "^5.4.1",
70
- "commander": "^12.1.0",
71
+ "commander": "^13.1.0",
71
72
  "i": "^0.3.7",
72
73
  "i18n": "^0.15.1",
73
74
  "jszip": "^3.10.1",
74
75
  "lodash": "^4.17.21",
75
- "npm": "^11.1.0",
76
- "pino": "^9.5.0",
76
+ "npm": "^11.2.0",
77
+ "pino": "^9.6.0",
77
78
  "pino-pretty": "^13.0.0",
78
- "yaml": "^2.7.0"
79
+ "yaml": "^2.7.1"
79
80
  },
80
81
  "devDependencies": {
81
82
  "@types/ali-oss": "^6.16.11",
82
83
  "@types/i18n": "^0.13.12",
83
84
  "@types/jest": "^29.5.14",
84
- "@types/lodash": "^4.17.13",
85
- "@types/node": "^22.10.1",
86
- "@typescript-eslint/eslint-plugin": "^8.17.0",
87
- "@typescript-eslint/parser": "^8.17.0",
88
- "eslint": "^9.16.0",
89
- "eslint-config-prettier": "^9.1.0",
90
- "eslint-plugin-prettier": "^5.2.1",
91
- "globals": "^15.13.0",
85
+ "@types/lodash": "^4.17.16",
86
+ "@types/node": "^22.14.0",
87
+ "@typescript-eslint/eslint-plugin": "^8.29.0",
88
+ "@typescript-eslint/parser": "^8.29.0",
89
+ "eslint": "^9.24.0",
90
+ "eslint-config-prettier": "^10.1.1",
91
+ "eslint-plugin-prettier": "^5.2.6",
92
+ "globals": "^16.0.0",
92
93
  "husky": "^9.1.7",
93
94
  "jest": "^29.7.0",
94
- "prettier": "^3.4.2",
95
- "ts-jest": "^29.2.5",
95
+ "prettier": "^3.5.3",
96
+ "ts-jest": "^29.3.1",
96
97
  "ts-node": "^10.9.2",
97
- "typescript": "^5.7.2"
98
+ "typescript": "^5.8.3"
98
99
  }
99
100
  }
@@ -8,9 +8,9 @@ const deploy = async (stackName, options) => {
8
8
  common_1.logger.info('Validating yaml...');
9
9
  const iac = (0, parser_1.parseYaml)((0, common_1.getIacLocation)(options.location));
10
10
  common_1.logger.info('Yaml is valid! 🎉');
11
- const context = (0, common_1.constructActionContext)({ ...options, stackName, iacProvider: iac.provider });
11
+ (0, common_1.setContext)({ ...options, stackName, iacProvider: iac.provider });
12
12
  common_1.logger.info('Deploying stack...');
13
- await (0, stack_1.deployStack)(stackName, iac, context);
13
+ await (0, stack_1.deployStack)(stackName, iac);
14
14
  common_1.logger.info('Stack deployed! 🎉');
15
15
  };
16
16
  exports.deploy = deploy;
@@ -5,7 +5,8 @@ const common_1 = require("../common");
5
5
  const parser_1 = require("../parser");
6
6
  const destroyStack = async (stackName, options) => {
7
7
  const iac = (0, parser_1.parseYaml)((0, common_1.getIacLocation)(options.location));
8
- const context = (0, common_1.constructActionContext)({ stackName, ...options, iacProvider: iac.provider });
8
+ (0, common_1.setContext)({ stackName, ...options, iacProvider: iac.provider });
9
+ const context = (0, common_1.getContext)();
9
10
  common_1.logger.info(`Destroying stack: ${stackName}, provider: ${context.provider}, region: ${context.region}...`);
10
11
  await (0, common_1.rosStackDelete)(context);
11
12
  };
@@ -14,7 +14,8 @@ program
14
14
  .command('show')
15
15
  .description('show string')
16
16
  .action(async (options) => {
17
- const context = (0, common_1.constructActionContext)({ ...options });
17
+ (0, common_1.setContext)({ ...options });
18
+ const context = (0, common_1.getContext)();
18
19
  const result = await (0, common_2.getIamInfo)(context);
19
20
  console.log('result:', JSON.stringify(result));
20
21
  });
@@ -33,10 +34,10 @@ program
33
34
  .option('-f, --file <path>', 'specify the yaml file')
34
35
  .option('-s, --stage <stage>', 'specify the stage')
35
36
  .option('-r, --region <region>', 'specify the region')
36
- .option('-pr, --provider <provider>', 'specify the provider')
37
- .option('-ak, --accessKeyId <accessKeyId>', 'specify the AccessKeyId')
38
- .option('-as, --accessKeySecret <accessKeySecret>', 'specify the AccessKeySecret')
39
- .option('-at, --securityToken <securityToken>', 'specify the SecurityToken')
37
+ .option('-v, --provider <provider>', 'specify the provider')
38
+ .option('-k, --accessKeyId <accessKeyId>', 'specify the AccessKeyId')
39
+ .option('-x, --accessKeySecret <accessKeySecret>', 'specify the AccessKeySecret')
40
+ .option('-n, --securityToken <securityToken>', 'specify the SecurityToken')
40
41
  .option('-p, --parameter <key=value>', 'override parameters', (value, previous) => {
41
42
  const [key, val] = value.split('=');
42
43
  previous[key] = val;
@@ -56,7 +57,7 @@ program
56
57
  });
57
58
  program
58
59
  .command('template <stackName>')
59
- .description('print ROS template')
60
+ .description('print platform specific infrastructure as code template')
60
61
  .option('-f, --file <path>', 'specify the yaml file')
61
62
  .option('-s, --stage <stage>', 'specify the stage')
62
63
  .option('-t, --format <type>', 'output content type (JSON or YAML)', 'JSON')
@@ -67,10 +68,10 @@ program
67
68
  .command('destroy <stackName>')
68
69
  .option('-f, --file <path>', 'specify the yaml file')
69
70
  .option('-r, --region <region>', 'specify the region')
70
- .option('-pr, --provider <provider>', 'specify the provider')
71
- .option('-ak, --accessKeyId <accessKeyId>', 'specify the AccessKeyId')
72
- .option('-as, --accessKeySecret <accessKeySecret>', 'specify the AccessKeySecret')
73
- .option('-at, --securityToken <securityToken>', 'specify the SecurityToken')
71
+ .option('-v, --provider <provider>', 'specify the provider')
72
+ .option('-k, --accessKeyId <accessKeyId>', 'specify the AccessKeyId')
73
+ .option('-x, --accessKeySecret <accessKeySecret>', 'specify the AccessKeySecret')
74
+ .option('-n, --securityToken <securityToken>', 'specify the SecurityToken')
74
75
  .description('destroy serverless stack')
75
76
  .action(async (stackName, { file, region, provider, accessKeyId, accessKeySecret, securityToken }) => {
76
77
  await (0, destroy_1.destroyStack)(stackName, {
@@ -11,8 +11,8 @@ const common_1 = require("../common");
11
11
  const parser_1 = require("../parser");
12
12
  const template = (stackName, options) => {
13
13
  const iac = (0, parser_1.parseYaml)((0, common_1.getIacLocation)(options.location));
14
- const context = (0, common_1.constructActionContext)({ ...options, stackName, provider: iac.provider.name });
15
- const { template } = (0, deploy_1.generateStackTemplate)(stackName, iac, context);
14
+ (0, common_1.setContext)({ ...options, stackName, provider: iac.provider.name });
15
+ const { template } = (0, deploy_1.generateStackTemplate)(stackName, iac);
16
16
  if (typeof template === 'string') {
17
17
  common_1.logger.info(`\n${template}`);
18
18
  }
@@ -4,7 +4,8 @@ exports.validate = void 0;
4
4
  const common_1 = require("../common");
5
5
  const parser_1 = require("../parser");
6
6
  const validate = (stackName, options) => {
7
- const context = (0, common_1.constructActionContext)({ stackName, ...options });
7
+ (0, common_1.setContext)({ stackName, ...options });
8
+ const context = (0, common_1.getContext)();
8
9
  (0, parser_1.parseYaml)(context.iacLocation);
9
10
  common_1.logger.info('Yaml is valid! 🎉');
10
11
  };
@@ -1,4 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CODE_ZIP_SIZE_LIMIT = void 0;
3
+ exports.OSS_DEPLOYMENT_TIMEOUT = exports.CODE_ZIP_SIZE_LIMIT = void 0;
4
4
  exports.CODE_ZIP_SIZE_LIMIT = 15 * 1000 * 1000;
5
+ exports.OSS_DEPLOYMENT_TIMEOUT = 3000; // in seconds
@@ -3,9 +3,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.constructActionContext = exports.getIacLocation = void 0;
6
+ exports.getContext = exports.setContext = exports.getIacLocation = void 0;
7
7
  const node_path_1 = __importDefault(require("node:path"));
8
8
  const providerEnum_1 = require("./providerEnum");
9
+ const node_async_hooks_1 = require("node:async_hooks");
10
+ const asyncLocalStorage = new node_async_hooks_1.AsyncLocalStorage();
9
11
  const getIacLocation = (location) => {
10
12
  const projectRoot = node_path_1.default.resolve(process.cwd());
11
13
  return location
@@ -16,8 +18,8 @@ const getIacLocation = (location) => {
16
18
  node_path_1.default.resolve(projectRoot, 'serverless-insight.yml');
17
19
  };
18
20
  exports.getIacLocation = getIacLocation;
19
- const constructActionContext = (config) => {
20
- return {
21
+ const setContext = (config) => {
22
+ const context = {
21
23
  stage: config.stage ?? 'default',
22
24
  stackName: config.stackName ?? '',
23
25
  provider: (config.provider ?? config.iacProvider?.name ?? providerEnum_1.ProviderEnum.ALIYUN),
@@ -31,6 +33,19 @@ const constructActionContext = (config) => {
31
33
  securityToken: config.securityToken ?? process.env.ALIYUN_SECURITY_TOKEN,
32
34
  iacLocation: (0, exports.getIacLocation)(config.location),
33
35
  parameters: Object.entries(config.parameters ?? {}).map(([key, value]) => ({ key, value })),
36
+ stages: Object.entries(config.stages ?? {}).reduce((acc, [stage, parameters]) => ({
37
+ ...acc,
38
+ [stage]: Object.entries(parameters).map(([key, value]) => ({ key, value })),
39
+ }), {}),
34
40
  };
41
+ asyncLocalStorage.enterWith(context);
35
42
  };
36
- exports.constructActionContext = constructActionContext;
43
+ exports.setContext = setContext;
44
+ const getContext = () => {
45
+ const context = asyncLocalStorage.getStore();
46
+ if (!context) {
47
+ throw new Error('No context found');
48
+ }
49
+ return context;
50
+ };
51
+ exports.getContext = getContext;
@@ -36,12 +36,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.replaceReference = exports.getFileSource = exports.readCodeSize = exports.resolveCode = void 0;
39
+ exports.formatRosId = exports.calcValue = exports.calcRefs = exports.getFileSource = exports.readCodeSize = exports.resolveCode = void 0;
40
40
  const node_path_1 = __importDefault(require("node:path"));
41
41
  const node_fs_1 = __importDefault(require("node:fs"));
42
42
  const ros = __importStar(require("@alicloud/ros-cdk-core"));
43
43
  const ossDeployment = __importStar(require("@alicloud/ros-cdk-ossdeployment"));
44
44
  const node_crypto_1 = __importDefault(require("node:crypto"));
45
+ const lodash_1 = require("lodash");
45
46
  const resolveCode = (location) => {
46
47
  const filePath = node_path_1.default.resolve(process.cwd(), location);
47
48
  const fileContent = node_fs_1.default.readFileSync(filePath);
@@ -65,19 +66,17 @@ const getFileSource = (fcName, location) => {
65
66
  return { source, objectKey };
66
67
  };
67
68
  exports.getFileSource = getFileSource;
68
- const evalCtx = (value, ctx) => {
69
- const containsStage = value.match(/\$\{ctx.\w+}/);
70
- return containsStage ? value.replace(/\$\{ctx.stage}/g, ctx.stage) : value;
71
- };
72
- const replaceReference = (value, ctx) => {
73
- if (typeof value === 'string') {
74
- const matchVar = value.match(/^\$\{vars\.(\w+)}$/);
75
- const containsVar = value.match(/\$\{vars\.(\w+)}/);
76
- const matchMap = value.match(/^\$\{stages\.(\w+)}$/);
77
- const containsMap = value.match(/\$\{stages\.(\w+)}/);
78
- const matchFn = value.match(/^\$\{functions\.(\w+(\.\w+)?)}$/);
79
- if (value.match(/\$\{ctx.\w+}/)) {
80
- return evalCtx(value, ctx);
69
+ const calcRefs = (rawValue, ctx) => {
70
+ if (typeof rawValue === 'string') {
71
+ const containsStage = rawValue.match(/\$\{ctx.\w+}/);
72
+ const matchVar = rawValue.match(/^\$\{vars\.(\w+)}$/);
73
+ const containsVar = rawValue.match(/\$\{vars\.(\w+)}/);
74
+ const matchMap = rawValue.match(/^\$\{stages\.(\w+)}$/);
75
+ const containsMap = rawValue.match(/\$\{stages\.(\w+)}/);
76
+ const matchFn = rawValue.match(/^\$\{functions\.(\w+(\.\w+)?)}$/);
77
+ let value = rawValue;
78
+ if (containsStage) {
79
+ value = value.replace(/\$\{ctx.stage}/g, ctx.stage);
81
80
  }
82
81
  if (matchVar?.length) {
83
82
  return ros.Fn.ref(matchVar[1]);
@@ -88,23 +87,51 @@ const replaceReference = (value, ctx) => {
88
87
  if (matchFn?.length) {
89
88
  return ros.Fn.getAtt(matchFn[1], 'FunctionName');
90
89
  }
91
- if (containsMap?.length && containsVar?.length) {
92
- return ros.Fn.sub(value.replace(/\$\{stages\.(\w+)}/g, '${$1}').replace(/\$\{vars\.(\w+)}/g, '${$1}'));
93
- }
94
- if (containsVar?.length) {
95
- return ros.Fn.sub(value.replace(/\$\{vars\.(\w+)}/g, '${$1}'));
96
- }
97
- if (containsMap?.length) {
98
- return ros.Fn.sub(value.replace(/\$\{stages\.(\w+)}/g, '${$1}'));
90
+ if (containsMap?.length || containsVar?.length) {
91
+ value = ros.Fn.sub(rawValue.replace(/\$\{stages\.(\w+)}/g, '${$1}').replace(/\$\{vars\.(\w+)}/g, '${$1}'));
99
92
  }
100
93
  return value;
101
94
  }
102
- if (Array.isArray(value)) {
103
- return value.map((item) => (0, exports.replaceReference)(item, ctx));
95
+ if (Array.isArray(rawValue)) {
96
+ return rawValue.map((item) => (0, exports.calcRefs)(item, ctx));
104
97
  }
105
- if (typeof value === 'object' && value !== null) {
106
- return Object.fromEntries(Object.entries(value).map(([key, val]) => [key, (0, exports.replaceReference)(val, ctx)]));
98
+ if (typeof rawValue === 'object' && rawValue !== null) {
99
+ return Object.fromEntries(Object.entries(rawValue).map(([key, val]) => [key, (0, exports.calcRefs)(val, ctx)]));
100
+ }
101
+ return rawValue;
102
+ };
103
+ exports.calcRefs = calcRefs;
104
+ const getParam = (key, records) => {
105
+ return records?.find((param) => param.key === key)?.value;
106
+ };
107
+ const calcValue = (rawValue, ctx) => {
108
+ const containsStage = rawValue.match(/\$\{ctx.stage}/);
109
+ const containsVar = rawValue.match(/\$\{vars.\w+}/);
110
+ const containsMap = rawValue.match(/\$\{stages\.(\w+)}/);
111
+ let value = rawValue;
112
+ if (containsStage?.length) {
113
+ value = rawValue.replace(/\$\{ctx.stage}/g, ctx.stage);
114
+ }
115
+ if (containsVar?.length) {
116
+ value = value.replace(/\$\{vars\.(\w+)}/g, (_, key) => getParam(key, ctx.parameters));
117
+ }
118
+ if (containsMap?.length) {
119
+ value = value.replace(/\$\{stages\.(\w+)}/g, (_, key) => getParam(key, (0, lodash_1.get)(ctx.stages, `${ctx.stage}`)));
107
120
  }
108
121
  return value;
109
122
  };
110
- exports.replaceReference = replaceReference;
123
+ exports.calcValue = calcValue;
124
+ const formatRosId = (id) => {
125
+ // Insert underscore before uppercase letters, but only when they follow a lowercase letter
126
+ let result = id.replace(/([a-z])([A-Z])/g, '$1_$2');
127
+ // Convert to lowercase
128
+ result = result.toLowerCase();
129
+ // Replace special characters with underscores
130
+ result = result.replace(/[/#,-]/g, '_');
131
+ // Remove any number of underscores to single one
132
+ result = result.replace(/_+/g, '_');
133
+ // Remove leading underscores
134
+ result = result.replace(/^_/, '');
135
+ return result;
136
+ };
137
+ exports.formatRosId = formatRosId;
@@ -2,7 +2,7 @@ export * from './providerEnum';
2
2
  export * from './logger';
3
3
  export * from './getVersion';
4
4
  export * from './rosClient';
5
- export * from './actionContext';
5
+ export * from './context';
6
6
  export * from './iacHelper';
7
7
  export * from './constants';
8
8
  export * from './imsClient';
@@ -18,7 +18,7 @@ __exportStar(require("./providerEnum"), exports);
18
18
  __exportStar(require("./logger"), exports);
19
19
  __exportStar(require("./getVersion"), exports);
20
20
  __exportStar(require("./rosClient"), exports);
21
- __exportStar(require("./actionContext"), exports);
21
+ __exportStar(require("./context"), exports);
22
22
  __exportStar(require("./iacHelper"), exports);
23
23
  __exportStar(require("./constants"), exports);
24
24
  __exportStar(require("./imsClient"), exports);
@@ -36,7 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.publishAssets = exports.getAssets = void 0;
39
+ exports.cleanupAssets = exports.publishAssets = exports.constructAssets = exports.getAssets = void 0;
40
40
  const node_fs_1 = __importDefault(require("node:fs"));
41
41
  const ossDeployment = __importStar(require("@alicloud/ros-cdk-ossdeployment"));
42
42
  const node_path_1 = __importDefault(require("node:path"));
@@ -44,6 +44,7 @@ const jszip_1 = __importDefault(require("jszip"));
44
44
  const logger_1 = require("./logger");
45
45
  const lodash_1 = require("lodash");
46
46
  const ali_oss_1 = __importDefault(require("ali-oss"));
47
+ const context_1 = require("./context");
47
48
  const buildAssets = (rootPath, relativePath) => {
48
49
  const location = node_path_1.default.resolve(rootPath, relativePath);
49
50
  if (!node_fs_1.default.existsSync(location)) {
@@ -95,7 +96,8 @@ const zipAssets = async (assetsPath) => {
95
96
  });
96
97
  return zipPath;
97
98
  };
98
- const constructAssets = async ({ files, rootPath }, region) => {
99
+ const constructAssets = async ({ files, rootPath, }) => {
100
+ const { region } = (0, context_1.getContext)();
99
101
  const assets = await Promise.all(Object.entries(files)
100
102
  .filter(([, fileItem]) => !fileItem.source.path.endsWith('.template.json'))
101
103
  .map(async ([, fileItem]) => {
@@ -111,6 +113,7 @@ const constructAssets = async ({ files, rootPath }, region) => {
111
113
  }));
112
114
  return !(0, lodash_1.isEmpty)(assets) ? assets : undefined;
113
115
  };
116
+ exports.constructAssets = constructAssets;
114
117
  const ensureBucketExits = async (bucketName, ossClient) => await ossClient.getBucketInfo(bucketName).catch((err) => {
115
118
  if (err.code === 'NoSuchBucket') {
116
119
  logger_1.logger.info(`Bucket: ${bucketName} not exists, creating...`);
@@ -124,13 +127,13 @@ const ensureBucketExits = async (bucketName, ossClient) => await ossClient.getBu
124
127
  throw err;
125
128
  }
126
129
  });
127
- const publishAssets = async (assets, context) => {
128
- const constructedAssets = await constructAssets(assets, context.region);
129
- if (!constructedAssets?.length) {
130
+ const publishAssets = async (assets) => {
131
+ if (!assets?.length) {
130
132
  logger_1.logger.info('No assets to publish, skipped!');
131
133
  return;
132
134
  }
133
- const bucketName = constructedAssets[0].bucketName;
135
+ const context = (0, context_1.getContext)();
136
+ const bucketName = assets[0].bucketName;
134
137
  const client = new ali_oss_1.default({
135
138
  region: `oss-${context.region}`,
136
139
  accessKeyId: context.accessKeyId,
@@ -143,10 +146,32 @@ const publishAssets = async (assets, context) => {
143
146
  'x-oss-object-acl': 'default',
144
147
  'x-oss-forbid-overwrite': 'false',
145
148
  };
146
- await Promise.all(constructedAssets.map(async ({ source, objectKey }) => {
149
+ await Promise.all(assets.map(async ({ source, objectKey }) => {
147
150
  await client.put(objectKey, node_path_1.default.normalize(source), { headers });
148
- logger_1.logger.info(`Upload file: ${source}) to bucket: ${bucketName} successfully!`);
151
+ logger_1.logger.debug(`Upload file: ${source} to bucket: ${bucketName} successfully!`);
149
152
  }));
150
153
  return bucketName;
151
154
  };
152
155
  exports.publishAssets = publishAssets;
156
+ const cleanupAssets = async (assets) => {
157
+ if (!assets?.length) {
158
+ logger_1.logger.info('No assets to cleanup, skipped!');
159
+ return;
160
+ }
161
+ const context = (0, context_1.getContext)();
162
+ const bucketName = assets[0].bucketName;
163
+ const client = new ali_oss_1.default({
164
+ region: `oss-${context.region}`,
165
+ accessKeyId: context.accessKeyId,
166
+ accessKeySecret: context.accessKeySecret,
167
+ bucket: bucketName,
168
+ });
169
+ await Promise.all(assets.map(async ({ objectKey }) => {
170
+ await client.delete(objectKey);
171
+ logger_1.logger.debug(`Cleanup file: ${objectKey} from bucket: ${bucketName} successfully!`);
172
+ }));
173
+ // delete the bucket
174
+ await client.deleteBucket(bucketName);
175
+ logger_1.logger.debug(`Cleanup bucket: ${bucketName} successfully!`);
176
+ };
177
+ exports.cleanupAssets = cleanupAssets;
@@ -42,6 +42,7 @@ const ros20190910_1 = __importStar(require("@alicloud/ros20190910"));
42
42
  const openapi_client_1 = require("@alicloud/openapi-client");
43
43
  const logger_1 = require("./logger");
44
44
  const lang_1 = require("../lang");
45
+ const context_1 = require("./context");
45
46
  const client = new ros20190910_1.default(new openapi_client_1.Config({
46
47
  accessKeyId: process.env.ALIYUN_ACCESS_KEY_ID,
47
48
  accessKeySecret: process.env.ALIYUN_ACCESS_KEY_SECRET,
@@ -85,7 +86,7 @@ const updateStack = async (stackId, templateBody, context) => {
85
86
  return await getStackActionResult(response.body?.stackId || '', context.region);
86
87
  }
87
88
  catch (err) {
88
- const { Message: message, statusCode } = err?.data || {};
89
+ const { message, statusCode } = err || {};
89
90
  if (statusCode === 400 && message.includes('Update the completely same stack')) {
90
91
  logger_1.logger.warn(`${lang_1.lang.__('UPDATE_COMPLETELY_SAME_STACK')}`);
91
92
  return null;
@@ -154,7 +155,8 @@ const getStackActionResult = async (stackId, region) => {
154
155
  }, 5000); // 5 seconds interval
155
156
  });
156
157
  };
157
- const rosStackDeploy = async (stackName, templateBody, context) => {
158
+ const rosStackDeploy = async (stackName, templateBody) => {
159
+ const context = (0, context_1.getContext)();
158
160
  const stackInfo = await getStackByName(stackName, context.region);
159
161
  if (stackInfo) {
160
162
  const { Status: stackStatus } = stackInfo;
@@ -186,7 +188,7 @@ const rosStackDelete = async ({ stackName, region, }) => {
186
188
  });
187
189
  await client.deleteStack(deleteStackRequest);
188
190
  await getStackActionResult(stackInfo.stackId, region);
189
- logger_1.logger.info(`Stack: ${stackName} deleted! ♻️`);
191
+ logger_1.logger.info(`Stack: ${stackName} deleted!🗑 `);
190
192
  }
191
193
  catch (err) {
192
194
  logger_1.logger.error(`Stack: ${stackName} delete failed! ❌, error: ${JSON.stringify(err)}`);
@@ -43,7 +43,8 @@ const common_1 = require("../common");
43
43
  const rosStack_1 = require("./rosStack");
44
44
  const rfsStack_1 = require("./rfsStack");
45
45
  const lodash_1 = require("lodash");
46
- const generateRosStackTemplate = (stackName, iac, context) => {
46
+ const generateRosStackTemplate = (stackName, iac) => {
47
+ const context = (0, common_1.getContext)();
47
48
  const app = new ros.App();
48
49
  new rosStack_1.RosStack(app, iac, context);
49
50
  const assembly = app.synth();
@@ -57,29 +58,45 @@ const generateRosStackTemplate = (stackName, iac, context) => {
57
58
  return { template, assets };
58
59
  };
59
60
  exports.generateRosStackTemplate = generateRosStackTemplate;
60
- const generateRfsStackTemplate = (stackName, iac, context) => {
61
- const stack = new rfsStack_1.RfsStack(iac, context);
61
+ const generateRfsStackTemplate = (stackName, iac) => {
62
+ const stack = new rfsStack_1.RfsStack(iac);
62
63
  const hcl = stack.toHclTerraform();
63
64
  console.log('HCL:', hcl);
64
65
  return { template: hcl };
65
66
  };
66
67
  exports.generateRfsStackTemplate = generateRfsStackTemplate;
67
- const deployStack = async (stackName, iac, context) => {
68
- const { template, assets } = (0, exports.generateRosStackTemplate)(stackName, iac, context);
69
- await (0, rosStack_1.prepareBootstrapStack)(context);
68
+ const deployStack = async (stackName, iac) => {
69
+ const { template, assets } = (0, exports.generateRosStackTemplate)(stackName, iac);
70
+ await (0, rosStack_1.prepareBootstrapStack)();
70
71
  common_1.logger.info(`Deploying stack, publishing assets...`);
71
- await (0, common_1.publishAssets)(assets, context);
72
- common_1.logger.info(`Assets published! 🎉`);
73
- await (0, common_1.rosStackDeploy)(stackName, template, context);
74
- common_1.logger.info(`Stack deployed! 🎉`);
72
+ const constructedAssets = await (0, common_1.constructAssets)(assets);
73
+ try {
74
+ await (0, common_1.publishAssets)(constructedAssets);
75
+ common_1.logger.info(`Assets published! 🎉`);
76
+ await (0, common_1.rosStackDeploy)(stackName, template);
77
+ }
78
+ catch (e) {
79
+ common_1.logger.error(`Failed to deploy stack: ${e}`);
80
+ throw e;
81
+ }
82
+ finally {
83
+ try {
84
+ common_1.logger.info(`Cleaning up temporary Assets...`);
85
+ await (0, common_1.cleanupAssets)(constructedAssets);
86
+ common_1.logger.info(`Assets cleaned up!♻️`);
87
+ }
88
+ catch (e) {
89
+ common_1.logger.error(`Failed to cleanup assets, it wont affect the deployment result, but to avoid potential cost, you can delete the temporary bucket : ${constructedAssets?.[0].bucketName}, error details:${e}`);
90
+ }
91
+ }
75
92
  };
76
93
  exports.deployStack = deployStack;
77
- const generateStackTemplate = (stackName, iac, context) => {
94
+ const generateStackTemplate = (stackName, iac) => {
78
95
  if (iac.provider.name === common_1.ProviderEnum.ALIYUN) {
79
- return (0, exports.generateRosStackTemplate)(stackName, iac, context);
96
+ return (0, exports.generateRosStackTemplate)(stackName, iac);
80
97
  }
81
98
  else if (iac.provider.name === common_1.ProviderEnum.HUAWEI) {
82
- return (0, exports.generateRfsStackTemplate)(stackName, iac, context);
99
+ return (0, exports.generateRfsStackTemplate)(stackName, iac);
83
100
  }
84
101
  return { template: '' };
85
102
  };
@@ -1,9 +1,9 @@
1
- import { ActionContext, ServerlessIac } from '../../types';
1
+ import { Context, ServerlessIac } from '../../types';
2
2
  export declare class RfsStack {
3
3
  private readonly iac;
4
4
  private readonly context;
5
5
  private hcl;
6
- constructor(iac: ServerlessIac, context: ActionContext);
6
+ constructor(iac: ServerlessIac, context?: Context);
7
7
  toHclTerraform(): string;
8
8
  appendHcl(hcl: string): void;
9
9
  }
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RfsStack = void 0;
4
4
  const function_1 = require("./function");
5
+ const common_1 = require("../../common");
5
6
  const provider = (stack, context) => {
6
7
  const hcl = `
7
8
  terraform {
@@ -22,7 +23,7 @@ provider "huaweicloud" {
22
23
  stack.appendHcl(hcl);
23
24
  };
24
25
  class RfsStack {
25
- constructor(iac, context) {
26
+ constructor(iac, context = (0, common_1.getContext)()) {
26
27
  this.iac = iac;
27
28
  this.context = context;
28
29
  this.hcl = '';
@@ -4,7 +4,7 @@ exports.prepareBootstrapStack = void 0;
4
4
  const common_1 = require("../../common");
5
5
  const getBootstrapTemplate = async (context) => {
6
6
  const iamInfo = await (0, common_1.getIamInfo)(context);
7
- const stackName = `serverlessInsight-bootstrap-${iamInfo?.accountId}-${context.region}`;
7
+ const stackName = `si-bootstrap-${iamInfo?.accountId}-${context.region}`;
8
8
  const template = {
9
9
  Description: 'ServerlessInsight Bootstrap Stack',
10
10
  Metadata: {
@@ -14,7 +14,7 @@ const getBootstrapTemplate = async (context) => {
14
14
  },
15
15
  ROSTemplateFormatVersion: '2015-09-01',
16
16
  Resources: {
17
- ServerlessInsight_artifacts_bucket: {
17
+ si_auto_artifacts_bucket: {
18
18
  Type: 'ALIYUN::OSS::Bucket',
19
19
  Properties: {
20
20
  BucketName: {
@@ -33,8 +33,9 @@ const getBootstrapTemplate = async (context) => {
33
33
  };
34
34
  return { stackName, template };
35
35
  };
36
- const prepareBootstrapStack = async (context) => {
36
+ const prepareBootstrapStack = async () => {
37
+ const context = (0, common_1.getContext)();
37
38
  const { stackName, template } = await getBootstrapTemplate(context);
38
- await (0, common_1.rosStackDeploy)(stackName, template, context);
39
+ await (0, common_1.rosStackDeploy)(stackName, template);
39
40
  };
40
41
  exports.prepareBootstrapStack = prepareBootstrapStack;