Skip to content

Commit 0b0a1b9

Browse files
authored
Merge pull request #484 from serverless-operations/feature/support-v3-new-log-api
Apply Serverless v3 new API/design for CLI output
2 parents d76d3b1 + 1b44a27 commit 0b0a1b9

12 files changed

+10642
-390
lines changed

lib/deploy/stepFunctions/compileAlarms.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const _ = require('lodash');
44
const BbPromise = require('bluebird');
55
const Joi = require('@hapi/joi');
66
const schema = require('./compileAlarms.schema');
7+
const logger = require('../../utils/logger');
78

89
const cloudWatchMetricNames = {
910
executionsTimedOut: 'ExecutionsTimedOut',
@@ -39,7 +40,7 @@ function getCloudWatchAlarms(
3940
);
4041

4142
if (!_.isEmpty(invalid)) {
42-
serverless.cli.consoleLog(
43+
logger.log(
4344
`state machine [${stateMachineName}] : alarms.metrics has invalid metrics `,
4445
`[${invalid.join(',')}]. `
4546
+ 'No CloudWatch Alarms would be created for these. '
@@ -96,7 +97,7 @@ function validateConfig(serverless, stateMachineName, alarmsObj) {
9697
const { error } = Joi.validate(alarmsObj, schema, { allowUnknown: false });
9798

9899
if (error) {
99-
serverless.cli.consoleLog(
100+
logger.log(
100101
`State machine [${stateMachineName}] : alarms config is malformed. `
101102
+ 'Please see https://github.com/horike37/serverless-step-functions for examples. '
102103
+ `${error}`,
@@ -109,6 +110,7 @@ function validateConfig(serverless, stateMachineName, alarmsObj) {
109110

110111
module.exports = {
111112
compileAlarms() {
113+
logger.config(this.serverless, this.v3Api);
112114
const cloudWatchAlarms = _.flatMap(this.getAllStateMachines(), (name) => {
113115
const stateMachineObj = this.getStateMachine(name);
114116
const stateMachineLogicalId = this.getStateMachineLogicalId(name, stateMachineObj);

lib/deploy/stepFunctions/compileIamRole.js

+7-4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ const path = require('path');
66
const { isIntrinsic, translateLocalFunctionNames, trimAliasFromLambdaArn } = require('../../utils/aws');
77
const { getArnPartition } = require('../../utils/arn');
88

9+
const logger = require('../../utils/logger');
10+
911
function getTaskStates(states) {
1012
return _.flatMap(states, (state) => {
1113
switch (state.Type) {
@@ -49,7 +51,7 @@ function sqsQueueUrlToArn(serverless, queueUrl) {
4951
// we need to use "*" as ARN
5052
return '*';
5153
}
52-
serverless.cli.consoleLog(`Unable to parse SQS queue url [${queueUrl}]`);
54+
logger.log(`Unable to parse SQS queue url [${queueUrl}]`);
5355
return [];
5456
}
5557

@@ -62,7 +64,7 @@ function getSqsPermissions(serverless, state) {
6264
: sqsQueueUrlToArn(serverless, state.Parameters.QueueUrl);
6365
return [{ action: 'sqs:SendMessage', resource: queueArn }];
6466
}
65-
serverless.cli.consoleLog('SQS task missing Parameters.QueueUrl or Parameters.QueueUrl.$');
67+
logger.log('SQS task missing Parameters.QueueUrl or Parameters.QueueUrl.$');
6668
return [];
6769
}
6870

@@ -73,7 +75,7 @@ function getSnsPermissions(serverless, state) {
7375
const topicArn = state.Parameters['TopicArn.$'] ? '*' : state.Parameters.TopicArn;
7476
return [{ action: 'sns:Publish', resource: topicArn }];
7577
}
76-
serverless.cli.consoleLog('SNS task missing Parameters.TopicArn or Parameters.TopicArn.$');
78+
logger.log('SNS task missing Parameters.TopicArn or Parameters.TopicArn.$');
7779
return [];
7880
}
7981

@@ -478,7 +480,7 @@ function getIamPermissions(taskStates) {
478480
],
479481
}];
480482
}
481-
this.serverless.cli.consoleLog('Cannot generate IAM policy statement for Task state', state);
483+
logger.log('Cannot generate IAM policy statement for Task state', state);
482484
return [];
483485
}
484486
});
@@ -505,6 +507,7 @@ function getIamStatements(iamPermissions) {
505507

506508
module.exports = {
507509
compileIamRole() {
510+
logger.config(this.serverless, this.v3Api);
508511
this.getAllStateMachines().forEach((stateMachineName) => {
509512
const stateMachineObj = this.getStateMachine(stateMachineName);
510513
if (stateMachineObj.role) {

lib/deploy/stepFunctions/compileNotifications.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const Joi = require('@hapi/joi');
55
const crypto = require('crypto');
66
const BbPromise = require('bluebird');
77
const schema = require('./compileNotifications.schema');
8+
const logger = require('../../utils/logger');
89

910
const executionStatuses = [
1011
'ABORTED', 'FAILED', 'RUNNING', 'SUCCEEDED', 'TIMED_OUT',
@@ -318,7 +319,7 @@ function validateConfig(serverless, stateMachineName, stateMachineObj, notificat
318319
}
319320

320321
if (stateMachineObj.type === 'EXPRESS') {
321-
serverless.cli.consoleLog(
322+
logger.log(
322323
`State machine [${stateMachineName}] : notifications are not supported on Express Workflows. `
323324
+ 'Please see https://docs.aws.amazon.com/step-functions/latest/dg/concepts-standard-vs-express.html for difference between Step Functions Standard and Express Workflow.',
324325
);
@@ -330,7 +331,7 @@ function validateConfig(serverless, stateMachineName, stateMachineObj, notificat
330331
);
331332

332333
if (error) {
333-
serverless.cli.consoleLog(
334+
logger.log(
334335
`State machine [${stateMachineName}] : notifications config is malformed. `
335336
+ 'Please see https://github.com/horike37/serverless-step-functions for examples. '
336337
+ `${error}`,
@@ -343,6 +344,7 @@ function validateConfig(serverless, stateMachineName, stateMachineObj, notificat
343344

344345
module.exports = {
345346
compileNotifications() {
347+
logger.config(this.serverless, this.v3Api);
346348
const newResourcePairs = _.flatMap(this.getAllStateMachines(), (name) => {
347349
const stateMachineObj = this.getStateMachine(name);
348350
const stateMachineLogicalId = this.getStateMachineLogicalId(name, stateMachineObj);

lib/deploy/stepFunctions/compileStateMachines.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const BbPromise = require('bluebird');
77
const crypto = require('crypto');
88
const schema = require('./compileStateMachines.schema');
99
const { isIntrinsic, translateLocalFunctionNames, convertToFunctionVersion } = require('../../utils/aws');
10+
const logger = require('../../utils/logger');
1011

1112
function generateSubVariableName(element) {
1213
return crypto
@@ -119,7 +120,7 @@ module.exports = {
119120
if (this.serverless.service.stepFunctions.validate) {
120121
const { isValid, errorsText } = aslValidator(stateMachineObj.definition);
121122
if (isValid) {
122-
this.serverless.cli.consoleLog(`✓ State machine "${stateMachineName}" definition is valid`);
123+
logger.log(`✓ State machine "${stateMachineName}" definition is valid`);
123124
} else {
124125
const errorMessage = [
125126
`✕ State machine "${stateMachineName}" definition is invalid:`,

lib/deploy/stepFunctions/compileStateMachines.test.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
const _ = require('lodash');
44
const expect = require('chai').expect;
55
const Serverless = require('serverless/lib/Serverless');
6+
const CLI = require('serverless/lib/classes/CLI');
67
const AwsProvider = require('serverless/lib/plugins/aws/provider');
78
const ServerlessStepFunctions = require('./../../index');
89

@@ -12,9 +13,7 @@ describe('#compileStateMachines', () => {
1213

1314
beforeEach(() => {
1415
serverless = new Serverless();
15-
serverless.cli = {
16-
consoleLog: () => {},
17-
};
16+
serverless.cli = new CLI(serverless);
1817
serverless.configSchemaHandler = {
1918
// eslint-disable-next-line no-unused-vars
2019
defineTopLevelProperty: (propertyName, propertySchema) => {},

lib/index.js

+20-7
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,20 @@ const invoke = require('./invoke/invoke');
2929
const yamlParser = require('./yamlParser');
3030
const naming = require('./naming');
3131

32+
const logger = require('./utils/logger');
33+
3234
class ServerlessStepFunctions {
33-
constructor(serverless, options) {
35+
constructor(serverless, options, v3Api) {
3436
this.serverless = serverless;
3537
this.options = options || {};
38+
this.v3Api = v3Api;
39+
3640
this.provider = this.serverless.getProvider('aws');
3741
this.service = this.serverless.service.service;
3842
this.region = this.provider.getRegion();
3943
this.stage = this.provider.getStage();
44+
45+
logger.config(serverless, v3Api);
4046
Object.assign(
4147
this,
4248
compileStateMachines,
@@ -171,17 +177,17 @@ class ServerlessStepFunctions {
171177
.then(this.startExecution)
172178
.then(this.describeExecution)
173179
.then((result) => {
174-
this.serverless.cli.consoleLog('');
180+
logger.log('');
175181
if (result.status === 'FAILED') {
176182
return this.getExecutionHistory()
177183
.then((error) => {
178-
this.serverless.cli.consoleLog(_.merge(result, error.events[error.events.length - 1]
184+
logger.log(_.merge(result, error.events[error.events.length - 1]
179185
.executionFailedEventDetails));
180186
process.exitCode = 1;
181187
});
182188
}
183189

184-
this.serverless.cli.consoleLog(result);
190+
logger.log(result);
185191
return BbPromise.resolve();
186192
});
187193
}
@@ -191,8 +197,15 @@ class ServerlessStepFunctions {
191197
let stateMachineMessages = '';
192198

193199
const endpointInfo = this.endpointInfo;
194-
message += `${chalk.yellow.underline('Serverless StepFunctions OutPuts')}\n`;
195-
message += `${chalk.yellow('endpoints:')}`;
200+
201+
if (this.v3Api) {
202+
const slsRed = chalk.hex('#fd5750');
203+
message += `\n${slsRed('✔')} Serverless StepFunctions OutPuts\n`;
204+
message += `${chalk.grey('endpoints:')}`;
205+
} else {
206+
message += `${chalk.yellow.underline('Serverless StepFunctions OutPuts')}\n`;
207+
message += `${chalk.yellow('endpoints:')}`;
208+
}
196209

197210
if (this.isStateMachines()) {
198211
_.forEach(this.getAllStateMachines(), (stateMachineName) => {
@@ -225,7 +238,7 @@ class ServerlessStepFunctions {
225238
message += stateMachineMessages;
226239
message += '\n';
227240

228-
this.serverless.cli.consoleLog(message);
241+
logger.log(message);
229242

230243
return message;
231244
}

lib/index.test.js

+12-9
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const AwsProvider = require('serverless/lib/plugins/aws/provider');
88
const CLI = require('serverless/lib/classes/CLI');
99
const chalk = require('chalk');
1010
const ServerlessStepFunctions = require('./index');
11+
const logger = require('./utils/logger');
1112

1213
describe('#index', () => {
1314
let serverless;
@@ -287,22 +288,24 @@ describe('#index', () => {
287288
});
288289

289290
describe('#deploy()', () => {
290-
let consoleLogStub;
291+
let logSpy;
291292

292293
beforeEach(() => {
293-
consoleLogStub = sinon.stub(serverless.cli, 'consoleLog').returns();
294+
logger.config(serverless);
295+
logSpy = sinon.spy(logger, 'log');
296+
serverless.cli = { consoleLog: logSpy };
294297
serverlessStepFunctions.endpointInfo = 'https://example.com';
295298
});
296299

297300
afterEach(() => {
298-
serverlessStepFunctions.serverless.cli.consoleLog.restore();
301+
logSpy.restore();
299302
});
300303

301304
it('should not display endpoints if http event not given', () => {
302305
serverlessStepFunctions.serverless.service.stepFunctions = {};
303306
const expectedMessage = '';
304307
const message = serverlessStepFunctions.display();
305-
expect(consoleLogStub.calledOnce).to.equal(false);
308+
expect(logSpy.calledOnce).to.equal(false);
306309
expect(message).to.equal(expectedMessage);
307310
});
308311

@@ -328,7 +331,7 @@ describe('#index', () => {
328331
expectedMessage += '\n POST - https://example.com/foo/bar';
329332
expectedMessage += '\n';
330333
const message = serverlessStepFunctions.display();
331-
expect(consoleLogStub.calledOnce).to.equal(true);
334+
expect(logSpy.calledOnce).to.equal(true);
332335
expect(message).to.equal(expectedMessage);
333336
});
334337

@@ -351,7 +354,7 @@ describe('#index', () => {
351354
expectedMessage += '\n POST - https://example.com/foo/bar';
352355
expectedMessage += '\n';
353356
const message = serverlessStepFunctions.display();
354-
expect(consoleLogStub.calledOnce).to.equal(true);
357+
expect(logSpy.calledOnce).to.equal(true);
355358
expect(message).to.equal(expectedMessage);
356359
});
357360

@@ -374,7 +377,7 @@ describe('#index', () => {
374377
expectedMessage += '\n POST - https://example.com';
375378
expectedMessage += '\n';
376379
const message = serverlessStepFunctions.display();
377-
expect(consoleLogStub.calledOnce).to.equal(true);
380+
expect(logSpy.calledOnce).to.equal(true);
378381
expect(message).to.equal(expectedMessage);
379382
});
380383

@@ -389,7 +392,7 @@ describe('#index', () => {
389392
};
390393
const expectedMessage = '';
391394
const message = serverlessStepFunctions.display();
392-
expect(consoleLogStub.calledOnce).to.equal(false);
395+
expect(logSpy.calledOnce).to.equal(false);
393396
expect(message).to.equal(expectedMessage);
394397
});
395398

@@ -408,7 +411,7 @@ describe('#index', () => {
408411
};
409412
const expectedMessage = '';
410413
const message = serverlessStepFunctions.display();
411-
expect(consoleLogStub.calledOnce).to.equal(false);
414+
expect(logSpy.calledOnce).to.equal(false);
412415
expect(message).to.equal(expectedMessage);
413416
});
414417
});

lib/utils/logger.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
'use strict';
2+
3+
class Logger {
4+
config(serverless, v3Api) {
5+
if (v3Api) {
6+
this.log = v3Api.log;
7+
} else {
8+
this.log = serverless.cli && serverless.cli.consoleLog;
9+
}
10+
11+
return this;
12+
}
13+
}
14+
15+
module.exports = new Logger();

lib/utils/logger.test.js

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
'use strict';
2+
3+
const expect = require('chai').expect;
4+
const sinon = require('sinon');
5+
const Serverless = require('serverless/lib/Serverless');
6+
const logger = require('../utils/logger');
7+
8+
describe('logger', () => {
9+
let serverless;
10+
let v3LogSpy;
11+
12+
beforeEach(() => {
13+
serverless = new Serverless();
14+
serverless.cli = { consoleLog: sinon.spy() };
15+
16+
v3LogSpy = sinon.spy();
17+
});
18+
19+
afterEach(() => {
20+
serverless.cli = null;
21+
v3LogSpy = null;
22+
});
23+
24+
it('should be assigned legacy logger (serverless.cli.consoleLog) if v3 log api is not supplied', () => {
25+
const { log } = logger.config(serverless);
26+
log('Testing purpose');
27+
28+
expect(serverless.cli.consoleLog.callCount).to.equal(1);
29+
expect(v3LogSpy.callCount).to.equal(0);
30+
});
31+
32+
it('should be assigned new log API if new log api is supplied', () => {
33+
const { log } = logger.config(serverless, { log: v3LogSpy });
34+
log('Testing purpose');
35+
36+
expect(serverless.cli.consoleLog.callCount).to.equal(0);
37+
expect(v3LogSpy.callCount).to.equal(1);
38+
});
39+
});

0 commit comments

Comments
 (0)