modulorails 1.5.2.pre.1 → 1.6.0

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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -1
  3. data/CHANGELOG.md +40 -7
  4. data/README.md +69 -9
  5. data/lib/generators/modulorails/claude_code/claude_code_generator.rb +64 -0
  6. data/lib/generators/modulorails/claude_code/templates/.gitlab-ci.yml.tt +120 -0
  7. data/lib/generators/modulorails/claude_code/templates/.modulorails-gitlab-ci +6 -0
  8. data/lib/generators/modulorails/claude_code/templates/bin/init-firewall.sh.tt +118 -0
  9. data/lib/generators/modulorails/docker/compose/compose_generator.rb +7 -6
  10. data/lib/generators/modulorails/docker/config/config_generator.rb +11 -5
  11. data/lib/generators/modulorails/docker/config/templates/config/database.yml.tt +7 -2
  12. data/lib/generators/modulorails/docker/devcontainer/devcontainer_generator.rb +52 -0
  13. data/lib/generators/modulorails/docker/devcontainer/templates/devcontainer/Dockerfile.tt +53 -0
  14. data/lib/generators/modulorails/docker/devcontainer/templates/devcontainer/compose.yml.tt +97 -0
  15. data/lib/generators/modulorails/docker/devcontainer/templates/devcontainer/devcontainer.json.tt +80 -0
  16. data/lib/generators/modulorails/docker/docker_generator.rb +7 -0
  17. data/lib/generators/modulorails/docker/dockerfile/dockerfile_generator.rb +15 -11
  18. data/lib/generators/modulorails/docker/dockerfile/templates/dockerfiles/{rails/Dockerfile.prod.tt → Dockerfile.prod.tt} +31 -12
  19. data/lib/generators/modulorails/docker/dockerfile/templates/dockerfiles/dockerignore.tt +120 -0
  20. data/lib/generators/modulorails/docker/entrypoint/entrypoint_generator.rb +11 -5
  21. data/lib/generators/modulorails/docker/entrypoint/templates/entrypoints/docker-entrypoint.sh.tt +5 -0
  22. data/lib/generators/modulorails/githooks/githooks_generator.rb +5 -3
  23. data/lib/generators/modulorails/githooks/templates/dc.sh +30 -0
  24. data/lib/generators/modulorails/githooks/templates/dcr.sh +47 -0
  25. data/lib/generators/modulorails/githooks/templates/post-rewrite.sh +1 -1
  26. data/lib/generators/modulorails/githooks/templates/pre-merge-commit.sh +1 -1
  27. data/lib/generators/modulorails/githooks/templates/refresh_generations.sh +17 -9
  28. data/lib/generators/modulorails/gitlabci/gitlabci_generator.rb +7 -1
  29. data/lib/generators/modulorails/gitlabci/templates/.gitlab-ci.yml.tt +15 -13
  30. data/lib/generators/modulorails/gitlabci/templates/bin/test.sh.tt +36 -0
  31. data/lib/generators/modulorails/gitlabci/templates/config/deploy/production.yaml.tt +4 -4
  32. data/lib/generators/modulorails/gitlabci/templates/config/deploy/review.yaml.tt +4 -4
  33. data/lib/generators/modulorails/gitlabci/templates/config/deploy/staging.yaml.tt +7 -7
  34. data/lib/generators/modulorails/moduloproject/moduloproject_generator.rb +8 -3
  35. data/lib/generators/modulorails/moduloproject/templates/config/environments/production.rb.tt +21 -51
  36. data/lib/generators/modulorails/rubocop/templates/rubocop.yml.tt +7 -1
  37. data/lib/generators/modulorails/self_update/self_update_generator.rb +4 -0
  38. data/lib/generators/modulorails/sidekiq/sidekiq_generator.rb +95 -38
  39. data/lib/generators/modulorails/sidekiq/templates/config/initializers/sidekiq.rb.tt +4 -4
  40. data/lib/modulorails/configuration.rb +17 -7
  41. data/lib/modulorails/data.rb +39 -12
  42. data/lib/modulorails/generators/base.rb +1 -1
  43. data/lib/modulorails/railtie.rb +7 -0
  44. data/lib/modulorails/services/base_service.rb +1 -1
  45. data/lib/modulorails/services/logs_for_method_service.rb +1 -1
  46. data/lib/modulorails/version.rb +1 -1
  47. data/lib/modulorails.rb +13 -0
  48. metadata +16 -13
  49. data/lib/generators/modulorails/docker/compose/templates/docker-compose.yml.tt +0 -81
  50. data/lib/generators/modulorails/docker/dockerfile/templates/dockerfiles/modulotech/Dockerfile.prod.tt +0 -66
  51. data/lib/generators/modulorails/docker/dockerfile/templates/dockerfiles/modulotech/Dockerfile.tt +0 -30
  52. data/lib/generators/modulorails/docker/entrypoint/templates/entrypoints/webpack-entrypoint.sh.tt +0 -7
  53. data/lib/generators/modulorails/githooks/templates/dockeruby.rb +0 -124
  54. data/lib/generators/modulorails/sidekiq/templates/entrypoints/sidekiq-entrypoint.sh.tt +0 -7
