jets 0.9.1 → 0.9.2

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: 662007ebe84e8e8ce5d9a773a4ec6905ed8a1da7caecf8870de788d60e5d337c
4
- data.tar.gz: e2a21d607b931d356fda5b743a578534466f65890a38ea7db942c2985eb30570
3
+ metadata.gz: 61d62ec1deed884ea8ccccd1b6f6cafdbccf8f9778b9ddfb9bc80d827c3b8f2d
4
+ data.tar.gz: 4edc9600af70c32b175ba077a5d75b55575c030807aa1c1ad26b96914b0c372b
5
5
  SHA512:
6
- metadata.gz: d5b1d727e2717b042774729a72aa889d35a98759299e3a6e3644527a6774fec05dbaa5669cc91ec92d082444cc980c464e5d887e74e055d273fecd3a27e2cf12
7
- data.tar.gz: b625070b21854521ccd111c06190cdc03703a3f336c48ea9370b51e675d21c028068319115cbc3f81a320431b4e480084b9b214fc4853ad89a1688b8aba64a5b
6
+ metadata.gz: 1ec1dcbb1c0a6a977dcdabbc2138178d43687d1257f40239e2e379400a435f84301f5b5105fb59d36860c9e4a8051c64547770963be63b6ea5a33c0ce4ffc142
7
+ data.tar.gz: 1e15d436ecf7fa3dea5852023afb2db0544ca56fc21c76c80d8554b8acffd1d98a20acceb1416038257a233bddeac95a3896ceddd4aceee62c505a55370742de
@@ -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
+ ## [0.9.2]
7
+ - s3 assets support: Merge pull request #44 from tongueroo/s3-assets
8
+
6
9
  ## [0.9.1]
7
10
  - add upgrading notes
8
11
  - fix iam policies: flatten
@@ -11,7 +11,7 @@ GIT
11
11
  PATH
12
12
  remote: .
13
13
  specs:
14
- jets (0.9.1)
14
+ jets (0.9.2)
15
15
  actionpack (>= 5.2.1)
16
16
  actionview (>= 5.2.1)
17
17
  activerecord (>= 5.2.1)
