jets 2.3.19 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/.gitmodules +0 -3
  3. data/.python-version +1 -1
  4. data/.ruby-version +1 -1
  5. data/CHANGELOG.md +28 -2
  6. data/README.md +2 -2
  7. data/backers.md +1 -0
  8. data/jets.gemspec +11 -10
  9. data/lib/jets.rb +9 -13
  10. data/lib/jets/application.rb +9 -2
  11. data/lib/jets/application/defaults.rb +17 -15
  12. data/lib/jets/autoloaders.rb +15 -1
  13. data/lib/jets/booter.rb +3 -3
  14. data/lib/jets/builders/code_builder.rb +16 -15
  15. data/lib/jets/builders/gem_replacer.rb +3 -16
  16. data/lib/jets/builders/lambda_layer.rb +4 -5
  17. data/lib/jets/builders/ruby_packager.rb +18 -42
  18. data/lib/jets/builders/tidy.rb +1 -2
  19. data/lib/jets/bundle.rb +6 -0
  20. data/lib/jets/cfn/builders/api_gateway_builder.rb +61 -7
  21. data/lib/jets/cfn/ship.rb +2 -1
  22. data/lib/jets/cli.rb +6 -1
  23. data/lib/jets/commands/base.rb +1 -1
  24. data/lib/jets/commands/call.rb +14 -1
  25. data/lib/jets/commands/clean.rb +1 -1
  26. data/lib/jets/commands/clean/base.rb +1 -1
  27. data/lib/jets/commands/configure.rb +51 -0
  28. data/lib/jets/commands/delete.rb +2 -2
  29. data/lib/jets/commands/gems.rb +2 -10
  30. data/lib/jets/commands/help/call.md +8 -0
  31. data/lib/jets/commands/help/gems/check.md +3 -5
  32. data/lib/jets/commands/main.rb +9 -1
  33. data/lib/jets/commands/new.rb +9 -1
  34. data/lib/jets/commands/sequence.rb +6 -0
  35. data/lib/jets/commands/templates/skeleton/Gemfile.tt +1 -1
  36. data/lib/jets/commands/templates/skeleton/config/application.rb.tt +1 -1
  37. data/lib/jets/commands/templates/skeleton/public/index.html.tt +1 -1
  38. data/lib/jets/commands/url.rb +1 -0
  39. data/lib/jets/controller/base.rb +14 -4
  40. data/lib/jets/controller/middleware/main.rb +2 -1
  41. data/lib/jets/controller/params.rb +26 -4
  42. data/lib/jets/controller/rack/env.rb +18 -1
  43. data/lib/jets/controller/rendering.rb +5 -2
  44. data/lib/jets/controller/rendering/rack_renderer.rb +7 -1
  45. data/lib/jets/core.rb +12 -4
  46. data/lib/jets/dotenv/ssm.rb +18 -4
  47. data/lib/jets/generator.rb +2 -3
  48. data/lib/jets/internal/app/functions/jets/base_path.rb +10 -149
  49. data/lib/jets/internal/app/functions/jets/base_path_mapping.rb +81 -0
  50. data/lib/jets/internal/app/shared/functions/jets/s3_bucket_config.rb +14 -24
  51. data/lib/jets/resource/api_gateway/base_path/function.rb +6 -1
  52. data/lib/jets/resource/api_gateway/deployment.rb +2 -0
  53. data/lib/jets/resource/api_gateway/rest_api/logical_id.rb +34 -0
  54. data/lib/jets/resource/api_gateway/rest_api/logical_id/message.rb +49 -0
  55. data/lib/jets/resource/child_stack/api_deployment.rb +2 -0
  56. data/lib/jets/resource/lambda/function.rb +1 -1
  57. data/lib/jets/router/dsl.rb +7 -1
  58. data/lib/jets/router/method_creator/code.rb +1 -1
  59. data/lib/jets/router/scope.rb +7 -3
  60. data/lib/jets/spec_helpers/controllers.rb +10 -3
  61. data/lib/jets/spec_helpers/controllers/request.rb +12 -5
  62. data/lib/jets/stack/main/dsl/lambda.rb +1 -1
  63. data/lib/jets/turbo.rb +1 -0
  64. data/lib/jets/version.rb +1 -1
  65. metadata +51 -58
  66. data/vendor/cfn-status/CHANGELOG.md +0 -14
  67. data/vendor/cfn-status/Gemfile +0 -4
  68. data/vendor/cfn-status/LICENSE.txt +0 -21
  69. data/vendor/cfn-status/README.md +0 -56
  70. data/vendor/cfn-status/Rakefile +0 -6
  71. data/vendor/cfn-status/bin/console +0 -14
  72. data/vendor/cfn-status/bin/setup +0 -8
  73. data/vendor/cfn-status/cfn-status.gemspec +0 -30
  74. data/vendor/cfn-status/lib/cfn-status.rb +0 -1
  75. data/vendor/cfn-status/lib/cfn_status.rb +0 -245
  76. data/vendor/cfn-status/lib/cfn_status/aws_service.rb +0 -51
  77. data/vendor/cfn-status/lib/cfn_status/version.rb +0 -3
  78. data/vendor/cfn-status/spec/fixtures/cfn/pages/fresh/describe_stack_events-1.json +0 -1103
  79. data/vendor/cfn-status/spec/fixtures/cfn/pages/fresh/describe_stack_events-2.json +0 -1104
  80. data/vendor/cfn-status/spec/fixtures/cfn/pages/fresh/describe_stack_events-3.json +0 -1103
  81. data/vendor/cfn-status/spec/fixtures/cfn/pages/updating/describe_stack_events-1.json +0 -1103
  82. data/vendor/cfn-status/spec/fixtures/cfn/pages/updating/describe_stack_events-2.json +0 -1104
  83. data/vendor/cfn-status/spec/fixtures/cfn/pages/updating/describe_stack_events-3.json +0 -1103
  84. data/vendor/cfn-status/spec/fixtures/cfn/stack-events-complete.json +0 -1080
  85. data/vendor/cfn-status/spec/fixtures/cfn/stack-events-in-progress.json +0 -1080
  86. data/vendor/cfn-status/spec/fixtures/cfn/stack-events-update-rollback-complete.json +0 -1086
  87. data/vendor/cfn-status/spec/lib/cfn_status_spec.rb +0 -153
  88. data/vendor/cfn-status/spec/spec_helper.rb +0 -14
