fly.io-rails 0.1.6 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 77922df296b340d88899a1249c1d962f1b13976c35af4d777f4572d999c10195
4
- data.tar.gz: 9a7738006ada1ce48323a0017dae4917ef974a4bbd7b1dab39c0428554a21086
3
+ metadata.gz: a9adb2bd6c53c8d27b9ade8898e4a5fb4621f5711781e35b8a273535e66996ec
4
+ data.tar.gz: 749a208099b67b3bad53c1b729ef873bb911ae7e69368f7b04863aa65519fee8
5
5
  SHA512:
6
- metadata.gz: ffc9e1793531cd8b3a399dab5bdcb7a93f75a37f051bbd868e5c78686e4fa34be94559dd573317317956cc7477ef131c5157671ef57f37e83a35eb47cd64362d
7
- data.tar.gz: ba8eda493ee0e6c530ee529f637e76d7c0e3ee46333a62acffcefa211914573f03ef7896c92f9f626c6aa66cdce229916eeaa3ddc998c6b6612a695fe5701cd6
6
+ metadata.gz: 60db97b7cf7f75b5c5485ca6395c2d6398b54148a8e5fb1547483c272366c052f2d6810a3882fe65eda906627e936555269dc71b1208404ab1d772d29082c640
7
+ data.tar.gz: 0fd8e2988a4ece554272b0a61e63994243bfa23ad421f2ffdd9f0fd7f5beb446ef09cad99acfbdd7c787ed21b398a597ada26f74d203310dd444667aad7a82a2
data/README.md CHANGED
@@ -10,6 +10,25 @@ For usage instructions, see the following guides:
10
10
  * [Lite FS](https://fly.io/docs/rails/advanced-guides/litefs/)
11
11
  * [Terraform](https://fly.io/docs/rails/advanced-guides/terraform/)
12
12
 
13
+ ## Generator options
14
+
15
+ * `--name` name of the application. If a name is not provided, one will be generated for you.
16
+ * `--org` the organization to operate on. Defaults to `personal`.
17
+ * `--region` region to launch the application in. Accepts multiple values, and can be specified multiple times.
18
+ * `--nomad` generates a nomad application instead of a machines application.
19
+ * `--litefs` adds support for replicated sqlite3 databases via [litefs](https://fly.io/blog/introducing-litefs/). Only works on nomad machines currently.
20
+ * `--passenger` run your Rails application with [nginx](https://www.nginx.com/) and [Phusion Passenger](https://www.phusionpassenger.com/).
21
+ * `--serverless` configures your application to exit after 5 minutes of inactivity. Machines will automatically restart when next accessed. Only works with passenger currently.
22
+
23
+ ## Automatically detected features
24
+
25
+ * _ruby_: the deployed application will use the same version of ruby and bundler as your development environment.
26
+ * _node_: if the use of node is detected, node, yarn, and your npm packages will be installed.
27
+ * _sqlite3_: if the production database is sqlite3 a volume will be allocated and the database will be put there.
28
+ * _postgres_: if the production database is postgres a postgres machine will be allocated
29
+ * _redis_: if redis is used for action cable, caching, or sidekiq your redis database will be added to this application. If you don't currently have a redis database, one will be allocated. If redis is used for caching, eviction will be turned on.
30
+ * _sidekiq_: if sidekiq is used it will be launched along side of your rails application.
31
+
13
32
  ## Key files
14
33
 
15
34
  * Entrypoints: [lib/tasks/fly.rake](./lib/tasks/fly.rake), [lib/generators/app_generator.rb](./lib/generators/app_generator.rb), [lib/generators/terraform_generator.rb](.lib/generators/terraform_generator.rb) contain the deploy task, fly:app generator and
@@ -26,8 +26,10 @@ module Fly
26
26
  regions = options[:region]&.flatten || []
27
27
  @litefs = options[:litefs]
28
28
  @nomad = options[:nomad]
29
+ @passenger = options[:passenger]
30
+ @serverless = options[:serverless]
29
31
 
30
- # prepare template variablesl
32
+ # prepare template variables
31
33
  @ruby_version = RUBY_VERSION
32
34
  @bundler_version = Bundler::VERSION
33
35
  @node = File.exist? 'node_modules'
@@ -56,6 +58,11 @@ module Fly
56
58
 
57
59
  # set additional variables based on application source
58
60
  scan_rails_app
61
+
62
+ # determine processes
63
+ @procs = {web: 'bin/rails server'}
64
+ @procs[:web] = "nginx -g 'daemon off;'" if @passenger
65
+ @procs[:worker] = 'bundle exec sidekiq' if @sidekiq
59
66
  end
60
67
 
61
68
  def app
@@ -91,6 +98,16 @@ module Fly
91
98
  app_template 'dockerignore.erb', '.dockerignore'
92
99
  end
93
100
 
101
+ def generate_nginx_conf
102
+ return unless @passenger
103
+ app_template 'nginx.conf.erb', 'config/nginx.conf'
104
+
105
+ if @serverless
106
+ app_template 'hook_detached_process.erb', 'config/hook_detached_process'
107
+ FileUtils.chmod 'u+x', 'config/hook_detached_process'
108
+ end
109
+ end
110
+
94
111
  def generate_terraform
95
112
  app_template 'main.tf.erb', 'main.tf'
96
113
  end
@@ -100,7 +117,7 @@ module Fly
100
117
  end
101
118
 
102
119
  def generate_procfile
103
- return unless @sidekiq
120
+ return unless @procs.length > 1
104
121
  app_template 'Procfile.fly.erb', 'Procfile.fly'
105
122
  end
106
123
 
@@ -187,7 +204,7 @@ module Fly
187
204
  start = Fly::Machines.create_and_start_machine(app, config: config)
188
205
  machine = start[:id]
189
206
 
190
- if !machine
207
+ if not machine
191
208
  STDERR.puts 'Error starting release machine'
192
209
  PP.pp start, STDERR
193
210
  exit 1
@@ -197,24 +214,27 @@ module Fly
197
214
  timeout: 60, state: 'started'
198
215
 
199
216
  # wait for release to copmlete
200
- status = nil
201
217
  5.times do
202
218
  status = Fly::Machines.wait_for_machine app, machine,
203
- timeout: 60, state: 'stopped'
204
- return machine if status[:ok]
219
+ instance_id: start[:instance_id], timeout: 60, state: 'stopped'
220
+ break if status[:ok]
205
221
  end
206
222
 
207
- # wait for release to copmlete
208
- event = nil
209
- 90.times do
210
- sleep 1
211
- status = Fly::Machines.get_a_machine app, machine
212
- event = status[:events]&.first
213
- return machine if event && event[:type] == 'exit'
214
- end
223
+ if status and status[:ok]
224
+ event = nil
225
+ 300.times do
226
+ status = Fly::Machines.get_a_machine app, start[:id]
227
+ event = status[:events]&.first
228
+ break if event[:type] == 'exit'
229
+ sleep 0.2
230
+ end
215
231
 
216
- STDERR.puts event.to_json
217
- exit 1
232
+ exit_code = event&.dig(:request, :exit_event, :exit_code)
233
+ Fly::Machines.delete_machine app, machine if machine
234
+ return event, exit_code, machine
235
+ else
236
+ return status, nil, nil
237
+ end
218
238
  end
219
239
 
220
240
  def launch(app)
@@ -296,8 +316,14 @@ module Fly
296
316
 
297
317
  # perform release
298
318
  say_status :fly, release_config[:env]['SERVER_COMMAND']
299
- machine = release(app, release_config)
300
- Fly::Machines.delete_machine app, machine if machine
319
+ event, exit_code, machine = release(app, release_config)
320
+
321
+ if exit_code != 0
322
+ STDERR.puts 'Error performing release'
323
+ STDERR.puts (exit_code ? {exit_code: exit_code} : event).inspect
324
+ STDERR.puts "run 'flyctl logs --instance #{machine}' for more information"
325
+ exit 1
326
+ end
301
327
 
302
328
  # start proxy, if necessary
303
329
  endpoint = Fly::Machines::fly_api_hostname!
@@ -357,18 +383,17 @@ module Fly
357
383
  end
358
384
 
359
385
  def terraform(app, image)
360
- # update main.tf with the image name
361
- tf = IO.read('main.tf')
362
- tf[/^\s*image\s*=\s*"(.*?)"/, 1] = image.strip
363
- IO.write 'main.tf', tf
364
-
365
- # find first machine in terraform config file
366
- machines = Fly::HCL.parse(IO.read('main.tf')).find {|block|
367
- block.keys.first == :resource and
368
- block.values.first.keys.first == 'fly_machine'}
386
+ # find first machine using the image ref in terraform config file
387
+ machine = Fly::HCL.parse(IO.read('main.tf')).
388
+ map {|block| block.dig(:resource, 'fly_machine')}.compact.
389
+ find {|machine| machine.values.first[:image] == 'var.image_ref'}
390
+ if not machine
391
+ STDERR.puts 'unable to find fly_machine with image = var.image_ref in main.rf'
392
+ exit 1
393
+ end
369
394
 
370
395
  # extract HCL configuration for the machine
371
- config = machines.values.first.values.first.values.first
396
+ config = machine.values.first
372
397
 
373
398
  # delete HCL specific configuration items
374
399
  %i(services for_each region app name depends_on).each do |key|
@@ -390,40 +415,25 @@ module Fly
390
415
  config[:env] ||= {}
391
416
  config[:env]['SERVER_COMMAND'] = 'bin/rails fly:release'
392
417
 
418
+ # fill in image
419
+ config[:image] = image
420
+
393
421
  # start proxy, if necessary
394
422
  endpoint = Fly::Machines::fly_api_hostname!
395
423
 
396
- # start release machine
397
- STDERR.puts "--> #{config[:env]['SERVER_COMMAND']}"
398
- start = Fly::Machines.create_and_start_machine(app, config: config)
399
- machine = start[:id]
400
-
401
- if !machine
402
- STDERR.puts 'Error starting release machine'
403
- PP.pp start, STDERR
404
- exit 1
405
- end
406
-
407
- # wait for release to copmlete
408
- event = nil
409
- 90.times do
410
- sleep 1
411
- status = Fly::Machines.get_a_machine app, machine
412
- event = status[:events]&.first
413
- break if event && event[:type] == 'exit'
424
+ # perform release, if necessary
425
+ if (IO.read('lib/tasks/fly.rake') rescue '') =~ /^\s*task[ \t]*+:?release"?[ \t]*\S/
426
+ say_status :fly, config[:env]['SERVER_COMMAND']
427
+ event, exit_code, machine = release(app, config)
428
+ else
429
+ exit_code = 0
414
430
  end
415
431
 
416
- # extract exit code
417
- exit_code = event.dig(:request, :exit_event, :exit_code)
418
-
419
432
  if exit_code == 0
420
- # delete release machine
421
- Fly::Machines.delete_machine app, machine
422
-
423
433
  # use terraform apply to deploy
424
434
  ENV['FLY_API_TOKEN'] = `flyctl auth token`.chomp
425
435
  ENV['FLY_HTTP_ENDPOINT'] = endpoint if endpoint
426
- system 'terraform apply -auto-approve'
436
+ system "terraform apply -auto-approve -var=\"image_ref=#{image}\""
427
437
  else
428
438
  STDERR.puts 'Error performing release'
429
439
  STDERR.puts (exit_code ? {exit_code: exit_code} : event).inspect
@@ -2,26 +2,26 @@ module Fly
2
2
  module DSL
3
3
  class Base
4
4
  def initialize
5
- @value = {}
5
+ @value = {}
6
6
  end
7
7
 
8
8
  def self.option name, default=nil
9
- @options ||= {}
10
- @options[name] = default
11
-
12
- define_method name do |*args|
13
- if args.length == 1
14
- @value[name] = args.first
15
- elsif args.length > 1
16
- raise ArgumentError.new("wrong number of arguments (given #{args.length}, expected 0..1)")
17
- end
18
-
19
- @value.include?(name) ? @value[name] : default
20
- end
9
+ @options ||= {}
10
+ @options[name] = default
11
+
12
+ define_method name do |*args|
13
+ if args.length == 1
14
+ @value[name] = args.first
15
+ elsif args.length > 1
16
+ raise ArgumentError.new("wrong number of arguments (given #{args.length}, expected 0..1)")
17
+ end
18
+
19
+ @value.include?(name) ? @value[name] : default
20
+ end
21
21
  end
22
22
 
23
23
  def self.options
24
- @options ||= {}
24
+ @options ||= {}
25
25
  end
26
26
  end
27
27
 
@@ -53,21 +53,21 @@ module Fly
53
53
  @@blocks = {}
54
54
 
55
55
  def initialize
56
- @config = {}
56
+ @config = {}
57
57
  end
58
58
 
59
59
  def self.block name, kind
60
- @@blocks[name] = kind
60
+ @@blocks[name] = kind
61
61
 
62
- define_method name do |&block|
63
- @config[name] ||= kind.new
64
- @config[name].instance_eval(&block) if block
65
- @config[name]
66
- end
62
+ define_method name do |&block|
63
+ @config[name] ||= kind.new
64
+ @config[name].instance_eval(&block) if block
65
+ @config[name]
66
+ end
67
67
  end
68
68
 
69
69
  def self.blocks
70
- @@blocks
70
+ @@blocks
71
71
  end
72
72
 
73
73
  block :machine, Machine
@@ -14,8 +14,10 @@ module Fly
14
14
 
15
15
  @sidekiq = IO.read('Gemfile').include? 'sidekiq' rescue false
16
16
 
17
+ @cable = ! Dir['app/channels/*.rb'].empty?
18
+
17
19
  if (YAML.load_file('config/cable.yml').dig('production', 'adapter') rescue false)
18
- @redis_cable = true
20
+ @redis_cable = @cable
19
21
  end
20
22
 
21
23
  if (IO.read('config/environments/production.rb') =~ /redis/i rescue false)
@@ -1,3 +1,3 @@
1
1
  module Fly_io
2
- VERSION = '0.1.6'
2
+ VERSION = '0.1.8'
3
3
  end
@@ -10,6 +10,8 @@ class AppGenerator < Rails::Generators::Base
10
10
  class_option :nomad, type: :boolean, default: false
11
11
 
12
12
  class_option :litefs, type: :boolean, default: false
13
+ class_option :passenger, type: :boolean, default: false
14
+ class_option :serverless, type: :boolean, default: false
13
15
 
14
16
  def generate_app
15
17
  source_paths.push File.expand_path('../templates', __dir__)
@@ -22,6 +24,7 @@ class AppGenerator < Rails::Generators::Base
22
24
  action.generate_fly_config unless File.exist? 'config/fly.rb'
23
25
  action.generate_dockerfile unless File.exist? 'Dockerfile'
24
26
  action.generate_dockerignore unless File.exist? '.dockerignore'
27
+ action.generate_nginx_conf unless File.exist? 'config/nginx.conf'
25
28
  action.generate_raketask unless File.exist? 'lib/tasks/fly.rake'
26
29
  action.generate_procfile unless File.exist? 'Procfile.rake'
27
30
  action.generate_litefs if options[:litefs] and not File.exist? 'config/litefs'
@@ -9,6 +9,8 @@ class TerraformGenerator < Rails::Generators::Base
9
9
  class_option :region, type: :array, repeatable: true, default: []
10
10
 
11
11
  class_option :litefs, type: :boolean, default: false
12
+ class_option :passenger, type: :boolean, default: false
13
+ class_option :serverless, type: :boolean, default: false
12
14
 
13
15
  def terraform
14
16
  source_paths.push File.expand_path('../templates', __dir__)
@@ -20,6 +22,7 @@ class TerraformGenerator < Rails::Generators::Base
20
22
  action.generate_toml
21
23
  action.generate_dockerfile
22
24
  action.generate_dockerignore
25
+ action.generate_nginx_conf
23
26
  action.generate_terraform
24
27
  action.generate_raketask
25
28
  action.generate_procfile
@@ -81,7 +81,7 @@ RUN gem update --system --no-document && \
81
81
 
82
82
  COPY Gemfile* ./
83
83
  RUN bundle install && rm -rf vendor/bundle/ruby/*/cache
84
- <% if @sidekiq -%>
84
+ <% if @procs.length > 1 -%>
85
85
  RUN gem install foreman
86
86
  <% end -%>
87
87
 
@@ -115,6 +115,7 @@ FROM base
115
115
 
116
116
  <%
117
117
  @deploy_packages = %w(file vim curl gzip)
118
+ @deploy_packages += %w(nginx passenger libnginx-mod-http-passenger) if @passenger
118
119
  @deploy_packages << 'postgresql-client' if @postgresql
119
120
  @deploy_packages << 'libsqlite3-0' if @sqlite3
120
121
  @deploy_packages << 'fuse' if @litefs
@@ -122,6 +123,13 @@ FROM base
122
123
  ARG DEPLOY_PACKAGES=<%= @deploy_packages.join(' ').inspect %>
123
124
  ENV DEPLOY_PACKAGES=${DEPLOY_PACKAGES}
124
125
 
126
+ <% if @passenger -%>
127
+ RUN apt-get install -y dirmngr gnupg apt-transport-https ca-certificates curl && \
128
+ curl https://oss-binaries.phusionpassenger.com/auto-software-signing-gpg-key.txt | \
129
+ gpg --dearmor > /etc/apt/trusted.gpg.d/phusion.gpg && \
130
+ sh -c 'echo deb https://oss-binaries.phusionpassenger.com/apt/passenger bullseye main > /etc/apt/sources.list.d/passenger.list'
131
+
132
+ <% end -%>
125
133
  RUN --mount=type=cache,id=prod-apt-cache,sharing=locked,target=/var/cache/apt \
126
134
  --mount=type=cache,id=prod-apt-lib,sharing=locked,target=/var/lib/apt \
127
135
  apt-get update -qq && \
@@ -150,6 +158,16 @@ ADD config/litefs.yml /etc/litefs.yml
150
158
  RUN mkdir /data
151
159
  <% end -%>
152
160
  #######################################################################
161
+ <% if @passenger -%>
162
+
163
+ # configure nginx/passenger
164
+ COPY config/nginx.conf /etc/nginx/sites-available/rails.conf
165
+ RUN rm /etc/nginx/sites-enabled/default && \
166
+ ln -s /etc/nginx/sites-available/rails.conf /etc/nginx/sites-enabled/
167
+ <% if @serverless -%>
168
+ COPY config/hook_detached_process /etc/nginx/
169
+ <% end -%>
170
+ <% end -%>
153
171
 
154
172
  # Deploy your application
155
173
  COPY . .
@@ -1,4 +1,3 @@
1
- web: bin/rails server
2
- <% if @sidekiq -%>
3
- worker: bundle exec sidekiq
1
+ <% @procs.each do |type, command| -%>
2
+ <%= type %>: <%= command %>
4
3
  <% end -%>
@@ -28,12 +28,12 @@ namespace :fly do
28
28
  <%- else -%>
29
29
  task :server => :swapfile do
30
30
  <%- end -%>
31
- <%- if @sidekiq -%>
31
+ <%- if @procs.length > 1 -%>
32
32
  Bundler.with_original_env do
33
33
  sh 'foreman start --procfile=Procfile.fly'
34
34
  end
35
35
  <%- else -%>
36
- sh 'bin/rails server'
36
+ sh <%= @procs.values.first.inspect %>
37
37
  <%- end -%>
38
38
  end
39
39
 
@@ -25,8 +25,8 @@ processes = []
25
25
  <% end -%>
26
26
 
27
27
  [mounts]
28
- source = <%= "#{app.gsub('-', '_')}_volume".inspect %>
29
- destination = "/mnt/volume"
28
+ source = <%= "#{app.gsub('-', '_')}_volume".inspect %>
29
+ destination = "/mnt/volume"
30
30
  <% end -%>
31
31
 
32
32
  [experimental]
@@ -43,8 +43,13 @@ destination = "/mnt/volume"
43
43
  protocol = "tcp"
44
44
  script_checks = []
45
45
  [services.concurrency]
46
+ <% if @cable -%>
47
+ hard_limit = 2500
48
+ soft_limit = 2000
49
+ <% else -%>
46
50
  hard_limit = 25
47
51
  soft_limit = 20
52
+ <% end -%>
48
53
  type = "connections"
49
54
 
50
55
  [[services.ports]]
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ status = `passenger-status`
4
+
5
+ processes = status[/^Processes\s*:\s*(\d*)/, 1].to_i
6
+ <% if @cable -%>
7
+ cable = status[/^<%= @app %>-cable.*?\n\n/m]
8
+ processes -= 1 if cable and cable =~ /Sessions:\s*[1-9]/
9
+ <% end -%>
10
+
11
+ system 'nginx -s stop' if processes == 0
@@ -2,11 +2,16 @@ terraform {
2
2
  required_providers {
3
3
  fly = {
4
4
  source = "fly-apps/fly"
5
- version = "0.0.18"
5
+ version = "0.0.20"
6
6
  }
7
7
  }
8
8
  }
9
9
 
10
+ variable "image_ref" {
11
+ type = string
12
+ description = "docker images containing the application"
13
+ }
14
+
10
15
  /* uncomment if you want an internal tunnel
11
16
  provider "fly" {
12
17
  useinternaltunnel = true
@@ -49,7 +54,7 @@ resource "fly_machine" "<%= @appName %>Machine" {
49
54
 
50
55
  app = <%= @app.inspect %>
51
56
  name = "<%= @app %>-${each.value}"
52
- image = "quay.io/evl.ms/fullstaq-ruby:<%= @ruby_version %>-jemalloc-slim"
57
+ image = var.image_ref
53
58
 
54
59
  # Scale application resources
55
60
  cpus = 1
@@ -0,0 +1,29 @@
1
+ <% if @serverless -%>
2
+ passenger_ctl hook_detached_process /etc/nginx/hook_detached_process;
3
+ passenger_min_instances 0;
4
+ passenger_pool_idle_time 300;
5
+
6
+ <% end -%>
7
+ server {
8
+ listen 8080;
9
+ server_name <%= @app %>.fly.dev;
10
+ root /app/public;
11
+
12
+ passenger_enabled on;
13
+ passenger_ruby /usr/lib/fullstaq-ruby/versions/<%= @ruby_version %>-jemalloc/bin/ruby;
14
+
15
+ <% if @cable -%>
16
+ location / {
17
+ passenger_app_group_name <%= @app%>;
18
+ }
19
+
20
+ location /cable {
21
+ passenger_app_group_name <%= @app%>-cable;
22
+ passenger_force_max_concurrent_requests_per_process 0;
23
+ }
24
+
25
+ <% end -%>
26
+ # Nginx has a default limit of 1 MB for request bodies, which also applies
27
+ # to file uploads. The following line enables uploads of up to 50 MB:
28
+ client_max_body_size 50M;
29
+ }
data/lib/tasks/fly.rake CHANGED
@@ -37,6 +37,18 @@ namespace :fly do
37
37
  action.generate_ipv6 if @app
38
38
  action.deploy(app, image)
39
39
  end
40
+
41
+ JSON.parse(`fly apps list --json`).each do |info|
42
+ if info['Name'] == app
43
+ 60.times do
44
+ response = Net::HTTP.get_response(URI::HTTPS.build(host: info['Hostname']))
45
+ puts "Server status: #{response.code} #{response.message}"
46
+ break
47
+ rescue Errno::ECONNRESET
48
+ sleep 0.5
49
+ end
50
+ end
51
+ end
40
52
  end
41
53
  end
42
54
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fly.io-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Ruby
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-10-03 00:00:00.000000000 Z
11
+ date: 2022-10-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fly-ruby
@@ -67,15 +67,17 @@ files:
67
67
  - lib/generators/templates/fly.rake.erb
68
68
  - lib/generators/templates/fly.rb.erb
69
69
  - lib/generators/templates/fly.toml.erb
70
+ - lib/generators/templates/hook_detached_process.erb
70
71
  - lib/generators/templates/litefs.yml.erb
71
72
  - lib/generators/templates/main.tf.erb
73
+ - lib/generators/templates/nginx.conf.erb
72
74
  - lib/generators/templates/patches/action_cable.rb
73
75
  - lib/tasks/fly.rake
74
- homepage: https://github.com/rubys/fly-io.rails
76
+ homepage: https://github.com/rubys/fly.io-rails
75
77
  licenses:
76
78
  - Apache-2.0
77
79
  metadata:
78
- homepage_uri: https://github.com/rubys/fly-io.rails
80
+ homepage_uri: https://github.com/rubys/fly.io-rails
79
81
  post_install_message:
80
82
  rdoc_options: []
81
83
  require_paths: