jets 1.5.8 → 1.5.9
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 +4 -4
- data/CHANGELOG.md +9 -0
- data/Gemfile.lock +4 -4
- data/jets.gemspec +5 -5
- data/lib/jets/builders/ruby_packager.rb +10 -5
- data/lib/jets/commands/deploy.rb +5 -1
- data/lib/jets/commands/upgrade.rb +14 -0
- data/lib/jets/preheat.rb +2 -2
- data/lib/jets/resource/api_gateway/rest_api/routes.rb +4 -120
- data/lib/jets/resource/api_gateway/rest_api/routes/base.rb +11 -0
- data/lib/jets/resource/api_gateway/rest_api/routes/change.rb +114 -0
- data/lib/jets/resource/api_gateway/rest_api/routes/collision.rb +119 -0
- data/lib/jets/resource/api_gateway/rest_api/routes/collision/variable_exception.rb +7 -0
- data/lib/jets/router.rb +8 -0
- data/lib/jets/version.rb +1 -1
- metadata +11 -8
- data/lib/jets/turbo/project/Gemfile.lock +0 -185
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 139636b38cc75e1677d5590c3ed58b2aa62615d8eb0ab2881e10617a7ecbcf42
|
|
4
|
+
data.tar.gz: e319b191d08ed15475f644c8348edac60e8a55c9e21f9b4aa8b3605a12fa6f10
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e1dbcc0bf66eb73a9d2ff93b1ba95044d4026734beff95bf16ead0ff3f2c5d2461738cf3ff82fc0f116729024a4a7c4ffb49d5bf7babe6469be6145610ca55c8
|
|
7
|
+
data.tar.gz: 3f6987b22c59c6dfdd294cfd81ce1de23eec5e386ec7b82b91c698c9a6956874f479a5bb31274790b511953329eca208a98eab7a98b33b7483448229ddc772bd
|
data/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,15 @@
|
|
|
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.9]
|
|
7
|
+
- #154 from tongueroo/variable-collision raise error on multiple sibling variable paths collision
|
|
8
|
+
- #156 from konnected-io/master: don't prewarm jobs, only prewarm controllers
|
|
9
|
+
- ensure remove BUNDLED WITH remove when no project Gemfile.lock and it gets created by build process
|
|
10
|
+
- jets upgrade: add dynomite to gemfile if needed
|
|
11
|
+
- only clean submodules for bundler version 2+
|
|
12
|
+
- turbo wrapper project: remove Gemfile.lock and let afterburner mode run on latest jets version
|
|
13
|
+
- use pessimistic version for dependencies
|
|
14
|
+
|
|
6
15
|
## [1.5.8]
|
|
7
16
|
- #155 remove BUNDLED WITH from Gemfile.lock to fix newly released bundler issue
|
|
8
17
|
|
data/Gemfile.lock
CHANGED
|
@@ -11,9 +11,9 @@ GIT
|
|
|
11
11
|
PATH
|
|
12
12
|
remote: .
|
|
13
13
|
specs:
|
|
14
|
-
jets (1.5.
|
|
15
|
-
activerecord (
|
|
16
|
-
activesupport (
|
|
14
|
+
jets (1.5.9)
|
|
15
|
+
activerecord (~> 5.2.1)
|
|
16
|
+
activesupport (~> 5.2.1)
|
|
17
17
|
aws-sdk-apigateway
|
|
18
18
|
aws-sdk-cloudformation
|
|
19
19
|
aws-sdk-cloudwatchlogs
|
|
@@ -32,7 +32,7 @@ PATH
|
|
|
32
32
|
memoist
|
|
33
33
|
mimemagic
|
|
34
34
|
rack
|
|
35
|
-
railties (
|
|
35
|
+
railties (~> 5.2.1)
|
|
36
36
|
recursive-open-struct
|
|
37
37
|
text-table
|
|
38
38
|
thor
|
data/jets.gemspec
CHANGED
|
@@ -27,10 +27,10 @@ Gem::Specification.new do |spec|
|
|
|
27
27
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
28
28
|
spec.require_paths = ["lib"]
|
|
29
29
|
|
|
30
|
-
# spec.add_dependency "actionpack", "
|
|
31
|
-
# spec.add_dependency "actionview", "
|
|
32
|
-
spec.add_dependency "activerecord", "
|
|
33
|
-
spec.add_dependency "activesupport", "
|
|
30
|
+
# spec.add_dependency "actionpack", "~> 5.2.1" # using vendor/rails version
|
|
31
|
+
# spec.add_dependency "actionview", "~> 5.2.1" # using vendor/rails version
|
|
32
|
+
spec.add_dependency "activerecord", "~> 5.2.1"
|
|
33
|
+
spec.add_dependency "activesupport", "~> 5.2.1"
|
|
34
34
|
spec.add_dependency "aws-sdk-apigateway"
|
|
35
35
|
spec.add_dependency "aws-sdk-cloudformation"
|
|
36
36
|
spec.add_dependency "aws-sdk-cloudwatchlogs"
|
|
@@ -49,7 +49,7 @@ Gem::Specification.new do |spec|
|
|
|
49
49
|
spec.add_dependency "memoist"
|
|
50
50
|
spec.add_dependency "mimemagic"
|
|
51
51
|
spec.add_dependency "rack"
|
|
52
|
-
spec.add_dependency "railties", "
|
|
52
|
+
spec.add_dependency "railties", "~> 5.2.1" # ActiveRecord database_tasks.rb require this
|
|
53
53
|
spec.add_dependency "recursive-open-struct"
|
|
54
54
|
spec.add_dependency "text-table"
|
|
55
55
|
spec.add_dependency "thor"
|
|
@@ -58,6 +58,8 @@ class Jets::Builders
|
|
|
58
58
|
)
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
+
remove_bundled_with("#{cache_area}/Gemfile.lock")
|
|
62
|
+
|
|
61
63
|
# Copy the Gemfile.lock back to the project in case it was updated.
|
|
62
64
|
# For example we add the jets-rails to the Gemfile.
|
|
63
65
|
copy_back_gemfile_lock
|
|
@@ -99,6 +101,8 @@ class Jets::Builders
|
|
|
99
101
|
lockfile = "#{cache_area}/Gemfile.lock"
|
|
100
102
|
return unless File.exist?(lockfile)
|
|
101
103
|
|
|
104
|
+
return if Bundler.bundler_major_version <= 1 # LockfileParser only works for Bundler version 2+
|
|
105
|
+
|
|
102
106
|
parser = Bundler::LockfileParser.new(Bundler.read_file(lockfile))
|
|
103
107
|
specs = parser.specs
|
|
104
108
|
|
|
@@ -131,20 +135,21 @@ class Jets::Builders
|
|
|
131
135
|
|
|
132
136
|
gemfile_lock = "#{full_project_path}/Gemfile.lock"
|
|
133
137
|
dest = "#{cache_area}/Gemfile.lock"
|
|
134
|
-
|
|
135
|
-
|
|
138
|
+
return unless File.exist?(gemfile_lock)
|
|
139
|
+
|
|
140
|
+
FileUtils.cp(gemfile_lock, dest)
|
|
136
141
|
end
|
|
137
142
|
|
|
138
143
|
# Remove the BUNDLED WITH line since we don't control the bundler gem version on AWS Lambda
|
|
139
144
|
# And this can cause issues with require 'bundler/setup'
|
|
140
|
-
def
|
|
141
|
-
lines = IO.readlines(
|
|
145
|
+
def remove_bundled_with(gemfile_lock)
|
|
146
|
+
lines = IO.readlines(gemfile_lock)
|
|
142
147
|
n = lines.index { |l| l.include?("BUNDLED WITH") }
|
|
143
148
|
return unless n
|
|
144
149
|
|
|
145
150
|
new_lines = lines[0..n-1]
|
|
146
151
|
content = new_lines.join('')
|
|
147
|
-
IO.write(
|
|
152
|
+
IO.write(gemfile_lock, content)
|
|
148
153
|
end
|
|
149
154
|
|
|
150
155
|
def setup_bundle_config
|
data/lib/jets/commands/deploy.rb
CHANGED
|
@@ -49,8 +49,12 @@ module Jets::Commands
|
|
|
49
49
|
Jets::Commands::Build.new(@options).build_code
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
-
# Checks that all routes are validate and have corresponding lambda functions
|
|
53
52
|
def validate_routes!
|
|
53
|
+
check_route_connected_functions
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Checks that all routes are validate and have corresponding lambda functions
|
|
57
|
+
def check_route_connected_functions
|
|
54
58
|
return if Jets::Router.all_routes_valid
|
|
55
59
|
|
|
56
60
|
puts "Deploy fail: The jets application contain invalid routes.".colorize(:red)
|
|
@@ -15,6 +15,7 @@ module Jets::Commands
|
|
|
15
15
|
update_config_ru
|
|
16
16
|
remove_ruby_lazy_load
|
|
17
17
|
update_webpack_binstubs
|
|
18
|
+
add_dynomite_to_gemfile
|
|
18
19
|
puts "Upgrade complete."
|
|
19
20
|
end
|
|
20
21
|
|
|
@@ -116,6 +117,19 @@ module Jets::Commands
|
|
|
116
117
|
puts "Updated webpack binstubs."
|
|
117
118
|
end
|
|
118
119
|
|
|
120
|
+
def add_dynomite_to_gemfile
|
|
121
|
+
return unless File.exist?("app/models/application_item.rb")
|
|
122
|
+
|
|
123
|
+
lines = IO.readlines("Gemfile")
|
|
124
|
+
dynomite_found = lines.detect { |l| l =~ /dynomite/ }
|
|
125
|
+
return if dynomite_found
|
|
126
|
+
|
|
127
|
+
File.open('Gemfile', 'a') do |f|
|
|
128
|
+
f.puts 'gem "dynomite"'
|
|
129
|
+
end
|
|
130
|
+
puts "Updated Gemfile: add dynomite gem"
|
|
131
|
+
end
|
|
132
|
+
|
|
119
133
|
private
|
|
120
134
|
def update_project_file(relative_path)
|
|
121
135
|
templates = File.expand_path("upgrade/templates", File.dirname(__FILE__))
|
data/lib/jets/preheat.rb
CHANGED
|
@@ -104,8 +104,8 @@ module Jets
|
|
|
104
104
|
|
|
105
105
|
def classes
|
|
106
106
|
Jets::Commands::Build.app_files.map do |path|
|
|
107
|
-
next if path.include?("preheat_job.rb") # dont want to cause an infinite loop
|
|
108
|
-
next
|
|
107
|
+
next if path.include?("preheat_job.rb") # dont want to cause an infinite loop, just in case
|
|
108
|
+
next unless path =~ %r{app/controllers} # only prewarm controllers
|
|
109
109
|
|
|
110
110
|
class_path = path.sub(%r{.*app/\w+/},'').sub(/\.rb$/,'')
|
|
111
111
|
class_name = class_path.classify
|
|
@@ -1,127 +1,11 @@
|
|
|
1
1
|
class Jets::Resource::ApiGateway::RestApi
|
|
2
2
|
class Routes
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
autoload :Base, 'jets/resource/api_gateway/rest_api/routes/base'
|
|
4
|
+
autoload :Change, 'jets/resource/api_gateway/rest_api/routes/change'
|
|
5
|
+
autoload :Collision, 'jets/resource/api_gateway/rest_api/routes/collision'
|
|
5
6
|
|
|
6
7
|
def self.changed?
|
|
7
|
-
new.changed?
|
|
8
|
+
Change.new.changed?
|
|
8
9
|
end
|
|
9
|
-
|
|
10
|
-
def changed?
|
|
11
|
-
deployed_routes = build
|
|
12
|
-
deployed_routes.each do |deployed_route|
|
|
13
|
-
new_route = find_comparable_route(deployed_route)
|
|
14
|
-
if new_route && new_route.to != deployed_route.to
|
|
15
|
-
# change in already deployed route has been detected, requires bluegreen deploy
|
|
16
|
-
return true
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
false # Reaching here means no routes have been changed in a way that requires a bluegreen deploy
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
# Build up deployed routes from the existing CloudFormation resources.
|
|
23
|
-
def build
|
|
24
|
-
routes = []
|
|
25
|
-
|
|
26
|
-
resources, position = [], true
|
|
27
|
-
while position
|
|
28
|
-
position = nil if position == true # start of loop
|
|
29
|
-
resp = apigateway.get_resources(
|
|
30
|
-
rest_api_id: rest_api_id,
|
|
31
|
-
position: position,
|
|
32
|
-
)
|
|
33
|
-
resources += resp.items
|
|
34
|
-
position = resp.position
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
resources.each do |resource|
|
|
38
|
-
resource_methods = resource.resource_methods
|
|
39
|
-
next if resource_methods.nil?
|
|
40
|
-
|
|
41
|
-
resource_methods.each do |http_verb, resource_method|
|
|
42
|
-
# puts "#{http_verb} #{resource.path} | resource.id #{resource.id}"
|
|
43
|
-
# puts to(resource.id, http_verb)
|
|
44
|
-
|
|
45
|
-
# Test changing config.cors and CloudFormation does an in-place update
|
|
46
|
-
# on the resource. So no need to do bluegreen deployments for OPTIONS.
|
|
47
|
-
next if http_verb == "OPTIONS"
|
|
48
|
-
|
|
49
|
-
path = recreate_path(resource.path)
|
|
50
|
-
method = http_verb.downcase.to_sym
|
|
51
|
-
to = to(resource.id, http_verb)
|
|
52
|
-
route = Jets::Route.new(path: path, method: method, to: to)
|
|
53
|
-
routes << route
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
routes
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
# Find a route that has the same path and method. This is a comparable route
|
|
60
|
-
# Then we will compare the to or controller action to see if an already
|
|
61
|
-
# deployed route has been changed.
|
|
62
|
-
def find_comparable_route(deployed_route)
|
|
63
|
-
new_routes.find do |new_route|
|
|
64
|
-
new_route.path == deployed_route.path &&
|
|
65
|
-
new_route.method == deployed_route.method
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
def new_routes
|
|
70
|
-
Jets::Router.routes
|
|
71
|
-
end
|
|
72
|
-
memoize :new_routes
|
|
73
|
-
|
|
74
|
-
def recreate_path(path)
|
|
75
|
-
path = path.gsub(%r{^/},'')
|
|
76
|
-
path = path.sub(/{(.*)\+}/, '*\1')
|
|
77
|
-
path.sub(/{(.*)}/, ':\1')
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def to(resource_id, http_method)
|
|
81
|
-
uri = method_uri(resource_id, http_method)
|
|
82
|
-
recreate_to(uri) unless uri.nil?
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
def method_uri(resource_id, http_method)
|
|
86
|
-
resp = apigateway.get_method(
|
|
87
|
-
rest_api_id: rest_api_id,
|
|
88
|
-
resource_id: resource_id,
|
|
89
|
-
http_method: http_method
|
|
90
|
-
)
|
|
91
|
-
resp.method_integration.uri
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
# Parses method uri and recreates a Route to argument.
|
|
95
|
-
# So:
|
|
96
|
-
# "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"
|
|
97
|
-
# Returns:
|
|
98
|
-
# posts#new
|
|
99
|
-
def recreate_to(method_uri)
|
|
100
|
-
md = method_uri.match(/function:(.*)\//)
|
|
101
|
-
function_name = md[1] # IE: demo-dev-posts_controller-new
|
|
102
|
-
controller_action = function_name.sub("#{Jets.project_namespace}-", '')
|
|
103
|
-
md = controller_action.match(/(.*)_controller-(.*)/)
|
|
104
|
-
controller = md[1]
|
|
105
|
-
controller = controller.gsub('-','/')
|
|
106
|
-
action = md[2]
|
|
107
|
-
"#{controller}##{action}" # IE: posts#new
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
# Duplicated in rest_api/change_detection.rb, base_path/role.rb, rest_api/routes.rb
|
|
111
|
-
def rest_api_id
|
|
112
|
-
stack_name = Jets::Naming.parent_stack_name
|
|
113
|
-
return default unless stack_exists?(stack_name)
|
|
114
|
-
|
|
115
|
-
stack = cfn.describe_stacks(stack_name: stack_name).stacks.first
|
|
116
|
-
|
|
117
|
-
api_gateway_stack_arn = lookup(stack[:outputs], "ApiGateway")
|
|
118
|
-
|
|
119
|
-
# resources = cfn.describe_stack_resources(stack_name: api_gateway_stack_arn).stack_resources
|
|
120
|
-
stack = cfn.describe_stacks(stack_name: api_gateway_stack_arn).stacks.first
|
|
121
|
-
rest_api_id = lookup(stack[:outputs], "RestApi")
|
|
122
|
-
end
|
|
123
|
-
memoize :rest_api_id
|
|
124
|
-
|
|
125
|
-
# apigateway.get_rest_api(rest_api_id: rest_api_id) # resp
|
|
126
10
|
end
|
|
127
11
|
end
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Detects route changes
|
|
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)
|
|
37
|
+
|
|
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
|
|
111
|
+
end
|
|
112
|
+
memoize :rest_api_id
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Detects path variable collisions
|
|
2
|
+
class Jets::Resource::ApiGateway::RestApi::Routes
|
|
3
|
+
class Collision < Base
|
|
4
|
+
autoload :VariableException, 'jets/resource/api_gateway/rest_api/routes/collision/variable_exception'
|
|
5
|
+
|
|
6
|
+
attr_reader :collisions
|
|
7
|
+
def initialize(routes)
|
|
8
|
+
@routes = routes
|
|
9
|
+
@collisions = []
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def collision?
|
|
13
|
+
paths = paths_with_variables(@routes.map(&:path))
|
|
14
|
+
parents = variable_parents(paths)
|
|
15
|
+
|
|
16
|
+
collide = false
|
|
17
|
+
parents.each do |parent|
|
|
18
|
+
collide ||= variable_collision_exists?(parent, paths)
|
|
19
|
+
end
|
|
20
|
+
collide
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def exception
|
|
24
|
+
collision_message = <<~EOL
|
|
25
|
+
There are routes with sibling variables under the same parent that collide.
|
|
26
|
+
|
|
27
|
+
Collisions:
|
|
28
|
+
#{@collisions.join("\n ")}
|
|
29
|
+
|
|
30
|
+
API Gateway only allows one unique variable path You must use the same variable name within
|
|
31
|
+
the same parent route path.
|
|
32
|
+
Example: /posts/:id and /posts/:post_id/reveal should both be /posts/:id and /posts/:id/reveal.
|
|
33
|
+
|
|
34
|
+
Please check your `config/routes.rb` and remove the colliding routes.
|
|
35
|
+
More info: http://rubyonjets.com/docs/considerations-api-gateway/
|
|
36
|
+
EOL
|
|
37
|
+
VariableException.new(collision_message)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def variable_collision_exists?(parent, paths)
|
|
41
|
+
paths = paths_with_variables(paths)
|
|
42
|
+
variables = parent_variables(parent, paths)
|
|
43
|
+
collide = variables.uniq.size > 1
|
|
44
|
+
register_collision(parent, variables) if collide
|
|
45
|
+
collide
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# register collision for later display
|
|
49
|
+
# We don't register the full path but this might be more helpful.
|
|
50
|
+
def register_collision(parent, variables)
|
|
51
|
+
return unless variables.uniq.size # check again just in case
|
|
52
|
+
|
|
53
|
+
variables.each do |v|
|
|
54
|
+
@collisions << "#{parent}/#{v}"
|
|
55
|
+
end
|
|
56
|
+
@collisions.uniq!
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def parent_variables(parent, paths)
|
|
60
|
+
paths = paths.select do |path|
|
|
61
|
+
parent?(parent, path)
|
|
62
|
+
end
|
|
63
|
+
paths.map do |path|
|
|
64
|
+
path.sub("#{parent}/",'').gsub(%r{/.*},'')
|
|
65
|
+
end.uniq.sort
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def parent?(parent, path)
|
|
69
|
+
parent_parts = parent.split('/')
|
|
70
|
+
path_parts = path.split('/')
|
|
71
|
+
|
|
72
|
+
n = parent_parts.size-1
|
|
73
|
+
parent_parts[0..n] == path_parts[0..n]
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def direct_parent?(parent, path)
|
|
77
|
+
leaf = variable_leaf(path)
|
|
78
|
+
leaf_parent = leaf.split('/')[0..-2].join('/')
|
|
79
|
+
parent == leaf_parent
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def variable_parents(paths)
|
|
83
|
+
parents = []
|
|
84
|
+
paths = paths_with_variables(paths)
|
|
85
|
+
paths.each do |path|
|
|
86
|
+
parents << variable_parent(path)
|
|
87
|
+
end
|
|
88
|
+
parents.uniq.sort
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def paths_with_variables(paths)
|
|
92
|
+
paths.select { |p| p.include?(':') }.uniq
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Strips the path down until only the leaf node part is a variable
|
|
96
|
+
# Example: users/:user_id/posts/:post_id/edit
|
|
97
|
+
# Returns: users/:user_id/posts/:post_id
|
|
98
|
+
def variable_parent(path)
|
|
99
|
+
path = variable_leaf(path)
|
|
100
|
+
# drop last variable to leave behind the parent
|
|
101
|
+
path.split('/')[0..-2].join('/')
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Strips the path down until only the leaf node part is a variable
|
|
105
|
+
# Example: users/:user_id/posts/:post_id/edit
|
|
106
|
+
# Returns: users/:user_id/posts
|
|
107
|
+
def variable_leaf(path)
|
|
108
|
+
return unless path.include?(':')
|
|
109
|
+
|
|
110
|
+
parts = path.split('/')
|
|
111
|
+
is_variable = parts.last.include?(':')
|
|
112
|
+
until is_variable
|
|
113
|
+
parts.pop
|
|
114
|
+
is_variable = parts.last.include?(':')
|
|
115
|
+
end
|
|
116
|
+
parts[0..-1].join('/') # parent
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
data/lib/jets/router.rb
CHANGED
|
@@ -11,6 +11,14 @@ module Jets
|
|
|
11
11
|
|
|
12
12
|
def draw(&block)
|
|
13
13
|
instance_eval(&block)
|
|
14
|
+
check_collision!
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Validate routes that deployable
|
|
18
|
+
def check_collision!
|
|
19
|
+
collision = Jets::Resource::ApiGateway::RestApi::Routes::Collision.new(self.routes)
|
|
20
|
+
collide = collision.collision?
|
|
21
|
+
raise collision.exception if collide
|
|
14
22
|
end
|
|
15
23
|
|
|
16
24
|
# Methods supported by API Gateway
|
data/lib/jets/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jets
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.5.
|
|
4
|
+
version: 1.5.9
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tung Nguyen
|
|
@@ -14,28 +14,28 @@ dependencies:
|
|
|
14
14
|
name: activerecord
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
-
- - "
|
|
17
|
+
- - "~>"
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
19
|
version: 5.2.1
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
|
-
- - "
|
|
24
|
+
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: 5.2.1
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: activesupport
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
|
-
- - "
|
|
31
|
+
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
33
|
version: 5.2.1
|
|
34
34
|
type: :runtime
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
|
-
- - "
|
|
38
|
+
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
40
|
version: 5.2.1
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
@@ -294,14 +294,14 @@ dependencies:
|
|
|
294
294
|
name: railties
|
|
295
295
|
requirement: !ruby/object:Gem::Requirement
|
|
296
296
|
requirements:
|
|
297
|
-
- - "
|
|
297
|
+
- - "~>"
|
|
298
298
|
- !ruby/object:Gem::Version
|
|
299
299
|
version: 5.2.1
|
|
300
300
|
type: :runtime
|
|
301
301
|
prerelease: false
|
|
302
302
|
version_requirements: !ruby/object:Gem::Requirement
|
|
303
303
|
requirements:
|
|
304
|
-
- - "
|
|
304
|
+
- - "~>"
|
|
305
305
|
- !ruby/object:Gem::Version
|
|
306
306
|
version: 5.2.1
|
|
307
307
|
- !ruby/object:Gem::Dependency
|
|
@@ -704,6 +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
|
+
- lib/jets/resource/api_gateway/rest_api/routes/change.rb
|
|
709
|
+
- lib/jets/resource/api_gateway/rest_api/routes/collision.rb
|
|
710
|
+
- lib/jets/resource/api_gateway/rest_api/routes/collision/variable_exception.rb
|
|
707
711
|
- lib/jets/resource/associated.rb
|
|
708
712
|
- lib/jets/resource/base.rb
|
|
709
713
|
- lib/jets/resource/child_stack.rb
|
|
@@ -768,7 +772,6 @@ files:
|
|
|
768
772
|
- lib/jets/turbo/project/.gitignore
|
|
769
773
|
- lib/jets/turbo/project/.jetskeep
|
|
770
774
|
- lib/jets/turbo/project/Gemfile
|
|
771
|
-
- lib/jets/turbo/project/Gemfile.lock
|
|
772
775
|
- lib/jets/turbo/project/Rakefile
|
|
773
776
|
- lib/jets/turbo/project/app/controllers/application_controller.rb
|
|
774
777
|
- lib/jets/turbo/project/app/helpers/application_helper.rb
|
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
GEM
|
|
2
|
-
remote: https://rubygems.org/
|
|
3
|
-
specs:
|
|
4
|
-
actionpack (5.2.2)
|
|
5
|
-
actionview (= 5.2.2)
|
|
6
|
-
activesupport (= 5.2.2)
|
|
7
|
-
rack (~> 2.0)
|
|
8
|
-
rack-test (>= 0.6.3)
|
|
9
|
-
rails-dom-testing (~> 2.0)
|
|
10
|
-
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
|
11
|
-
actionview (5.2.2)
|
|
12
|
-
activesupport (= 5.2.2)
|
|
13
|
-
builder (~> 3.1)
|
|
14
|
-
erubi (~> 1.4)
|
|
15
|
-
rails-dom-testing (~> 2.0)
|
|
16
|
-
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
|
17
|
-
activemodel (5.2.2)
|
|
18
|
-
activesupport (= 5.2.2)
|
|
19
|
-
activerecord (5.2.2)
|
|
20
|
-
activemodel (= 5.2.2)
|
|
21
|
-
activesupport (= 5.2.2)
|
|
22
|
-
arel (>= 9.0)
|
|
23
|
-
activesupport (5.2.2)
|
|
24
|
-
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
25
|
-
i18n (>= 0.7, < 2)
|
|
26
|
-
minitest (~> 5.1)
|
|
27
|
-
tzinfo (~> 1.1)
|
|
28
|
-
addressable (2.5.2)
|
|
29
|
-
public_suffix (>= 2.0.2, < 4.0)
|
|
30
|
-
arel (9.0.0)
|
|
31
|
-
aws-eventstream (1.0.1)
|
|
32
|
-
aws-partitions (1.131.0)
|
|
33
|
-
aws-sdk-apigateway (1.23.0)
|
|
34
|
-
aws-sdk-core (~> 3, >= 3.39.0)
|
|
35
|
-
aws-sigv4 (~> 1.0)
|
|
36
|
-
aws-sdk-cloudformation (1.14.0)
|
|
37
|
-
aws-sdk-core (~> 3, >= 3.39.0)
|
|
38
|
-
aws-sigv4 (~> 1.0)
|
|
39
|
-
aws-sdk-cloudwatchlogs (1.12.0)
|
|
40
|
-
aws-sdk-core (~> 3, >= 3.39.0)
|
|
41
|
-
aws-sigv4 (~> 1.0)
|
|
42
|
-
aws-sdk-core (3.45.0)
|
|
43
|
-
aws-eventstream (~> 1.0)
|
|
44
|
-
aws-partitions (~> 1.0)
|
|
45
|
-
aws-sigv4 (~> 1.0)
|
|
46
|
-
jmespath (~> 1.0)
|
|
47
|
-
aws-sdk-dynamodb (1.19.0)
|
|
48
|
-
aws-sdk-core (~> 3, >= 3.39.0)
|
|
49
|
-
aws-sigv4 (~> 1.0)
|
|
50
|
-
aws-sdk-kms (1.13.0)
|
|
51
|
-
aws-sdk-core (~> 3, >= 3.39.0)
|
|
52
|
-
aws-sigv4 (~> 1.0)
|
|
53
|
-
aws-sdk-lambda (1.16.0)
|
|
54
|
-
aws-sdk-core (~> 3, >= 3.39.0)
|
|
55
|
-
aws-sigv4 (~> 1.0)
|
|
56
|
-
aws-sdk-s3 (1.30.1)
|
|
57
|
-
aws-sdk-core (~> 3, >= 3.39.0)
|
|
58
|
-
aws-sdk-kms (~> 1)
|
|
59
|
-
aws-sigv4 (~> 1.0)
|
|
60
|
-
aws-sdk-sns (1.9.0)
|
|
61
|
-
aws-sdk-core (~> 3, >= 3.39.0)
|
|
62
|
-
aws-sigv4 (~> 1.0)
|
|
63
|
-
aws-sdk-sqs (1.10.0)
|
|
64
|
-
aws-sdk-core (~> 3, >= 3.39.0)
|
|
65
|
-
aws-sigv4 (~> 1.0)
|
|
66
|
-
aws-sigv4 (1.0.3)
|
|
67
|
-
builder (3.2.3)
|
|
68
|
-
byebug (10.0.2)
|
|
69
|
-
capybara (3.12.0)
|
|
70
|
-
addressable
|
|
71
|
-
mini_mime (>= 0.1.3)
|
|
72
|
-
nokogiri (~> 1.8)
|
|
73
|
-
rack (>= 1.6.0)
|
|
74
|
-
rack-test (>= 0.6.3)
|
|
75
|
-
regexp_parser (~> 1.2)
|
|
76
|
-
xpath (~> 3.2)
|
|
77
|
-
colorize (0.8.1)
|
|
78
|
-
concurrent-ruby (1.1.4)
|
|
79
|
-
crass (1.0.4)
|
|
80
|
-
diff-lcs (1.3)
|
|
81
|
-
dotenv (2.6.0)
|
|
82
|
-
erubi (1.8.0)
|
|
83
|
-
gems (1.1.1)
|
|
84
|
-
json
|
|
85
|
-
hashie (3.6.0)
|
|
86
|
-
i18n (1.5.2)
|
|
87
|
-
concurrent-ruby (~> 1.0)
|
|
88
|
-
jets (1.5.3)
|
|
89
|
-
activerecord (>= 5.2.1)
|
|
90
|
-
activesupport (>= 5.2.1)
|
|
91
|
-
aws-sdk-apigateway
|
|
92
|
-
aws-sdk-cloudformation
|
|
93
|
-
aws-sdk-cloudwatchlogs
|
|
94
|
-
aws-sdk-dynamodb
|
|
95
|
-
aws-sdk-lambda
|
|
96
|
-
aws-sdk-s3
|
|
97
|
-
aws-sdk-sns
|
|
98
|
-
aws-sdk-sqs
|
|
99
|
-
colorize
|
|
100
|
-
dotenv
|
|
101
|
-
gems
|
|
102
|
-
hashie
|
|
103
|
-
jets-html-sanitizer
|
|
104
|
-
json
|
|
105
|
-
kramdown
|
|
106
|
-
memoist
|
|
107
|
-
mimemagic
|
|
108
|
-
rack
|
|
109
|
-
railties (>= 5.2.1)
|
|
110
|
-
recursive-open-struct
|
|
111
|
-
text-table
|
|
112
|
-
thor
|
|
113
|
-
jets-html-sanitizer (1.0.4)
|
|
114
|
-
loofah (~> 2.2, >= 2.2.2)
|
|
115
|
-
jmespath (1.4.0)
|
|
116
|
-
json (2.1.0)
|
|
117
|
-
kramdown (1.17.0)
|
|
118
|
-
launchy (2.4.3)
|
|
119
|
-
addressable (~> 2.3)
|
|
120
|
-
loofah (2.2.3)
|
|
121
|
-
crass (~> 1.0.2)
|
|
122
|
-
nokogiri (>= 1.5.9)
|
|
123
|
-
memoist (0.16.0)
|
|
124
|
-
method_source (0.9.2)
|
|
125
|
-
mimemagic (0.3.3)
|
|
126
|
-
mini_mime (1.0.1)
|
|
127
|
-
mini_portile2 (2.4.0)
|
|
128
|
-
minitest (5.11.3)
|
|
129
|
-
nokogiri (1.10.1)
|
|
130
|
-
mini_portile2 (~> 2.4.0)
|
|
131
|
-
public_suffix (3.0.3)
|
|
132
|
-
rack (2.0.6)
|
|
133
|
-
rack-test (1.1.0)
|
|
134
|
-
rack (>= 1.0, < 3)
|
|
135
|
-
rails-dom-testing (2.0.3)
|
|
136
|
-
activesupport (>= 4.2.0)
|
|
137
|
-
nokogiri (>= 1.6)
|
|
138
|
-
rails-html-sanitizer (1.0.4)
|
|
139
|
-
loofah (~> 2.2, >= 2.2.2)
|
|
140
|
-
railties (5.2.2)
|
|
141
|
-
actionpack (= 5.2.2)
|
|
142
|
-
activesupport (= 5.2.2)
|
|
143
|
-
method_source
|
|
144
|
-
rake (>= 0.8.7)
|
|
145
|
-
thor (>= 0.19.0, < 2.0)
|
|
146
|
-
rake (12.3.2)
|
|
147
|
-
recursive-open-struct (1.1.0)
|
|
148
|
-
regexp_parser (1.3.0)
|
|
149
|
-
rspec (3.8.0)
|
|
150
|
-
rspec-core (~> 3.8.0)
|
|
151
|
-
rspec-expectations (~> 3.8.0)
|
|
152
|
-
rspec-mocks (~> 3.8.0)
|
|
153
|
-
rspec-core (3.8.0)
|
|
154
|
-
rspec-support (~> 3.8.0)
|
|
155
|
-
rspec-expectations (3.8.2)
|
|
156
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
|
157
|
-
rspec-support (~> 3.8.0)
|
|
158
|
-
rspec-mocks (3.8.0)
|
|
159
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
|
160
|
-
rspec-support (~> 3.8.0)
|
|
161
|
-
rspec-support (3.8.0)
|
|
162
|
-
shotgun (0.9.2)
|
|
163
|
-
rack (>= 1.0)
|
|
164
|
-
text-table (1.2.4)
|
|
165
|
-
thor (0.20.3)
|
|
166
|
-
thread_safe (0.3.6)
|
|
167
|
-
tzinfo (1.2.5)
|
|
168
|
-
thread_safe (~> 0.1)
|
|
169
|
-
xpath (3.2.0)
|
|
170
|
-
nokogiri (~> 1.8)
|
|
171
|
-
|
|
172
|
-
PLATFORMS
|
|
173
|
-
ruby
|
|
174
|
-
|
|
175
|
-
DEPENDENCIES
|
|
176
|
-
byebug
|
|
177
|
-
capybara
|
|
178
|
-
jets
|
|
179
|
-
launchy
|
|
180
|
-
rack
|
|
181
|
-
rspec
|
|
182
|
-
shotgun
|
|
183
|
-
|
|
184
|
-
BUNDLED WITH
|
|
185
|
-
1.17.2
|