jets 2.2.5 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f191f33dde592fc0b2aaa7b5959d2955c277ac428ebce5041e1e37133555f6be
4
- data.tar.gz: 195760363e6602d1d983d361371455b2085987fe10255889b410ea72d7e0a173
3
+ metadata.gz: 80c5f0edcf627cb62ec53f7db4daac61b8b6f917d455e7c89c232fdb9c3dcfb9
4
+ data.tar.gz: bba8a0fd1a5d236142183032b4831ccfaaad6f13d54da14a17523ddb594131c5
5
5
  SHA512:
6
- metadata.gz: e8e191c328450dd8b50fce323579ce9fe1859fcb688188eb26b01e48d67117a62f0bf0b29f50b2782bc1f1805bd151453ac904e81c36d95f2c9e05124e442b38
7
- data.tar.gz: 408768c1d40e76ea4a40a6c5cbaf7447c5c5900ce429b91de626b8f8afac2d83ffe36fa79a13252d4c64bfb7979b5ca94f90422872577cfdeb78f0bd0b02d769
6
+ metadata.gz: 799c0964c8c2dca73780688ca0fd648ce659aa23882918694504151d340d0a499dceb8850b91d5ff007c712dbdce830c5857763bf991d4a7a0075a35e4c0bf48
7
+ data.tar.gz: 0c3197ba7f2914a12e4fa919dd08d629b56bc3c08d56942a4c372c53373441a632e0223810719f34d90d0a41bae0c8adbf36eb5173d86c0fc2e15df8bfc4f708
@@ -3,6 +3,9 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  This project *loosely tries* to adhere to [Semantic Versioning](http://semver.org/).
5
5
 
6
+ ## [2.3.0]
7
+ - #377 routes mount support
8
+
6
9
  ## [2.2.5]
7
10
  - #374 fix rspec execution for projects with no database
8
11
  - #375 add jets dotenv:show command
data/backers.md CHANGED
@@ -13,4 +13,5 @@ Funds donated via Patreon go directly to support Tung Nguyen's full-time work on
13
13
  <!--10 start-->
14
14
  - Erlend Finvåg
15
15
  - Nate Clark
16
+ - Hirokatsu Endo
16
17
  <!--10 end-->
@@ -57,6 +57,8 @@ module Jets
57
57
  sts.get_caller_identity.account
58
58
  rescue Aws::Errors::MissingCredentialsError, Aws::Errors::NoSuchEndpointError
59
59
  puts "INFO: You're missing AWS credentials. Only local services are currently available"
60
+ rescue Seahorse::Client::NetworkingError
61
+ puts "INFO: No internet connection available. Only local services are currently available"
60
62
  end
61
63
  end
62
64
  memoize :account
@@ -4,6 +4,7 @@ module Jets::AwsServices
4
4
  @@stack_exists_cache = [] # helps with CloudFormation rate limit
5
5
  def stack_exists?(stack_name)
6
6
  return false if ENV['TEST']
7
+ return true if ENV['JETS_BUILD_NO_INTERNET']
7
8
  return true if @@stack_exists_cache.include?(stack_name)
8
9
 
9
10
  exist = nil
@@ -60,4 +61,4 @@ module Jets::AwsServices
60
61
  out&.output_value
61
62
  end
62
63
  end
63
- end
64
+ end
@@ -131,8 +131,8 @@ module Jets::Commands
131
131
  # how project classes are loaded.
132
132
  # TODO: rework code so that Dir.pwd does not have to be in tmp_code for build to work.
133
133
  #
134
- # app_files method is mainly used to determine what templates to build.
135
- # app_files method is also used to determine what handlers to build.
134
+ # app_files used to determine what CloudFormation templates to build.
135
+ # app_files also used to determine what handlers to build.
136
136
  def app_files
137
137
  paths = []
138
138
  expression = "#{Jets.root}/app/**/**/*.rb"
@@ -224,25 +224,25 @@ module Jets::Commands
224
224
  # The copying of other internal files like views is done in builders/code_builder.rb copy_internal_jets_code
225
225
  def internal_app_files
226
226
  paths = []
227
- controllers = File.expand_path("../../internal/app/controllers/jets", __FILE__)
227
+ internal = File.expand_path("../internal", __dir__)
228
228
 
229
- public_catchall = Jets::Router.has_controller?("Jets::PublicController")
230
- paths << "#{controllers}/public_controller.rb" if public_catchall
231
-
232
- rack_catchall = Jets::Router.has_controller?("Jets::RackController")
233
- paths << "#{controllers}/rack_controller.rb" if rack_catchall
234
-
235
- mailer_controller = Jets::Router.has_controller?("Jets::MailersController")
236
- paths << "#{controllers}/mailers_controller.rb" if mailer_controller
229
+ controllers = "#{internal}/app/controllers/jets"
230
+ paths << "#{controllers}/public_controller.rb" if router_has?("Jets::PublicController")
231
+ paths << "#{controllers}/rack_controller.rb" if router_has?("Jets::RackController")
232
+ paths << "#{controllers}/mailers_controller.rb" if router_has?("Jets::MailersController")
233
+ paths << "#{controllers}/mount_controller.rb" if router_has?("Jets::MountController")
237
234
 
238
235
  if Jets.config.prewarm.enable
239
- jobs = File.expand_path("../../internal/app/jobs/jets", __FILE__)
240
- paths << "#{jobs}/preheat_job.rb"
236
+ paths << "#{internal}/app/jobs/jets/preheat_job.rb"
241
237
  end
242
238
 
243
239
  paths
244
240
  end
245
241
 
242
+ def router_has?(controller)
243
+ Jets::Router.has_controller?(controller)
244
+ end
245
+
246
246
  def tmp_code(full_build_path=false)
247
247
  full_build_path ? "#{Jets.build_root}/stage/code" : "stage/code"
248
248
  end
@@ -11,8 +11,8 @@ module Jets::Commands::StackInfo
11
11
 
12
12
  def s3_bucket
13
13
  return @s3_bucket if @s3_bucket
14
-
15
14
  return nil if first_run?
15
+ return "fake-bucket" if ENV['JETS_BUILD_NO_INTERNET']
16
16
 
17
17
  resp = cfn.describe_stacks(stack_name: parent_stack_name)
18
18
  output = resp.stacks[0].outputs.find {|o| o.output_key == 'S3Bucket'}
@@ -31,6 +31,7 @@ class Jets::Controller
31
31
  # it doesnt create a lambda function. It's doesnt matter what scope process!
32
32
  # is in Controller::Base because Jets lambda functions inheritance doesnt
33
33
  # include methods in Controller::Base.
34
+ # TODO: Can process! be a protected method to avoid this?
34
35
  controller.send(:process!)
35
36
  end
36
37
 
@@ -49,11 +50,30 @@ class Jets::Controller
49
50
  'lambda.event' => event,
50
51
  'lambda.meth' => meth,
51
52
  )
