diff --git a/.circleci/config.yml b/.circleci/config.yml index 1a14fd998..8727017a1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -92,24 +92,6 @@ jobs: - run: name: Run linters command: bundle exec rake lint - deploy: - <<: *defaults - steps: - - checkout - - *bundle_restore_cache - - *bundle_install - - add_ssh_keys: - fingerprints: - - "0e:db:db:9c:54:ac:60:1a:d3:ba:28:03:2e:7d:0e:9a" - - deploy: - command: | - if [ "${CIRCLE_BRANCH}" == "dev" ]; then - bundle exec rake deploy to=staging - fi - - if [ "${CIRCLE_BRANCH}" == "master" ]; then - bundle exec rake deploy to=production - fi workflows: version: 2 @@ -122,12 +104,3 @@ workflows: - lint: requires: - build - - deploy: - filters: - branches: - only: - - dev - - master - requires: - - test - - lint diff --git a/Gemfile b/Gemfile index 35c8dd8d8..8b19a11d5 100644 --- a/Gemfile +++ b/Gemfile @@ -17,8 +17,8 @@ gem 'deep_cloneable' gem 'warden', git: 'https://github.com/hassox/warden.git', branch: 'master' -# Use Unicorn as the app server -gem 'unicorn' +# Use Puma as the app server +gem 'puma' # serializer gem 'active_model_serializers' @@ -171,7 +171,7 @@ group :development, :test do gem 'rspec-rails' # Deploy - gem 'mina', ref: '343a7', git: 'https://github.com/mina-deploy/mina.git' + gem 'mina', git: 'https://github.com/mina-deploy/mina.git' gem 'rspec_junit_formatter' end diff --git a/Gemfile.lock b/Gemfile.lock index a69a5d7c1..68e1b2e9b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -8,10 +8,9 @@ GIT GIT remote: https://github.com/mina-deploy/mina.git - revision: 343a7ab672d8b4f0ddb84ec240cde7d94b46397a - ref: 343a7 + revision: 0dd5fdb8bb82a180d35e1fc033de2fac48257e30 specs: - mina (0.3.8) + mina (1.2.3) open4 (~> 1.3.4) rake @@ -450,7 +449,6 @@ GEM activerecord kaminari-core (= 1.1.1) kaminari-core (1.1.1) - kgio (2.11.2) launchy (2.4.3) addressable (~> 2.3) letter_opener (1.6.0) @@ -558,6 +556,7 @@ GEM byebug (~> 10.0) pry (~> 0.10) public_suffix (3.0.2) + puma (3.12.0) rack (2.0.5) rack-handlers (0.7.3) rack @@ -607,7 +606,6 @@ GEM rake (>= 0.8.7) thor (>= 0.19.0, < 2.0) rainbow (3.0.0) - raindrops (0.19.0) rake (12.3.1) rb-fsevent (0.10.3) rb-inotify (0.9.10) @@ -764,9 +762,6 @@ GEM unf_ext unf_ext (0.0.7.5) unicode-display_width (1.4.0) - unicorn (5.4.1) - kgio (~> 2.6) - raindrops (~> 0.7) validate_email (0.1.6) activemodel (>= 3.0) mail (>= 2.2.5) @@ -863,6 +858,7 @@ DEPENDENCIES prawn_rails premailer-rails pry-byebug + puma rack-handlers rack-mini-profiler rails @@ -891,7 +887,6 @@ DEPENDENCIES timecop turbolinks typhoeus - unicorn vcr warden! web-console diff --git a/app/controllers/champs/dossier_link_controller.rb b/app/controllers/champs/dossier_link_controller.rb index d4297c733..1ba3823e1 100644 --- a/app/controllers/champs/dossier_link_controller.rb +++ b/app/controllers/champs/dossier_link_controller.rb @@ -2,6 +2,8 @@ class Champs::DossierLinkController < ApplicationController before_action :authenticate_logged_user! def show + @position = params[:position] + if params[:dossier].key?(:champs_attributes) @dossier_id = params[:dossier][:champs_attributes][params[:position]][:value] else diff --git a/app/views/champs/dossier_link/show.js.erb b/app/views/champs/dossier_link/show.js.erb index d561ee26a..dece3758a 100644 --- a/app/views/champs/dossier_link/show.js.erb +++ b/app/views/champs/dossier_link/show.js.erb @@ -1,3 +1,3 @@ -<%= render_to_element('.dossier-link .help-block', +<%= render_to_element(".dossier-link-#{@position} .help-block", partial: 'shared/champs/dossier_link/help_block', locals: { id: @dossier_id }) %> diff --git a/app/views/shared/dossiers/editable_champs/_dossier_link.html.haml b/app/views/shared/dossiers/editable_champs/_dossier_link.html.haml index 40d830ad8..37e67954c 100644 --- a/app/views/shared/dossiers/editable_champs/_dossier_link.html.haml +++ b/app/views/shared/dossiers/editable_champs/_dossier_link.html.haml @@ -1,4 +1,4 @@ -.dossier-link +.dossier-link{ class: "dossier-link-#{form.index}" } = form.number_field :value, placeholder: "Numéro de dossier", autocomplete: 'off', diff --git a/config/deploy.rb b/config/deploy.rb index ac764f6e5..8e1dcedbe 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -13,91 +13,47 @@ require 'mina/rbenv' # forward_agent - SSH forward_agent # user - Username in the server to SSH to -if !["staging", "production"].include?(ENV['to']) - raise "missing or incorrect `to` (should be 'staging' or 'production')" -end - -if ENV['domain'].nil? - raise "missing `domain`" -end - -set :domain, ENV['domain'] +set :domain, ENV.fetch('domain') set :repository, 'https://github.com/betagouv/tps.git' -set :port, 2200 -set :rails_env, 'production' -set :rbenv_path, "/usr/local/rbenv/bin/rbenv" -set :forward_agent, true +deploy_to = '/var/www/ds' +set :deploy_to, deploy_to +set :user, 'ds' +set :branch, ENV.fetch('branch') # Manually create these paths in shared/ (eg: shared/config/database.yml) in your server. # They will be linked in the 'deploy:link_shared_paths' step. -set :shared_paths, [ - '.env', +set :shared_dirs, [ 'log', - 'uploads', + 'sockets', 'tmp/pids', - 'tmp/cache', - 'tmp/sockets', - 'public/system', - 'public/uploads', - 'config/unicorn.rb' + 'tmp/cache' ] -case ENV["to"] -when "staging" - set :branch, ENV['branch'] || 'dev' - set :deploy_to, '/var/www/tps_dev' - set :user, 'tps_dev' - appname = 'tps_dev' -when "production" - set :branch, ENV['branch'] || 'master' - set :deploy_to, '/var/www/tps' - set :user, 'tps' - appname = 'tps' -end +set :rbenv_path, "/home/ds/.rbenv/bin/rbenv" +set :forward_agent, true # SSH forward_agent. -print "Deploy to #{ENV['to']} environment branch #{branch}\n" +puts "Deploy to #{ENV.fetch('domain')}, branch: #{ENV.fetch('branch')}" # This task is the environment that is loaded for most commands, such as # `mina deploy` or `mina rake`. -task :setup => :environment do - queue! %[mkdir -p "#{deploy_to}/shared/log"] - queue! %[chmod g+rx,u+rwx "#{deploy_to}/shared/log"] +task :setup do + command %[mkdir -p "#{deploy_to}/shared/log"] + command %[chmod g+rx,u+rwx "#{deploy_to}/shared/log"] - queue! %[mkdir -p "#{deploy_to}/shared/bin"] - queue! %[chmod g+rx,u+rwx "#{deploy_to}/shared/bin"] + command %[mkdir -p "#{deploy_to}/shared/tmp/pids"] + command %[chmod g+rx,u+rwx "#{deploy_to}/shared/tmp/pids"] - queue! %[mkdir -p "#{deploy_to}/shared/tmp/pids"] - queue! %[chmod g+rx,u+rwx "#{deploy_to}/shared/tmp/pids"] + command %[mkdir -p "#{deploy_to}/shared/tmp/cache"] + command %[chmod g+rx,u+rwx "#{deploy_to}/shared/tmp/cache"] - queue! %[mkdir -p "#{deploy_to}/shared/tmp/cache"] - queue! %[chmod g+rx,u+rwx "#{deploy_to}/shared/tmp/cache"] - - queue! %[mkdir -p "#{deploy_to}/shared/tmp/sockets"] - queue! %[chmod g+rx,u+rwx "#{deploy_to}/shared/tmp/sockets"] - - queue! %[mkdir -p "#{deploy_to}/shared/public/system"] - queue! %[chmod g+rx,u+rwx "#{deploy_to}/shared/public/system"] - - queue! %[mkdir -p "#{deploy_to}/shared/public/uploads"] - queue! %[chmod g+rx,u+rwx "#{deploy_to}/shared/public/uploads"] - - queue! %[mkdir -p "#{deploy_to}/shared/config"] - queue! %[chmod g+rx,u+rwx "#{deploy_to}/shared/config"] - - queue! %[mkdir -p "#{deploy_to}/shared/app"] - queue! %[chmod g+rx,u+rwx "#{deploy_to}/shared/app"] - - queue! %[mkdir -p "#{deploy_to}/shared/views/layouts"] - queue! %[chmod g+rx,u+rwx "#{deploy_to}/shared/views/layouts"] - - queue! %[mkdir -p "#{deploy_to}/shared/config/locales/dynamics"] - queue! %[chmod g+rx,u+rwx "#{deploy_to}/shared/config/locales/dynamics"] + command %[mkdir -p "#{deploy_to}/shared/sockets"] + command %[chmod g+rx,u+rwx "#{deploy_to}/shared/sockets"] end namespace :yarn do desc "Install package dependencies using yarn." task :install do - queue %{ + command %{ echo "-----> Installing package dependencies using yarn" #{echo_cmd %[yarn install --non-interactive]} } @@ -107,34 +63,52 @@ end namespace :after_party do desc "Run after_party tasks." task :run do - queue %{ + command %{ echo "-----> Running deploy tasks" - #{echo_cmd %[#{rake} after_party:run]} + #{echo_cmd %[bundle exec rake after_party:run]} + } + end +end + +namespace :service do + desc "Restart puma" + task :restart_puma do + command %{ + echo "-----> Restarting puma service" + #{echo_cmd %[sudo systemctl restart puma]} + echo "-----> Reloading nginx service" + #{echo_cmd %[sudo systemctl reload nginx]} + } + end + + desc "Restart delayed_job" + task :restart_delayed_job do + command %{ + echo "-----> Restarting delayed_job service" + #{echo_cmd %[sudo systemctl restart delayed_job]} } end end desc "Deploys the current version to the server." -task :deploy => :environment do - queue 'export PATH=$PATH:/usr/local/rbenv/bin:/usr/local/rbenv/shims' +task :deploy do + command 'export PATH=$PATH:/home/ds/.rbenv/bin:/home/ds/.rbenv/shims' + command 'source /home/ds/.profile' deploy do - queue %[sudo service delayed_job_#{user!} stop || true] # Put things that will set up an empty directory into a fully set-up # instance of your project. invoke :'git:clone' + invoke :'deploy:link_shared_paths' invoke :'bundle:install' invoke :'yarn:install' invoke :'rails:db_migrate' invoke :'after_party:run' - invoke :'rails:assets_precompile:force' + invoke :'rails:assets_precompile' - to :launch do - queue "/etc/init.d/#{user} upgrade " - queue! %[sudo service delayed_job_#{user!} start] - - # If you are deploying a review app on a fresh testing environment, - # now can be a good time to seed the database. + on :launch do + invoke :'service:restart_puma' + invoke :'service:restart_delayed_job' end end end diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 000000000..1e19380dc --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,56 @@ +# Puma can serve each request in a thread from an internal thread pool. +# The `threads` method setting takes two numbers: a minimum and maximum. +# Any libraries that use thread pools should be configured to match +# the maximum value specified for Puma. Default is set to 5 threads for minimum +# and maximum; this matches the default thread size of Active Record. +# +threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +threads threads_count, threads_count + +# Specifies the `port` that Puma will listen on to receive requests; default is 3000. +# +port ENV.fetch("PORT") { 3000 } + +# Specifies the `environment` that Puma will run in. +# +environment ENV.fetch("RAILS_ENV") { "development" } + +# Specifies the number of `workers` to boot in clustered mode. +# Workers are forked webserver processes. If using threads and workers together +# the concurrency of the application would be max `threads` * `workers`. +# Workers do not work on JRuby or Windows (both of which do not support +# processes). +# +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } + +# Use the `preload_app!` method when specifying a `workers` number. +# This directive tells Puma to first boot the application and load code +# before forking the application. This takes advantage of Copy On Write +# process behavior so workers use less memory. If you use this option +# you need to make sure to reconnect any threads in the `on_worker_boot` +# block. +# +# preload_app! + +# If you are preloading your application and using Active Record, it's +# recommended that you close any connections to the database before workers +# are forked to prevent connection leakage. +# +# before_fork do +# ActiveRecord::Base.connection_pool.disconnect! if defined?(ActiveRecord) +# end + +# The code in the `on_worker_boot` will be called if you are using +# clustered mode by specifying a number of `workers`. After each worker +# process is booted, this block will be run. If you are using the `preload_app!` +# option, you will want to use this block to reconnect to any threads +# or connections that may have been created at application boot, as Ruby +# cannot share connections between processes. +# +# on_worker_boot do +# ActiveRecord::Base.establish_connection if defined?(ActiveRecord) +# end +# + +# Allow puma to be restarted by `rails restart` command. +plugin :tmp_restart diff --git a/config/unicorn.rb b/config/unicorn.rb deleted file mode 100644 index 1b754e734..000000000 --- a/config/unicorn.rb +++ /dev/null @@ -1,105 +0,0 @@ -# Sample verbose configuration file for Unicorn (not Rack) -# -# This configuration file documents many features of Unicorn -# that may not be needed for some applications. See -# http://unicorn.bogomips.org/examples/unicorn.conf.minimal.rb -# for a much simpler configuration file. -# -# See http://unicorn.bogomips.org/Unicorn/Configurator.html for complete -# documentation. - -# Use at least one worker per core if you're on a dedicated server, -# more will usually help for _short_ waits on databases/caches. -worker_processes 2 - -# Since Unicorn is never exposed to outside clients, it does not need to -# run on the standard HTTP port (80), there is no reason to start Unicorn -# as root unless it's from system init scripts. -# If running the master process as root and the workers as an unprivileged -# user, do this to switch euid/egid in the workers (also chowns logs): -# user "unprivileged_user", "unprivileged_group" - -# Help ensure your application will always spawn in the symlinked -# "current" directory that Capistrano sets up. - -# listen on both a Unix domain socket and a TCP port, -# we use a shorter backlog for quicker failover when busy -listen "127.0.0.1:3000", :tcp_nopush => true - -timeout 60 - -# By default, the Unicorn logger will write to stderr. -# Additionally, ome applications/frameworks log to stderr or stdout, -# so prevent them from going to /dev/null when daemonized here: - -# combine Ruby 2.0.0dev or REE with "preload_app true" for memory savings -# http://rubyenterpriseedition.com/faq.html#adapt_apps_for_cow -preload_app true -GC.respond_to?(:copy_on_write_friendly=) and - GC.copy_on_write_friendly = true - -# Enable this flag to have unicorn test client connections by writing the -# beginning of the HTTP headers before calling the application. This -# prevents calling the application for connections that have disconnected -# while queued. This is only guaranteed to detect clients on the same -# host unicorn runs on, and unlikely to detect disconnects even on a -# fast LAN. -check_client_connection false - -# local variable to guard against running a hook multiple times -run_once = true - -before_fork do |server, worker| - # the following is highly recomended for Rails + "preload_app true" - # as there's no need for the master process to hold a connection - defined?(ActiveRecord::Base) and - ActiveRecord::Base.connection.disconnect! - - # Occasionally, it may be necessary to run non-idempotent code in the - # master before forking. Keep in mind the above disconnect! example - # is idempotent and does not need a guard. - if run_once - # do_something_once_here ... - run_once = false # prevent from firing again - end - - # The following is only recommended for memory/DB-constrained - # installations. It is not needed if your system can house - # twice as many worker_processes as you have configured. - # - # # This allows a new master process to incrementally - # # phase out the old master process with SIGTTOU to avoid a - # # thundering herd (especially in the "preload_app false" case) - # # when doing a transparent upgrade. The last worker spawned - # # will then kill off the old master process with a SIGQUIT. - old_pid = "#{server.config[:pid]}.oldbin" - if old_pid != server.pid - begin - sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU - Process.kill(sig, File.read(old_pid).to_i) - rescue Errno::ENOENT, Errno::ESRCH - end - end - # - # Throttle the master from forking too quickly by sleeping. Due - # to the implementation of standard Unix signal handlers, this - # helps (but does not completely) prevent identical, repeated signals - # from being lost when the receiving process is busy. - sleep 1 -end - -after_fork do |server, worker| - # per-process listener ports for debugging/admin/migrations - # addr = "127.0.0.1:#{9293 + worker.nr}" - # server.listen(addr, :tries => -1, :delay => 5, :tcp_nopush => true) - - # the following is *required* for Rails + "preload_app true", - defined?(ActiveRecord::Base) and - ActiveRecord::Base.establish_connection - - # if preload_app is true, then you may also want to check and - # restart any other shared sockets/descriptors such as Memcached, - # and Redis. TokyoCabinet file handles are safe to reuse - # between any number of forked children (assuming your kernel - # correctly implements pread()/pwrite() system calls) -end diff --git a/lib/tasks/deploy.rake b/lib/tasks/deploy.rake index d117fe39f..749c22d74 100644 --- a/lib/tasks/deploy.rake +++ b/lib/tasks/deploy.rake @@ -1,6 +1,27 @@ -task :deploy do - domains = ['149.202.72.152', '149.202.198.6'] - domains.each do |domain| - sh "mina deploy domain=#{domain}" +def domains_from_env(env) + case env + when 'dev' + ['web1.dev', 'web2.dev'] + when 'prod' + ['web1', 'web2'] + else + raise "STAGE #{env} is unknown. It must be either dev or prod" + end +end + +task :deploy do + domains = domains_from_env(ENV.fetch('STAGE')) + branch = ENV.fetch('BRANCH') + + domains.each do |domain| + sh "mina deploy domain=#{domain} branch=#{branch} force_asset_precompile=true" + end +end + +task :setup do + domains = domains_from_env(ENV['STAGE']) + + domains.each do |domain| + sh "mina setup domain=#{domain} force_asset_precompile=true" end end diff --git a/spec/controllers/champs/dossier_link_controller_spec.rb b/spec/controllers/champs/dossier_link_controller_spec.rb index f2f5be448..f4cda12de 100644 --- a/spec/controllers/champs/dossier_link_controller_spec.rb +++ b/spec/controllers/champs/dossier_link_controller_spec.rb @@ -28,10 +28,11 @@ describe Champs::DossierLinkController, type: :controller do get :show, params: params, format: 'js' } - it 'returns the procedure name' do + it 'renders the procedure name' do expect(response.body).to include('Dossier en brouillon') expect(response.body).to include(procedure.libelle) expect(response.body).to include(procedure.organisation) + expect(response.body).to include('.dossier-link-1 .help-block') end end @@ -41,7 +42,10 @@ describe Champs::DossierLinkController, type: :controller do get :show, params: params, format: 'js' } - it { expect(response.body).to include('Ce dossier est inconnu') } + it 'renders error message' do + expect(response.body).to include('Ce dossier est inconnu') + expect(response.body).to include('.dossier-link-1 .help-block') + end end end