Class: Dependabot::NpmAndYarn::YarnErrorHandler

Inherits:
Object
  • Object
show all
Extended by:
T::Sig
Defined in:
lib/dependabot/npm_and_yarn/file_updater/yarn_lockfile_updater.rb

Instance Method Summary collapse

Constructor Details

#initialize(dependencies:, dependency_files:) ⇒ YarnErrorHandler

Returns a new instance of YarnErrorHandler.



739
740
741
742
# File 'lib/dependabot/npm_and_yarn/file_updater/yarn_lockfile_updater.rb', line 739

def initialize(dependencies:, dependency_files:)
  @dependencies = dependencies
  @dependency_files = dependency_files
end

Instance Method Details

#create_error(handler, message, error, params) ⇒ Object



848
849
850
851
852
853
854
855
856
857
858
# File 'lib/dependabot/npm_and_yarn/file_updater/yarn_lockfile_updater.rb', line 848

def create_error(handler, message, error, params)
  handler.call(
    message,
    error,
    {
      dependencies: dependencies,
      dependency_files: dependency_files,
      **params
    }
  )
end

#find_usage_error(error_message) ⇒ Object



756
757
758
759
760
761
762
# File 'lib/dependabot/npm_and_yarn/file_updater/yarn_lockfile_updater.rb', line 756

def find_usage_error(error_message)
  start_index = error_message.rindex(YARN_USAGE_ERROR_TEXT)
  return nil unless start_index

  error_details = error_message[start_index..-1]
  error_details&.strip
end

#handle_error(error, params) ⇒ Object



766
767
768
769
770
771
772
773
774
775
776
777
778
# File 'lib/dependabot/npm_and_yarn/file_updater/yarn_lockfile_updater.rb', line 766

def handle_error(error, params)
  error_message = error.message

  # Extract the usage error message from the raw error message
  usage_error_message = find_usage_error(error_message) || ""

  # Check if the error message contains any group patterns and raise the corresponding error class
  handle_group_patterns(error, usage_error_message, params)

  # Check if defined yarn error codes contained in the error message
  # and raise the corresponding error class
  handle_yarn_error(error, params)
end

#handle_group_patterns(error, usage_error_message, params) ⇒ Object

rubocop:disable Metrics/PerceivedComplexity



818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
# File 'lib/dependabot/npm_and_yarn/file_updater/yarn_lockfile_updater.rb', line 818

