# frozen_string_literal: true require_relative 'utils' require_relative 'github' require_relative 'todos' require_relative 'rubocop_exceptions' require_relative 'commit_lint' require_relative 'reek' require_relative 'jshint' require_relative 'dependencies' class Danger::DangerWCC < Danger::Plugin include Utils include Github DEFAULT_OPTIONS = { rubocop_exceptions: true, flay: true, todos: true, brakeman: true, commit_lint: false, reek: false, jshint: false, dependencies: true }.freeze # Runs all the included checks in the plugin def all(options = {}) options = DEFAULT_OPTIONS.merge(options) to_run = options.keys.reject { |check_name| options[check_name] == false } raise ArgumentError, 'No Enabled Checks' if to_run.empty? to_run.each do |check_name| check_options = options.fetch(check_name, {}) public_send(check_name, check_options == true ? {} : check_options) end end # Checks for added TODOs def todos(options = {}) logger.info "TODOs: #{options}" Todos.new(self, options).perform end # Checks for if Rubocop was disabled in the source def rubocop_exceptions(options = {}) logger.info "rubocop_exceptions: #{options}" RubocopExceptions.new(self, options).perform end # Lints the commit messages def commit_lint(options = {}) logger.info "commit_lint: #{options}" CommitLint.new(self, DEFAULT_COMMIT_LINT_OPTIONS.merge(options)).perform end def reek(options = {}) logger.info "reek: #{options}" Reek.new(self, options).perform end def brakeman(options = {}) logger.info "brakeman: #{options}" diff = run_and_diff('bundle exec brakeman -f tabs 2>/dev/null '\ '| sed s@`pwd`/@@ | sed -E "s/([0-9]+)//g"') diff = GitDiff.from_string(diff) brakeman_lines = run 'bundle exec brakeman -f tabs 2>/dev/null '\ '| sed s@`pwd`/@@' brakeman_lines = brakeman_lines.lines each_addition_in_diff(diff) do |line| fields = brakeman_lines[line.line_number.right - 1].split("\t") add_brakeman_error(fields, fields[0]) end end def flay(options = {}) logger.info "flay: #{options}" flay_results = parse_flay_results each_addition_in_diff do |add, _h, file| search = "#{file.b_path}:#{add.line_number.right}" flay_results.each do |warning, lines| other = lines.reject { |l| l == search } next unless other.length < lines.length add_flay_warning(warning, other, file, add) end end end def jshint(options = {}) logger.info "jshint: #{options}" Jshint.new(self, options).perform end def dependencies(options = {}) logger.info "dependencies: #{options}" Dependencies.new(self, options).perform end private def parse_flay_results flay = run('bundle exec flay app/**/*.rb lib/**/*.rb') flay_results = {} current = nil flay.lines.each do |flay_line| if m = flay_line.match(/^\d+\)\s+(.+)$/i) current = [] flay_results[m.captures[0]] = current elsif current && flay_line =~ /^\s+.+\:\d+\s*$/i current << flay_line.strip! end end flay_results end def add_brakeman_error(fields, file) message = "#{fields[2]} #{fields[3]} #{fields[4]} confidence: #{fields[5]}" fail(message, file: file, line: fields[1].to_i) end def add_flay_warning(warning, other, file, line) other = other.map { |l| github.html_link(l.gsub(/\:/, '#L')) } message = "#{warning} at:\n " + other.join("\n ") warn(message, file: file.b_path, line: line.line_number.right) end DEFAULT_COMMIT_LINT_OPTIONS = { warn: :all, disable: %i[subject_period subject_cap], subject_length: { max: 72 } }.freeze end