@@ -12,10 +12,9 @@ module Jets::Builders
12
12
  def install
13
13
  return unless gemfile_exist?
14
14
 
15
- reconfigure_ruby_version
16
15
  clean_old_submodules
17
16
  bundle_install
18
- setup_bundle_config
17
+ copy_bundle_config
19
18
  copy_cache_gems
20
19
  end
21
20
 
@@ -46,6 +45,7 @@ module Jets::Builders
46
45
  headline "Bundling: running bundle install in cache area: #{cache_area}."
47
46
 
48
47
  copy_gemfiles(full_project_path)
48
+ copy_bundled_gems(full_project_path)
49
49
 
50
50
  # Uncomment out to always remove the cache/vendor/gems to debug
51
51
  # FileUtils.rm_rf("#{cache_area}/vendor/gems")
@@ -57,16 +57,17 @@ module Jets::Builders
57
57
  # bundle config gems.myprivatesource.com user:pass
58
58
  #
59
59
 
60
- FileUtils.rm_rf("#{cache_area}/.bundle")
60
+ create_bundle_config
61
61
  require "bundler" # dynamically require bundler so user can use any bundler
62
62
  Bundler.with_unbundled_env do
63
63
  sh(
64
64
  "cd #{cache_area} && " \
65
- "env bundle install --path #{cache_area}/vendor/gems --without development test"
65
+ "env bundle install"
66
66
  )
67
67
  end
68
+ create_bundle_config(frozen: true)
68
69
 
69
- rewrite_gemfile_lock("#{cache_area}/Gemfile.lock")
70
+ remove_bundled_with("#{cache_area}/Gemfile.lock")
70
71
 
71
72
  # Copy the Gemfile.lock back to the project in case it was updated.
72
73
  # For example we add the jets-rails to the Gemfile.
@@ -94,14 +95,6 @@ module Jets::Builders
94
95
  Tidy.new(path).cleanup!
95
96
  end
96
97
 
