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.



556
557
558
559
# File 'lib/dependabot/npm_and_yarn/file_updater/yarn_lockfile_updater.rb', line 556

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

Instance Method Details

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



665
666
667
668
669
670
671
# File 'lib/dependabot/npm_and_yarn/file_updater/yarn_lockfile_updater.rb', line 665

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



573
574
575
576
577
578
579
# File 'lib/dependabot/npm_and_yarn/file_updater/yarn_lockfile_updater.rb', line 573

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



583
584
585
586
587
588
589
590
591
592
593
594
595
# File 'lib/dependabot/npm_and_yarn/file_updater/yarn_lockfile_updater.rb', line 583

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



635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
# File 'lib/dependabot/npm_and_yarn/file_updater/yarn_lockfile_updater.rb', line 635

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



708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
# File 'lib/dependabot/npm_and_yarn/file_updater/yarn_lockfile_updater.rb', line 708

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



599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
# File 'lib/dependabot/npm_and_yarn/file_updater/yarn_lockfile_updater.rb', line 599

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



744
745
746
747
748
# File 'lib/dependabot/npm_and_yarn/file_updater/yarn_lockfile_updater.rb', line 744

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



693
694
695
696
697
698
699
700
701
702
# File 'lib/dependabot/npm_and_yarn/file_updater/yarn_lockfile_updater.rb', line 693

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)


680
681
682
683
684
# File 'lib/dependabot/npm_and_yarn/file_updater/yarn_lockfile_updater.rb', line 680

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



751
752
753
754
755
# File 'lib/dependabot/npm_and_yarn/file_updater/yarn_lockfile_updater.rb', line 751

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

  nil
end