jets 1.7.2 → 1.8.0

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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/README.md +1 -1
  4. data/jets.gemspec +2 -0
  5. data/lib/jets.rb +1 -0
  6. data/lib/jets/application.rb +45 -21
  7. data/lib/jets/aws_services.rb +2 -0
  8. data/lib/jets/aws_services/s3_bucket.rb +26 -0
  9. data/lib/jets/booter.rb +82 -2
  10. data/lib/jets/builders/code_builder.rb +20 -7
  11. data/lib/jets/builders/handler_generator.rb +20 -6
  12. data/lib/jets/cfn/builders/base_child_builder.rb +5 -17
  13. data/lib/jets/cfn/builders/parent_builder.rb +1 -1
  14. data/lib/jets/commands/build.rb +6 -0
  15. data/lib/jets/commands/deploy.rb +10 -0
  16. data/lib/jets/commands/templates/skeleton/config/environments/development.rb +4 -1
  17. data/lib/jets/commands/templates/skeleton/config/environments/production.rb +6 -1
  18. data/lib/jets/commands/templates/skeleton/config/environments/test.rb +7 -0
  19. data/lib/jets/controller/base.rb +1 -2
  20. data/lib/jets/controller/rendering/rack_renderer.rb +11 -3
  21. data/lib/jets/core.rb +5 -72
  22. data/lib/jets/internal/app/controllers/jets/mailers_controller.rb +97 -0
  23. data/lib/jets/internal/app/helpers/jets/mailers_helper.rb +9 -0
  24. data/lib/jets/internal/app/shared/functions/jets/s3_bucket_config.rb +43 -0
  25. data/lib/jets/internal/app/views/jets/mailers/email.html.erb +145 -0
  26. data/lib/jets/internal/app/views/jets/mailers/index.html.erb +8 -0
  27. data/lib/jets/internal/app/views/jets/mailers/mailer.html.erb +6 -0
  28. data/lib/jets/job/base.rb +10 -0
  29. data/lib/jets/job/dsl.rb +2 -0
  30. data/lib/jets/job/dsl/s3_event.rb +36 -0
  31. data/lib/jets/job/dsl/sns_event.rb +8 -0
  32. data/lib/jets/job/s3_event_helper.rb +13 -0
  33. data/lib/jets/lambda/dsl.rb +11 -1
  34. data/lib/jets/mailer.rb +51 -0
  35. data/lib/jets/resource/child_stack/app_class.rb +6 -15
  36. data/lib/jets/resource/child_stack/shared.rb +3 -1
  37. data/lib/jets/resource/events/rule.rb +1 -1
  38. data/lib/jets/resource/lambda/event_source_mapping.rb +1 -1
  39. data/lib/jets/resource/permission.rb +1 -1
  40. data/lib/jets/resource/replacer.rb +8 -0
  41. data/lib/jets/resource/s3.rb +3 -17
  42. data/lib/jets/resource/s3/bucket.rb +24 -0
  43. data/lib/jets/resource/sns.rb +1 -0
  44. data/lib/jets/resource/sns/subscription.rb +1 -1
  45. data/lib/jets/resource/sns/topic.rb +1 -1
  46. data/lib/jets/resource/sns/topic_policy.rb +40 -0
  47. data/lib/jets/resource/sqs/queue.rb +1 -1
  48. data/lib/jets/stack.rb +19 -3
  49. data/lib/jets/stack/builder.rb +6 -1
  50. data/lib/jets/stack/depends.rb +36 -0
  51. data/lib/jets/stack/depends/item.rb +9 -0
  52. data/lib/jets/stack/function.rb +19 -10
  53. data/lib/jets/stack/main/dsl.rb +4 -0
  54. data/lib/jets/stack/main/extensions/iam.rb +8 -0
  55. data/lib/jets/stack/main/extensions/lambda.rb +20 -7
  56. data/lib/jets/stack/main/extensions/s3.rb +12 -0
  57. data/lib/jets/stack/main/extensions/sns.rb +4 -0
  58. data/lib/jets/stack/s3_event.rb +87 -0
  59. data/lib/jets/turbine.rb +11 -0
  60. data/lib/jets/version.rb +1 -1
  61. metadata +48 -2