def handle_group_patterns(error, usage_error_message, params) # rubocop:disable Metrics/PerceivedComplexity
  error_message = error.message.gsub(/\e\[\d+(;\d+)*m/, "")
  VALIDATION_GROUP_PATTERNS.each do |group|
    patterns = group[:patterns]
    matchfn = group[:matchfn]
    handler = group[:handler]
    in_usage = group[:in_usage] || false

    next unless (patterns || matchfn) && handler

    message = usage_error_message.empty? ? error_message : usage_error_message
    if in_usage && pattern_in_message(patterns, usage_error_message)
      raise create_error(handler, message, error, params)
    elsif !in_usage && pattern_in_message(patterns, error_message)
      raise create_error(handler, error_message, error, params)
    end

    raise create_error(handler, message, error, params) if matchfn&.call(usage_error_message, error_message)
  end
end

#handle_package_not_found(error_message, yarn_lock) ⇒ Object

rubocop:disable Metrics/PerceivedComplexity



895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
# File 'lib/dependabot/npm_and_yarn/file_updater/yarn_lockfile_updater.rb', line 895

def handle_package_not_found(error_message, yarn_lock) # rubocop:disable Metrics/PerceivedComplexity
  # There are 2 different package not found error messages
  package_not_found = error_message.include?(PACKAGE_NOT_FOUND)
  package_not_found2 = error_message.match?(PACKAGE_NOT_FOUND2)

  # If non of the patterns are found, return an empty hash
  return {} unless package_not_found || package_not_found2

  sanitized_name = T.let(nil, T.nilable(String))

  if package_not_found
    package_name =
      error_message
      .match(PACKAGE_NOT_FOUND_PACKAGE_NAME_REGEX)
      &.named_captures
      &.[](PACKAGE_NOT_FOUND_PACKAGE_NAME_CAPTURE)
      &.split(PACKAGE_NOT_FOUND_PACKAGE_NAME_CAPTURE_SPLIT_REGEX)
      &.first
  end

  if package_not_found2
    package_name =
      error_message
      .match(PACKAGE_NOT_FOUND2_PACKAGE_NAME_REGEX)
      &.named_captures
      &.[](PACKAGE_NOT_FOUND2_PACKAGE_NAME_CAPTURE)
  end

  raise_resolvability_error(error_message, yarn_lock) unless package_name
  sanitized_name = sanitize_package_name(package_name) if package_name
  error_message = error_message.gsub(package_name, sanitized_name) if package_name && sanitized_name
  { sanitized_name: sanitized_name, sanitized_message: error_message }
end

#handle_yarn_error(error, params) ⇒ Object



782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
# File 'lib/dependabot/npm_and_yarn/file_updater/yarn_lockfile_updater.rb', line 782

def handle_yarn_error(error, params)
  ## Clean error message from ANSI escape codes
  error_message = error.message.gsub(/\e\[\d+(;\d+)*m/, "")
  matches = error_message.scan(YARN_CODE_REGEX)
  return if matches.empty?

  # Go through each match backwards in the error message and raise the corresponding error class
  matches.reverse_each do |match|
    code = match[0]
    next unless code

    yarn_error = YARN_ERROR_CODES[code]
    next unless yarn_error.is_a?(Hash)

    message = yarn_error[:message]
    handler = yarn_error[:handler]
    next unless handler

    modified_error_message = if message
                               "[#{code}]: #{message}, Detail: #{error_message}"
                             else
                               "[#{code}]: #{error_message}"
                             end

    raise  create_error(handler, modified_error_message, error, params)
  end
end

#package_missing(error_message) ⇒ Object



931
932
933
934
935
# File 'lib/dependabot/npm_and_yarn/file_updater/yarn_lockfile_updater.rb', line 931

def package_missing(error_message)
  names = dependencies.map(&:name)
  package_missing = names.any? { |name| error_message.include?("find package \"#{name}") }
  !!error_message.match(PACKAGE_MISSING_REGEX) || package_missing
end

#pattern_in_message(patterns, message) ⇒ Object



880
881
882
883
884
885
886
887
888
889
# File 'lib/dependabot/npm_and_yarn/file_updater/yarn_lockfile_updater.rb', line 880

def pattern_in_message(patterns, message)
  patterns.each do |pattern|
    if pattern.is_a?(String)
      return true if message.include?(pattern)
    elsif pattern.is_a?(Regexp)
      return true if message.gsub(/\e\[[\d;]*[A-Za-z]/, "").match?(pattern)
    end
  end
  false
end

#raise_resolvability_error(error_message, yarn_lock) ⇒ Object

Raises:

  • (Dependabot::DependencyFileNotResolvable)


867
868
869
870
871
# File 'lib/dependabot/npm_and_yarn/file_updater/yarn_lockfile_updater.rb', line 867

def raise_resolvability_error(error_message, yarn_lock)
  dependency_names = dependencies.map(&:name).join(", ")
  msg = "Error whilst updating #{dependency_names} in #{yarn_lock.path}:\n#{error_message}"
  raise Dependabot::DependencyFileNotResolvable, msg
end

#sanitize_package_name(package_name) ⇒ Object



938
939
940
941
942
# File 'lib/dependabot/npm_and_yarn/file_updater/yarn_lockfile_updater.rb', line 938

def sanitize_package_name(package_name)
  return package_name.gsub("%2f", "/").gsub("%2F", "/") if package_name

  nil
end