52
- # adapter.process ultimately calls app controller action at the very last
53
- # middleware stack.
53
+
54
+ # adapter.process calls
55
+ #
56
+ # Jets.application.call(env)
57
+ #
58
+ # and that goes through the middleware stacks. The last middleware stack is Jets::Controller::Middleware::Main
59
+ #
60
+ # class Jets::Controller::Middleware::Main
61
+ # def call!
62
+ # setup
63
+ # @controller.dispatch! # Returns triplet
64
+ # end
65
+ # end
66
+ #
54
67
  adapter.process # Returns API Gateway hash structure
55
68
  end
56
69
 
70
+ # One key difference between process! vs dispatch!
71
+ #
72
+ # process! - takes the request through the middleware stack
73
+ # dispatch! - does not
74
+ #
75
+ # dispatch! is useful for megamode or mounted applications
76
+ #
57
77
  def dispatch!
58
78
  t1 = Time.now
59
79
  log_info_start
@@ -30,9 +30,10 @@ module Jets::Controller::Middleware
30
30
  status, headers, body = @controller.dispatch! # jets/rack_controller
31
31
  headers.delete "transfer-encoding"
32
32
  [status, headers, body]
33
+ elsif route.to == 'jets/mount#call' # mount route
34
+ status, headers, body = @controller.dispatch! # jets/mount_controller
35
+ [status, headers, body]
33
36
  elsif polymorphic_function?
34
- # Will never hit when calling polymorphic function on AWS Lambda.
35
- # This can only really get called with the local server.
36
37
  run_polymophic_function
37
38
  else # Normal Jets request
38
39
  mimic_aws_lambda!(env, mimic.vars) unless on_aws?(env)
@@ -40,7 +41,9 @@ module Jets::Controller::Middleware
40
41
  end
41
42
  end
42
43
 
44
+ # Never hit when calling polymorphic function on AWS Lambda. Can only get called with the local server.
43
45
  def polymorphic_function?