@@ -4,13 +4,18 @@ require 'modulorails/generators/base'
4
4
 
5
5
  class Modulorails::GitlabciGenerator < Modulorails::Generators::Base
6
6
 
7
- VERSION = 1
7
+ VERSION = 2
8
8
 
9
9
  desc 'This generator creates a template for a .gitlab-ci.yml file at root'
10
10
 
11
11
  protected
12
12
 
13
13
  def create_config
14
+ Modulorails.deprecator.warn(<<~MESSAGE)
15
+ Modulorails::GitlabciGenerator is deprecated and will be removed in version 2.0.
16
+ Use Moduloproject 3.0 (available later) to initialize new projects with GitLab CI configuration.
17
+ MESSAGE
18
+
14
19
  remove_old_keepfile('.modulorails-gitlab-ci')
15
20
  remove_old_keepfile('.modulorails-gitlabci')
16
21
 
@@ -24,6 +29,7 @@ class Modulorails::GitlabciGenerator < Modulorails::Generators::Base
24
29
 
25
30
  # Update the gitlab-ci template
26
31
  template '.gitlab-ci.yml'
32
+ template 'bin/test.sh', 'bin/test'
27
33
  template 'config/deploy/production.yaml' if @production_url.present?
28
34
  template 'config/deploy/staging.yaml' if @staging_url.present?
29
35
  template 'config/deploy/review.yaml' if @review_base_url.present?
@@ -7,16 +7,6 @@ include:
7
7
 
8
8
  variables:
9
9
  IMAGE_NAME: <%= @image_name %>
10
- <%- if @adapter =~ /mysql/ -%>
11
- MYSQL_DATABASE: <%= @image_name %>_test
12
- MYSQL_ALLOW_EMPTY_PASSWORD: 'true'
13
- <%= @environment_name %>_DATABASE_HOST: mysql
14
- <%- else -%>
15
- POSTGRES_DB: <%= @image_name %>_test
16
- POSTGRES_USER: postgres
17
- POSTGRES_PASSWORD: postgres
18
- <%= @environment_name %>_DATABASE_HOST: postgres
19
- <%- end -%>
20
10
 
21
11
  stages:
22
12
  - test
@@ -25,6 +15,8 @@ stages:
25
15
 
26
16
  build_integration_image:
27
17
  extends: .build_integration_image
18
+ variables:
19
+ DOCKERFILE: .devcontainer/Dockerfile
28
20
 
29
21
  test:
30
22
  extends: .test
@@ -37,13 +29,23 @@ test:
37
29
  - redis:7-alpine
38
30
  variables:
39
31
  RAILS_ENV: test
32
+ <%- if @adapter =~ /mysql/ -%>
33
+ MYSQL_DATABASE: <%= @image_name %>-test
34
+ MYSQL_ALLOW_EMPTY_PASSWORD: 'true'
35
+ DATABASE_TEST_URL: 'mysql2://root@mysql/<%= @image_name %>-test'
36
+ <%- else -%>
37
+ POSTGRES_DB: <%= @image_name %>-test
38
+ POSTGRES_USER: postgres
39
+ POSTGRES_PASSWORD: postgres
40
+ DATABASE_TEST_URL: 'postgresql://postgres:postgres@postgres/<%= @image_name %>-test'
41
+ <%- end -%>
40
42
  script:
41
- - bundle exec rake db:create
42
- - bundle exec rake db:migrate:reset
43
- - bundle exec rspec --format progress --format RspecJunitFormatter --out rspec.xml
43
+ - bin/test
44
44
 
45
45
  docker_build:
46
46
  extends: .docker_buildx_push
47
+ variables:
48
+ DOCKERFILE: Dockerfile
47
49
  only:
48
50
  - merge_requests
49
51
  - staging
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env sh
2
+
3
+ export RAILS_ENV=test
4
+
5
+ if ! grep -q rspec Gemfile
6
+ then
7
+ echo 'Install RSpec and add some tests:'
8
+ echo ' bundle add rspec-rails rspec_junit_formatter'
9
+ echo ' bundle exec rails generate rspec:install'
10
+ exit 0
11
+ end
12
+
13
+ if [ -z "$1" ]
14
+ then
15
+ bundle exec rake db:drop db:create db:schema:load db:migrate
16
+ <%- case @js_engine -%>
17
+ <%- when :webpacker -%>
18
+ bundle exec yarn install
19
+ bundle exec rails webpacker:compile
20
+ <%- when :bun -%>
21
+ bun install
22
+ bun run build
23
+ bun run build:css
24
+ <%- end -%>
25
+ fi
26
+
27
+ if [ -z "$CI" ]
28
+ then
29
+ # For dev environment, we use the options specified in `.rspec` file
30
+ bundle exec rspec --profile "$@"
31
+ elif grep -q rspec_junit_formatter Gemfile
32
+ then
33
+ bundle exec rspec --format progress --format RspecJunitFormatter --out rspec.xml --profile "$@"
34
+ else
35
+ bundle exec rspec --format progress --profile "$@"
36
+ fi
@@ -18,9 +18,9 @@ ingress:
18
18
  resources:
19
19
  requests:
20
20
  cpu: 100m
21
- memory: 512Mi
21
+ memory: 1024Mi
22
22
  limits:
23
- memory: 512Mi
23
+ memory: 1024Mi
24
24
 
25
25
  autoscaling:
26
26
  enabled: true
@@ -47,10 +47,10 @@ sidekiq:
47
47
  # resources:
48
48
  # requests:
49
49
  # cpu: 100m
50
- # memory: 512Mi
50
+ # memory: 1024Mi
51
51
  # limits:
52
52
  # cpu: 100m
53
- # memory: 512Mi
53
+ # memory: 1024Mi
54
54
  # autoscaling:
55
55
  # enabled: true
56
56
  # minReplicas: 1
@@ -18,9 +18,9 @@ ingress:
18
18
  resources:
19
19
  requests:
20
20
  cpu: 100m
21
- memory: 512Mi
21
+ memory: 1024Mi
22
22
  limits:
23
- memory: 512Mi
23
+ memory: 1024Mi
24
24
 
25
25
  autoscaling:
26
26
  enabled: true
@@ -46,10 +46,10 @@ sidekiq:
46
46
  # resources:
47
47
  # requests:
48
48
  # cpu: 100m
49
- # memory: 512Mi
49
+ # memory: 1024Mi
50
50
  # limits:
51
51
  # cpu: 100m
52
- # memory: 512Mi
52
+ # memory: 1024Mi
53
53
  # autoscaling:
54
54
  # enabled: true
55
55
  # minReplicas: 1
@@ -18,14 +18,14 @@ ingress:
18
18
  resources:
19
19
  requests:
20
20
  cpu: 100m
21
- memory: 512Mi
21
+ memory: 1024Mi
22
22
  limits:
23
- memory: 512Mi
23
+ memory: 1024Mi
24
24
 
25
25
  autoscaling:
26
26
  enabled: true
27
27
  minReplicas: 1
28
- maxReplicas: 10
28
+ maxReplicas: 2
29
29
  targetCPUUtilizationPercentage: 80
30
30
 
31
31
  database:
@@ -42,16 +42,16 @@ redis:
42
42
  enabled: true
43
43
 
44
44
  sidekiq:
45
- enabled: true
45
+ enabled: false
46
46
  # resources:
47
47
  # requests:
48
48
  # cpu: 100m
49
- # memory: 512Mi
49
+ # memory: 1024Mi
50
50
  # limits:
51
51
  # cpu: 100m
52
- # memory: 512Mi
52
+ # memory: 1024Mi
53
53
  # autoscaling:
54
54
  # enabled: true
55
55
  # minReplicas: 1
56
- # maxReplicas: 10
56
+ # maxReplicas: 2
57
57
  # targetCPUUtilizationPercentage: 80
@@ -4,16 +4,21 @@ require 'rails/generators'
4
4
 
5
5
  class Modulorails::ModuloprojectGenerator < Modulorails::Generators::Base
6
6
 
7
- VERSION = 1
7
+ VERSION = 2
8
8
 
