diff --git a/.rubocop.yml b/.rubocop.yml index 82e04ba6f..2d1193107 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,10 +1,11 @@ +inherit_from: .rubocop_todo.yml + +require: + - .rubocop/custom_cop/top_level_constants_per_file.rb + AllCops: TargetRubyVersion: 2.5 TargetRailsVersion: 5.1 - Include: - - '**/config.ru' - - '**/Rakefile' - - '**/*.rake' Exclude: - 'bin/**/*' - 'db/**/*' @@ -62,3 +63,11 @@ Style/TrailingCommaInArrayLiteral: Style/TrailingCommaInHashLiteral: Enabled: false + +CustomCop/TopLevelConstantsPerFile: + Enabled: true + Include: + - 'app/**/*' + - 'lib/**/*' + Exclude: + - '**/*[^.rb]' # exclude non-.rb files (ex: .rake files) diff --git a/.rubocop/custom_cop/top_level_constants_per_file.rb b/.rubocop/custom_cop/top_level_constants_per_file.rb new file mode 100644 index 000000000..90832839f --- /dev/null +++ b/.rubocop/custom_cop/top_level_constants_per_file.rb @@ -0,0 +1,28 @@ +module RuboCop + module CustomCop + class TopLevelConstantsPerFile < RuboCop::Cop::Cop + MSG = "Multiple top-level constants detected in one file. The autoloader expects one top-level constant per file." + + def investigate(processed_source) + return unless processed_source + + # If more than one top-level constant in the file, add offense on the second one + if top_level_constant_nodes.size > 1 + add_offense(top_level_constant_nodes[1], message: MSG) + end + end + + private + + def top_level_constant_nodes + @top_level_constant_nodes ||= + processed_source.ast.each_node(:class, :module).select { |node| top_level_constant?(node) } + end + + def top_level_constant?(node) + # node is not nested within a class or module node? + node.ancestors.none? { |ancestor| ancestor.class_type? || ancestor.module_type? } + end + end + end +end diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml new file mode 100644 index 000000000..dce59c222 --- /dev/null +++ b/.rubocop_todo.yml @@ -0,0 +1,506 @@ +# This configuration was generated by +# `rubocop --auto-gen-config` +# on 2024-10-09 19:23:15 -0400 using RuboCop version 0.83.0. +# The point is for the user to remove these configuration records +# one by one as the offenses are removed from the code base. +# Note that changes in the inspected code, or installation of new +# versions of RuboCop, may require this file to be generated again. + +# Offense count: 2 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, IndentationWidth. +# SupportedStyles: with_first_argument, with_fixed_indentation +Layout/ArgumentAlignment: + Exclude: + - 'app/services/manifest_fetcher.rb' + - 'app/services/record_fetcher.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +Layout/ClosingHeredocIndentation: + Exclude: + - 'spec/services/pdf_service_spec.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +Layout/ClosingParenthesisIndentation: + Exclude: + - 'spec/initializers/deprecation_warning_subscriber_spec.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +Layout/CommentIndentation: + Exclude: + - 'spec/features/help_spec.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +Layout/ElseAlignment: + Exclude: + - 'spec/features/user_error_flows_spec.rb' + +# Offense count: 16 +# Cop supports --auto-correct. +Layout/EmptyLineAfterGuardClause: + Exclude: + - 'app/controllers/api/v2/manifests_controller.rb' + - 'app/controllers/api/v2/records_controller.rb' + - 'app/controllers/sessions_controller.rb' + - 'app/helpers/application_helper.rb' + - 'app/models/manifest.rb' + - 'app/models/manifest_source.rb' + - 'app/services/external_api/bgs_service.rb' + - 'app/services/manifest_fetcher.rb' + - 'lib/fakes/bgs_service.rb' + - 'lib/fakes/document_service.rb' + - 'spec/support/download_helper.rb' + +# Offense count: 2 +# Cop supports --auto-correct. +# Configuration parameters: AllowAdjacentOneLineDefs, NumberOfEmptyLines. +Layout/EmptyLineBetweenDefs: + Exclude: + - 'app/services/manifest_fetcher.rb' + +# Offense count: 2 +# Cop supports --auto-correct. +Layout/EmptyLines: + Exclude: + - 'app/services/external_api/bgs_service.rb' + - 'app/services/manifest_fetcher.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: around, only_before +Layout/EmptyLinesAroundAccessModifier: + Exclude: + - 'app/controllers/health_checks_controller.rb' + +# Offense count: 6 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: empty_lines, empty_lines_except_namespace, empty_lines_special, no_empty_lines, beginning_only, ending_only +Layout/EmptyLinesAroundClassBody: + Exclude: + - 'app/controllers/health_checks_controller.rb' + - 'app/services/record_api_fetcher.rb' + - 'app/services/record_fetcher.rb' + - 'app/services/record_fetcher_base.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyleAlignWith, AutoCorrect, Severity. +# SupportedStylesAlignWith: keyword, variable, start_of_line +Layout/EndAlignment: + Exclude: + - 'spec/features/user_error_flows_spec.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, IndentationWidth. +# SupportedStyles: consistent, consistent_relative_to_receiver, special_for_inner_method_call, special_for_inner_method_call_in_parentheses +Layout/FirstArgumentIndentation: + Exclude: + - 'spec/initializers/deprecation_warning_subscriber_spec.rb' + +# Offense count: 8 +# Cop supports --auto-correct. +# Configuration parameters: IndentationWidth. +# SupportedStyles: special_inside_parentheses, consistent, align_brackets +Layout/FirstArrayElementIndentation: + EnforcedStyle: consistent + +# Offense count: 2 +# Cop supports --auto-correct. +# Configuration parameters: IndentationWidth. +# SupportedStyles: special_inside_parentheses, consistent, align_braces +Layout/FirstHashElementIndentation: + EnforcedStyle: consistent + +# Offense count: 27 +# Cop supports --auto-correct. +# Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle. +# SupportedHashRocketStyles: key, separator, table +# SupportedColonStyles: key, separator, table +# SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit +Layout/HashAlignment: + Exclude: + - 'spec/requests/api/v2/manifests_spec.rb' + - 'spec/services/external_api/bgs_service_spec.rb' + - 'spec/services/user_authorizer_spec.rb' + - 'spec/services/veteran_finder_spec.rb' + +# Offense count: 2 +# Cop supports --auto-correct. +# Configuration parameters: Width, IgnoredPatterns. +Layout/IndentationWidth: + Exclude: + - 'spec/features/user_error_flows_spec.rb' + +# Offense count: 14 +# Cop supports --auto-correct. +# Configuration parameters: AllowDoxygenCommentStyle, AllowGemfileRubyComment. +Layout/LeadingCommentSpace: + Exclude: + - 'Gemfile' + - 'ci-bin/concatenate-log.rb' + - 'spec/rails_helper.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +Layout/LeadingEmptyLines: + Exclude: + - 'lib/fakes/bgs_service.rb' + +# Offense count: 9 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, IndentationWidth. +# SupportedStyles: aligned, indented, indented_relative_to_receiver +Layout/MultilineMethodCallIndentation: + Exclude: + - 'spec/controllers/api_v2_application_controller_spec.rb' + - 'spec/helpers/application_helper_spec.rb' + - 'spec/services/external_api/vbms_service_spec.rb' + +# Offense count: 38 +# Cop supports --auto-correct. +# Configuration parameters: AllowForAlignment, EnforcedStyleForExponentOperator. +# SupportedStylesForExponentOperator: space, no_space +Layout/SpaceAroundOperators: + Exclude: + - 'spec/services/external_api/bgs_service_spec.rb' + - 'spec/services/user_authorizer_spec.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces. +# SupportedStyles: space, no_space +# SupportedStylesForEmptyBraces: space, no_space +Layout/SpaceBeforeBlockBraces: + Exclude: + - 'spec/services/manifest_fetcher_spec.rb' + +# Offense count: 14 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBrackets. +# SupportedStyles: space, no_space, compact +# SupportedStylesForEmptyBrackets: space, no_space +Layout/SpaceInsideArrayLiteralBrackets: + Exclude: + - 'spec/features/backend_error_flows_spec.rb' + - 'spec/features/react_download_spec.rb' + - 'spec/jobs/v2/download_manifest_job_spec.rb' + - 'spec/requests/api/v2/document_counts_spec.rb' + - 'spec/requests/api/v2/manifests_spec.rb' + - 'spec/services/document_counter_spec.rb' + - 'spec/services/manifest_fetcher_spec.rb' + +# Offense count: 6 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters. +# SupportedStyles: space, no_space +# SupportedStylesForEmptyBraces: space, no_space +Layout/SpaceInsideBlockBraces: + Exclude: + - 'spec/services/document_creator_spec.rb' + - 'spec/services/manifest_fetcher_spec.rb' + +# Offense count: 6 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces. +# SupportedStyles: space, no_space, compact +# SupportedStylesForEmptyBraces: space, no_space +Layout/SpaceInsideHashLiteralBraces: + Exclude: + - 'spec/services/external_api/bgs_service_spec.rb' + +# Offense count: 3 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: final_newline, final_blank_line +Layout/TrailingEmptyLines: + Exclude: + - '.simplecov' + - 'app/services/metrics_service.rb' + - 'spec/services/manifest_fetcher_spec.rb' + +# Offense count: 31 +# Cop supports --auto-correct. +# Configuration parameters: AllowInHeredoc. +Layout/TrailingWhitespace: + Exclude: + - 'app/services/external_api/vbms_service.rb' + - 'app/services/manifest_fetcher.rb' + - 'app/services/record_fetcher.rb' + - 'spec/controllers/sessions_controller_spec.rb' + - 'spec/jobs/v2/download_manifest_job_spec.rb' + - 'spec/services/document_creator_spec.rb' + - 'spec/services/manifest_fetcher_spec.rb' + - 'spec/services/user_authorizer_spec.rb' + - 'spec/support/capybara.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +Lint/AmbiguousRegexpLiteral: + Exclude: + - 'spec/requests/sso_spec.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +Lint/DeprecatedClassMethods: + Exclude: + - 'spec/services/zipfile_creator_spec.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +Lint/EnsureReturn: + Exclude: + - 'app/services/manifest_fetcher.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +Lint/NonDeterministicRequireOrder: + Exclude: + - 'spec/rails_helper.rb' + +# Offense count: 3 +# Cop supports --auto-correct. +Lint/RedundantCopDisableDirective: + Exclude: + - 'app/helpers/application_helper.rb' + - 'app/services/metrics_service.rb' + - 'spec/features/help_spec.rb' + +# Offense count: 5 +# Cop supports --auto-correct. +# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods, IgnoreNotImplementedMethods. +Lint/UnusedMethodArgument: + Exclude: + - 'app/services/metrics_service.rb' + - 'lib/fakes/bgs_service.rb' + - 'lib/fakes/document_service.rb' + - 'spec/requests/sso_spec.rb' + +# Offense count: 1 +Lint/UselessAssignment: + Exclude: + - 'app/services/manifest_fetcher.rb' + +# Offense count: 2 +# Configuration parameters: IgnoredMethods. +Metrics/AbcSize: + Max: 65 + Exclude: + - 'app/services/document_creator.rb' + - 'app/services/external_api/bgs_service.rb' + +# Offense count: 4 +# Configuration parameters: IgnoredMethods. +Metrics/CyclomaticComplexity: + Max: 15 + +# Offense count: 3 +# Configuration parameters: CountComments, ExcludedMethods. +Metrics/MethodLength: + Max: 32 + Exclude: + - 'app/services/external_api/bgs_service.rb' + - 'lib/fakes/bgs_service.rb' + - 'spec/support/fake_saml_idp.rb' + +# Offense count: 4 +# Configuration parameters: IgnoredMethods. +Metrics/PerceivedComplexity: + Max: 15 + +# Offense count: 1 +# Configuration parameters: IgnoredPatterns. +# SupportedStyles: snake_case, camelCase +Naming/MethodName: + EnforcedStyle: snake_case + Exclude: + - 'app/controllers/base_controller.rb' + +# Offense count: 4 +# Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames. +# AllowedNames: io, id, to, by, on, in, at, ip, db, os, pp +Naming/MethodParameterName: + Exclude: + - 'app/services/zipfile_creator.rb' + - 'lib/fakes/bgs_service.rb' + - 'lib/fakes/document_service.rb' + +# Offense count: 12 +# Cop supports --auto-correct. +# Configuration parameters: PreferredName. +Naming/RescuedExceptionsVariableName: + Exclude: + - 'app/controllers/sessions_controller.rb' + - 'app/jobs/middleware/job_metrics_service_metric_middleware.rb' + - 'app/jobs/v2/download_manifest_job.rb' + - 'app/jobs/v2/package_files_job.rb' + - 'app/services/external_api/bgs_service.rb' + - 'app/services/manifest_fetcher.rb' + - 'app/services/metrics_service.rb' + - 'app/services/record_api_fetcher.rb' + - 'app/services/record_fetcher.rb' + - 'app/services/user_authorizer.rb' + - 'lib/efolder/migration.rb' + +# Offense count: 1 +Security/Open: + Exclude: + - 'app/jobs/touch_file_job.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SingleLineConditionsOnly, IncludeTernaryExpressions. +# SupportedStyles: assign_to_condition, assign_inside_condition +Style/ConditionalAssignment: + Exclude: + - 'app/services/manifest_fetcher.rb' + +# Offense count: 2 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: compact, expanded +Style/EmptyMethod: + Exclude: + - 'app/controllers/sessions_controller.rb' + - 'app/controllers/test_controller.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +Style/ExpandPathArguments: + Exclude: + - 'spec/rails_helper.rb' + +# Offense count: 1 +# Configuration parameters: EnforcedStyle. +# SupportedStyles: annotated, template, unannotated +Style/FormatStringToken: + Exclude: + - 'app/services/zipfile_creator.rb' + +# Offense count: 38 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, UseHashRocketsWithSymbolValues, PreferHashRocketsForNonAlnumEndingSymbols. +# SupportedStyles: ruby19, hash_rockets, no_mixed_keys, ruby19_no_mixed_keys +Style/HashSyntax: + Exclude: + - 'spec/services/external_api/bgs_service_spec.rb' + - 'spec/services/user_authorizer_spec.rb' + +# Offense count: 3 +# Cop supports --auto-correct. +Style/IfUnlessModifier: + Exclude: + - '.simplecov' + - 'app/controllers/application_controller.rb' + - 'app/models/user.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: line_count_dependent, lambda, literal +Style/Lambda: + Exclude: + - 'spec/jobs/application_job_spec.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedOctalStyle. +# SupportedOctalStyles: zero_with_o, zero_only +Style/NumericLiteralPrefix: + Exclude: + - 'spec/services/user_authorizer_spec.rb' + +# Offense count: 8 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: compact, exploded +Style/RaiseArgs: + Exclude: + - 'spec/controllers/api_v2_application_controller_spec.rb' + - 'spec/features/backend_error_flows_spec.rb' + - 'spec/features/user_error_flows_spec.rb' + - 'spec/requests/api/v2/manifests_spec.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +Style/RedundantBegin: + Exclude: + - 'app/services/manifest_fetcher.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +Style/RedundantCondition: + Exclude: + - 'app/services/external_api/bgs_service.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +Style/RedundantInterpolation: + Exclude: + - 'spec/support/fake_saml_idp.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: AllowMultipleReturnValues. +Style/RedundantReturn: + Exclude: + - 'app/controllers/api/v2/document_counts_controller.rb' + +# Offense count: 4 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, AllowInnerSlashes. +# SupportedStyles: slashes, percent_r, mixed +Style/RegexpLiteral: + Exclude: + - 'spec/requests/sso_spec.rb' + +# Offense count: 16 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: only_raise, only_fail, semantic +Style/SignalException: + Exclude: + - 'app/controllers/sessions_controller.rb' + - 'app/models/css_authentication_session.rb' + - 'app/services/external_api/bgs_service.rb' + - 'app/services/manifest_fetcher.rb' + - 'lib/fakes/bgs_service.rb' + +# Offense count: 37 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, ConsistentQuotesInMultiline. +# SupportedStyles: single_quotes, double_quotes +Style/StringLiterals: + Exclude: + - 'app/controllers/api/v2/files_downloads_controller.rb' + - 'app/controllers/application_controller.rb' + - 'app/controllers/test_controller.rb' + - 'app/jobs/touch_file_job.rb' + - 'app/services/external_api/bgs_service.rb' + - 'app/services/record_fetcher.rb' + - 'app/services/record_fetcher_base.rb' + - 'spec/controllers/api_v2_application_controller_spec.rb' + - 'spec/features/active_job_spec.rb' + - 'spec/requests/sso_spec.rb' + - 'spec/support/capybara.rb' + - 'spec/support/fake_saml_idp.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyleForMultiline. +# SupportedStylesForMultiline: comma, consistent_comma, no_comma +Style/TrailingCommaInArguments: + Exclude: + - 'app/models/css_authentication_session.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +Style/WhileUntilDo: + Exclude: + - 'spec/support/download_helper.rb' diff --git a/.simplecov b/.simplecov index 7ee2d5008..2195e2327 100644 --- a/.simplecov +++ b/.simplecov @@ -1,17 +1,18 @@ if ENV["RAILS_ENV"] == "test" SimpleCov.start do + add_filter "app/controllers/errors_controller.rb" add_filter "app/services/test_data_service.rb" + add_filter "config/environments/test.rb" + add_filter "config/initializers" + add_filter "lib/efolder/migration.rb" add_filter "lib/fakes" add_filter "lib/generators" - add_filter "spec/support" - add_filter "spec/rails_helper.rb" - add_filter "spec/spec_helper.rb" - add_filter "config/initializers" - add_filter "config/environments/test.rb" add_filter "lib/tasks" - add_filter "app/controllers/errors_controller.rb" - add_filter "spec/factories" add_filter "spec/" + add_filter "spec/factories" + add_filter "spec/rails_helper.rb" + add_filter "spec/spec_helper.rb" + add_filter "spec/support" end SimpleCov.coverage_dir ENV["COVERAGE_DIR"] || nil SimpleCov.command_name ENV["TEST_SUBCATEGORY"] || "all" diff --git a/Gemfile b/Gemfile index 20b39d724..8b456abf3 100644 --- a/Gemfile +++ b/Gemfile @@ -10,7 +10,7 @@ gem "aws-sdk-s3" gem "aws-sdk-sqs" gem "bgs", git: "https://github.com/department-of-veterans-affairs/ruby-bgs.git", ref: "a2e055b5a52bd1e2bb8c2b3b8d5820b1a404cd3d" gem "bootsnap", require: false -gem "caseflow", git: "https://github.com/department-of-veterans-affairs/caseflow-commons", ref: "9bd3635fbd8094d25160669f38d8699e2f1d7a98" +gem "caseflow", git: "https://github.com/department-of-veterans-affairs/caseflow-commons", ref: "dbd86859856d161d84b0bba4d67a8b62e4684996" gem "coffee-rails", "> 4.1.0" gem "connect_vbms", git: "https://github.com/department-of-veterans-affairs/connect_vbms.git", branch: "master" gem "connect_vva", git: "https://github.com/department-of-veterans-affairs/connect_vva.git", ref: "dfd1aeb2605c1f237f520bcdc41b059202e8944d" diff --git a/Gemfile.lock b/Gemfile.lock index 923449742..01b1faf22 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -20,8 +20,8 @@ GIT GIT remote: https://github.com/department-of-veterans-affairs/caseflow-commons - revision: 9bd3635fbd8094d25160669f38d8699e2f1d7a98 - ref: 9bd3635fbd8094d25160669f38d8699e2f1d7a98 + revision: dbd86859856d161d84b0bba4d67a8b62e4684996 + ref: dbd86859856d161d84b0bba4d67a8b62e4684996 specs: caseflow (0.4.8) aws-sdk-s3 diff --git a/app/exceptions/bgs_errors.rb b/app/exceptions/bgs_errors.rb deleted file mode 100644 index a61d1a594..000000000 --- a/app/exceptions/bgs_errors.rb +++ /dev/null @@ -1,8 +0,0 @@ -module BGS - class InvalidUsername < StandardError; end - class InvalidStation < StandardError; end - class InvalidApplication < StandardError; end - class NoActiveStations < StandardError; end - class NoCaseflowAccess < StandardError; end - class StationAssertionRequired < StandardError; end -end diff --git a/app/services/external_api/bgs_service.rb b/app/services/external_api/bgs_service.rb index 42658082a..e8dee9867 100644 --- a/app/services/external_api/bgs_service.rb +++ b/app/services/external_api/bgs_service.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "bgs" -require "bgs_errors" + # Thin interface to all things BGS class ExternalApi::BGSService diff --git a/app/services/external_api/vbms_service.rb b/app/services/external_api/vbms_service.rb index 08fe2d8c2..9a2038b0c 100644 --- a/app/services/external_api/vbms_service.rb +++ b/app/services/external_api/vbms_service.rb @@ -1,22 +1,20 @@ -require "vbms" - -class RailsVBMSLogger - def log(event, data) - case event - when :request - if data[:response_code] != 200 - name = data[:request].class.name.split("::").last - - Rails.logger.error( - "VBMS HTTP Error #{data[:response_code]}\n" \ - "VBMS #{name} Response #{data[:response_body]}" - ) +class ExternalApi::VBMSService + class RailsVBMSLogger + def log(event, data) + case event + when :request + if data[:response_code] != 200 + name = data[:request].class.name.split("::").last + + Rails.logger.error( + "VBMS HTTP Error #{data[:response_code]}\n" \ + "VBMS #{name} Response #{data[:response_body]}" + ) + end end end end -end -class ExternalApi::VBMSService def self.fetch_documents_for(download) request = VBMS::Requests::ListDocuments.new(download.file_number) diff --git a/config/application.rb b/config/application.rb index 25f1bd0f3..e33ceaeec 100644 --- a/config/application.rb +++ b/config/application.rb @@ -10,7 +10,6 @@ module CaseflowEfolder class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. config.load_defaults 6.1 - config.autoloader = :classic # Configuration for the application, engines, and railties goes here. # @@ -122,9 +121,51 @@ class Application < Rails::Application # eFolder Specific configs #--------------------------------------------------------------------------------------- config.download_filepath = Rails.root + "tmp/files" - config.autoload_paths += Dir[Rails.root + 'app/jobs'] - config.autoload_paths << Rails.root.join('lib') - config.autoload_paths << Rails.root.join('lib/scripts') + + + # -------------------------------------------------------------------------------------- + # Autoloading & Eager loading + + # Zeitwerk has specific requirements for auto/eager loading. See below links for more details + # https://guides.rubyonrails.org/classic_to_zeitwerk_howto.html + # https://github.com/fxn/zeitwerk + + config.autoload_paths += [ + "#{root}/lib", + ] + + config.eager_load_paths += [ + "#{root}/lib", + ] + + Rails.autoloaders.each do | autoloader | + # "file_name" => Expected Module or Class name. + autoloader.inflector.inflect( + "bgs" => "BGS", + "bgs_service" => "BGSService", + "poa_mapper" => "POAMapper", + "vbms_service" => "VBMSService", + "vva_service" => "VVAService" + ) + end + + # A collapse statement will remove the need for a namespace based on the direcotry given. + # Tasks::Support::ModuleOrClassName becomes ModuleOrClassName with the two statements below. + Rails.autoloaders.main.collapse( + "#{root}/lib/tasks", + "#{root}/lib/tasks/support" + ) + + # Will not autoload any files within directories added here + Rails.autoloaders.main.ignore( + "#{root}/app/jobs/middleware", + "#{root}/lib/assets", + "#{root}/lib/pdfs", + "#{root}/lib/scripts", + "#{root}/lib/fakes/test_auth_strategy.rb" + ) + # -------------------------------------------------------------------------------------- + # Currently the Caseflow client makes calls to get document content directly # from eFolder Express to reduce load on Caseflow. Since Caseflow and eFolder diff --git a/config/initializers/bgs.rb b/config/initializers/bgs.rb index da7707d1d..ddb1ef447 100644 --- a/config/initializers/bgs.rb +++ b/config/initializers/bgs.rb @@ -1 +1,13 @@ -BGSService = (!BaseController.dependencies_faked? ? ExternalApi::BGSService : Fakes::BGSService) +Rails.application.config.to_prepare do + require "bgs" + + module BGS + class InvalidUsername < StandardError; end + class InvalidStation < StandardError; end + class InvalidApplication < StandardError; end + class NoActiveStations < StandardError; end + class NoCaseflowAccess < StandardError; end + class StationAssertionRequired < StandardError; end + end +end + diff --git a/config/initializers/bgs_service.rb b/config/initializers/bgs_service.rb new file mode 100644 index 000000000..1c12184ef --- /dev/null +++ b/config/initializers/bgs_service.rb @@ -0,0 +1,3 @@ +Rails.application.reloader.to_prepare do + BGSService = (!BaseController.dependencies_faked? ? ExternalApi::BGSService : Fakes::BGSService) +end diff --git a/config/initializers/deprecation_warning_subscriber.rb b/config/initializers/deprecation_warning_subscriber.rb index 26fe96972..c8abd92ff 100644 --- a/config/initializers/deprecation_warning_subscriber.rb +++ b/config/initializers/deprecation_warning_subscriber.rb @@ -3,51 +3,53 @@ # @note For use in conjuction with setting `Rails.application.config.active_support.deprecation = :notify`. # Whenever a “deprecation.rails” notification is published, it will dispatch the event # (ActiveSupport::Notifications::Event) to method #deprecation. -class DeprecationWarningSubscriber < ActiveSupport::Subscriber - APP_NAME = "efolder" - SLACK_ALERT_CHANNEL = "#appeals-deprecation-alerts" - - attach_to :rails - - def deprecation(event) - emit_warning_to_application_logs(event) - emit_warning_to_sentry(event) - ## Skip until we have ENV["SSL_CERT_FILE"] set in eFolder environments, as needed by SlackService - # emit_warning_to_slack_alerts_channel(event) - rescue StandardError => error - Raven.capture_exception(error) - end - - private - - def emit_warning_to_application_logs(event) - Rails.logger.warn(event.payload[:message]) - end - - def emit_warning_to_sentry(event) - # Need to convert callstack elements from `Thread::Backtrace::Location` objects to `Strings` - # to avoid a `TypeError` on `options.deep_dup` in `Raven.capture_message`: - # https://github.com/getsentry/sentry-ruby/blob/2e07e0295ba83df4c76c7bf3315d199c7050a7f9/lib/raven/instance.rb#L114 - callstack_strings = event.payload[:callstack].map(&:to_s) - - Raven.capture_message( - event.payload[:message], - level: "warning", - extra: { - message: event.payload[:message], - gem_name: event.payload[:gem_name], - deprecation_horizon: event.payload[:deprecation_horizon], - callstack: callstack_strings, - environment: Rails.env - } - ) - end - - def emit_warning_to_slack_alerts_channel(event) - slack_alert_title = "Deprecation Warning - #{APP_NAME} (#{ENV['DEPLOY_ENV']})" - - SlackService - .new(url: ENV["SLACK_DISPATCH_ALERT_URL"]) - .send_notification(event.payload[:message], slack_alert_title, SLACK_ALERT_CHANNEL) +Rails.application.config.after_initialize do + class DeprecationWarningSubscriber < ActiveSupport::Subscriber + APP_NAME = "efolder" + SLACK_ALERT_CHANNEL = "#appeals-deprecation-alerts" + + attach_to :rails + + def deprecation(event) + emit_warning_to_application_logs(event) + emit_warning_to_sentry(event) + ## Skip until we have ENV["SSL_CERT_FILE"] set in eFolder environments, as needed by SlackService + # emit_warning_to_slack_alerts_channel(event) + rescue StandardError => error + Raven.capture_exception(error) + end + + private + + def emit_warning_to_application_logs(event) + Rails.logger.warn(event.payload[:message]) + end + + def emit_warning_to_sentry(event) + # Need to convert callstack elements from `Thread::Backtrace::Location` objects to `Strings` + # to avoid a `TypeError` on `options.deep_dup` in `Raven.capture_message`: + # https://github.com/getsentry/sentry-ruby/blob/2e07e0295ba83df4c76c7bf3315d199c7050a7f9/lib/raven/instance.rb#L114 + callstack_strings = event.payload[:callstack].map(&:to_s) + + Raven.capture_message( + event.payload[:message], + level: "warning", + extra: { + message: event.payload[:message], + gem_name: event.payload[:gem_name], + deprecation_horizon: event.payload[:deprecation_horizon], + callstack: callstack_strings, + environment: Rails.env + } + ) + end + + def emit_warning_to_slack_alerts_channel(event) + slack_alert_title = "Deprecation Warning - #{APP_NAME} (#{ENV['DEPLOY_ENV']})" + + SlackService + .new(url: ENV["SLACK_DISPATCH_ALERT_URL"]) + .send_notification(event.payload[:message], slack_alert_title, SLACK_ALERT_CHANNEL) + end end end diff --git a/config/initializers/ruby_claim_evidence_api.rb b/config/initializers/ruby_claim_evidence_api.rb index b888776da..b7bedf7bf 100644 --- a/config/initializers/ruby_claim_evidence_api.rb +++ b/config/initializers/ruby_claim_evidence_api.rb @@ -1,4 +1,6 @@ # frozen_string_literal: true -VeteranFileFetcher = ExternalApi::VeteranFileFetcher - .new(use_canned_api_responses: BaseController.dependencies_faked_for_CEAPI?, logger: Rails.logger) +Rails.application.reloader.to_prepare do + VeteranFileFetcher = ExternalApi::VeteranFileFetcher + .new(use_canned_api_responses: BaseController.dependencies_faked_for_CEAPI?, logger: Rails.logger) +end diff --git a/config/initializers/s3.rb b/config/initializers/s3.rb deleted file mode 100644 index 89160ef81..000000000 --- a/config/initializers/s3.rb +++ /dev/null @@ -1 +0,0 @@ -S3Service = (Rails.application.config.s3_enabled ? Caseflow::S3Service : Caseflow::Fakes::S3Service) diff --git a/config/initializers/s3_service.rb b/config/initializers/s3_service.rb new file mode 100644 index 000000000..7ad21e6c1 --- /dev/null +++ b/config/initializers/s3_service.rb @@ -0,0 +1,3 @@ +Rails.application.reloader.to_prepare do + S3Service = (Rails.application.config.s3_enabled ? Caseflow::S3Service : Caseflow::Fakes::S3Service) +end diff --git a/config/initializers/errors.rb b/config/initializers/standard_error.rb similarity index 51% rename from config/initializers/errors.rb rename to config/initializers/standard_error.rb index f71765294..39bc6a6b8 100644 --- a/config/initializers/errors.rb +++ b/config/initializers/standard_error.rb @@ -1,9 +1,10 @@ # frozen_string_literal: true # monkeypatch some error classes to conform with BGS/VBMS error classes. - -class StandardError - def ignorable? - false +Rails.application.config.before_initialize do + class StandardError + def ignorable? + false + end end end diff --git a/config/initializers/vbms.rb b/config/initializers/vbms.rb deleted file mode 100644 index fe2496de9..000000000 --- a/config/initializers/vbms.rb +++ /dev/null @@ -1 +0,0 @@ -VBMSService = (!BaseController.dependencies_faked? ? ExternalApi::VBMSService : Fakes::VBMSService) diff --git a/config/initializers/vbms_service.rb b/config/initializers/vbms_service.rb new file mode 100644 index 000000000..7b3e323e1 --- /dev/null +++ b/config/initializers/vbms_service.rb @@ -0,0 +1,3 @@ +Rails.application.reloader.to_prepare do + VBMSService = (!BaseController.dependencies_faked? ? ExternalApi::VBMSService : Fakes::VBMSService) +end diff --git a/config/initializers/vva.rb b/config/initializers/vva.rb deleted file mode 100644 index bfe115237..000000000 --- a/config/initializers/vva.rb +++ /dev/null @@ -1 +0,0 @@ -VVAService = (!BaseController.dependencies_faked? ? ExternalApi::VVAService : Fakes::VVAService) diff --git a/config/initializers/vva_service.rb b/config/initializers/vva_service.rb new file mode 100644 index 000000000..82102da02 --- /dev/null +++ b/config/initializers/vva_service.rb @@ -0,0 +1,3 @@ +Rails.application.reloader.to_prepare do + VVAService = (!BaseController.dependencies_faked? ? ExternalApi::VVAService : Fakes::VVAService) +end diff --git a/lib/fakes/bgs_service.rb b/lib/fakes/bgs_service.rb index 641415651..65de30350 100644 --- a/lib/fakes/bgs_service.rb +++ b/lib/fakes/bgs_service.rb @@ -1,4 +1,4 @@ -require 'bgs_errors' + class Fakes::BGSService include ActiveModel::Model diff --git a/lib/fakes/test_auth_strategy.rb b/lib/fakes/test_auth_strategy.rb index a724db4a4..9193f972b 100644 --- a/lib/fakes/test_auth_strategy.rb +++ b/lib/fakes/test_auth_strategy.rb @@ -1,43 +1,47 @@ require "omniauth/strategies/developer" require "omniauth/form" -class EfolderAuthForm < OmniAuth::Form - def hidden_field(name, value) - @html << "\n" - self - end +module Fakes + module TestAuthStrategy + class EfolderAuthForm < OmniAuth::Form + def hidden_field(name, value) + @html << "\n" + self + end - def header(title, header_info) - @html << <<-HTML - - - - - #{title} - #{css} - #{header_info} - - -