46
+ return false if ENV['_HANDLER'] # slight speed improvement on Lambda
44
47
  polymorphic_function.task.lang != :ruby
45
48
  end
46
49
 
@@ -7,7 +7,7 @@ module Kernel
7
7
  def require(path)
8
8
  # Hack to prevent Rails const from being defined
9
9
  # Actionview requires "rails-html-sanitizer" and that creates a Rails module
10
- path = "jets-html-sanitizer" if path == "rails-html-sanitizer"
10
+ path = "jets-html-sanitizer" if path == "rails-html-sanitizer" && !ENV['JETS_RAILS_CONST']
11
11
  jets_original_require(path)
12
12
  end
13
13
  end
@@ -32,6 +32,8 @@ class Jets::Dotenv
32
32
  end
33
33
 
34
34
  def fetch_ssm_value(key, value)
35
+ return "fake-ssm-value" if ENV['JETS_BUILD_NO_INTERNET']
36
+
35
37
  name = value.start_with?("/") ? value :
36
38
  "/#{Jets.config.project_name}/#{Jets.env}/#{value}"
37
39
  response = ssm.get_parameter(name: name, with_decryption: true)
@@ -45,4 +47,4 @@ class Jets::Dotenv
45
47
  @ssm ||= Aws::SSM::Client.new
46
48
  end
47
49
  end
48
- end
50
+ end
@@ -0,0 +1,16 @@
1
+ # Parent class for MountController and RackController
2
+ class Jets::BareController < Jets::Controller::Base
3
+ layout false
4
+ internal true
5
+ skip_forgery_protection
6
+
7
+ private
8
+ # Override process! so it doesnt go through the complete Jets project middleware stack which could interfer with
9
+ # the mounted Rack app.
10
+ def process!
11
+ status, headers, body = dispatch!
12
+ # Use the adapter only to convert the Rack triplet to a API Gateway hash structure
13
+ adapter = Jets::Controller::Rack::Adapter.new(event, context, meth)
14
+ adapter.convert_to_api_gateway(status, headers, body)
15
+ end
16
+ end
@@ -0,0 +1,56 @@
1
+ # routes mount support
2
+ class Jets::MountController < Jets::BareController
3
+ def call
4
+ route = find_route
5
+ # On Lambda, the route should always be found so this check on lambda is not needed.
6
+ # But this is useful when we're testing locally with the shim directly.
7
+ unless route
8
+ render json: {status: "route not found"}, status: 404
9
+ return
10
+ end
11
+
12
+ # The reason we look up the route is because it contains mounted class info
13
+ mount_class = route.mount_class # IE: RackApp
14
+ env = build_env(route.path)
15
+
16
+ status, headers, io = mount_class.call(env)
17
+ body = read_body(io)
18
+ render(
19
+ status: status,
20
+ headers: headers,
21
+ body: body,
22
+ )
23
+ end
24
+
25
+ private
26
+ # Rack response will return an IO object that responds to each. Sometimes this a Rack::BodyProxy
27
+ # Found this to be the case in Rails and Grape.
28
+ # Doing an IO#read may not work. So we'll always use the IO#each method
29
+ def read_body(io)
30
+ result = []
31
+ io.each { |body| result << body }
32
+ result.join
33
+ end
34
+
35
+ # Locally Jets::Router::Finder gets called twice because it also gets called in Jets::Controller::Middleware::Local
36
+ # On Lambda, Jets::Router::Finder only gets called once.
37
+ # TODO: Maybe add caching improvement.
38
+ def find_route
39
+ Jets::Router::Finder.new(event["path"], "ANY").run
40
+ end
41
+
42
+ def build_env(path)
43
+ env = Jets::Controller::Rack::Env.new(event, context, adapter: true).convert
44
+ # remap path info
45
+ mount_at = mount_at(path)
46
+ path_info = env["PATH_INFO"]
47
+ env["PATH_INFO"] = path_info.sub(mount_at,'')
48
+ env["ORIGINAL_PATH_INFO"] = path_info
49
+ env
50
+ end
51
+
52
+ # Removes the wildcard: rack/*path => rack
53
+ def mount_at(path)
54
+ path.gsub(/\*.*/,'')
55
+ end
56
+ end
@@ -1,8 +1,4 @@
1
- class Jets::RackController < Jets::Controller::Base
2
- layout false
3
- internal true
4
- skip_forgery_protection
5
-
1
+ class Jets::RackController < Jets::BareController
6
2
  # Megamode
