jets 3.2.2 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +18 -0
  3. data/jets.gemspec +1 -1
  4. data/lib/jets/application/defaults.rb +2 -0
  5. data/lib/jets/application.rb +6 -7
  6. data/lib/jets/aws_info.rb +2 -2
  7. data/lib/jets/booter.rb +48 -1
  8. data/lib/jets/builders/code_builder.rb +2 -21
  9. data/lib/jets/builders/gem_replacer.rb +2 -7
  10. data/lib/jets/builders/ruby_packager.rb +37 -4
  11. data/lib/jets/cfn/builders/api_deployment_builder.rb +1 -1
  12. data/lib/jets/cfn/builders/api_gateway_builder.rb +25 -22
  13. data/lib/jets/cfn/builders/api_resources_builder.rb +1 -1
  14. data/lib/jets/cfn/builders/authorizer_builder.rb +1 -1
  15. data/lib/jets/cfn/builders/base_child_builder.rb +20 -1
  16. data/lib/jets/cfn/builders/interface.rb +19 -0
  17. data/lib/jets/cfn/builders/parent_builder.rb +3 -3
  18. data/lib/jets/cfn/builders/shared_builder.rb +1 -1
  19. data/lib/jets/cfn/built_template.rb +1 -1
  20. data/lib/jets/cfn/ship.rb +2 -2
  21. data/lib/jets/cfn/status.rb +1 -1
  22. data/lib/jets/cfn/upload.rb +2 -2
  23. data/lib/jets/cli.rb +10 -4
  24. data/lib/jets/commands/call/base_guesser.rb +1 -1
  25. data/lib/jets/commands/clean/log.rb +3 -3
  26. data/lib/jets/commands/configure.rb +1 -1
  27. data/lib/jets/commands/delete.rb +1 -1
  28. data/lib/jets/commands/deploy.rb +2 -2
  29. data/lib/jets/commands/stack_info.rb +1 -1
  30. data/lib/jets/commands/templates/skeleton/config/application.rb.tt +1 -1
  31. data/lib/jets/commands/url.rb +1 -1
  32. data/lib/jets/core.rb +14 -2
  33. data/lib/jets/core_ext/file.rb +9 -0
  34. data/lib/jets/dotenv.rb +2 -2
  35. data/lib/jets/erb.rb +1 -1
  36. data/lib/jets/inflections.rb +1 -1
  37. data/lib/jets/internal/app/controllers/jets/bare_controller.rb +1 -1
  38. data/lib/jets/internal/app/jobs/jets/preheat_job.rb +6 -2
  39. data/lib/jets/lambda/dsl.rb +6 -1
  40. data/lib/jets/{naming.rb → names.rb} +3 -3
  41. data/lib/jets/preheat.rb +9 -6
  42. data/lib/jets/resource/api_gateway/base_path/role.rb +1 -1
  43. data/lib/jets/resource/api_gateway/deployment.rb +2 -2
  44. data/lib/jets/resource/api_gateway/rest_api/logical_id.rb +1 -1
  45. data/lib/jets/resource/api_gateway/rest_api/routes/change/base.rb +1 -1
  46. data/lib/jets/resource/api_gateway/rest_api/routes/change/media_types.rb +1 -1
  47. data/lib/jets/resource/api_gateway/rest_api/routes/change/page.rb +2 -2
  48. data/lib/jets/resource/api_gateway/rest_api/routes/change.rb +1 -1
  49. data/lib/jets/resource/api_gateway/rest_api.rb +1 -1
  50. data/lib/jets/resource/child_stack/api_deployment.rb +1 -1
  51. data/lib/jets/resource/child_stack/api_resource/page.rb +1 -1
  52. data/lib/jets/resource/child_stack/api_resource.rb +1 -1
  53. data/lib/jets/resource/child_stack/app_class.rb +1 -1
  54. data/lib/jets/resource/child_stack/shared.rb +1 -1
  55. data/lib/jets/resource/iam/base_role_definition.rb +0 -5
  56. data/lib/jets/resource/iam/policy.rb +31 -0
  57. data/lib/jets/resource/lambda/function/environment.rb +2 -1
  58. data/lib/jets/resource/lambda/function.rb +3 -3
  59. data/lib/jets/router/route.rb +16 -4
  60. data/lib/jets/tmp_loader.rb +1 -1
  61. data/lib/jets/turbo/database_yaml.rb +1 -1
  62. data/lib/jets/util/yamler.rb +16 -0
  63. data/lib/jets/version.rb +1 -1
  64. data/lib/jets.rb +1 -0
  65. metadata +7 -9
  66. data/.python-version +0 -1
  67. data/.ruby-version +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 12689dd61b554f0b5a049ee578cf14566593788a3a2ebb7353ea26a5f7bd803c