9
9
  desc 'This generator creates templates for Moduloproject'
10
10
 
11
11
  def create_config
12
+ Modulorails.deprecator.warn(<<~MESSAGE)
13
+ Modulorails::ModuloprojectGenerator is deprecated and will be removed in version 2.0.
14
+ This generator will be moved to Moduloproject 3.0 (available later).
15
+ MESSAGE
16
+
12
17
  remove_old_keepfile(".modulorails-#{generator_name}")
13
- template 'config/environments/production.rb'
18
+ template 'config/environments/production.rb', force: true
14
19
  copy_file('config/environments/production.rb', 'config/environments/staging.rb')
15
20
  update_application_rb
16
- create_file('config/locales/fr.yml', "--\nfr: {}\n")
21
+ create_file('config/locales/fr.yml', "fr: {}\n")
17
22
  rescue StandardError => e
18
23
  warn("[Modulorails] Error: cannot generate Moduloproject configuration: #{e.message}")
19
24
  end
@@ -6,55 +6,25 @@ Rails.application.configure do
6
6
  # Code is not reloaded between requests.
7
7
  config.enable_reloading = false
8
8
 
9
- # Eager load code on boot. This eager loads most of Rails and
10
- # your application in memory, allowing both threaded web servers
11
- # and those relying on copy on write to perform better.
12
- # Rake tasks automatically ignore this option for performance.
9
+ # Eager load code on boot for better performance and memory savings (ignored by Rake tasks).
13
10
  config.eager_load = true
14
11
 
15
- # Custom directories with classes and modules you want to be autoloadable.
16
- # config.eager_load_paths += %W[
17
- # #{config.root}/lib/constraints
18
- # ]
19
-
20
- # Full error reports are disabled and caching is turned on.
12
+ # Full error reports are disabled.
21
13
  config.consider_all_requests_local = false
22
- config.action_controller.perform_caching = true
23
-
24
- # Ensures that a master key has been made available in ENV["RAILS_MASTER_KEY"], config/master.key, or an environment
25
- # key such as config/credentials/production.key. This key is used to decrypt credentials (and other encrypted files).
26
- # config.require_master_key = true
27
-
28
- # Disable serving static files from `public/`, relying on NGINX/Apache to do so instead.
29
- config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
30
14
 
31
- # Compress CSS using a preprocessor.
32
- # config.assets.css_compressor = :sass
15
+ # Turn on fragment caching in view templates.
16
+ config.action_controller.perform_caching = true
33
17
 
34
- # Do not fallback to assets pipeline if a precompiled asset is missed.
35
- config.assets.compile = false
18
+ # Cache assets for far-future expiry since they are all digest stamped.
19
+ config.public_file_server.headers = { "cache-control" => "public, max-age=#{1.year.to_i}" }
36
20
 
37
21
  # Enable serving of images, stylesheets, and JavaScripts from an asset server.
38
22
  # config.asset_host = "http://assets.example.com"
39
23
 
40
- # Specifies the header that your server uses for sending files.
41
- # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache
42
- # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX
43
-
44
24
  # Store uploaded files on the local file system (see config/storage.yml for options).
45
25
  config.active_storage.service = :local
46
26
 
47
- # Mount Action Cable outside main process or domain.
48
- # config.action_cable.mount_path = nil
49
- # host = URI(ENV.fetch('URL', 'http://localhost:3000/')).host
50
- # config.action_cable.url = "wss://#{host}/cable"
51
- # config.action_cable.disable_request_forgery_protection = true
52
- # config.action_cable.allowed_request_origins = [
53
- # %r{(https|wss)://host}
54
- # ]
55
-
56
27
  # Assume all access to the app is happening through a SSL-terminating reverse proxy.
57
- # Can be used together with config.force_ssl for Strict-Transport-Security and secure cookies.
58
28
  config.assume_ssl = true
59
29
 
60
30
  # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
@@ -63,27 +33,26 @@ Rails.application.configure do
63
33
  # Skip http-to-https redirect for the default health check endpoint.
64
34
  # config.ssl_options = { redirect: { exclude: ->(request) { request.path == "/up" } } }
65
35
 
66
- # Log to STDOUT by default
36
+ # Log to STDOUT with the current request id as a default log tag.
37
+ config.log_tags = [ :request_id ]
67
38
  config.logger = ActiveSupport::Logger.new(STDOUT)
68
39
  .tap { |logger| logger.formatter = ::Logger::Formatter.new }