7
3
  def process
8
4
  resp = mega_request
@@ -10,16 +6,6 @@ class Jets::RackController < Jets::Controller::Base
10
6
  end
11
7
 
12
8
  private
13
- # Override process! so it doesnt go through middleware adapter and hits
14
- # process logic directly. This handles the case for AWS Lambda.
15
- # For local server, we adjust the Middleware::Local logic.
16
- def process!
17
- status, headers, body = dispatch!
18
- # Use the adapter only to convert the Rack triplet to a API Gateway hash structure
19
- adapter = Jets::Controller::Rack::Adapter.new(event, context, meth)
20
- adapter.convert_to_api_gateway(status, headers, body)
21
- end
22
-
23
9
  def mega_request
24
10
  Jets::Mega::Request.new(event, self).proxy
25
11
  end
@@ -1,6 +1,7 @@
1
1
  ActiveSupport.on_load :action_controller do
2
2
  class ActionController::Base
3
3
  class << self
4
+ @@_prefixes = nil
4
5
  def _prefixes
5
6
  @@_prefixes
6
7
  end
@@ -4,6 +4,7 @@ class Jets::Resource::ApiGateway::RestApi
4
4
  include Jets::AwsServices
5
5
 
6
6
  def get
7
+ return default if ENV['JETS_BUILD_NO_INTERNET']
7
8
  return default unless stack_exists?(parent_stack_name) && api_gateway_exists?
8
9
 
9
10
  if changed?
@@ -1,5 +1,7 @@
1
1
  class Jets::Router
2
2
  module Dsl
3
+ include Mount
4
+
3
5
  # Methods supported by API Gateway
4
6
  %w[any delete get head options patch post put].each do |method_name|
5
7
  define_method method_name do |path, options={}|
@@ -0,0 +1,12 @@
1
+ module Jets::Router::Dsl
2
+ module Mount
3
+ # The mounted class must be a Rack compatiable class
4
+ def mount(klass, at:)
5
+ options = {to: "jets/mount#call", mount_class: klass}
6
+ at_wildcard = at.blank? ? "*path" : "#{at}/*path"
7
+
8
+ any at, options
9
+ any at_wildcard, options
10
+ end
11
+ end
12
+ end
@@ -30,7 +30,9 @@ class Jets::Router
30
30
  prefix = account_scope(prefix)
31
31
  prefix = account_on(prefix)
32
32
 
33
- [prefix, @options[:path]].compact.join('/')
33
+ path = [prefix, @options[:path]].compact.join('/')
34
+ path = path[1..-1] if path.starts_with?('/') # be more forgiving if / accidentally included
35
+ path
34
36
  end
35
37
 
36
38
  def account_scope(prefix)
@@ -185,6 +187,10 @@ class Jets::Router
185
187
  end.to_h
186
188
  end
187
189
 
190
+ def mount_class
191
+ @options[:mount_class]
192
+ end
193
+
188
194
  private
189
195
  def ensure_jets_format(path)
190
196
  path.split('/').map do |s|
@@ -1,3 +1,3 @@
1
1
  module Jets
2
- VERSION = "2.2.5"
2
+ VERSION = "2.3.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jets
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.5
4
+ version: 2.3.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-09-27 00:00:00.000000000 Z
11
+ date: 2019-09-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionmailer
@@ -802,7 +802,9 @@ files:
802
802
  - lib/jets/generator/templates/rails/scaffold_controller/api_controller.rb
803
803
  - lib/jets/generator/templates/rails/scaffold_controller/controller.rb
804
804
  - lib/jets/inflections.rb
805
+ - lib/jets/internal/app/controllers/jets/bare_controller.rb
805
806
  - lib/jets/internal/app/controllers/jets/mailers_controller.rb
807
+ - lib/jets/internal/app/controllers/jets/mount_controller.rb
806
808
  - lib/jets/internal/app/controllers/jets/public_controller.rb
807
809
  - lib/jets/internal/app/controllers/jets/rack_controller.rb
808
810
  - lib/jets/internal/app/functions/jets/base_path.rb
@@ -925,6 +927,7 @@ files:
925
927
  - lib/jets/resource/standardizer.rb
926
928
  - lib/jets/router.rb
927
929
  - lib/jets/router/dsl.rb
930
+ - lib/jets/router/dsl/mount.rb
928
931
  - lib/jets/router/error.rb
929
932
  - lib/jets/router/finder.rb
930
933
  - lib/jets/router/helpers.rb