97
- # This is in case the user has a 2.5.x variant.
98
- # Force usage of ruby version that jets supports
99
- # The lambda server only has ruby 2.5.0 installed.
100
- def reconfigure_ruby_version
101
- ruby_version = "#{@full_app_root}/.ruby-version"
102
- IO.write(ruby_version, Jets::RUBY_VERSION)
103
- end
104
-
105
98
  # When using submodules, bundler leaves old submodules behind. Over time this inflates
106
99
  # the size of the the cache gems. So we'll clean it up.
107
100
  def clean_old_submodules
@@ -137,6 +130,12 @@ module Jets::Builders
137
130
  end
138
131
  end
139
132
 
133
+ def copy_bundled_gems(full_project_path)
134
+ src = "#{full_project_path}/bundled_gems"
135
+ return unless File.exist?(src)
136
+ Jets::Util.cp_r(src, "#{cache_area}/bundled_gems")
137
+ end
138
+
140
139
  def copy_gemfiles(full_project_path)
141
140
  FileUtils.mkdir_p(cache_area)
142
141
  FileUtils.cp("#{full_project_path}/Gemfile", "#{cache_area}/Gemfile")
@@ -150,10 +149,9 @@ module Jets::Builders
150
149
 
151
150
  # Remove the BUNDLED WITH line since we don't control the bundler gem version on AWS Lambda
152
151
  # And this can cause issues with require 'bundler/setup'
153
- def rewrite_gemfile_lock(gemfile_lock)
152
+ def remove_bundled_with(gemfile_lock)
154
153
  lines = IO.readlines(gemfile_lock)
155
154
 
156
- # Remove BUNDLED WITH
157
155
  # amount is the number of lines to remove
158
156
  new_lines, capture, count, amount = [], true, 0, 2
159
157
  lines.each do |l|
@@ -167,34 +165,11 @@ module Jets::Builders
167
165
  end
168
166
  end
169
167
 
170
- # Replace things like nokogiri (1.11.1-x86_64-darwin) => nokogiri (1.11.1)
171
- lines, new_lines = new_lines, []
172
- lines.each do |l|
173
- if l.include?("-x86_64-darwin")
174
- l = l.sub('-x86_64-darwin','')
175
- end
176
- new_lines << l
177
- end
178
-
179
- # Make sure platform is ruby
180
- lines, new_lines, marker = new_lines, [], false
181
- lines.each do |l|
182
- if marker # the next loop has the platform we want to replace
183
- new_lines << " ruby\n"
184
- marker = false
185
- next
186
- end
187
- marker = l.include?('PLATFORMS')
188
- new_lines << l
189
- end
190
-
191
168
  content = new_lines.join('')
192
169
  IO.write(gemfile_lock, content)
193
170
  end
194
171
 
195
- def setup_bundle_config
196
- ensure_build_cache_bundle_config_exists!
197
-
172
+ def copy_bundle_config
198
173
  # Override project's .bundle/config and ensure that .bundle/config matches
199
174
  # at these 2 spots:
200
175
  # app_root/.bundle/config
@@ -209,11 +184,12 @@ module Jets::Builders
209
184
  # this only happens with ssh debugging, not when the ci.sh script gets ran.
210
185
  # But on macosx it exists.
211
186
  # Dont know why this is the case.
212
- def ensure_build_cache_bundle_config_exists!
187
+ def create_bundle_config(frozen: false)
188
+ FileUtils.rm_rf("#{cache_area}/.bundle")
189
+ frozen_line = %Q|BUNDLE_FROZEN: "true"\n| if frozen
213
190
  text =<<-EOL
214
191
  ---
215
- BUNDLE_FROZEN: "true"
216
- BUNDLE_PATH: "vendor/gems"
192
+ #{frozen_line}BUNDLE_PATH: "vendor/gems"
217
193
  BUNDLE_WITHOUT: "development:test"
218
194
  EOL
219
195
  bundle_config = "#{cache_area}/.bundle/config"
@@ -81,8 +81,7 @@ module Jets::Builders
81
81
  # Reason do not remove the cache folder generally is because some gems have
82
82
  # actual cache folders that they used.
83
83
  def remove_gem_cache
84
- ruby_minor_version = Jets::RUBY_VERSION.split('.')[0..1].join('.') + '.0'
85
- cache_path = "#{@project_root}/vendor/gems/ruby/#{ruby_minor_version}/cache"
84
+ cache_path = "#{@project_root}/vendor/gems/ruby/#{Jets.ruby_folder}/cache"
86
85
  FileUtils.rm_rf(cache_path)
