diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index d3f5e5b5..18a45cba 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -32,7 +32,7 @@ jobs: secrets: inherit with: name: Preview - target: production + target: staging image: "gmmcal/gmmcal:preview-${{ github.event.number }}-${{ github.run_number }}" publish: true diff --git a/Dockerfile b/Dockerfile index 7911f1f7..91dc0559 100644 --- a/Dockerfile +++ b/Dockerfile @@ -61,6 +61,20 @@ ENTRYPOINT ["/rails/bin/docker-entrypoint"] EXPOSE 3000 CMD ["bundle", "exec", "puma", "-C", "config/puma.rb"] +FROM production AS staging + +ENV RAILS_ENV="staging" \ + BUNDLE_DEPLOYMENT="1" \ + BUNDLE_PATH="/usr/local/bundle" \ + BUNDLE_WITHOUT="development" + +# Entrypoint prepares the database. +ENTRYPOINT ["/rails/bin/docker-entrypoint"] + +# Start the server by default, this can be overwritten at runtime +EXPOSE 3000 +CMD ["bundle", "exec", "puma", "-C", "config/puma.rb"] + # Development image FROM base AS development diff --git a/Gemfile b/Gemfile index d6f07917..a53250ce 100644 --- a/Gemfile +++ b/Gemfile @@ -65,7 +65,7 @@ group :test, :development do gem "cypress-on-rails" end -group :production do +group :production, :staging do # Use puma as the app server gem "puma" gem "rack-cors" diff --git a/bin/docker-entrypoint b/bin/docker-entrypoint index fe6a8424..47b13a02 100755 --- a/bin/docker-entrypoint +++ b/bin/docker-entrypoint @@ -1,7 +1,8 @@ #!/bin/bash -e # ./bin/rails server (executed on production image) -if [ "${1}" == "./bin/rails" ] && [ "${2}" == "server" ]; then +if [ "${3}" == "puma" ]; then + echo "booting application on staging" ./bin/rails db:migrate ./bin/rails db:seed:all fi diff --git a/config/cable.yml b/config/cable.yml index b9adc5aa..cb8a0080 100644 --- a/config/cable.yml +++ b/config/cable.yml @@ -8,6 +8,9 @@ development: test: adapter: test +staging: + adapter: async + production: adapter: solid_cable connects_to: diff --git a/config/cache.yml b/config/cache.yml index 25358872..14959edd 100644 --- a/config/cache.yml +++ b/config/cache.yml @@ -12,6 +12,9 @@ development: test: <<: *default +staging: + <<: *default + production: database: cache <<: *default diff --git a/config/database.yml b/config/database.yml index 684c19a3..55d9ed05 100644 --- a/config/database.yml +++ b/config/database.yml @@ -77,6 +77,11 @@ test: # Read https://guides.rubyonrails.org/configuring.html#configuring-a-database # for a full overview on how database connection configuration can be specified. # + +staging: + <<: *default + url: <%= ENV['DATABASE_URL'] %> + production: primary: &primary_production <<: *default diff --git a/config/environments/staging.rb b/config/environments/staging.rb new file mode 100644 index 00000000..c5a4568d --- /dev/null +++ b/config/environments/staging.rb @@ -0,0 +1,117 @@ +# frozen_string_literal: true + +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.enable_reloading = false + + # Eager load code on boot for better performance and memory savings (ignored by Rake tasks). + config.eager_load = true + + # Full error reports are disabled. + config.consider_all_requests_local = false + + # Turn on fragment caching in view templates. + config.action_controller.perform_caching = true + + # Cache assets for far-future expiry since they are all digest stamped. + config.public_file_server.headers = { "cache-control" => "public, max-age=#{1.year.to_i}" } + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Assume all access to the app is happening through a SSL-terminating reverse proxy. + config.assume_ssl = true + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + config.force_ssl = true + + # Skip http-to-https redirect for the default health check endpoint. + # config.ssl_options = { redirect: { exclude: ->(request) { request.path == "/up" } } } + + # Log to STDOUT with the current request id as a default log tag. + config.log_tags = [ :request_id ] + config.logger = ActiveSupport::TaggedLogging.logger($stdout) + + # Change to "debug" to log everything (including potentially personally-identifiable information!) + config.log_level = ENV.fetch("RAILS_LOG_LEVEL", "info") + + # Prevent health checks from clogging up the logs. + config.silence_healthcheck_path = "/up" + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Replace the default in-process memory cache store with a durable alternative. + config.cache_store = :memory_store + + # Replace the default in-process and non-durable queuing backend for Active Job. + # config.active_job.queue_adapter = :solid_queue + # config.solid_queue.connects_to = { database: { writing: :queue } } + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Set host to be used by links generated in mailer templates. + config.action_mailer.default_url_options = { host: "example.com" } + + # Specify outgoing SMTP server. Remember to add smtp/* credentials via rails credentials:edit. + # config.action_mailer.smtp_settings = { + # user_name: Rails.application.credentials.dig(:smtp, :user_name), + # password: Rails.application.credentials.dig(:smtp, :password), + # address: "smtp.example.com", + # port: 587, + # authentication: :plain + # } + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false + + # Only use :id for inspections in production. + config.active_record.attributes_for_inspect = [ :id ] + + # Enable DNS rebinding protection and other `Host` header attacks. + # config.hosts = [ + # "example.com", # Allow requests from example.com + # /.*\.example\.com/ # Allow requests from subdomains like `www.example.com` + # ] + # + # Skip DNS rebinding protection for the default health check endpoint. + # config.host_authorization = { exclude: ->(request) { request.path == "/up" } } +end + +Rails.application.configure do + # Ensures that a master key has been made available in either + # ENV["RAILS_MASTER_KEY"] or in config/master.key. This key is used to decrypt + # credentials (and other encrypted files). + config.require_master_key = true + + # Prepend all log lines with the following tags. + config.log_tags = %i[request_id] + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + config.action_controller.asset_host = ENV.fetch("ASSET_HOST", nil) + + # Enforce secure protocol for URL generated by helpers + config.action_controller.default_url_options = { protocol: :https } + + if ENV["CORS_HOSTS"].present? + config.middleware.insert_before 0, Rack::Cors do + allow do + origins ENV["CORS_HOSTS"].split(",") + resource "*", headers: :any, methods: %i[get] + end + end + end +end diff --git a/config/queue.yml b/config/queue.yml index 9eace59c..917317c1 100644 --- a/config/queue.yml +++ b/config/queue.yml @@ -14,5 +14,8 @@ development: test: <<: *default +staging: + <<: *default + production: <<: *default