Skip to content

Commit 672eb90

Browse files
author
Kevin Formsma
authored
Include valid line numbers for SAM transformed resources (#94)
1 parent c066771 commit 672eb90

File tree

2 files changed

+58
-17
lines changed

2 files changed

+58
-17
lines changed

lib/cfn-model/transforms/serverless.rb

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
class CfnModel
44
class Transforms
55
# Handle transformation of model elements performed by the
6-
# Serverless trasnform, see
6+
# Serverless transform, see
77
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/transform-aws-serverless.html
88
class Serverless
99
def perform_transform(cfn_hash)
@@ -108,6 +108,8 @@ def serverless_function_properties(cfn_hash, serverless_function, fn_name, with_
108108
def replace_serverless_function(cfn_hash, resource_name, with_line_numbers)
109109
serverless_function = cfn_hash['Resources'][resource_name]
110110

111+
original_line_number = serverless_function['Type']['line']
112+
111113
lambda_fn_params = serverless_function_properties(cfn_hash,
112114
serverless_function,
113115
resource_name,
@@ -120,15 +122,17 @@ def replace_serverless_function(cfn_hash, resource_name, with_line_numbers)
120122
role: lambda_fn_params[:role],
121123
runtime: lambda_fn_params[:runtime],
122124
reserved_concurrent_executions: lambda_fn_params[:reserved_concurrent_executions],
125+
line_number: original_line_number,
123126
with_line_numbers: lambda_fn_params[:with_line_numbers]
124127
)
125128
unless serverless_function['Properties']['Role']
126129
cfn_hash['Resources'][resource_name + 'Role'] = function_role(serverless_function,
127130
resource_name,
131+
original_line_number,
128132
with_line_numbers)
129133
end
130134

131-
transform_function_events(cfn_hash, serverless_function, resource_name, with_line_numbers) if \
135+
transform_function_events(cfn_hash, serverless_function, resource_name, original_line_number, with_line_numbers) if \
132136
serverless_function['Properties']['Events']
133137

134138
# Handle passing along cfn-nag specific metadata. SAM itself does not support metadata during transformation.
@@ -156,9 +160,9 @@ def lambda_service_can_assume_role
156160

157161
# Return the hash structure of the '<function_name>Role'
158162
# AWS::IAM::Role resource as created by Serverless transform
159-
def function_role(serverless_function, function_name, with_line_numbers)
163+
def function_role(serverless_function, function_name, line_number, with_line_numbers)
160164
fn_role = {
161-
'Type' => format_resource_type('AWS::IAM::Role', -1, with_line_numbers),
165+
'Type' => format_resource_type('AWS::IAM::Role', line_number, with_line_numbers),
162166
'Properties' => {
163167
'ManagedPolicyArns' => function_role_managed_policies(serverless_function['Properties']),
164168
'AssumeRolePolicyDocument' => lambda_service_can_assume_role
@@ -226,9 +230,10 @@ def lambda_function(handler:,
226230
role:,
227231
runtime:,
228232
reserved_concurrent_executions:,
233+
line_number:,
229234
with_line_numbers: false)
230235
fn_resource = {
231-
'Type' => format_resource_type('AWS::Lambda::Function', -1, with_line_numbers),
236+
'Type' => format_resource_type('AWS::Lambda::Function', line_number, with_line_numbers),
232237
'Properties' => {
233238
'Handler' => handler,
234239
'Role' => role,
@@ -242,32 +247,32 @@ def lambda_function(handler:,
242247

243248
# Return the Event structure of a AWS::Lambda::Function as created
244249
# by Serverless transform
245-
def transform_function_events(cfn_hash, serverless_function, function_name, with_line_numbers)
250+
def transform_function_events(cfn_hash, serverless_function, function_name, line_number, with_line_numbers)
246251
serverless_function['Properties']['Events'].each do |_, event|
247-
serverlessrestapi_resources(cfn_hash, event, function_name, with_line_numbers) if \
252+
serverlessrestapi_resources(cfn_hash, event, function_name, line_number, with_line_numbers) if \
248253
matching_resource_type?(event['Type'], 'Api')
249254
end
250255
end
251256

252-
def serverlessrestapi_resources(cfn_hash, event, func_name, with_line_numbers)
257+
def serverlessrestapi_resources(cfn_hash, event, func_name, line_number, with_line_numbers)
253258
# ServerlessRestApi
254-
cfn_hash['Resources']['ServerlessRestApi'] ||= serverlessrestapi_base with_line_numbers
259+
cfn_hash['Resources']['ServerlessRestApi'] ||= serverlessrestapi_base line_number, with_line_numbers
255260
add_serverlessrestapi_event(
256261
cfn_hash['Resources']['ServerlessRestApi']['Properties']['Body']['paths'],
257262
event,
258263
func_name
259264
)
260265

261266
# ServerlessRestApiDeployment
262-
cfn_hash['Resources']['ServerlessRestApiDeployment'] = serverlessrestapi_deployment with_line_numbers
267+
cfn_hash['Resources']['ServerlessRestApiDeployment'] ||= serverlessrestapi_deployment line_number, with_line_numbers
263268

264269
# ServerlessRestApiProdStage
265-
cfn_hash['Resources']['ServerlessRestApiProdStage'] = serverlessrestapi_stage with_line_numbers
270+
cfn_hash['Resources']['ServerlessRestApiProdStage'] ||= serverlessrestapi_stage line_number, with_line_numbers
266271
end
267272

268-
def serverlessrestapi_base(with_line_nos)
273+
def serverlessrestapi_base(line_number, with_line_numbers)
269274
{
270-
'Type' => format_resource_type('AWS::ApiGateway::RestApi', -1, with_line_nos),
275+
'Type' => format_resource_type('AWS::ApiGateway::RestApi', line_number, with_line_numbers),
271276
'Properties' => {
272277
'Body' => {
273278
'info' => {
@@ -294,9 +299,9 @@ def add_serverlessrestapi_event(paths_hash, event, function_name)
294299
}
295300
end
296301

297-
def serverlessrestapi_deployment(with_line_nos)
302+
def serverlessrestapi_deployment(line_number, with_line_numbers)
298303
{
299-
'Type' => format_resource_type('AWS::ApiGateway::Deployment', -1, with_line_nos),
304+
'Type' => format_resource_type('AWS::ApiGateway::Deployment', line_number, with_line_numbers),
300305
'Properties' => {
301306
'Description' => 'Generated by cfn-model',
302307
'RestApiId' => { 'Ref' => 'ServerlessRestApi' },
@@ -311,9 +316,9 @@ def serverlessrestapi_deployment(with_line_nos)
311316
}
312317
end
313318

314-
def serverlessrestapi_stage(with_line_nos)
319+
def serverlessrestapi_stage(line_number, with_line_numbers)
315320
{
316-
'Type' => format_resource_type('AWS::ApiGateway::Stage', -1, with_line_nos),
321+
'Type' => format_resource_type('AWS::ApiGateway::Stage', line_number, with_line_numbers),
317322
'Properties' => {
318323
'DeploymentId' => { 'Ref' => 'ServerlessRestApiDeployment' },
319324
'RestApiId' => { 'Ref' => 'ServerlessRestApi' },

spec/transforms/serverless_spec.rb

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,4 +224,40 @@
224224
expect(serverlessrestapi_stage).to be_nil
225225
end
226226
end
227+
228+
context 'Templates with line numbers enabled' do
229+
it 'assigns line numbers to function resource' do
230+
cloudformation_template_yml = yaml_test_template('sam/valid_simple_lambda_fn')
231+
actual_cfn_model = @cfn_parser.parse cloudformation_template_yml, nil, true
232+
233+
lambda_function = actual_cfn_model.resources_by_type('AWS::Lambda::Function').first
234+
expect(actual_cfn_model.line_numbers[lambda_function.logical_resource_id]).to eq(7)
235+
end
236+
237+
it 'assigns line numbers to role resource' do
238+
cloudformation_template_yml = yaml_test_template('sam/valid_simple_lambda_fn')
239+
actual_cfn_model = @cfn_parser.parse cloudformation_template_yml, nil, true
240+
241+
iam_role = actual_cfn_model.resources_by_type('AWS::IAM::Role').first
242+
expect(actual_cfn_model.line_numbers[iam_role.logical_resource_id]).to eq(7)
243+
end
244+
245+
it 'assigns line numbers to serverless event resources' do
246+
cloudformation_template_yml = yaml_test_template('sam/serverlessrestapi_as_ref')
247+
actual_cfn_model = @cfn_parser.parse cloudformation_template_yml, nil, true
248+
249+
expect(actual_cfn_model.line_numbers['ServerlessRestApi']).to eq(15)
250+
expect(actual_cfn_model.line_numbers['ServerlessRestApiDeployment']).to eq(15)
251+
expect(actual_cfn_model.line_numbers['ServerlessRestApiProdStage']).to eq(15)
252+
end
253+
end
254+
255+
context 'Templates with line numbers disabled' do
256+
it 'does not assign line numbers to function resource' do
257+
cloudformation_template_yml = yaml_test_template('sam/valid_simple_lambda_fn')
258+
actual_cfn_model = @cfn_parser.parse cloudformation_template_yml, nil, false
259+
260+
expect(actual_cfn_model.line_numbers).to be_empty
261+
end
262+
end
227263
end

0 commit comments

Comments
 (0)