87
86
  end
88
87
 
data/lib/jets/bundle.rb CHANGED
@@ -15,6 +15,7 @@ module Jets
15
15
  # Later in Jets::Booter, Bundle.require is called and includes the Jets.env group.
16
16
  #
17
17
  def setup
18
+ return unless jets_project?
18
19
  return unless bundler_enabled?
19
20
  Kernel.require "bundler/setup"
20
21
  Bundler.setup # Same as Bundler.setup(:default)
@@ -38,6 +39,7 @@ module Jets
38
39
  # rescued gracefully. This is done in Jets::Commands::RakeTasks.load! In the case when user is in another
39
40
  # project with another Gemfile, the load errors will also be rescued.
40
41
  def require
42
+ return unless jets_project?
41
43
  return unless bundler_enabled?
42
44
  Kernel.require "bundler/setup"
43
45
  Bundler.require(*bundler_groups)
@@ -77,6 +79,10 @@ module Jets
77
79
  [:default, Jets.env.to_sym]
78
80
  end
79
81
 
82
+ def jets_project?
83
+ File.exist?("config/application.rb")
84
+ end
85
+
80
86
  extend self
81
87
  end
82
88
  end
@@ -1,5 +1,6 @@
1
1
  module Jets::Cfn::Builders
2
2
  class ApiGatewayBuilder
3
+ extend Memoist
3
4
  include Interface
4
5
  include Jets::AwsServices
5
6
 
@@ -43,22 +44,75 @@ module Jets::Cfn::Builders
43
44
  end
44
45
 
45
46
  def add_domain_name
46
- domain_name = Jets::Resource::ApiGateway::DomainName.new
47
- add_resource(domain_name)
48
- add_outputs(domain_name.outputs)
47
+ add_outputs(create_domain_name)
49
48
  end
50
49
 
51
50
  def add_route53_dns
52
51
  dns = Jets::Resource::Route53::RecordSet.new
53
- add_resource(dns)
54
- add_outputs(dns.outputs)
52
+ if !existing_domain_name?(dns.domain_name) or existing_dns_record_on_stack?
53
+ add_resource(dns)
54
+ add_outputs(dns.outputs)
55
+ end
56
+ end
57
+
58
+ def create_domain_name()
59
+ resource = Jets::Resource::ApiGateway::DomainName.new
60
+
61
+ return {
62
+ "DomainName" => resource.domain_name
63
+ } if (existing_domain_name?(resource) and !existing_domain_name_on_stack?)
64
+
65
+ add_resource(resource)
66
+ return resource.outputs
67
+ end
68
+
69
+ def existing_domain_name?(resource)
70
+ apigateway.get_domain_name({
71
+ domain_name: resource.domain_name
72
+ })
73
+ return true
74
+ rescue
75
+ return false
76
+ end
77
+ memoize :existing_domain_name?
78
+
79
+ def existing_domain_name_on_stack?
80
+ cfn.describe_stack_resource({
81
+ stack_name: api_gateway_physical_resource_id,
82
+ logical_resource_id: "DomainName"
83
+ })
84
+ return true
85
+ rescue
86
+ return false
87
+ end
88
+
89
+ def existing_dns_record_on_stack?
90
+ cfn.describe_stack_resource({
91
+ stack_name: api_gateway_physical_resource_id,
92
+ logical_resource_id: "DnsRecord"
93
+ })
94
+ return true
95
+ rescue
96
+ return false
97
+ end
98
+
99
+ def api_gateway_physical_resource_id
100
+ cfn.describe_stack_resource({
101
+ stack_name: Jets::Naming.parent_stack_name,
102
+ logical_resource_id: "ApiGateway"
103
+ })
104
+ .stack_resource_detail
105
+ .physical_resource_id
106
+ rescue
107
+ return nil
55
108
  end
109
+ memoize :api_gateway_physical_resource_id
56
110
 
57
111
  # Adds route related Resources and Outputs
58
112
  # Delegates to ApiResourcesBuilder