69
40
  .then { |logger| ActiveSupport::TaggedLogging.new(logger) }
70
41
 
71
- # Prepend all log lines with the following tags.
72
- config.log_tags = [:request_id]
73
-
74
- # Info include generic and useful information about system operation, but avoids logging too much
75
- # information to avoid inadvertent exposure of personally identifiable information (PII). If you
76
- # want to log everything, set the level to "debug".
42
+ # Change to "debug" to log everything (including potentially personally-identifiable information!)
77
43
  config.log_level = ENV.fetch("RAILS_LOG_LEVEL", "info")
78
44
 
79
- # Use a different cache store in production.
45
+ # Prevent health checks from clogging up the logs.
46
+ config.silence_healthcheck_path = "/up"
47
+
48
+ # Don't log any deprecations.
49
+ config.active_support.report_deprecations = false
50
+
51
+ # Use Redis as a cache store
80
52
  config.cache_store = :redis_cache_store, { url: ENV['REDIS_URL'], expires_in: 6.hours }
81
53
 
82
- # Use a real queuing backend for Active Job (and separate queues per environment).
54
+ # Replace the default in-process and non-durable queuing backend for Active Job.
83
55
  # config.active_job.queue_adapter = :sidekiq
84
- # config.active_job.queue_name_prefix = "<%= Modulorails.data.rails_name.underscore %>_production"
85
-
86
- config.action_mailer.perform_caching = false
87
56
 
88
57
  # Ignore bad email addresses and do not raise email delivery errors.
89
58
  # Set this to true and configure the email server for immediate delivery to raise delivery errors.
@@ -93,17 +62,18 @@ Rails.application.configure do
93
62
  # the I18n.default_locale when a translation cannot be found).
94
63
  config.i18n.fallbacks = true
95
64
 
96
- # Don't log any deprecations.
97
- config.active_support.report_deprecations = false
98
-
99
65
  # Do not dump schema after migrations.
100
66
  config.active_record.dump_schema_after_migration = false
101
67
 
68
+ # Only use :id for inspections in production.
69
+ config.active_record.attributes_for_inspect = [ :id ]
70
+
102
71
  # Enable DNS rebinding protection and other `Host` header attacks.
103
72
  # config.hosts = [
104
73
  # "example.com", # Allow requests from example.com
105
74
  # /.*\.example\.com/ # Allow requests from subdomains like `www.example.com`
106
75
  # ]
76
+ #
107
77
  # Skip DNS rebinding protection for the default health check endpoint.
108
78
  # config.host_authorization = { exclude: ->(request) { request.path == "/up" } }
109
79
  end
@@ -10,7 +10,8 @@
10
10
  # See https://docs.rubocop.org/rubocop/configuration
11
11
 
12
12
  # Enabling Rails-specific cops.
13
- require: rubocop-rails
13
+ plugins:
14
+ - rubocop-rails
14
15
 
15
16
  inherit_mode:
16
17
  merge:
@@ -102,6 +103,7 @@ Metrics/CyclomaticComplexity:
102
103
  # Commonly used screens these days easily fit more than 80 characters.
103
104
  Layout/LineLength:
104
105
  Max: 120
106
+ AllowedPatterns: ['\A\s*#']
105
107
 
106
108
  # Too short methods lead to extraction of single-use methods, which can make
107
109
  # the code easier to read (by naming things), but can also clutter the class
@@ -235,6 +237,10 @@ Metrics/BlockLength:
235
237
  Exclude:
236
238
  - 'app/admin/**/*'
237
239
  - 'lib/tasks/**/*'
240
+ # Allow big blocks for Concerns
241
+ AllowedMethods:
242
+ - class_methods
243
+ - included
238
244
 
239
245
  # Checks if empty lines around the bodies of classes match the configuration.
240
246
  Layout/EmptyLinesAroundClassBody:
@@ -12,6 +12,10 @@ class Modulorails::SelfUpdateGenerator < Rails::Generators::Base
12
12
  LATEST_VERSION_URL = 'https://rubygems.org/api/v1/versions/modulorails.json'
13
13
 
14
14
  def create_config_file
15
+ Modulorails.deprecator.warn(<<~MESSAGE)
16
+ Modulorails::SelfUpdateGenerator is deprecated and will be removed in version 2.0.
17
+ MESSAGE
18
+
15
19
  # Get the last published version
16
20
  versions = HTTParty.get(LATEST_VERSION_URL).parsed_response