data/README.md CHANGED
@@ -8,6 +8,8 @@ Ruby and Lambda splat out a baby and that child's name is [Jets](http://rubyonje
8
8
  [![CircleCI](https://circleci.com/gh/tongueroo/jets.svg?style=svg)](https://circleci.com/gh/tongueroo/jets)
9
9
  [![Gem Version](https://badge.fury.io/rb/jets.svg)](https://badge.fury.io/rb/jets)
10
10
 
11
+ **Upgrading**: If you are upgrading Jets, please check on the [Upgrading Notes](http://rubyonjets.com/docs/upgrading/).
12
+
11
13
  ## What is Jets?
12
14
 
13
15
  Jets is a Ruby Serverless Framework. Jets allows you to create serverless applications with a beautiful language: Ruby. It includes everything required to build an application and deploy it to AWS Lambda.
@@ -19,8 +21,6 @@ It is key to understand AWS Lambda and API Gateway to understand Jets conceptual
19
21
 
20
22
  The official documentation is at: [Ruby on Jets](http://rubyonjets.com).
21
23
 
22
- **Upgrading Note**: If you are upgrading Jets, please check on the [Upgrading Notes](http://rubyonjets.com/docs/upgrading/).
23
-
24
24
  Refer to the official docs for more info, but here's a quick intro.
25
25
 
26
26
  ### Jets Controllers
@@ -21,6 +21,7 @@ class Jets::Application
21
21
  Jets::Inflections.load!
22
22
  end
23
23
 
24
+ # Default config
24
25
  def config
25
26
  config = ActiveSupport::OrderedOptions.new
26
27
 
@@ -28,7 +29,7 @@ class Jets::Application
28
29
  config.prewarm.enable = true
29
30
  config.prewarm.rate = '30 minutes'
30
31
  config.prewarm.concurrency = 2
31
- config.prewarm.public_ratio = 10
32
+ config.prewarm.public_ratio = 3
32
33
 
33
34
  config.lambdagems = ActiveSupport::OrderedOptions.new
34
35
  config.lambdagems.sources = [
@@ -38,6 +39,12 @@ class Jets::Application
38
39
  config.inflections = ActiveSupport::OrderedOptions.new
39
40
  config.inflections.irregular = {}
40
41
 
42
+ config.assets = ActiveSupport::OrderedOptions.new
43
+ config.assets.folders = %w[packs images assets]
44
+ config.assets.base_url = nil # IE: https://cloudfront.com/my/base/path
45
+ config.assets.max_age = 3600
46
+ config.assets.cache_control = nil # IE: public, max-age=3600 , max_age is a shorter way to set cache_control.
47
+
41
48
  config
42
49
  end
43
50
  memoize :config
@@ -53,6 +53,7 @@ class Jets::Builders
53
53
  class CodeBuilder
54
54
  include Jets::Timing
55
55
  include ActionView::Helpers::NumberHelper # number_to_human_size
56
+ include Jets::AwsServices
56
57
 
57
58
  attr_reader :full_project_path
58
59
  def initialize
@@ -103,9 +104,34 @@ class Jets::Builders
103
104
  setup_bundle_config
104
105
  extract_ruby
105
106
  extract_gems
107
+ store_s3_base_url
106
108
  end
107
109
  time :finish_app_root_setup
108
110
 
111
+ # At this point the minimal stack exists.
112
+ def store_s3_base_url
113
+ IO.write("#{full(tmp_app_root)}/config/s3_base_url.txt", s3_base_url)
114
+ end
115
+
116
+ def s3_base_url
117
+ # Allow user to set assets.base_url
118
+ #
119
+ # Jets.application.configure do
120
+ # config.assets.base_url = "https://cloudfront.com/my/base/path"
121
+ # end
122
+ #
123
+ return Jets.config.assets.base_url if Jets.config.assets.base_url
124
+
125
+ resp = cfn.describe_stacks(stack_name: Jets::Naming.parent_stack_name)
126
+ stack = resp.stacks.first
127
+ output = stack["outputs"].find { |o| o["output_key"] == "S3Bucket" }
128
+ bucket_name = output["output_value"] # s3_bucket
129
+ region = Jets.aws.region
130
+
131
+ asset_base_url = "https://s3-#{region}.amazonaws.com"
132
+ "#{asset_base_url}/#{bucket_name}/jets/public" # s3_base_url
133
+ end
134
+
109
135
  def lambdagem_options
110
136
  {
111
137
  s3: "lambdagems",
@@ -143,8 +143,17 @@ class Jets::Cfn
143
143
  def upload_to_s3
144
144
  raise "Did not specify @options[:s3_bucket] #{@options[:s3_bucket].inspect}" unless @options[:s3_bucket]
145
145
 
146
- bucket_name = @options[:s3_bucket]
146
+ upload_cfn_templates
147
+ upload_code
148
+ upload_assets
149
+ end
150
+ time :upload_to_s3
151
+
152
+ def bucket_name
153
+ @options[:s3_bucket]
154
+ end
147
155
 
156
+ def upload_cfn_templates
148
157
  puts "Uploading child CloudFormation templates to S3"
149
158
  expression = "#{Jets::Naming.template_path_prefix}-*"
150
159
  Dir.glob(expression).each do |path|
@@ -154,7 +163,9 @@ class Jets::Cfn
154
163
  obj = s3_resource.bucket(bucket_name).object(key)
155
164
  obj.upload_file(path)
156
165
  end
166
+ end
157
167
 
168
+ def upload_code
158
169
  md5_code_zipfile = Jets::Naming.md5_code_zipfile
159
170
  file_size = number_to_human_size(File.size(md5_code_zipfile))
160
171
 
@@ -165,7 +176,60 @@ class Jets::Cfn
165
176
  obj.upload_file(md5_code_zipfile)
166
177
  puts "Time to upload code to s3: #{pretty_time(Time.now-start_time).colorize(:green)}"
167
178
  end
168
- time :upload_to_s3
179
+
180
+ def upload_assets
181
+ puts "Uploading public assets"
182
+ start_time = Time.now
183
+ asset_folders = Jets.config.assets.folders
184
+ asset_folders.each do |folder|
185
+ upload_asset_folder(folder)
186
+ end
187
+ puts "Time to upload public assets to s3: #{pretty_time(Time.now-start_time).colorize(:green)}"
188
+ end
189
+
190
+ def upload_asset_folder(folder)
191
+ expression = "#{Jets.root}public/#{folder}/**/*"
192
+ group_size = 10
193
+ Dir.glob(expression).each_slice(group_size) do |paths|
194
+ threads = []
195
+ paths.each do |path|
196
+ next unless File.file?(path)
197
+
198
+ regexp = Regexp.new(".*/#{folder}/")
199
+ relative_path = path.sub(regexp,'')
200
+ file = "#{folder}/#{relative_path}"
201
+
202
+ threads << Thread.new do
203
+ upload_asset_file(file)
204
+ end
205
+ end
206
+ threads.each(&:join)
207
+ end
208
+ end
209
+
210
+ def upload_asset_file(file)
211
+ path = "#{Jets.root}public/#{file}"
212
+ key = "jets/public/#{file}"
213
+ puts "Uploading s3://#{bucket_name}/#{key}" # uncomment to see and debug
214
+ obj = s3_resource.bucket(bucket_name).object(key)
215
+ obj.upload_file(path, acl: "public-read", cache_control: cache_control)
216
+ end
217
+
218
+ # If cache_control is provided, then it will set the entire cache-control header.
219
+ # If only max_age is provided, then we'll generate a cache_control header.
220
+ # Using max_age is the shorter and simply way of setting the cache_control header.
221
+ def cache_control
222
+ cache_control = Jets.config.assets.cache_control
223
+ unless cache_control
224
+ max_age = Jets.config.assets.max_age # defaults to 3600 in jets/application.rb
225
+ cache_control = "public, max-age=#{max_age}"
226
+ end
227
+ cache_control
228
+ end
229
+
230
+ def s3_bucket
231
+ @options[:s3_bucket]
232
+ end
169
233
 
170
234
  # http://stackoverflow.com/questions/4175733/convert-duration-to-hoursminutesseconds-or-similar-in-rails-3-or-ruby
171
235
  def pretty_time(total_seconds)
@@ -14,26 +14,29 @@ module Jets::Commands
14
14
  return if @options[:noop]
15
15
 
16
16
  check_dev_mode
17
- build_code
18
17
  validate_routes!
19
18
 
20
19
  # Delete existing rollback stack from previous bad minimal deploy
21
- if minimal_rollback_complete?
22
- puts "Existing stack is in ROLLBACK_COMPLETE state from a previous failed minimal deploy. Deleting stack and continuing."
23
- cfn.delete_stack(stack_name: stack_name)
24
- status.wait
25
- status.reset
26
- end
20
+ delete_minimal_stack if minimal_rollback_complete?
21
+ exit_unless_updateable! # Stack could be in a weird rollback state or in progress state
22
+ ship(stack_type: :minimal) if first_run?
27
23
 
28
- # Stack could be in a weird rollback state or in progress state
29
- exit_unless_updateable!
24
+ # Build code after the minimal stack because need s3 bucket for assets
25
+ # on_aws? and s3_base_url logic
26
+ build_code
30
27
 
31
- ship(stack_type: :minimal) if first_run?
32
28
  # deploy full nested stack when stack already exists
33
29
  ship(stack_type: :full, s3_bucket: s3_bucket)
34
30
  end
35
31
  time :run
36
32
 
33
+ def delete_minimal_stack
34
+ puts "Existing stack is in ROLLBACK_COMPLETE state from a previous failed minimal deploy. Deleting stack and continuing."
35
+ cfn.delete_stack(stack_name: stack_name)
36
+ status.wait
37
+ status.reset
38
+ end
39
+
37
40
  def check_dev_mode
38
41
  if File.exist?("#{Jets.root}dev.mode")
39
42
  puts "The dev.mode file exists. Please removed it and run bundle update before you deploy.".colorize(:red)
@@ -8,6 +8,7 @@
8
8
  <title>Jets App</title>
9
9
  <%%= javascript_pack_tag "application" %>
10
10
  <%%= stylesheet_pack_tag "theme" %>
11
+ <link rel="shortcut icon" href="<%%= asset_path("/images/favicon.ico") %>">
11
12
  </head>
12
13
  <body>
13
14
  <section class="starter">
@@ -5,11 +5,13 @@ Jets.application.configure do
5
5
  # config.prewarm.enable = true # default is true
6
6
  # config.prewarm.rate = '30 minutes' # default is '30 minutes'
7
7
  # config.prewarm.concurrency = 2 # default is 2
8
- # config.prewarm.public_ratio = 10 # default is 10
8
+ # config.prewarm.public_ratio = 3 # default is 3
9
9
 
10
10
  # config.env_extra = 2 # can also set this with JETS_ENV_EXTRA
11
11
  # config.extra_autoload_paths = []
12
12
 
13
+ # config.asset_base_url = 'https://cloudfront.domain.com/assets' # example
14
+
13
15
  config.cors = true # for '*''
14
16
  # config.cors = '*.mydomain.com' # for specific domain
15
17
 
@@ -30,4 +32,10 @@ Jets.application.configure do
30
32
  # The config.function settings to the CloudFormation Lambda Function properties.
31
33
  # http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html
32
34
  # Underscored format can be used for keys to make it look more ruby-ish.
35
+
36
+ # Assets settings
37
+ # config.assets.folders = %w[packs images assets] # default packs images assets
38
+ # config.assets.base_url = nil # IE: https://cloudfront.com/my/base/path , defaults to use s3
39
+ # config.assets.max_age = 3600 # when to expire assets
40
+ # config.assets.cache_control = nil # IE: public, max-age=3600 , max_age is a shorter way to set cache_control.
33
41
  end
@@ -29,6 +29,7 @@ module Jets
29
29
  def warm_all
30
30
  threads = []
31
31
  all_functions.each do |function_name|
32
+ next if function_name.include?('jets-public_controller') # handled by warm_public_controller_more
32
33
  threads << Thread.new do
33
34
  warm(function_name)
34
35
  end
@@ -1,17 +1,56 @@
1
1
  # Override to prepend stage name when on AWS.
2
2
  module Jets::AssetTagHelper
3
+ extend Memoist
3
4
  include Jets::CommonMethods
5
+ include Jets::AwsServices
4
6
 
5
7
  def javascript_include_tag(*sources, **options)
6
- sources = sources.map { |s| stage_name_asset_url(s, :javascripts) }
8
+ sources = sources.map { |s| s3_asset_url(s, :javascripts) }
7
9
  super
8
10
  end
9
11
 
10
12
  def stylesheet_link_tag(*sources, **options)
11
- sources = sources.map { |s| stage_name_asset_url(s, :stylesheets) }
13
+ sources = sources.map { |s| s3_asset_url(s, :stylesheets) }
12
14
  super
13
15
  end
14
16
 
17
+ # Locally:
18
+ #
19
+ # image_tag("jets.png") => /images/jets.png
20
+ # image_tag("/images/jets.png") => /images/jets.png
21
+ #
22
+ # Remotely:
23
+ #
24
+ # image_tag("jets.png") => https://s3-us-west-2.amazonaws.com/demo-dev-s3bucket-1kih4n2te0n66/jets/public/images/jets.png
25
+ def image_tag(source, options = {})
26
+ # mimic original behavior to get /images in source
27
+ source = "/images/#{source}" unless source.starts_with?('/')
28
+ if on_aws?(source)
29
+ source = "#{s3_base_url}#{source}"
30
+ end
31
+
32
+ super
33
+ end
34
+
35
+ def asset_path(source, options = {})
36
+ if on_aws?(source) && asset_folder?(source)
37
+ # mimic original behavior to get /images in source
38
+ source = "/images/#{source}" unless source.starts_with?('/')
39
+ source = "#{s3_base_url}#{source}"
40
+ end
41
+
42
+ super
43
+ end
44
+
45
+ private
46
+ # Whatever is configured in Jets.config.assets.folders
47
+ # Example: packs, images, assets
48
+ def asset_folder?(url)
49
+ Jets.config.assets.folders.detect do |folder|
50
+ url.include?(folder)
51
+ end
52
+ end
53
+
15
54
  # User can use:
16
55
  # javascript_include_tag "assets/test"
17
56
  #
@@ -30,12 +69,25 @@ module Jets::AssetTagHelper
30
69
  # If there's a / in front then rails will not add the "javascript":
31
70
  # So we can add the javascript ourselves and then add the stag with a
32
71
  # / in front.
33
- def stage_name_asset_url(url, asset_type)
72
+ def s3_asset_url(url, asset_type)
34
73
  unless url.starts_with?('/') or url.starts_with?('http')
35
74
  url = "/#{asset_type}/#{url}" # /javascript/asset/test
36
75
  end
37
- url = add_stage_name(url)
38
- url
76
+ add_s3_base_url(url)
77
+ end
78
+
79
+ # Example:
80
+ # Url: /packs/application-e7654c50abd78161b641.js
81
+ # Returns: https://s3-us-west-2.amazonaws.com/demo-dev-s3bucket-1jg5o076egkk4/jets/public/packs/application-e7654c50abd78161b641.js
82
+ def add_s3_base_url(url)
83
+ return url unless on_aws?(url)
84
+ "#{s3_base_url}#{url}"
85
+ end
86
+
87
+ def s3_base_url
88
+ # s3_base_url.txt is created as part of the build process
89
+ IO.read("#{Jets.root}config/s3_base_url.txt").strip
39
90
  end
91
+ memoize :s3_base_url
40
92
  end
41
93
  ActionView::Helpers.send(:include, Jets::AssetTagHelper)
@@ -1,13 +1,13 @@
1
1
  module Jets::CommonMethods
2
2
  # Add API Gateway Stage Name
3
3
  def add_stage_name(url)
4
- if request.host.include?("amazonaws.com") &&
5
- url.starts_with?('/') &&
6
- !url.starts_with?('http')
7
- stage_name = Jets::Resource::ApiGateway::Deployment.stage_name
8
- url = "/#{stage_name}#{url}"
9
- end
4
+ return url unless on_aws?(url)
10
5
 
11
- url
6
+ stage_name = Jets::Resource::ApiGateway::Deployment.stage_name
7
+ "/#{stage_name}#{url}"
8
+ end
9
+
10
+ def on_aws?(url)
11
+ request.host.include?("amazonaws.com") && url.starts_with?('/')
12
12
  end
13
13
  end
@@ -19,8 +19,7 @@ module Jets::UrlHelper
19
19
  raise ArgumentError, "Please provided a String to link_to as the the second argument. The Jets link_to helper takes as the second argument."
20
20
  end
21
21
 
22
- url = add_stage_name(url)
23
- url
22
+ add_stage_name(url)
24
23
  end
25
24
  end # UrlHelper
26
25
  ActionView::Helpers.send(:include, Jets::UrlHelper)
@@ -1,3 +1,3 @@
1
1
  module Jets
2
- VERSION = "0.9.1"
2
+ VERSION = "0.9.2"
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: 0.9.1
4
+ version: 0.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tung Nguyen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-09-25 00:00:00.000000000 Z
11
+ date: 2018-09-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -541,7 +541,7 @@ files:
541
541
  - lib/jets/commands/templates/skeleton/public/404.html
542
542
  - lib/jets/commands/templates/skeleton/public/422.html
543
543
  - lib/jets/commands/templates/skeleton/public/500.html
544
- - lib/jets/commands/templates/skeleton/public/favicon.ico
544
+ - lib/jets/commands/templates/skeleton/public/images/favicon.ico
545
545
  - lib/jets/commands/templates/skeleton/public/index.html.tt
546
546
  - lib/jets/commands/templates/skeleton/spec/controllers/posts_controller_spec.rb
547
547
  - lib/jets/commands/templates/skeleton/spec/fixtures/payloads/posts-index.json