jets 2.2.5 → 2.3.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.
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