17
21
  last_published_version = versions&.reject { |version| Gem::Version.new(version['number']).prerelease? }&.first
@@ -8,12 +8,15 @@ class Modulorails::SidekiqGenerator < Rails::Generators::Base
8
8
 
9
9
  desc 'This generator adds Sidekiq to the project'
10
10
 
11
+ def deprecation_warning
12
+ Modulorails.deprecator.warn(<<~MESSAGE)
13
+ Modulorails::SidekiqGenerator is deprecated and will be removed in version 2.0.
14
+ Use Moduloproject 3.0 (available later) to initialize new projects with Sidekiq configuration.
15
+ MESSAGE
16
+ end
17
+
11
18
  def add_to_docker_compose
12
- if Rails.root.join('compose.yml').exist?
13
- add_to_docker_compose_yml_file(Rails.root.join('compose.yml'))
14
- elsif Rails.root.join('docker-compose.yml').exist?
15
- add_to_docker_compose_yml_file(Rails.root.join('docker-compose.yml'))
16
- end
19
+ add_to_docker_compose_yml_file(Rails.root.join('.devcontainer/compose.yml'))
17
20
  end
18
21
 
19
22
  def add_to_deploy_files
@@ -26,12 +29,15 @@ class Modulorails::SidekiqGenerator < Rails::Generators::Base
26
29
  gemfile_path = Rails.root.join('Gemfile')
27
30
 
28
31
  # Add gem redis unless already present