59
- PAGE_LIMIT = Integer(ENV['JETS_AWS_OUTPUTS_LIMIT'] || 60) # Allow override for testing
113
+ PAGE_LIMIT = Integer(ENV['JETS_AWS_OUTPUTS_LIMIT'] || 200) # Allow override for testing
60
114
  def add_gateway_routes
61
- # Reject homepage. Otherwise we have 60 - 1 resources on the first page.
115
+ # Reject homepage. Otherwise we have 200 - 1 resources on the first page.
62
116
  # There's a next call in ApiResources.add_gateway_resources to skip the homepage.
63
117
  all_paths = Jets::Router.all_paths.reject { |p| p == '' }
64
118
  all_paths.each_slice(PAGE_LIMIT).each_with_index do |paths, i|
data/lib/jets/cfn/ship.rb CHANGED
@@ -102,7 +102,7 @@ module Jets::Cfn
102
102
  end
103
103
 
104
104
  def clean_deploy_logs
105
- Jets::Commands::Clean::Log.new.clean_deploys
105
+ Jets::Commands::Clean::Log.new(@options).clean_deploys
106
106
  end
107
107
 
108
108
  def endpoint_unavailable?
@@ -146,6 +146,7 @@ module Jets::Cfn
146
146
  # domain_name is a method on the Jets::Resource::ApiGateway::Domain instance
147
147
  url = "https://#{domain_name.domain_name}"
148
148
  puts "Custom Domain: #{url}"
149
+ puts "App Domain: #{Jets.config.app.domain}" if Jets.config.app.domain
149
150
  end
150
151
 
151
152
  # All CloudFormation states listed here:
data/lib/jets/cli.rb CHANGED
@@ -135,12 +135,17 @@ class Jets::CLI
135
135
  return Jets::Commands::Base.klass_from_namespace(namespace)
136
136
  end
137
137
 
138
+ return unless jets_project?
138
139
  rake_task_found = Jets::Commands::RakeCommand.namespaced_commands.include?(full_command)
139
140
  if rake_task_found
140
141
  return Jets::Commands::RakeCommand
141
142
  end
142
143
  end
143
144
 
145
+ def jets_project?
146
+ File.exist?("config/application.rb")
147
+ end
148
+
144
149
  # ["-h", "-?", "--help", "-D", "help"]
145
150
  def help_flags
146
151
  Thor::HELP_MAPPINGS + ["help"]
@@ -161,7 +166,7 @@ class Jets::CLI
161
166
  shell.say "Commands:"
162
167
  shell.print_table(thor_list, :indent => 2, :truncate => true)
163
168
 
164
- unless rake_list.empty?
169
+ if jets_project? && !rake_list.empty?
165
170
  shell.say "\nCommands via rake:"
166
171
  shell.print_table(rake_list, :indent => 2, :truncate => true)
167
172
  end
@@ -138,7 +138,7 @@ class Jets::Commands::Base < Thor
138
138
  def eager_load!
139
139
  return if Jets::Turbo.afterburner?
140
140
 
141
- Jets::Autoloaders.once.eager_load
141
+ Jets::Autoloaders.cli.eager_load
142
142
  end
143
143
  memoize :eager_load!
144
144
  end
@@ -59,8 +59,9 @@ class Jets::Commands::Call
59
59
  payload: transformed_event, # "fileb://file-path/input.json", <= JSON
60
60
  qualifier: @qualifier, # "1",
61
61
  }
62
+
62
63
  begin
63
- resp = aws_lambda.invoke(options)
64
+ resp = lambda_client.invoke(options)
64
65
  rescue Aws::Lambda::Errors::ResourceNotFoundException
65
66
  puts "The function #{function_name} was not found. Maybe check the spelling or the AWS_PROFILE?".color(:red)
66
67
  return
@@ -166,4 +167,16 @@ class Jets::Commands::Call
166
167
  $stderr.puts(text)
167
168
  end
168
169
 
170
+ def lambda_client
171
+ opt = {}
172
+ opt = opt.merge({retry_limit: @options[:retry_limit]}) if @options[:retry_limit].present?
173
+ opt = opt.merge({http_read_timeout: @options[:read_timeout]}) if @options[:read_timeout].present?
174
+
175
+ if opt.empty?
176
+ aws_lambda
177
+ else
178
+ Aws::Lambda::Client.new(opt)
179
+ end
180
+ end
181
+
169
182
  end
