jets 1.5.9 → 1.5.10

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: 139636b38cc75e1677d5590c3ed58b2aa62615d8eb0ab2881e10617a7ecbcf42
4
- data.tar.gz: e319b191d08ed15475f644c8348edac60e8a55c9e21f9b4aa8b3605a12fa6f10
3
+ metadata.gz: 39b6cde7b66e43e4c253e0f055952680298287d9e7c534c4a465ca075b3dfb62
4
+ data.tar.gz: d3312104416979ca67bd31cebd3a7c2ba604185349c2c368de438d50a68914ef
5
5
  SHA512:
6
- metadata.gz: e1dbcc0bf66eb73a9d2ff93b1ba95044d4026734beff95bf16ead0ff3f2c5d2461738cf3ff82fc0f116729024a4a7c4ffb49d5bf7babe6469be6145610ca55c8
7
- data.tar.gz: 3f6987b22c59c6dfdd294cfd81ce1de23eec5e386ec7b82b91c698c9a6956874f479a5bb31274790b511953329eca208a98eab7a98b33b7483448229ddc772bd
6
+ metadata.gz: 1b670d6b6a2c0189fd608d4a7ba61a02206a4ddf78d2c8eda2c4f06d8c4c1beddb2588b417211e697ea0b24f8c426975c9ab08819a56fc3da41f6c959fb272ca
7
+ data.tar.gz: c84383ea55a03f9b0576fb5ea7c4a895a9e5ae818bd79df008a9e7f621f93ce2d5e4e189d7f4aa9a9a2c0fef12ae7a668747308b263785de0b8d0c46da8330f7
@@ -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/), even before v1.0.
5
5
 
6
+ ## [1.5.10]
7
+ - #157 Improve Route Change Detection: Path Variables
8
+
6
9
  ## [1.5.9]
7
10
  - #154 from tongueroo/variable-collision raise error on multiple sibling variable paths collision
8
11
  - #156 from konnected-io/master: don't prewarm jobs, only prewarm controllers
@@ -11,7 +11,7 @@ GIT
11
11
  PATH
12
12
  remote: .
13
13
  specs:
14
- jets (1.5.9)
14
+ jets (1.5.10)
15
15
  activerecord (~> 5.2.1)
16
16
  activesupport (~> 5.2.1)
17
17
  aws-sdk-apigateway
@@ -66,7 +66,7 @@ GEM
66
66
  tzinfo (~> 1.1)
67
67
  arel (9.0.0)
68
68
  aws-eventstream (1.0.1)
69
- aws-partitions (1.132.0)
69
+ aws-partitions (1.133.0)
70
70
  aws-sdk-apigateway (1.23.0)
71
71
  aws-sdk-core (~> 3, >= 3.39.0)
72
72
  aws-sigv4 (~> 1.0)
@@ -87,7 +87,7 @@ GEM
87
87
  aws-sdk-kms (1.13.0)
88
88
  aws-sdk-core (~> 3, >= 3.39.0)
89
89
  aws-sigv4 (~> 1.0)
90
- aws-sdk-lambda (1.16.0)
90
+ aws-sdk-lambda (1.17.0)
91
91
  aws-sdk-core (~> 3, >= 3.39.0)
92
92
  aws-sigv4 (~> 1.0)
93
93
  aws-sdk-s3 (1.30.1)
@@ -134,6 +134,7 @@ JS
134
134
 
135
135
  Scaffold example:
136
136
  jets generate scaffold Post title:string body:text published:boolean
137
+ jets db:create db:migrate
137
138
 
138
139
  To deploy to AWS Lambda, edit your .env.development.remote and add a DATABASE_URL endpoint.
139
140
  Then run:
@@ -55,7 +55,7 @@ module Jets::Resource::ApiGateway::BasePath
55
55
  # Duplicated in rest_api/change_detection.rb, base_path/role.rb, rest_api/routes.rb
56
56
  def rest_api_id
57
57
  stack_name = Jets::Naming.parent_stack_name
58
- return default unless stack_exists?(stack_name)
58
+ return "RestApi" unless stack_exists?(stack_name)
59
59
 
60
60
  stack = cfn.describe_stacks(stack_name: stack_name).stacks.first
61
61
 