@@ -17,7 +17,12 @@ class Jets::Stack
17
17
 
18
18
  def build_section(section)
19
19
  elements = build_elements(section)
20
- @template[section] = elements if elements
20
+ return unless elements
21
+
22
+ if section == :parameters
23
+ elements["GemLayer"] = {"Type"=>"String"} unless Jets.poly_only?
24
+ end
25
+ @template[section] = elements
21
26
  end
22
27
 
23
28
  def build_elements(section)
@@ -0,0 +1,36 @@
1
+ class Jets::Stack
2
+ class Depends
3
+ autoload :Item, "jets/stack/depends/item"
4
+
5
+ def initialize(items)
6
+ @items = items
7
+ end
8
+
9
+ def params
10
+ result = {}
11
+ @items.each do |item|
12
+ logical_id = item.stack.to_s.camelize # logical_id
13
+ dependency_outputs(logical_id).each do |output|
14
+ dependency_class = logical_id.to_s.classify
15
+ output_key = item.options[:class_prefix] ?
16
+ "#{dependency_class}#{output}" : # already camelized
17
+ output
18
+
19
+ output_value = "!GetAtt #{dependency_class}.Outputs.#{output}"
20
+ result[output_key] = output_value
21
+ end
22
+ end
23
+ result
24
+ end
25
+
26
+ def stack_list
27
+ @items.map do |item|
28
+ item.stack.to_s.camelize # logical_id # logical_id
29
+ end
30
+ end
31
+
32
+ def dependency_outputs(logical_id)
33
+ logical_id.to_s.classify.constantize.output_keys
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,9 @@
1
+ class Jets::Stack::Depends
2
+ class Item
3
+ attr_reader :stack, :options
4
+ def initialize(stack, options={})
5
+ @stack = stack
6
+ @options = options
7
+ end
8
+ end
9
+ end
@@ -14,6 +14,8 @@ class Jets::Stack
14
14
  end
15
15
 
16
16
  def lang
17
+ return if internal?
18
+
17
19
  if source_file
18
20
  # Detect language from file extension
19
21
  ext = File.extname(source_file).sub(/^\./,'').to_sym
@@ -37,24 +39,31 @@ class Jets::Stack
37
39
  memoize :source_file
38
40
 
39
41
  def search_expression
42
+ base_search_expression.sub('handlers/shared/', "#{Jets.root}/app/shared/")
43
+ end
44
+
45
+ def internal_search_expression
46
+ internal = File.expand_path("../internal", File.dirname(__FILE__))
47
+ base_search_expression.sub('handlers/shared/', "#{internal}/app/shared/")
48
+ end
49
+
50
+ def base_search_expression
40
51
  attributes = @template.values.first
41
52
  handler = attributes['Properties']['Handler']
42
- search_expression = handler.split('.')[0..-2].join('.') + '.*'
43
- search_expression.sub('handlers/shared/', "#{Jets.root}/app/shared/")
53
+ handler.split('.')[0..-2].join('.') + '.*' # search_expression
54
+ # Example: handlers/shared/functions/jets/s3_bucket_config.*
55
+ end
56
+
57
+ # Internal flag is mainly used to disable WARN messages
58
+ def internal?
59
+ !!Dir.glob(internal_search_expression).first
44
60
  end
45
61
 
46
62
  # Relative path
47
63
  # app/shared/functions/kevin.py => handlers/shared/functions/kevin.py
48
64
  def handler_dest
49
65
  return unless source_file
50
-
51
- dest = source_file.sub(%r{.*/app/}, "handlers/")
52
- if lang == :ruby
53
- filename = dest.split('.').first
54
- filename + '.js' # change extension to .js because ruby uses a node shim
55
- else
56
- dest
57
- end
66
+ source_file.sub(%r{.*/app/}, "handlers/")
58
67
  end