4
- data.tar.gz: c54ebb36356ac71a8e9d211eb9187e761eba9aca2c650abd50e55ffdbf14f6d3
3
+ metadata.gz: 557e01dec1b92f8a04213ef4b7f5ee9d8a35f25dd20231c96ba24b0d9890b7cd
4
+ data.tar.gz: 5c8c12ae959d76dc9e5a681c8f18a40d5d60defcc4eead52ed9d9ad2571a3fe1
5
5
  SHA512:
6
- metadata.gz: 9834c8acaa032e002820e7ba7855f62f318160942287e2c1d23b31f4746d62cbb92253c97097bc94ca6d463044b95d7ef97f5030c6c8105682155ec6d568941d
7
- data.tar.gz: 707f58aae8c4b8730db0a6e160830eea8a45fc840300a1f1e2a79ffb656118774446e24f1b91722e974bd0f5126a1b755c68eaea6147a8403d2aad76cfc4e697
6
+ metadata.gz: 944a1d09ba4da26110e292cdf42d73a240d283d066dbe1ca677787c20b03ee925cf12e3d92555bc16e6327c7096ce59782cd271ff802f5d8554819674f040020
7
+ data.tar.gz: 987eac8ef96a9cc10b0ac071ff099c02245cf5143bb75d23622513aba73ba447414ab0c542f7a734c30ba6ce07f20cd479daecc030c02d9a5d3505c10c0a5c34
data/CHANGELOG.md CHANGED
@@ -3,6 +3,24 @@
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
+ ## [4.0.0] - 2023-05-27
7
+ - [#641](https://github.com/boltops-tools/jets/pull/641) bundle check and prevent error from getting to aws lambda
8
+ - [#642](https://github.com/boltops-tools/jets/pull/642) Fix rack mounted apps: update interface with removed meth
9
+ - [#643](https://github.com/boltops-tools/jets/pull/643) JETS_EXTRA support, deprecate JETS_ENV_EXTRA
10
+ - [#644](https://github.com/boltops-tools/jets/pull/644) remove docs to separate repo
11
+ - [#645](https://github.com/boltops-tools/jets/pull/645) PreheatJob: fix function lookups and iam function permission
12
+ - [#646](https://github.com/boltops-tools/jets/pull/646) log debug uploading and setting content type
13
+ - [#647](https://github.com/boltops-tools/jets/pull/647) fix Jets.logger call
14
+ - [#648](https://github.com/boltops-tools/jets/pull/648) make sure logger level info is default
15
+ - [#649](https://github.com/boltops-tools/jets/pull/649) Custom Domain: Hard fail on IAM permission error
16
+ - [#650](https://github.com/boltops-tools/jets/pull/650) Validate lambda function names
17
+ - [#651](https://github.com/boltops-tools/jets/pull/651) allow custom rake tasks with params to work with jets as well as rake command
18
+ - [#652](https://github.com/boltops-tools/jets/pull/652) Validate lambda function names: fix regexp
19
+ - [#653](https://github.com/boltops-tools/jets/pull/653) refactor cleanup: rename Jets::Naming to Jets::Names
20
+ - [#654](https://github.com/boltops-tools/jets/pull/654) Ruby 3.2 Support
21
+ - apigw routes state save: fix to_json infinite loop from Grape apps
22
+ - delete .python-version: more general approach. fixes specs when specific version of python is not installed
23
+
6
24
  ## [3.2.2] - 2023-05-19
7
25
  - [#640](https://github.com/boltops-tools/jets/pull/640) Base path mapping CloudFormation custom resource and lambda function hardening
8
26
 
data/jets.gemspec CHANGED
@@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
14
14
  spec.homepage = "https://rubyonjets.com"
15
15
  spec.license = "MIT"
16
16
 
17
- spec.required_ruby_version = ['>= 2.5.0', '< 3.0.0']
17
+ spec.required_ruby_version = ['>= 2.5.0']
18
18
  spec.rdoc_options += Jets::Rdoc.options
19
19
 
20
20
  vendor_files = Dir.glob("vendor/**/*")
@@ -51,6 +51,7 @@ class Jets::Application
51
51
  config.autoload_paths = [] # allows for customization
52
52
  config.ignore_paths = [] # allows for customization
53
53
  config.logger = Jets::Logger.new($stderr)
54
+ config.logger.level = Logger::INFO
54
55
  config.time_zone = "UTC"
55
56
 
56
57
  # function properties defaults
@@ -162,6 +163,7 @@ class Jets::Application
162
163
 
163
164
  config.ruby = ActiveSupport::OrderedOptions.new
164
165
  config.ruby.check = true
166
+ config.ruby.supported_versions = %w[2.5 2.7 3.2] # supported by AWS Lambda
165
167
 
166
168
  config
167
169
  end
@@ -163,13 +163,12 @@ class Jets::Application
163
163
  staging: 'stag',
164
164
  }
165
165
  def set_computed_configs!
166
- # env_extra can be also be set with JETS_ENV_EXTRA.
167
- # JETS_ENV_EXTRA higher precedence than config.env_extra
168
- config.env_extra = ENV['JETS_ENV_EXTRA'] if ENV['JETS_ENV_EXTRA']
169
- # IE: With env_extra: project-dev-1
170
- # Without env_extra: project-dev
166
+ # env var JETS_EXTRA higher precedence than config.extra
167
+ config.extra = Jets.extra
168
+ # IE: With extra: project-dev-1
169
+ # Without extra: project-dev
171
170
  config.short_env = ENV_MAP[Jets.env.to_sym] || Jets.env
172
- # table_namespace does not have the env_extra, more common case desired.
171
+ # table_namespace does not have the extra, more common case desired.
173
172
  config.table_namespace = [config.project_name, config.short_env].compact.join('-')
174
173
 
175
174
  config.project_namespace = Jets.project_namespace
@@ -205,7 +204,7 @@ class Jets::Application
205
204
  if File.exist?(database_yml)
206
205
  require "active_record/database_configurations" # lazy require
207
206
  text = Jets::Erb.result(database_yml)
208
- db_configs = YAML.load(text)
207
+ db_configs = Jets::Util::Yamler.load(text)
209
208
  configurations = ActiveRecord::DatabaseConfigurations.new(db_configs)
210
209
  config.database = configurations
211
210
  end
data/lib/jets/aws_info.rb CHANGED
@@ -73,7 +73,7 @@ module Jets
73
73
  return "fake-test-s3-bucket" if Jets.env.test?
74
74
  return @@s3_bucket unless @@s3_bucket == BUCKET_DOES_NOT_YET_EXIST
75
75
 
76
- resp = cfn.describe_stacks(stack_name: Jets::Naming.parent_stack_name)
76
+ resp = cfn.describe_stacks(stack_name: Jets::Names.parent_stack_name)
77
77
  stack = resp.stacks.first
78
78
  output = stack["outputs"].find { |o| o["output_key"] == "S3Bucket" }
79
79
  @@s3_bucket = output["output_value"] # s3_bucket
@@ -83,7 +83,7 @@ module Jets
83
83
  # not been loaded in the config yet. We do some trickery with loading
84
84
  # the config twice in Application#load_app_config
85
85
  # The first load will result in a Aws::CloudFormation::Errors::ValidationError
86
- # since the Jets::Naming.parent_stack_name has not been properly set yet.
86
+ # since the Jets::Names.parent_stack_name has not been properly set yet.
87
87
  #
88
88
  # Rescuing all exceptions in case there are other exceptions dont know about yet
89
89
  # Here are the known ones: Aws::CloudFormation::Errors::ValidationError, Aws::CloudFormation::Errors::InvalidClientTokenId
data/lib/jets/booter.rb CHANGED
@@ -10,6 +10,7 @@ class Jets::Booter
10
10
  Jets::Bundle.require
11
11
 
12
12
  Jets.application.setup!
13
+ check_ruby_version!
13
14
 
14
15
  # Turbines are loaded after setup_autoload_paths in Jets.application.setup! Some Turbine options are defined
15
16
  # in the project so setup must happen before internal Turbines are loaded.
@@ -98,7 +99,7 @@ class Jets::Booter
98
99
  primary_hash_config = ActiveRecord::Base.configurations.configs_for(env_name: Jets.env).find { |hash_config|
99
100
  hash_config.name == "primary"
100
101
  }
101
-
102
+
102
103
  primary_config = primary_hash_config.configuration_hash # configuration_hash is a normal Ruby Hash
103
104
 
104
105
  ActiveRecord::Base.establish_connection(primary_config)
@@ -174,5 +175,51 @@ class Jets::Booter
174
175
  exit 1
175
176
  end
176
177
  end
178
+
179
+ def check_ruby_version!
180
+ return if ENV['JETS_RUBY_CHECK'] == '0'
181
+ return if !Jets.config.ruby.check
182
+ return if ruby_version_supported?
183
+
184
+ puts <<~EOL.color(:red)
185
+ You are using Ruby #{RUBY_VERSION}
186
+ AWS Lambda does not support this version.
187
+ Please use one of the supported Ruby versions: #{supported_ruby_versions.join(' ')}
188
+ EOL
189
+
190
+ puts <<~EOL
191
+ If you would like to skip this check, you can set: JETS_RUBY_CHECK=0 or configure
192
+
193
+ config/application.rb
194
+
195
+ Jets.application.configure do
196
+ config.ruby.check = false
197
+ end
198
+
199
+ Or if you want to allow additional Ruby versions, then configure:
200
+
201
+ config/application.rb
202
+
203
+ Jets.application.configure do
204
+ config.ruby.supported_versions = ["2.5", "2.7", "3.2"]
205
+ end
206
+
207
+ Note: If AWS Lambda does not officially support the Ruby version,
208
+ you'll need to also provide the Ruby Custom Runtime Layer.
209
+ Related Docs: https://rubyonjets.com/docs/extras/custom-runtime/
210
+ EOL
211
+ exit 1
212
+ end
213
+
214
+ def ruby_version_supported?
215
+ md = RUBY_VERSION.match(/(\d+)\.(\d+)\.\d+/)
216
+ major, minor = md[1], md[2]
217
+ detected_ruby = [major, minor].join('.')
218
+ supported_ruby_versions.include?(detected_ruby)
219
+ end
220
+
221
+ def supported_ruby_versions
222
+ Jets.config.ruby.supported_versions
223
+ end
177
224
  end
178
225
  end
@@ -26,7 +26,6 @@ module Jets::Builders
26
26
  end
27
27
 
28
28
  def build
29
- check_ruby_version
30
29
  @version_purger.purge
31
30
  cache_check_message
32
31
 
@@ -80,6 +79,7 @@ module Jets::Builders
80
79
  return false if ENV['JETS_BUILD_NO_INTERNET']
81
80
  s3_key = "jets/code/#{filename}"
82
81
  begin
82
+ Jets.logger.debug "Checking s3://#{s3_bucket}/#{s3_key}"
83
83
  s3.head_object(bucket: s3_bucket, key: s3_key)
84
84
  true
85
85
  rescue Aws::S3::Errors::NotFound, Aws::S3::Errors::Forbidden
@@ -355,7 +355,7 @@ module Jets::Builders
355
355
  webpacker_yml = "#{"#{stage_area}/code"}/config/webpacker.yml"
356
356
  return unless File.exist?(webpacker_yml)
357
357
 
358
- config = YAML.load_file(webpacker_yml)
358
+ config = Jets::Util::Yamler.load_file(webpacker_yml)
359
359
  config["development"]["compile"] = false # force this to be false for deployment
360
360
  new_yaml = YAML.dump(config)
361
361
  IO.write(webpacker_yml, new_yaml)
@@ -412,25 +412,6 @@ module Jets::Builders
412
412
  FileUtils.cp_r(ruby_version_path, build_area)
413
413
  end
414
414
 
415
- SUPPORTED_RUBY_VERSIONS = %w[2.5 2.7]
416
- def check_ruby_version
417
- return unless ENV['JETS_RUBY_CHECK'] == '0' || Jets.config.ruby.check == false
418
- return if ruby_version_supported?
419
- puts <<~EOL.color(:red)
420
- You are using Ruby version #{RUBY_VERSION} which is not supported by Jets.
421
- Please use one of the Jets supported ruby versions: #{SUPPORTED_RUBY_VERSIONS.join(' ')}
422
- If you would like to skip this check you can set: JETS_RUBY_CHECK=0
423
- EOL
424
- exit 1
425
- end
426
-
427
- def ruby_version_supported?
428
- md = RUBY_VERSION.match(/(\d+)\.(\d+)\.\d+/)
429
- major, minor = md[1], md[2]
430
- detected_ruby = [major, minor].join('.')
431
- SUPPORTED_RUBY_VERSIONS.include?(detected_ruby)
432
- end
433
-
434
415
  # Group all the path settings together here
435
416
  def self.tmp_code
436
417
  Jets::Commands::Build.tmp_code
@@ -1,6 +1,8 @@
1
1
  module Jets::Builders
2
2
  class GemReplacer
3
3
  extend Memoist
4
+ include Util
5
+
4
6
  def initialize(options)
5
7
  @options = options
6
8
  end
@@ -37,13 +39,6 @@ module Jets::Builders
37
39
  FileUtils.mv(src, dest) unless File.exist?(dest) # looks like rename_gem actually runs twice
38
40
  end
39
41
 
40
- def sh(command)
41
- puts "=> #{command}".color(:green)
42
- success = system(command)
43
- abort("Command Failed: #{command}") unless success
44
- success
45
- end
46
-
47
42
  def ruby_folder
48
43
  Jets::Gems.ruby_folder
49
44
  end
@@ -3,9 +3,9 @@ require "bundler" # for clean_old_submodules only
3
3
  module Jets::Builders
4
4
  class RubyPackager
5
5
  include Util
6
-
7
- GEM_REGEXP = /-(arm|x)\d+.*-(darwin|linux)/
8
-
6
+
7
+ GEM_REGEXP = /-(arm|x)\d+.*-(darwin|linux)/
8
+
9
9
  attr_reader :full_app_root
10
10
  def initialize(relative_app_root)
11
11
  @full_app_root = "#{build_area}/#{relative_app_root}"
@@ -16,6 +16,7 @@ module Jets::Builders
16
16
 
17
17
  clean_old_submodules
18
18
  bundle_install
19
+ bundle_check
19
20
  copy_bundle_config
20
21
  copy_cache_gems
21
22
  end
@@ -75,7 +76,39 @@ module Jets::Builders
75
76
  # For example we add the jets-rails to the Gemfile.
76
77
  copy_back_gemfile_lock
77
78
 
78
- puts 'Bundle install success.'
79
+ puts 'Bundle install completed'
80
+ end
81
+
82
+ # Example `bundle check` error:
83
+ #
84
+ # The following gems are missing
85
+ # * date (3.3.3)
86
+ # * timeout (0.3.2)
87
+ # Install missing gems with `bundle install`
88
+ #
89
+ # Example success:
90
+ #
91
+ # The Gemfile's dependencies are satisfied
92
+ #
93
+ def bundle_check
94
+ out = ''
95
+ Bundler.with_unbundled_env do
96
+ out = `cd #{cache_area} && bundle check 2>&1`
97
+ end
98
+ if out.include?("missing")
99
+ puts "Failed: bundle check".color(:red)
100
+ puts <<~EOL
101
+ This means something went wrong with the bundle install.
102
+ Jets will prevent the deployment to AWS Lambda.
103
+ It's better to error now instead of finding out on AWS Lambda.
104
+ The bundle install can fail for different system-specific reasons.
105
+ It could be an outdated or incompatible version of RubyGems and Ruby.
106
+
107
+ Related: https://community.boltops.com/t/could-not-find-timeout-0-3-1-in-any-of-the-sources/996
108
+
109
+ EOL
110
+ exit 1
111
+ end
79
112
  end
80
113
 
81
114
  def copy_back_gemfile_lock
@@ -45,7 +45,7 @@ module Jets::Cfn::Builders
45
45
 
46
46
  # template_path is an interface method
47
47
  def template_path
48
- Jets::Naming.api_deployment_template_path
48
+ Jets::Names.api_deployment_template_path
49
49
  end
50
50
 
51
51
  # do not bother writing a template if routes are empty
@@ -18,7 +18,7 @@ module Jets::Cfn::Builders
18
18
 
19
19
  # template_path is an interface method
20
20
  def template_path
21
- Jets::Naming.api_gateway_template_path
21
+ Jets::Names.api_gateway_template_path
22
22
  end
23
23
 
24
24
  # do not bother writing a template if routes are empty
@@ -55,7 +55,7 @@ module Jets::Cfn::Builders
55
55
  end
56
56
  end
57
57
 
58
- def create_domain_name()
58
+ def create_domain_name
59
59
  resource = Jets::Resource::ApiGateway::DomainName.new
60
60
 
61
61
  return {
@@ -70,41 +70,44 @@ module Jets::Cfn::Builders
70
70
  apigateway.get_domain_name({
71
71
  domain_name: resource.domain_name
72
72
  })
73
- return true
74
- rescue
75
- return false
73
+ true
74
+ # IE: Aws::APIGateway::Errors::NotFoundException Invalid domain name identifier specified
75
+ rescue Aws::APIGateway::Errors::NotFoundException
76
+ false
76
77
  end
77
78
  memoize :existing_domain_name?
78
79
 
79
80
  def existing_domain_name_on_stack?
80
- cfn.describe_stack_resource({
81
+ cfn.describe_stack_resource(
81
82
  stack_name: api_gateway_physical_resource_id,
82
83
  logical_resource_id: "DomainName"
83
- })
84
- return true
85
- rescue
86
- return false
84
+ )
85
+ true
86
+ # IE: Aws::CloudFormation::Errors::ValidationError (Resource DomainName does not exist for stack demo-dev)
87
+ rescue Aws::CloudFormation::Errors::ValidationError
88
+ false
87
89
  end
88
90
 
89
91
  def existing_dns_record_on_stack?
90
- cfn.describe_stack_resource({
92
+ cfn.describe_stack_resource(
91
93
  stack_name: api_gateway_physical_resource_id,
92
94
  logical_resource_id: "DnsRecord"
93
- })
94
- return true
95
- rescue
96
- return false
95
+ )
96
+ true
97
+ # IE: Aws::CloudFormation::Errors::ValidationError (Resource DnsRecord does not exist for stack demo-dev)
98
+ rescue Aws::CloudFormation::Errors::ValidationError
99
+ false
97
100
  end
98
101
 
99
102
  def api_gateway_physical_resource_id
100
- cfn.describe_stack_resource({
101
- stack_name: Jets::Naming.parent_stack_name,
103
+ resp = cfn.describe_stack_resource(
104
+ stack_name: Jets::Names.parent_stack_name,
102
105
  logical_resource_id: "ApiGateway"
103
- })
104
- .stack_resource_detail
105
- .physical_resource_id
106
- rescue
107
- return nil
106
+ )
107
+ resp&.stack_resource_detail&.physical_resource_id
108
+ # IE: Aws::CloudFormation::Errors::ValidationError (Resource ApiGateway does not exist for stack demo-dev)
109
+ rescue Aws::CloudFormation::Errors::ValidationError
110
+ nil
108
111
  end
109
112
  memoize :api_gateway_physical_resource_id
110
113
 
@@ -16,7 +16,7 @@ module Jets::Cfn::Builders
16
16
 
17
17
  # template_path is an interface method
18
18
  def template_path
19
- Jets::Naming.api_resources_template_path(@page)
19
+ Jets::Names.api_resources_template_path(@page)
20
20
  end
21
21
 
22
22
  def add_rest_api_parameter
@@ -61,7 +61,7 @@ module Jets::Cfn::Builders
61
61
  end
62
62
 
63
63
  def template_path
64
- Jets::Naming.authorizer_template_path(@path)
64
+ Jets::Names.authorizer_template_path(@path)
65
65
  end
66
66
  end
67
67
  end
@@ -18,7 +18,7 @@ module Jets::Cfn::Builders
18
18
 
19
19
  # template_path is an interface method for Interface module
20
20
  def template_path
21
- Jets::Naming.app_template_path(@app_class)
21
+ Jets::Names.app_template_path(@app_class)
22
22
  end
23
23
 
24
24
  def add_common_parameters
@@ -40,6 +40,7 @@ module Jets::Cfn::Builders
40
40
  end
41
41
 
42
42
  def add_functions
43
+ validate_function_names!
43
44
  add_class_iam_policy
44
45
  @app_class.tasks.each do |task|
45
46
  add_function(task)
@@ -65,5 +66,23 @@ module Jets::Cfn::Builders
65
66
  resource = Jets::Resource::Iam::FunctionRole.new(task)
66
67
  add_resource(resource)
67
68
  end
69
+
70
+ def validate_function_names!
71
+ invalids = @app_class.tasks.reject do |task|
72
+ task.meth.to_s =~ /^[a-zA-Z][a-zA-Z0-9_]/
73
+ end
74
+ return if invalids.empty?
75
+ list = invalids.map do |task|
76
+ " #{task.class_name}##{task.meth}" # IE: PostsController#index
77
+ end.join("\n")
78
+ puts "ERROR: Detected invalid AWS Lambda function names".color(:red)
79
+ puts <<~EOL
80
+ Lambda function names must start with a letter and can only contain letters, numbers, and underscores.
81
+ Invalid function names:
82
+
83
+ #{list}
84
+ EOL
85
+ exit 1
86
+ end
68
87
  end
69
88
  end
@@ -88,8 +88,27 @@ module Jets::Cfn::Builders
88
88
  end
89
89
  end
90
90
 
91
+ # Note: Jets::Resource::Iam classes are special treated. They are the only resources that result
92
+ # in creating 2 CloudFormation resources: Iam::Policy and Iam::Role.
93
+ # This allows the user to refer to the Lambda Function name in the IAM Policy itself.
94
+ # We need separate resources to avoid CloudFormation erroring with a circular dependency.
95
+ # Using separate IAM::Policy and IAM::Role resources allows us avoid the circular dependency error.
96
+ #
97
+ # Handling logic here also centralizes code for this special behavior.
98
+ # Also important to note, this does not change the user-facing interface.
99
+ # IE: Users still uses code like:
100
+ #
101
+ # iam_policy("s3", "sns")
102
+ #
103
+ # and be none-the-wiser about the special behavior.
91
104
  def add_resource(resource)
92
105
  add_template_resource(resource.logical_id, resource.type, resource.attributes)
106
+
107
+ if resource.class.to_s.include?("Jets::Resource::Iam")
108
+ role = resource # for clarity: resource is a Iam::*Role class
109
+ iam_policy = Jets::Resource::Iam::Policy.new(role)
110
+ add_template_resource(iam_policy.logical_id, iam_policy.type, iam_policy.attributes)
111
+ end
93
112
  end
94
113
 
95
114
  # The add_resource method can take an options Hash with both with either
@@ -19,7 +19,7 @@ module Jets::Cfn::Builders
19
19
 
20
20
  # template_path is an interface method
21
21
  def template_path
22
- Jets::Naming.parent_template_path
22
+ Jets::Names.parent_template_path
23
23
  end
24
24
 
25
25
  def build_minimal_resources
@@ -90,7 +90,7 @@ module Jets::Cfn::Builders
90
90
  # #{Jets.build_root}/templates/demo-dev-2-app-comments_controller.yml
91
91
  # #{Jets.build_root}/templates/demo-dev-2-authorizers-main_authorizer.yml
92
92
  def for_each_path(type)
93
- expression = "#{Jets::Naming.template_path_prefix}-#{type}-*"
93
+ expression = "#{Jets::Names.template_path_prefix}-#{type}-*"
94
94
  Dir.glob(expression).each do |path|
95
95
  next unless File.file?(path)
96
96
  yield(path)
@@ -123,7 +123,7 @@ module Jets::Cfn::Builders
123
123
  end
124
124
 
125
125
  def add_api_resources
126
- expression = "#{Jets::Naming.template_path_prefix}-api-resources-*"
126
+ expression = "#{Jets::Names.template_path_prefix}-api-resources-*"
127
127
  # IE: path: #{Jets.build_root}/templates/demo-dev-2-api-resources-1.yml"
128
128
  Dir.glob(expression).sort.each do |path|
129
129
  next unless File.file?(path)
@@ -8,7 +8,7 @@ module Jets::Cfn::Builders
8
8
 
9
9
  # template_path is an interface method for Interface module
10
10
  def template_path
11
- Jets::Naming.shared_template_path(@app_class)
11
+ Jets::Names.shared_template_path(@app_class)
12
12
  end
13
13
  end
14
14
  end
@@ -7,7 +7,7 @@ module Jets::Cfn
7
7
  if @@cache[path]
8
8
  @@cache[path] # using cache
9
9
  else
10
- @@cache[path] = YAML.load_file(path) # setting and using cache
10
+ @@cache[path] = Jets::Util::Yamler.load_file(path) # setting and using cache
11
11
  end
12
12
  end
13
13
  end
data/lib/jets/cfn/ship.rb CHANGED
@@ -5,7 +5,7 @@ module Jets::Cfn
5
5
 
6
6
  def initialize(options)
7
7
  @options = options
8
- @parent_stack_name = Jets::Naming.parent_stack_name
8
+ @parent_stack_name = Jets::Names.parent_stack_name
9
9
  end
10
10
 
11
11
  def run
@@ -81,7 +81,7 @@ module Jets::Cfn
81
81
  end
82
82
 
83
83
  def template
84
- @template ||= TemplateSource.new(Jets::Naming.parent_template_path, @options)
84
+ @template ||= TemplateSource.new(Jets::Names.parent_template_path, @options)
85
85
  end
86
86
 
87
87
  # check for /(_COMPLETE|_FAILED)$/ status
@@ -3,7 +3,7 @@ require 'cfn_status'
3
3
  module Jets::Cfn
4
4
  class Status < CfnStatus
5
5
  def initialize(options={})
6
- @stack_name = Jets::Naming.parent_stack_name
6
+ @stack_name = Jets::Names.parent_stack_name
7
7
  super(@stack_name, options)
8
8
  end
9
9
  end
@@ -21,7 +21,7 @@ module Jets::Cfn
21
21
 
22
22
  def upload_cfn_templates
23
23
  puts "Uploading CloudFormation templates to S3."
24
- expression = "#{Jets::Naming.template_path_prefix}-*"
24
+ expression = "#{Jets::Names.template_path_prefix}-*"
25
25
  Dir.glob(expression).each do |path|
26
26
  next unless File.file?(path)
27
27
 
@@ -93,7 +93,7 @@ module Jets::Cfn
93
93
  key = s3_key(full_path)
94
94
  obj = s3_resource.bucket(bucket_name).object(key)
95
95
  content_type = content_type_headers(full_path)
96
- puts "Uploading and setting content type for s3://#{bucket_name}/#{key} content_type #{content_type[:content_type].inspect}"
96
+ Jets.logger.debug "Uploading and setting content type for s3://#{bucket_name}/#{key} content_type #{content_type[:content_type].inspect}"
97
97
  obj.upload_file(full_path, { acl: "public-read", cache_control: cache_control }.merge(content_type))
98
98
  end
99
99
 
data/lib/jets/cli.rb CHANGED
@@ -137,10 +137,16 @@ class Jets::CLI
137
137
  end
138
138
 
139
139
  return unless jets_project?
140
- rake_task_found = Jets::Commands::RakeCommand.namespaced_commands.include?(full_command)
141
- if rake_task_found
142
- return Jets::Commands::RakeCommand
143
- end
140
+
141
+ Jets::Commands::RakeCommand if rake_task_found
142
+ end
143
+
144
+ def rake_task_found
145
+ return false unless full_command # can be nil for subcommands and would break jets help without this check
146
+ bracket_regex = /\[.*/ # matches everything after the first [
147
+ command = full_command.sub(bracket_regex, '') # remove everything after the first [
148
+ namespaced_commands = Jets::Commands::RakeCommand.namespaced_commands.map {|x| x.sub(bracket_regex, '') }
149
+ namespaced_commands.include?(command)
144
150
  end
145
151
 
146
152
  def jets_project?
@@ -56,7 +56,7 @@ class Jets::Commands::Call
56
56
 
57
57
  @@parent_stack = nil
58
58
  def parent_stack
59
- @@parent_stack ||= cfn.describe_stacks(stack_name: Jets::Naming.parent_stack_name).stacks.first
59
+ @@parent_stack ||= cfn.describe_stacks(stack_name: Jets::Names.parent_stack_name).stacks.first
60
60
  end
61
61
  end
62
62
  end
@@ -4,7 +4,7 @@
4
4
  # /aws/lambda/demo-dev-2-jets-preheat_job-warm
5
5
  # /aws/lambda/demo-dev-2-jets-public_controller-show
6
6
  #
7
- # We're doing this because JETS_ENV_EXTRA environments can create additional matching
7
+ # We're doing this because Jets.extra environments can create additional matching
8
8
  # log groups and we don't want to overly-aggressively delete them.
9
9
  #
10
10
  # The `keep_prefixes(log_group_names)` method calcuates the log groups to keep.
@@ -49,7 +49,7 @@ class Jets::Commands::Clean
49
49
 
50
50
  private
51
51
  def prefix_guess
52
- Jets::Naming.parent_stack_name
52
+ Jets::Names.parent_stack_name
53
53
  end
54
54
 
55
55
  def log_groups
@@ -78,7 +78,7 @@ class Jets::Commands::Clean
78
78
 
79
79
  # Check for the prefixes to keep. The slightly tricky thing to watch for is
80
80
  # for the prefix matching addiitonal log groups that belong to other
81
- # JETS_ENV_EXTRA=xxx created environments.
81
+ # JETS_EXTRA=xxx created environments.
82
82
  #
83
83
  # We find and store the prefixes to keep so we don't over aggressively delete
84
84
  # log groups.
@@ -16,7 +16,7 @@ module Jets::Commands
16
16
 
17
17
  def load_yaml
18
18
  if File.exist?(path)
19
- YAML.load_file(path)
19
+ Jets::Util::Yamler.load_file(path)
20
20
  else
21
21
  {}
22
22
  end