@@ -6,7 +6,6 @@ class Jets::Resource::ApiGateway::RestApi
6
6
  def get
7
7
  return default unless stack_exists?(parent_stack_name) && api_gateway_exists?
8
8
 
9
-
10
9
  if changed?
11
10
  new_id
12
11
  else
@@ -1,114 +1,12 @@
1
1
  # Detects route changes
2
2
  class Jets::Resource::ApiGateway::RestApi::Routes
3
- class Change < Base
4
- def changed?
5
- deployed_routes.each do |deployed_route|
6
- new_route = find_comparable_route(deployed_route)
7
- if new_route && new_route.to != deployed_route.to
8
- # change in already deployed route has been detected, requires bluegreen deploy
9
- return true
10
- end
11
- end
12
- false # Reaching here means no routes have been changed in a way that requires a bluegreen deploy
13
- end
14
-
15
- # Build up deployed routes from the existing CloudFormation resources.
16
- def deployed_routes
17
- routes = []
18
-
19
- resources, position = [], true
20
- while position
21
- position = nil if position == true # start of loop
22
- resp = apigateway.get_resources(
23
- rest_api_id: rest_api_id,
24
- position: position,
25
- )
26
- resources += resp.items
27
- position = resp.position
28
- end
29
-
30
- resources.each do |resource|
31
- resource_methods = resource.resource_methods
32
- next if resource_methods.nil?
33
-
34
- resource_methods.each do |http_verb, resource_method|
35
- # puts "#{http_verb} #{resource.path} | resource.id #{resource.id}"
36
- # puts to(resource.id, http_verb)
3
+ class Change
4
+ autoload :Base, 'jets/resource/api_gateway/rest_api/routes/change/base'
5
+ autoload :To, 'jets/resource/api_gateway/rest_api/routes/change/to'
6
+ autoload :Variable, 'jets/resource/api_gateway/rest_api/routes/change/variable'
37
7
 