59
68
  end
60
69
  end
@@ -4,14 +4,18 @@ class Jets::Stack
4
4
  extend ActiveSupport::Concern
5
5
  autoload :Base, 'jets/stack/main/extensions/base'
6
6
  autoload :Cloudwatch, 'jets/stack/main/extensions/cloudwatch'
7
+ autoload :Iam, 'jets/stack/main/extensions/iam'
7
8
  autoload :Lambda, 'jets/stack/main/extensions/lambda'
9
+ autoload :S3, 'jets/stack/main/extensions/s3'
8
10
  autoload :Sns, 'jets/stack/main/extensions/sns'
9
11
  autoload :Sqs, 'jets/stack/main/extensions/sqs'
10
12
 
11
13
  class_methods do
12
14
  include Base
13
15
  include Cloudwatch
16
+ include Iam
14
17
  include Lambda
18
+ include S3
15
19
  include Sns
16
20
  include Sqs
17
21
  end
@@ -0,0 +1,8 @@
1
+ module Jets::Stack::Main::Dsl
2
+ module Iam
3
+ def iam_role(id, props={})
4
+ resource(id, "AWS::IAM::Role", props)
5
+ output(id) # IAM Arn
6
+ end
7
+ end
8
+ end
@@ -1,5 +1,6 @@
1
1
  module Jets::Stack::Main::Dsl
2
2
  module Lambda
3
+ MAX_FUNCTION_NAME_SIZE = 64
3
4
  # Example:
4
5
  #
5
6
  # function(:hello,
@@ -20,39 +21,45 @@ module Jets::Stack::Main::Dsl
20
21
  #
21
22
  def function(id, props={})
22
23
  # Required: code, handler, role, runtime Docs: https://amzn.to/2pdot7S
23
- meth = id.to_s.underscore
24
+ meth = sanitize_method_name(id)
24
25
  class_namespace = self.to_s.underscore.gsub('/','-') # IE: Jets::Domain => jets-domain
25
- function_name = "#{Jets.config.project_namespace}-#{class_namespace}-#{id.to_s.underscore}"
26
+ description = "#{self.to_s} #{meth}" # not bother adding extension
26
27
  defaults = {
27
- function_name: function_name,
28
28
  code: {
29
29
  s3_bucket: "!Ref S3Bucket",
30
30
  s3_key: code_s3_key
31
31
  },
32
32
  role: "!Ref IamRole",
33
- handler: "#{meth}.handle", # default ruby convention
33
+ handler: "#{id}.lambda_handler", # default ruby convention
34
34
  runtime: :ruby,
35
35
  timeout: Jets.config.function.timeout,
36
36
  memory_size: Jets.config.function.memory_size,
37
+ description: description,
37
38
  }
39
+
40
+ function_name = "#{Jets.config.project_namespace}-#{class_namespace}-#{meth}"
41
+ function_name.size > MAX_FUNCTION_NAME_SIZE ? nil : function_name
42
+ defaults[:function_name] = function_name if function_name
43
+
38
44
  props = defaults.merge(props)
39
45
  props[:runtime] = "ruby2.5" if props[:runtime].to_s == "ruby"
40
46
  props[:handler] = handler(props[:handler])
41
47
 
42
- resource(id, "AWS::Lambda::Function", props)
48
+ logical_id = id.to_s.gsub('/','_')
49
+ resource(logical_id, "AWS::Lambda::Function", props)
43
50
  end
44
51
  alias_method :ruby_function, :function
45
52
  alias_method :lambda_function, :function
46
53
 
47
54
  def python_function(id, props={})
48
- meth = id.to_s.underscore
55
+ meth = sanitize_method_name(id)
49
56
  props[:handler] ||= "#{meth}.lambda_handler" # default python convention
50
57
  props[:runtime] = "python3.6"
51
58
  function(id, props)
52
59
  end
53
60
 
54
61
  def node_function(id, props={})
55
- meth = id.to_s.underscore
62
+ meth = sanitize_method_name(id)
56
63
  props[:handler] ||= "#{meth}.handler" # default python convention