@@ -2,7 +2,7 @@ module Jets::Commands
2
2
  class Clean < Jets::Commands::Base
3
3
  class_option :noop, type: :boolean, desc: "noop or dry-run mode"
4
4
  class_option :mute, type: :boolean, desc: "mute output"
5
- class_option :sure, type: :boolean, desc: "bypass are you sure prompt"
5
+ class_option :yes, type: :boolean, desc: "bypass are you sure prompt"
6
6
 
7
7
  desc "log", "Cleans CloudWatch log groups assocated with app"
8
8
  long_desc Help.text('clean:log')
@@ -11,7 +11,7 @@ class Jets::Commands::Clean
11
11
  end
12
12
 
13
13
  def are_you_sure?(message)
14
- return true if @options[:sure]
14
+ return true if @options[:yes]
15
15
 
16
16
  puts "Are you sure that you want to #{message}? (y/N)"
17
17
  yes = $stdin.gets.strip
@@ -0,0 +1,51 @@
1
+ module Jets::Commands
2
+ class Configure
3
+ extend Memoist
4
+
5
+ def initialize(options)
6
+ @options = options
7
+ end
8
+
9
+ def run
10
+ data = load_yaml
11
+ data['key'] = token
12
+ FileUtils.mkdir_p(File.dirname(path))
13
+ IO.write(path, YAML.dump(data))
14
+ puts "Updated #{pretty(path)}"
15
+ end
16
+
17
+ def load_yaml
18
+ if File.exist?(path)
19
+ YAML.load_file(path)
20
+ else
21
+ {}
22
+ end
23
+ rescue Psych::SyntaxError => e
24
+ puts "WARN: There was an error reading #{pretty(path)}".color(:yellow)
25
+ puts "WARN: #{e.class} #{e.message}".color(:yellow)
26
+ {}
27
+ end
28
+
29
+ def pretty(path)
30
+ path.sub(ENV['HOME'], '~')
31
+ end
32
+
33
+ def path
34
+ "#{ENV['HOME']}/.jets/config.yml"
35
+ end
36
+
37
+ def token
38
+ @options[:token] || prompt
39
+ end
40
+ memoize :token
41
+
42
+ def prompt
43
+ puts <<~EOL
44
+ You are about to configure your ~/.jets/config.yml
45
+ You can get a token from serverlessgems.com
46
+ EOL
47
+ print "Please provide your token: "
48
+ $stdin.gets.strip
49
+ end
50
+ end
51
+ end
@@ -39,7 +39,7 @@ class Jets::Commands::Delete
39
39
 
40
40
  def delete_logs
41
41
  puts "Deleting CloudWatch logs"
42
- log = Jets::Commands::Clean::Log.new(mute: true, sure: true)
42
+ log = Jets::Commands::Clean::Log.new(mute: true, yes: true)
43
43
  log.clean
44
44
  end
45
45
 
@@ -114,7 +114,7 @@ class Jets::Commands::Delete
114
114
  end
115
115
 
116
116
  def are_you_sure?
117
- if @options[:sure]
117
+ if @options[:yes]
118
118
  sure = 'y'
119
119
  else
120
120
  puts "Are you sure you want to want to delete the #{Jets.config.project_namespace.color(:green)} project? (y/N)"
@@ -2,20 +2,12 @@ module Jets::Commands
2
2
  class Gems < Jets::Commands::Base
3
3
  desc "check", "Check if pre-built Lambda gems are available from the sources"
4
4
  long_desc Help.text("gems:check")
5
+ option :show_source, type: :boolean, desc: "Show source"
5
6
  def check
6
- check = Jets::Gems::Check.new
7
+ check = Jets::Gems::Check.new(@options)
7
8
  check.run! # exits early if missing gems found
8
9
  # If reach here, means all gems are ok.
9
10
  puts "Congrats! All gems are available in as pre-built Lambda gems 👍"
10
11
  end
11
-
12
- desc "sources", "List pre-built Lambda gem sources"
13
- long_desc Help.text("gems:sources")
14
- def sources
15
- puts "Your pre-built Lambda gem sources are:"
16
- Jets.config.gems.sources.each do |source|
17
- puts " #{source}"
18
- end
19
- end
20
12
  end
21
13
  end