38
- # Test changing config.cors and CloudFormation does an in-place update
39
- # on the resource. So no need to do bluegreen deployments for OPTIONS.
40
- next if http_verb == "OPTIONS"
41
-
42
- path = recreate_path(resource.path)
43
- method = http_verb.downcase.to_sym
44
- to = to(resource.id, http_verb)
45
- route = Jets::Route.new(path: path, method: method, to: to)
46
- routes << route
47
- end
48
- end
49
- routes
50
- end
51
- memoize :deployed_routes
52
-
53
- # Find a route that has the same path and method. This is a comparable route
54
- # Then we will compare the to or controller action to see if an already
55
- # deployed route has been changed.
56
- def find_comparable_route(deployed_route)
57
- new_routes.find do |new_route|
58
- new_route.path == deployed_route.path &&
59
- new_route.method == deployed_route.method
60
- end
61
- end
62
-
63
- def recreate_path(path)
64
- path = path.gsub(%r{^/},'')
65
- path = path.sub(/{(.*)\+}/, '*\1')
66
- path.sub(/{(.*)}/, ':\1')
67
- end
68
-
69
- def to(resource_id, http_method)
70
- uri = method_uri(resource_id, http_method)
71
- recreate_to(uri) unless uri.nil?
72
- end
73
-
74
- def method_uri(resource_id, http_method)
75
- resp = apigateway.get_method(
76
- rest_api_id: rest_api_id,
77
- resource_id: resource_id,
78
- http_method: http_method
79
- )
80
- resp.method_integration.uri
81
- end
82
-
83
- # Parses method uri and recreates a Route to argument.
84
- # So:
85
- # "arn:aws:apigateway:us-west-2:lambda:path/2015-03-31/functions/arn:aws:lambda:us-west-2:112233445566:function:demo-test-posts_controller-new/invocations"
86
- # Returns:
87
- # posts#new
88
- def recreate_to(method_uri)
89
- md = method_uri.match(/function:(.*)\//)
90
- function_name = md[1] # IE: demo-dev-posts_controller-new
91
- controller_action = function_name.sub("#{Jets.project_namespace}-", '')
92
- md = controller_action.match(/(.*)_controller-(.*)/)
93
- controller = md[1]
94
- controller = controller.gsub('-','/')
95
- action = md[2]
96
- "#{controller}##{action}" # IE: posts#new
97
- end
98
-
99
- # Duplicated in rest_api/change_detection.rb, base_path/role.rb, rest_api/routes.rb
100
- def rest_api_id
101
- stack_name = Jets::Naming.parent_stack_name
102
- return default unless stack_exists?(stack_name)
103
-
104
- stack = cfn.describe_stacks(stack_name: stack_name).stacks.first
105
-
106
- api_gateway_stack_arn = lookup(stack[:outputs], "ApiGateway")
107
-
108
- # resources = cfn.describe_stack_resources(stack_name: api_gateway_stack_arn).stack_resources
109
- stack = cfn.describe_stacks(stack_name: api_gateway_stack_arn).stacks.first
110
- lookup(stack[:outputs], "RestApi") # rest_api_id
8
+ def changed?
9
+ To.changed? || Variable.changed? || ENV['JETS_REPLACE_API']
111
10
  end
112
- memoize :rest_api_id
113
11
  end
114
12
  end
@@ -0,0 +1,100 @@
1
+ class Jets::Resource::ApiGateway::RestApi::Routes::Change
2
+ class Base
3
+ extend Memoist
4
+ include Jets::AwsServices
5
+
6
+ # Build up deployed routes from the existing CloudFormation resources.
7
+ def deployed_routes
8
+ routes = []
9
+
10
+ resources, position = [], true
11
+ while position
12
+ position = nil if position == true # start of loop
13
+ resp = apigateway.get_resources(
14
+ rest_api_id: rest_api_id,
15
+ position: position,
16
+ )
17
+ resources += resp.items
18
+ position = resp.position
19
+ end
20
+
21
+ resources.each do |resource|
22
+ resource_methods = resource.resource_methods
23
+ next if resource_methods.nil?
24
+
25
+ resource_methods.each do |http_verb, resource_method|
26
+ # puts "#{http_verb} #{resource.path} | resource.id #{resource.id}"
27
+ # puts to(resource.id, http_verb)
28
+
29
+ # Test changing config.cors and CloudFormation does an in-place update
30
+ # on the resource. So no need to do bluegreen deployments for OPTIONS.
31
+ next if http_verb == "OPTIONS"
32
+
33
+ path = recreate_path(resource.path)
34
+ method = http_verb.downcase.to_sym
35
+ to = to(resource.id, http_verb)
36
+ route = Jets::Route.new(path: path, method: method, to: to)
37
+ routes << route
38
+ end
39
+ end
40
+ routes
41
+ end
42
+ memoize :deployed_routes
43
+
44
+ def recreate_path(path)
45
+ path = path.gsub(%r{^/},'')
46
+ path = path.sub(/{(.*)\+}/, '*\1')
47
+ path.sub(/{(.*)}/, ':\1')
48
+ end
49
+
50
+ def to(resource_id, http_method)
51
+ uri = method_uri(resource_id, http_method)
52
+ recreate_to(uri) unless uri.nil?
53
+ end
54
+
55
+ def method_uri(resource_id, http_method)
56
+ resp = apigateway.get_method(
57
+ rest_api_id: rest_api_id,
58
+ resource_id: resource_id,
59
+ http_method: http_method
60
+ )
61
+ resp.method_integration.uri
62
+ end
63
+
64
+ # Parses method uri and recreates a Route to argument.
65
+ # So:
66
+ # "arn:aws:apigateway:us-west-2:lambda:path/2015-03-31/functions/arn:aws:lambda:us-west-2:112233445566:function:demo-test-posts_controller-new/invocations"
67
+ # Returns:
68
+ # posts#new
69
+ def recreate_to(method_uri)
70
+ md = method_uri.match(/function:(.*)\//)
71
+ function_name = md[1] # IE: demo-dev-posts_controller-new
72
+ controller_action = function_name.sub("#{Jets.project_namespace}-", '')
73
+ md = controller_action.match(/(.*)_controller-(.*)/)
74
+ controller = md[1]
75
+ controller = controller.gsub('-','/')
76
+ action = md[2]
77
+ "#{controller}##{action}" # IE: posts#new
78
+ end
79
+
80
+ # Duplicated in rest_api/change_detection.rb, base_path/role.rb, rest_api/routes.rb
81
+ def rest_api_id
82
+ stack_name = Jets::Naming.parent_stack_name
83
+ return "RestApi" unless stack_exists?(stack_name)
84
+
85
+ stack = cfn.describe_stacks(stack_name: stack_name).stacks.first
86
+
87
+ api_gateway_stack_arn = lookup(stack[:outputs], "ApiGateway")
88
+
89
+ # resources = cfn.describe_stack_resources(stack_name: api_gateway_stack_arn).stack_resources
90
+ stack = cfn.describe_stacks(stack_name: api_gateway_stack_arn).stacks.first
91
+ lookup(stack[:outputs], "RestApi") # rest_api_id
92
+ end
93
+ memoize :rest_api_id
94
+
95
+ def new_routes
96
+ Jets::Router.routes
97
+ end
98
+ memoize :new_routes
99
+ end
100
+ end
@@ -0,0 +1,29 @@
1
+ # Detects route to changes
2
+ class Jets::Resource::ApiGateway::RestApi::Routes::Change
3
+ class To < Base
4
+ def self.changed?
5
+ new.changed?
6
+ end
7
+
8
+ def changed?
9
+ deployed_routes.each do |deployed_route|
10
+ new_route = find_comparable_route(deployed_route)
11
+ if new_route && new_route.to != deployed_route.to
12
+ # change in already deployed route has been detected, requires bluegreen deploy
13
+ return true
14
+ end
15
+ end
16
+ false # Reaching here means no routes have been changed in a way that requires a bluegreen deploy
17
+ end
18
+
19
+ # Find a route that has the same path and method. This is a comparable route
20
+ # Then we will compare the to or controller action to see if an already
21
+ # deployed route has been changed.
22
+ def find_comparable_route(deployed_route)
23
+ new_routes.find do |new_route|
24
+ new_route.path == deployed_route.path &&
25
+ new_route.method == deployed_route.method
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,39 @@
1
+ # Detects route variable changes
2
+ class Jets::Resource::ApiGateway::RestApi::Routes::Change
3
+ class Variable < Base
4
+ def self.changed?
5
+ new.changed?
6
+ end
7
+
8
+ def changed?
9
+ changed = false
10
+ deployed_routes.each do |deployed_route|
11
+ parent = collision.variable_parent(deployed_route.path)
12
+ parent_variables = collision.parent_variables(parent, [deployed_route.path])
13
+ new_parent_variables = collision.parent_variables(parent, new_paths)
14
+
15
+ changed = parent_variables.size > 0 && new_parent_variables.size > 0 &&
16
+ parent_variables != new_parent_variables
17
+ break if changed
18
+ end
19
+ changed
20
+ end
21
+
22
+ # Only consider paths with variables
23
+ def new_paths
24
+ new_routes.map(&:path).select {|p| p.include?(':')}.uniq
25
+ end
26
+
27
+ # Only consider deployed routes with variables
28
+ def deployed_routes
29
+ deployed_routes = super
30
+ deployed_routes.select do |route|
31
+ route.path.include?(':')
32
+ end
33
+ end
34
+
35
+ def collision
36
+ @collision ||= Jets::Resource::ApiGateway::RestApi::Routes::Collision.new
37
+ end
38
+ end
39
+ end
@@ -1,16 +1,15 @@
1
1
  # Detects path variable collisions
2
2
  class Jets::Resource::ApiGateway::RestApi::Routes
3
- class Collision < Base
3
+ class Collision
4
4
  autoload :VariableException, 'jets/resource/api_gateway/rest_api/routes/collision/variable_exception'
5
5
 
6
6
  attr_reader :collisions
7
- def initialize(routes)
8
- @routes = routes
7
+ def initialize
9
8
  @collisions = []
10
9
  end
11
10
 
12
- def collision?
13
- paths = paths_with_variables(@routes.map(&:path))
11
+ def collision?(paths)
12
+ paths = paths_with_variables(paths)
14
13
  parents = variable_parents(paths)
15
14
 
16
15
  collide = false
@@ -21,7 +20,11 @@ class Jets::Resource::ApiGateway::RestApi::Routes
21
20
  end
22
21
 
23
22
  def exception
24
- collision_message = <<~EOL
23
+ VariableException.new(collision_message)
24
+ end
25
+
26
+ def collision_message
27
+ <<~EOL
25
28
  There are routes with sibling variables under the same parent that collide.
26
29
 
27
30
  Collisions:
@@ -34,7 +37,6 @@ class Jets::Resource::ApiGateway::RestApi::Routes
34
37
  Please check your `config/routes.rb` and remove the colliding routes.
35
38
  More info: http://rubyonjets.com/docs/considerations-api-gateway/
36
39
  EOL
37
- VariableException.new(collision_message)
38
40
  end
39
41
 
40
42
  def variable_collision_exists?(parent, paths)
@@ -88,13 +90,9 @@ class Jets::Resource::ApiGateway::RestApi::Routes
88
90
  parents.uniq.sort
89
91
  end
90
92
 
91
- def paths_with_variables(paths)
92
- paths.select { |p| p.include?(':') }.uniq
93
- end
94
-
95
93
  # Strips the path down until only the leaf node part is a variable
96
94
  # Example: users/:user_id/posts/:post_id/edit
97
- # Returns: users/:user_id/posts/:post_id
95
+ # Returns: users/:user_id/posts
98
96
  def variable_parent(path)
99
97
  path = variable_leaf(path)
100
98
  # drop last variable to leave behind the parent
@@ -105,7 +103,7 @@ class Jets::Resource::ApiGateway::RestApi::Routes
105
103
  # Example: users/:user_id/posts/:post_id/edit
106
104
  # Returns: users/:user_id/posts
107
105
  def variable_leaf(path)
108
- return unless path.include?(':')
106
+ return '' unless path.include?(':')
109
107
 
110
108
  parts = path.split('/')
111
109
  is_variable = parts.last.include?(':')
@@ -115,5 +113,9 @@ class Jets::Resource::ApiGateway::RestApi::Routes
115
113
  end
116
114
  parts[0..-1].join('/') # parent
117
115
  end
116
+
117
+ def paths_with_variables(paths)
118
+ paths.select { |p| p.include?(':') }.uniq
119
+ end
118
120
  end
119
121
  end
@@ -16,8 +16,9 @@ module Jets
16
16
 
17
17
  # Validate routes that deployable
18
18
  def check_collision!
19
- collision = Jets::Resource::ApiGateway::RestApi::Routes::Collision.new(self.routes)
20
- collide = collision.collision?
19
+ paths = self.routes.map(&:path)
20
+ collision = Jets::Resource::ApiGateway::RestApi::Routes::Collision.new
21
+ collide = collision.collision?(paths)
21
22
  raise collision.exception if collide
22
23
  end
23
24
 
@@ -1,3 +1,3 @@
1
1
  module Jets
2
- VERSION = "1.5.9"
2
+ VERSION = "1.5.10"
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: 1.5.9
4
+ version: 1.5.10
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-01-17 00:00:00.000000000 Z
11
+ date: 2019-01-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -704,8 +704,10 @@ files:
704
704
  - lib/jets/resource/api_gateway/rest_api/change_detection.rb
705
705
  - lib/jets/resource/api_gateway/rest_api/logical_id.rb
706
706
  - lib/jets/resource/api_gateway/rest_api/routes.rb
707
- - lib/jets/resource/api_gateway/rest_api/routes/base.rb
708
707
  - lib/jets/resource/api_gateway/rest_api/routes/change.rb
708
+ - lib/jets/resource/api_gateway/rest_api/routes/change/base.rb
709
+ - lib/jets/resource/api_gateway/rest_api/routes/change/to.rb
710
+ - lib/jets/resource/api_gateway/rest_api/routes/change/variable.rb
709
711
  - lib/jets/resource/api_gateway/rest_api/routes/collision.rb
710
712
  - lib/jets/resource/api_gateway/rest_api/routes/collision/variable_exception.rb
711
713
  - lib/jets/resource/associated.rb
@@ -1,11 +0,0 @@
1
- class Jets::Resource::ApiGateway::RestApi::Routes
2
- class Base
3
- extend Memoist
4
- include Jets::AwsServices
5
-
6
- def new_routes
7
- Jets::Router.routes
8
- end
9
- memoize :new_routes
10
- end
11
- end