57
64
  props[:runtime] = "nodejs8.10"
58
65
  function(id, props)
@@ -67,5 +74,11 @@ module Jets::Stack::Main::Dsl
67
74
  props = defaults.merge(props)
68
75
  resource(id, "AWS::Lambda::Permission", props)
69
76
  end
77
+
78
+ private
79
+ # demo-dev-hard_job-dig_me
80
+ def sanitize_method_name(id)
81
+ id.to_s.gsub('/','-')
82
+ end
70
83
  end
71
84
  end
@@ -0,0 +1,12 @@
1
+ module Jets::Stack::Main::Dsl
2
+ module S3
3
+ def s3_bucket(id, props={})
4
+ resource(id, "AWS::S3::Bucket", props)
5
+ output(id) # Bucket name
6
+ end
7
+
8
+ def s3_bucket_configuration(id, props={})
9
+ resource(id, "Custom::S3BucketConfiguration", props)
10
+ end
11
+ end
12
+ end
@@ -5,6 +5,10 @@ module Jets::Stack::Main::Dsl
5
5
  output(id) # Topic Arn
6
6
  end
7
7
 
8
+ def sns_topic_policy(id, props={})
9
+ resource(id, "AWS::SNS::TopicPolicy", props)
10
+ end
11
+
8
12
  def sns_subscription(id, props={})
9
13
  resource(id, "AWS::SNS::Subscription", props)
10
14
  end