#{title}

-
- HTML - self - end -end + def header(title, header_info) + @html << <<-HTML + + + + + #{title} + #{css} + #{header_info} + + +

#{title}

+ + HTML + self + end + end -class OmniAuth::Strategies::TestAuthStrategy < OmniAuth::Strategies::Developer - # custom form rendering - def request_phase - form = EfolderAuthForm.new(title: "Test VA Saml", url: callback_path) - form.hidden_field :username, session["login"]["username"] - form.hidden_field :station_id, session["login"]["station_id"] - form.button "Fake PIV Login" - form.to_response - end + class OmniAuth::Strategies::TestAuthStrategy < OmniAuth::Strategies::Developer + # custom form rendering + def request_phase + form = EfolderAuthForm.new(title: "Test VA Saml", url: callback_path) + form.hidden_field :username, session["login"]["username"] + form.hidden_field :station_id, session["login"]["station_id"] + form.button "Fake PIV Login" + form.to_response + end - def auth_hash - hash = super - hash.uid = hash["info"]["css_id"] - hash + def auth_hash + hash = super + hash.uid = hash["info"]["css_id"] + hash + end + end end end diff --git a/lib/scripts/current_user_load_test.rb b/lib/scripts/current_user_load_test.rb index 8968600f6..1e69682be 100644 --- a/lib/scripts/current_user_load_test.rb +++ b/lib/scripts/current_user_load_test.rb @@ -1,4 +1,4 @@ -class CurrentUserLoadTests +class CurrentUserLoadTest def initialize(iterations = 100) @iterations = iterations end diff --git a/lib/tasks/support/shell_command.rb b/lib/tasks/support/shell_command.rb deleted file mode 100644 index cf11bc63e..000000000 --- a/lib/tasks/support/shell_command.rb +++ /dev/null @@ -1,17 +0,0 @@ -class ShellCommand - # runs shell command and prints output - # returns boolean depending on the success of the command - def self.run(command) - success = false - - Open3.popen2e(command) do |_stdin, stdout_and_stderr, thread| - while (line = stdout_and_stderr.gets) - puts(line) - end - - success = thread.value.zero? - end - - success - end -end diff --git a/spec/config/zeitwerk_spec.rb b/spec/config/zeitwerk_spec.rb new file mode 100644 index 000000000..99a4cbc8c --- /dev/null +++ b/spec/config/zeitwerk_spec.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +RSpec.describe "Zeitwerk Compliance Check" do + it "Eager loads all files without errors" do + expect { Rails.application.eager_load! }.not_to raise_error + end +end diff --git a/spec/rubocop/custom_cop/top_level_constants_per_file_spec.rb b/spec/rubocop/custom_cop/top_level_constants_per_file_spec.rb new file mode 100644 index 000000000..98d7543ef --- /dev/null +++ b/spec/rubocop/custom_cop/top_level_constants_per_file_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require "spec_helper" +require "rubocop" +require "rubocop/rspec/support" +require_relative "../../../.rubocop/custom_cop/top_level_constants_per_file" + +describe RuboCop::CustomCop::TopLevelConstantsPerFile do + include RuboCop::RSpec::ExpectOffense + + subject(:cop) { described_class.new(config) } + let(:config) { RuboCop::Config.new } + + let(:message) do + "Multiple top-level constants detected in one file. The autoloader expects one top-level constant per file." + end + + context "when there is only one top-level class in file" do + it "does not register an offense" do + expect_no_offenses(<<~RUBY) + class SomeClass; end + RUBY + end + end + + context "when there is only one top-level module in file" do + it "does not register an offense" do + expect_no_offenses(<<~RUBY) + module SomeModule; end + RUBY + end + end + + context "when there is only one top-level class/module in file, having one or more nested classes/modules" do + it "does not register an offense" do + expect_no_offenses(<<~RUBY) + module SomeModule + class FirstNestedClass; end + class SecondNestedClass; end + end + RUBY + end + end + + context "when there are multiple top-level classes/modules in file" do + it "registers an offense on the second one" do + expect_offense(<<~RUBY) + class FirstClass; end + module SomeModule; end + ^^^^^^^^^^^^^^^^^^^^^^ #{message} + class SecondClass; end + RUBY + end + end +end diff --git a/spec/services/bgs_service_spec.rb b/spec/services/external_api/bgs_service_spec.rb similarity index 100% rename from spec/services/bgs_service_spec.rb rename to spec/services/external_api/bgs_service_spec.rb