Class: Cloudflare::Email::Generators::InstallGenerator

Inherits:
Rails::Generators::Base
  • Object
show all
Defined in:
lib/generators/cloudflare/email/install_generator.rb

Instance Method Summary collapse

Instance Method Details

#configure_action_mailbox_ingressObject



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/generators/cloudflare/email/install_generator.rb', line 74

def configure_action_mailbox_ingress
  return unless options[:inbound]

  envs = ["production"]
  envs += ["development", "test"] if options[:all_envs]

  envs.each do |env|
    file = "config/environments/#{env}.rb"
    next unless File.exist?(file)
    next if File.read(file).include?("action_mailbox.ingress = :cloudflare")

    inject_into_file file,
      "  config.action_mailbox.ingress = :cloudflare\n",
      after: /Rails\.application\.configure do\n/
  end
end

#copy_worker_templateObject



91
92
93
94
95
96
# File 'lib/generators/cloudflare/email/install_generator.rb', line 91

def copy_worker_template
  return unless options[:inbound]

  worker_src = File.expand_path("../../../../templates/worker", __dir__)
  directory worker_src, options[:worker_dir]
end

#create_initializerObject



27
28
29
# File 'lib/generators/cloudflare/email/install_generator.rb', line 27

def create_initializer
  template "initializer.rb", "config/initializers/cloudflare_email.rb"
end

#ensure_action_mailbox_installedObject



31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/generators/cloudflare/email/install_generator.rb', line 31

def ensure_action_mailbox_installed
  return unless options[:inbound]
  return if File.exist?("app/mailboxes/application_mailbox.rb")

  say ""
  if yes?("ActionMailbox isn't installed yet. Run `bin/rails action_mailbox:install` now? [Y/n]", :green)
    rails_command "action_mailbox:install", inline: true
    rails_command "db:migrate",             inline: true
  else
    say "  Skipping — run `bin/rails action_mailbox:install` manually before inbound will work.", :yellow
  end
end

#maybe_deploy_workerObject



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/generators/cloudflare/email/install_generator.rb', line 98

def maybe_deploy_worker
  return unless options[:inbound]

  should_deploy = options[:deploy_worker]
  if should_deploy.nil?
    say ""
    say "  The Worker can be deployed via the Cloudflare API (pure Ruby, no wrangler/Node)"
    say "  once you've set cloudflare.account_id and cloudflare.api_token in Rails credentials."
    say "  Run `bin/rails cloudflare:email:deploy_worker URL=https://yourapp.com#{ingress_path}`"
    say "  after `bin/rails credentials:edit`."
    say ""
    say "  Alternatively, deploy now via wrangler if it's installed locally." if wrangler_installed?
  end

  if should_deploy && wrangler_installed?
    wrangler_deploy
  end
end

#maybe_scaffold_mailboxObject



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/generators/cloudflare/email/install_generator.rb', line 44

def maybe_scaffold_mailbox
  return unless options[:inbound]
  return unless File.exist?("app/mailboxes/application_mailbox.rb")

  if File.exist?("app/mailboxes/main_mailbox.rb")
    say "  app/mailboxes/main_mailbox.rb already exists — skipping.", :cyan
    return
  end

  if active_route?("app/mailboxes/application_mailbox.rb")
    say "  ApplicationMailbox already has routes — skipping MainMailbox scaffold.", :cyan
    return
  end

  should_scaffold = options[:scaffold_mailbox]
  if should_scaffold.nil?
    should_scaffold = yes?(
      "Scaffold a default MainMailbox + catch-all route so inbound has somewhere to land? [Y/n]",
      :green,
    )
  end
  return unless should_scaffold

  template "main_mailbox.rb", "app/mailboxes/main_mailbox.rb"

  inject_into_class "app/mailboxes/application_mailbox.rb", "ApplicationMailbox" do
    "  routing :all => :main\n"
  end
end

#print_post_installObject



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/generators/cloudflare/email/install_generator.rb', line 137

def print_post_install
  @ingress_secret ||= SecureRandom.hex(32) if options[:inbound]

  say ""
  say "  cloudflare-email installed.", :green
  say ""
  say "  Next steps:"
  say ""
  say "  1. Add credentials:"
  say "       bin/rails credentials:edit"
  say "     cloudflare:"
  say "       account_id: <your-account-id>"
  say "       api_token:  <your-api-token>"
  if options[:inbound]
    say "       ingress_secret: #{@ingress_secret}"
  end
  say ""
  say "  2. Verify your setup:"
  say "       bin/rails cloudflare:email:doctor"
  say ""
  say "  3. Send a test email:"
  say "       TO=you@example.com bin/rails cloudflare:email:send_test"
  say ""

  if options[:inbound] && !@worker_deployed
    say "  4. Deploy the Worker (pick one):"
    say "       # Pure Ruby (recommended — no wrangler/Node required):"
    say "       bin/rails cloudflare:email:deploy_worker URL=https://yourapp.com#{ingress_path}"
    say ""
    say "       # Or via wrangler if you have it installed:"
    say "       cd #{options[:worker_dir]}"
    say "       npm install --legacy-peer-deps"
    say "       wrangler secret put INGRESS_SECRET     # paste #{@ingress_secret[0, 8]}..."
    say "       wrangler secret put RAILS_INGRESS_URL  # https://yourapp.com#{ingress_path}"
    say "       wrangler deploy"
    say ""
  end

  if options[:inbound]
    say "  5. For local dev (tunnels cloudflared to your Worker):"
    say "       bin/rails cloudflare:email:dev"
    say ""
    say "  6. In the Cloudflare dashboard:"
    say "       Email Routing -> Routes -> Send to a Worker -> #{worker_name}"
    say ""
    say "  Dashboard deep-links:"
    say "    API tokens:       https://dash.cloudflare.com/profile/api-tokens"
    say "    Sending domains:  https://dash.cloudflare.com/?to=/:account/email/sending"
    say "    Email routing:    https://dash.cloudflare.com/?to=/:account/email/routing"
    say ""
    say "  Rotation: to rotate the ingress secret, update cloudflare.ingress_secret"
    say "  in Rails credentials AND re-run `wrangler secret put INGRESS_SECRET` in"
    say "  #{options[:worker_dir]}/ with the new value, then redeploy the Worker."
    say ""
    say "  Dev/test: by default only production.rb is wired to :cloudflare ingress."
    say "  Re-run with --all-envs to also configure development.rb and test.rb."
  end
  say ""
end

#wrangler_deployObject



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/generators/cloudflare/email/install_generator.rb', line 117

def wrangler_deploy
  @ingress_secret = SecureRandom.hex(32)

  inside options[:worker_dir] do
    run "npm install --legacy-peer-deps", abort_on_failure: true

    ingress_url = ask("Rails ingress URL? (e.g. https://yourapp.com#{ingress_path})")
    if ingress_url.to_s.strip.empty?
      say "  Skipping Worker deploy — no URL supplied. Re-run `wrangler deploy` manually when ready.", :yellow
      return
    end

    run_with_stdin("wrangler secret put RAILS_INGRESS_URL", ingress_url.strip)
    run_with_stdin("wrangler secret put INGRESS_SECRET",    @ingress_secret)
    run "wrangler deploy", abort_on_failure: false
  end

  @worker_deployed = true
end