@@ -0,0 +1,87 @@
1
+ class Jets::Stack
2
+ class S3Event
3
+ def initialize(bucket_name)
4
+ @bucket_name = bucket_name
5
+ end
6
+
7
+ # Stack names can only contain alpha numeric chars.
8
+ # Bucket names are limit to 64 chars: https://amzn.to/2SIzvme
9
+ # Stack names are limit to 128 chars: https://amzn.to/2SFkrG0
10
+ # This gsub should handle this.
11
+ def stack_name
12
+ @bucket_name.gsub(/[^0-9a-z\-_]/i, '').gsub('-','_').camelize
13
+ end
14
+
15
+ def build_stack
16
+ # assign to local variable so its available in the block
17
+ bucket = @bucket_name
18
+
19
+ Jets::Stack.new_class(stack_name) do
20
+ s3_bucket_configuration(:s3_bucket_configuration,
21
+ service_token: "!GetAtt JetsS3BucketConfig.Arn", # Cannot change this w/o changing the logical id
22
+ # These properties correspond to the ruby aws-sdk s3.put_bucket_notification_configuration
23
+ # in jets/s3_bucket_config.rb, not the CloudFormation Bucket properties. The CloudFormation
24
+ # bucket properties have a similiar structure but is slightly different so it can be confusing.
25
+ #
26
+ # Ruby aws-sdk S3 Docs: https://amzn.to/2N7m5Lr
27
+ bucket: bucket,
28
+ notification_configuration: Jets.config.s3_event.notification_configuration,
29
+ ) if Jets.config.s3_event.configure_bucket
30
+
31
+ # Important note: If we change the name of this function we should also change the
32
+ # logical id of the s3_bucket_configuration custom resource or we'll get this error:
33
+ # Modifying service token is not allowed.
34
+ function("jets/s3_bucket_config",
35
+ role: "!GetAtt BucketConfigIamRole.Arn",
36
+ layers: ["!Ref GemLayer"],
37
+ )
38
+
39
+ sns_topic(:sns_topic)
40
+ sns_topic_policy(:sns_topic_policy,
41
+ policy_document: {
42
+ version: "2012-10-17",
43
+ statement: {
44
+ effect: "Allow",
45
+ principal: { service: "s3.amazonaws.com"},
46
+ action: "sns:Publish",
47
+ resource: "!Ref SnsTopic",
48
+ condition: {
49
+ arn_like: {
50
+ "aws:SourceArn" => "!Sub arn:aws:s3:*:*:#{bucket}"
51
+ }
52
+ }
53
+ }
54
+ },
55
+ topics: ["!Ref SnsTopic"],
56
+ )
57
+
58
+ iam_role(:bucket_config_iam_role,
59
+ assume_role_policy_document: {
60
+ version: '2012-10-17',
61
+ statement: [
62
+ effect: "Allow",
63
+ principal: {service: ["lambda.amazonaws.com"]},
64
+ action: ['sts:AssumeRole'],
65
+ ]
66
+ },
67
+ path: "/",
68
+ managed_policy_arns: ["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],
69
+ policies: [
70
+ policy_name: "S3Policy",
71
+ policy_document: {
72
+ version: '2012-10-17',
73
+ statement: [
74
+ effect: "Allow",
75
+ action: [
76
+ 's3:GetBucketNotification',
77
+ 's3:PutBucketNotification',
78
+ ],
79
+ resource: "*"
80
+ ]
81
+ }
82
+ ]
83
+ )
84
+ end
85
+ end
86
+ end
87
+ end
data/lib/jets/turbine.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  module Jets
2
2
  class Turbine
3
+ class_attribute :after_initializers
3
4
  class_attribute :initializers
4
5
  class_attribute :on_exceptions
5
6
 
@@ -12,6 +13,11 @@ module Jets
12
13
  subclasses << base
13
14
  end
14
15
 
16
+ def after_initializer(label, &block)
17
+ self.after_initializers ||= {}
18
+ self.after_initializers[label] = block
19
+ end
20
+
15
21
  def initializer(label, &block)
16
22
  self.initializers ||= {}
17
23
  self.initializers[label] = block
@@ -25,6 +31,11 @@ module Jets
25
31
  def exception_reporter(label, &block)
26
32
  on_exception(label, &block)
27
33
  end
34
+
35
+ # Make config available in Turbine. Note only available outside of hooks like initializers.
36
+ def config
37
+ Jets.application.config
38
+ end
28
39
  end
29
40
  end
30
41
  end
data/lib/jets/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Jets
2
- VERSION = "1.7.2"
2
+ VERSION = "1.8.0"
3
3
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jets
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.2
4
+ version: 1.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tung Nguyen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-02-09 00:00:00.000000000 Z
11
+ date: 2019-02-13 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: actionmailer
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 5.2.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 5.2.1
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: activerecord
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -150,6 +164,20 @@ dependencies:
150
164
  - - ">="
151
165
  - !ruby/object:Gem::Version
152
166
  version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: cfnresponse
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :runtime
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
153
181
  - !ruby/object:Gem::Dependency
154
182
  name: dotenv
155
183
  requirement: !ruby/object:Gem::Requirement
@@ -452,6 +480,7 @@ files:
452
480
  - lib/jets/application.rb
453
481
  - lib/jets/aws_info.rb
454
482
  - lib/jets/aws_services.rb
483
+ - lib/jets/aws_services/s3_bucket.rb
455
484
  - lib/jets/aws_services/stack_status.rb
456
485
  - lib/jets/booter.rb
457
486
  - lib/jets/builders.rb
@@ -581,6 +610,7 @@ files:
581
610
  - lib/jets/commands/templates/skeleton/config/dynamodb.yml
582
611
  - lib/jets/commands/templates/skeleton/config/environments/development.rb
583
612
  - lib/jets/commands/templates/skeleton/config/environments/production.rb
613
+ - lib/jets/commands/templates/skeleton/config/environments/test.rb
584
614
  - lib/jets/commands/templates/skeleton/config/routes.rb
585
615
  - lib/jets/commands/templates/skeleton/db/.gitkeep
586
616
  - lib/jets/commands/templates/skeleton/public/404.html
@@ -643,17 +673,25 @@ files:
643
673
  - lib/jets/generator/templates/rails/scaffold_controller/api_controller.rb
644
674
  - lib/jets/generator/templates/rails/scaffold_controller/controller.rb
645
675
  - lib/jets/inflections.rb
676
+ - lib/jets/internal/app/controllers/jets/mailers_controller.rb
646
677
  - lib/jets/internal/app/controllers/jets/public_controller.rb
647
678
  - lib/jets/internal/app/controllers/jets/rack_controller.rb
648
679
  - lib/jets/internal/app/functions/jets/base_path.rb
680
+ - lib/jets/internal/app/helpers/jets/mailers_helper.rb
649
681
  - lib/jets/internal/app/jobs/jets/preheat_job.rb
682
+ - lib/jets/internal/app/shared/functions/jets/s3_bucket_config.rb
683
+ - lib/jets/internal/app/views/jets/mailers/email.html.erb
684
+ - lib/jets/internal/app/views/jets/mailers/index.html.erb
685
+ - lib/jets/internal/app/views/jets/mailers/mailer.html.erb
650
686
  - lib/jets/io.rb
651
687
  - lib/jets/job.rb
652
688
  - lib/jets/job/base.rb
653
689
  - lib/jets/job/dsl.rb
654
690
  - lib/jets/job/dsl/event_source_mapping.rb
691
+ - lib/jets/job/dsl/s3_event.rb
655
692
  - lib/jets/job/dsl/sns_event.rb
656
693
  - lib/jets/job/dsl/sqs_event.rb
694
+ - lib/jets/job/s3_event_helper.rb
657
695
  - lib/jets/klass.rb
658
696
  - lib/jets/lambda.rb
659
697
  - lib/jets/lambda/dsl.rb
@@ -662,6 +700,7 @@ files:
662
700
  - lib/jets/lambda/functions.rb
663
701
  - lib/jets/lambda/task.rb
664
702
  - lib/jets/logger.rb
703
+ - lib/jets/mailer.rb
665
704
  - lib/jets/mega.rb
666
705
  - lib/jets/mega/hash_converter.rb
667
706
  - lib/jets/mega/request.rb
@@ -744,9 +783,11 @@ files:
744
783
  - lib/jets/resource/route53.rb
745
784
  - lib/jets/resource/route53/record_set.rb
746
785
  - lib/jets/resource/s3.rb
786
+ - lib/jets/resource/s3/bucket.rb
747
787
  - lib/jets/resource/sns.rb
748
788
  - lib/jets/resource/sns/subscription.rb
749
789
  - lib/jets/resource/sns/topic.rb
790
+ - lib/jets/resource/sns/topic_policy.rb
750
791
  - lib/jets/resource/sqs.rb
751
792
  - lib/jets/resource/sqs/queue.rb
752
793
  - lib/jets/resource/standardizer.rb
@@ -763,12 +804,16 @@ files:
763
804
  - lib/jets/stack.rb
764
805
  - lib/jets/stack/builder.rb
765
806
  - lib/jets/stack/definition.rb
807
+ - lib/jets/stack/depends.rb
808
+ - lib/jets/stack/depends/item.rb
766
809
  - lib/jets/stack/function.rb
767
810
  - lib/jets/stack/main.rb
768
811
  - lib/jets/stack/main/dsl.rb
769
812
  - lib/jets/stack/main/extensions/base.rb
770
813
  - lib/jets/stack/main/extensions/cloudwatch.rb
814
+ - lib/jets/stack/main/extensions/iam.rb
771
815
  - lib/jets/stack/main/extensions/lambda.rb
816
+ - lib/jets/stack/main/extensions/s3.rb
772
817
  - lib/jets/stack/main/extensions/sns.rb
773
818
  - lib/jets/stack/main/extensions/sqs.rb
774
819
  - lib/jets/stack/output.rb
@@ -778,6 +823,7 @@ files:
778
823
  - lib/jets/stack/parameter/dsl.rb
779
824
  - lib/jets/stack/resource.rb
780
825
  - lib/jets/stack/resource/dsl.rb
826
+ - lib/jets/stack/s3_event.rb
781
827
  - lib/jets/tmp_loader.rb
782
828
  - lib/jets/turbine.rb
783
829
  - lib/jets/turbo.rb