29
- append_to_file(gemfile_path, "gem 'redis'\n") unless File.read(gemfile_path).match?(/^\s*gem ['"]redis['"]/)
32
+ append_to_file(gemfile_path, "\ngem 'redis'\n") unless File.read(gemfile_path).match?(/^\s*gem ['"]redis['"]/)
30
33
 
31
34
  # Add gem sidekiq unless already present
32
- return if File.read(gemfile_path).match?(/^\s*gem ['"]sidekiq['"]/)
35
+ append_to_file(gemfile_path, "\ngem 'sidekiq'\n") unless File.read(gemfile_path).match?(/^\s*gem ['"]sidekiq['"]/)
36
+
37
+ # Add gem sidekiq-datadog-error-tracking unless already present
38
+ return if File.read(gemfile_path).match?(/^\s*gem ['"]sidekiq-datadog-error-tracking['"]/)
33
39
 
34
- append_to_file(gemfile_path, "gem 'sidekiq'\n")
40
+ append_to_file(gemfile_path, "\ngem 'sidekiq-datadog-error-tracking'\n")
35
41
  end
36
42
 
37
43
  def add_to_config
@@ -46,20 +52,19 @@ class Modulorails::SidekiqGenerator < Rails::Generators::Base
46
52
 
47
53
  def add_routes
48
54
  routes_path = Rails.root.join('config/routes.rb')
49
-
50
55
  return if File.read(routes_path).match?(%r{require ['"]sidekiq/web["']})
51
56
 
52
- inject_into_file routes_path, after: "Rails.application.routes.draw do\n" do
53
- <<-RUBY
54
- require 'sidekiq/web'
55
- mount Sidekiq::Web => '/sidekiq'
56
-
57
- RUBY
57
+ authentication_type = Modulorails.data.authentication_type
58
+ if respond_to?("add_#{authentication_type}_authenticated_route")
59
+ send("add_#{authentication_type}_authenticated_route", routes_path)
60
+ else
61
+ add_unauthenticated_route(routes_path)
58
62
  end
59
63
  end
60
64
 
61
65
  def add_health_check
62
66
  file_path = Rails.root.join('config/initializers/health_check.rb')
67
+ return unless File.exist?(file_path)
63
68
 
64
69
  return if File.read(file_path).match?(/add_custom_check\s*\(?\s*['"]sidekiq-queues['"]\s*\)?/)
65
70
 
@@ -73,10 +78,10 @@ class Modulorails::SidekiqGenerator < Rails::Generators::Base
73
78
  # No queues, means no jobs, ok!
74
79
  next '' if queues.empty?
75
80
 
76
- enqueued_jobs_count = queues.each.map { |queue| queue.count }.sum
81
+ global_latency = queues.each.map { |queue| queue.latency }.sum
77
82
 
78
- # Less than 200 enqueued jobs, ok!
79
- enqueued_jobs_count < 200 ? '' : "\#{enqueued_jobs_count} are currently enqueued."
83
+ # Global latency is less than 5 minutes, ok!
84
+ global_latency < 5.minutes ? '' : "Global latency (\#{global_latency}) is too high."
80
85
  end
81
86
 
82
87
  # Add one or more custom checks that return a blank string if ok, or an error message if there is an error
@@ -90,9 +95,9 @@ class Modulorails::SidekiqGenerator < Rails::Generators::Base
90
95
  end
91
96
  end
92
97
 
93
- def add_entrypoint
94
- template 'entrypoints/sidekiq-entrypoint.sh', 'bin/sidekiq-entrypoint'
95
- chmod 'bin/sidekiq-entrypoint', 0o755
98
+ def remove_entrypoint
99
+ remove_file 'entrypoints/sidekiq-entrypoint.sh'
100
+ remove_file 'bin/sidekiq-entrypoint'
96
101
  end
97
102
 
98
103
  private
@@ -100,31 +105,43 @@ class Modulorails::SidekiqGenerator < Rails::Generators::Base
100
105
  def add_to_docker_compose_yml_file(file_path)
101
106
  @image_name ||= Modulorails.data.name.parameterize
102
107
 
103
- # Create docker-compose.yml unless present
104
- invoke(Modulorails::DockerGenerator, []) unless File.exist?(file_path)
108
+ unless File.exist?(file_path)
109
+ puts("Compose file not found at #{file_path}. Ignoring.")
110
+ return
111
+ end
105
112
 
106
- return if File.read(file_path).match?(/^ {2}sidekiq:$/)
113
+ # Update existing Sidekiq service
114
+ if File.read(file_path).match?(/^ {2}sidekiq:$/)
115
+ pattern = /^(\s*)entrypoint:(\s*).\/(bin\/sidekiq-entrypoint|entrypoints\/sidekiq-entrypoint\.sh)/
116
+ gsub_file file_path, pattern, '\1command:\2./bin/bundle exec sidekiq'
117
+ return
118
+ end
107
119
 
120
+ add_sidekiq_service(file_path)
121
+ end
122
+
123
+ def add_sidekiq_service(file_path)
108
124
  insert_into_file file_path, after: /^services:/ do
125
+ # Using `<<-` Heredoc syntax to preserve YAML indentation
109
126
  <<-YAML
110
127
 
111
128
  sidekiq:
112
129
  image: modulotechgroup/#{@image_name}:dev
113
130
  build:
114
- context: .
115
- dockerfile: Dockerfile
131
+ context: ..
132
+ dockerfile: .devcontainer/Dockerfile
116
133
  depends_on:
117
134
  - database
118
135
  - redis
119
136
  volumes:
120
- - .:/app
137
+ - ..:/rails
121
138
  environment:
122
139
  RAILS_ENV: development
123
140
  URL: http://app:3000
124
- #{@image_name.upcase}_DATABASE_HOST: database
125
- #{@image_name.upcase}_DATABASE_NAME: #{@image_name}
126
- REDIS_URL: redis://redis:6379/1
127
- entrypoint: ./bin/sidekiq-entrypoint
141
+ env_file:
142
+ - path: .env
143
+ required: false
144
+ command: ./bin/bundle exec sidekiq
128
145
  stdin_open: true
129
146
  tty: true
130
147
  YAML
@@ -146,8 +163,9 @@ class Modulorails::SidekiqGenerator < Rails::Generators::Base
146
163
  end
147
164
 
148
165
  def add_to_deploy_file(file_path)
149
- # Do nothing if file does not exists or Sidekiq is already enabled
150
- return if !File.exist?(file_path) || File.read(file_path).match?(/^ {2}sidekiq:$/)
166
+ # Do nothing if file does not exist or Sidekiq is already enabled
167
+ return unless File.exist?(file_path)
168
+ return if File.read(file_path).match?(/^sidekiq:\n {2}enabled: true$/m)
151
169
 
152
170
  # Add sidekiq to deploy file
153
171
  insert_into_file file_path do
@@ -158,17 +176,56 @@ class Modulorails::SidekiqGenerator < Rails::Generators::Base
158
176
  resources:
159
177
  requests:
160
178
  cpu: 100m
161
- memory: 512Mi
179
+ memory: 1024Mi
162
180
  limits:
163
- cpu: 100m
164
- memory: 512Mi
181
+ memory: 1024Mi
165
182
  autoscaling:
166
183
  enabled: true
167
- minReplicas: 1
168
- maxReplicas: 10
184
+ minReplicas: #{file_path.to_s.match?('production.y') ? 2 : 1}
185
+ maxReplicas: #{file_path.to_s.match?('production.y') ? 10 : 2}
169
186
  targetCPUUtilizationPercentage: 80
187
+ command: ["./bin/bundle", "exec", "sidekiq"]
170
188
  YAML
171
189
  end
172
190
  end
173
191
 
192
+ RAILS_AUTHENTICATION_TEMPLATE = <<~RUBY.freeze
193
+ require 'sidekiq/web'
194
+ constraints lambda { |request| Session.find_by(id: request.cookie_jar.signed[:session_id])&.user&.role == 'admin' } do
195
+ mount Sidekiq::Web => '/admin/sidekiq'
196
+ end
197
+
198
+
199
+ RUBY
200
+
201
+ def add_devise_authenticated_route(routes_path)
202
+ template = <<~RUBY
203
+ require 'sidekiq/web'
204
+ authenticate :user, lambda { |u| u.respond_to?('role') && u.role == 'admin' } do
205
+ mount Sidekiq::Web => '/admin/sidekiq'
206
+ end
207
+
208
+ RUBY
209
+ puts("Injecting #{template} into #{routes_path}: update the authentication block.")
210
+ inject_into_file routes_path, template, after: "Rails.application.routes.draw do\n"
211
+ end
212
+
213
+ def add_rails_authenticated_route(routes_path)
214
+ template = RAILS_AUTHENTICATION_TEMPLATE
215
+ puts("Injecting #{template} into #{routes_path}: update the authentication block.")
216
+ inject_into_file routes_path, template, after: "Rails.application.routes.draw do\n"
217
+ end
218
+
219
+ def add_unauthenticated_route(routes_path)
220
+ template = <<~RUBY
221
+ require 'sidekiq/web'
222
+ mount Sidekiq::Web => '/admin/sidekiq'
223
+
224
+ RUBY
225
+ puts("Injecting #{template} into #{routes_path}: you should add authentication to the route.")
226
+ puts("If you do not have authentication, execute `rails generate authentication` and replace \
227
+ the route by #{RAILS_AUTHENTICATION_TEMPLATE}.")
228
+ inject_into_file routes_path, template, after: "Rails.application.routes.draw do\n"
229
+ end
230
+
174
231
  end
@@ -1,9 +1,9 @@
1
- redis_url = Rails.application.config_for('cable')['url']
2
-
3
1
  Sidekiq.configure_server do |config|
4
- config.redis = { url: redis_url }
2
+ config.redis = { url: REDIS_URL }
3
+ config.logger.formatter = Sidekiq::Logger::Formatters::Datadog.new
4
+ config.error_handlers << Sidekiq::Datadog::Error::Tracking
5
5
  end
6
6
 
7
7
  Sidekiq.configure_client do |config|
8
- config.redis = { url: redis_url }
8
+ config.redis = { url: REDIS_URL }
9
9
  end
@@ -16,14 +16,8 @@ module Modulorails
16
16
  # config.project_manager 'pm@modulotech.fr'
17
17
  # config.endpoint "intranet's endpoint"
18
18
  # config.api_key "intranet's api key"
19
- # config.production_url "production.app.com"
20
- # config.staging_url "staging.app.com"
21
- # config.review_base_url "review.app.com"
22
19
  # end
23
- %i[
24
- name main_developer project_manager endpoint api_key no_auto_update production_url staging_url
25
- review_base_url
26
- ].each do |field|
20
+ %i[name main_developer project_manager endpoint api_key].each do |field|
27
21
  define_method(field) do |value=nil|
28
22
  # No value means we want to get the field
29
23
  return send("_#{field}") unless value
@@ -33,6 +27,22 @@ module Modulorails
33
27
  end
34
28
  end
35
29
 
30
+ # Deprecated configuration options - will be removed in 2.0
31
+ %i[no_auto_update production_url staging_url review_base_url].each do |field|
32
+ define_method(field) do |value=nil|
33
+ # No value means we want to get the field
34
+ return send("_#{field}") unless value
35
+
36
+ # Warn only when setting the value (i.e., in the initializer)
37
+ Modulorails.deprecator.warn(
38
+ "Modulorails configuration `#{field}` is deprecated and will be removed in version 2.0."
39
+ )
40
+
41
+ # Else we want to set the field
42
+ send("_#{field}=", value)
43
+ end
44
+ end
45
+
36
46
  end
37
47
 
38
48
  end