canvas-lms/script/linter.rb

208 lines
5.4 KiB
Ruby

#
# Copyright (C) 2016 - present Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
$LOAD_PATH.push File.expand_path("../../gems/dr_diff/lib", __FILE__)
require 'dr_diff'
require 'json'
class Linter
DEFAULT_OPTIONS = {
append_files_to_command: false,
auto_correct: false,
boyscout_mode: true,
campsite_mode: true,
comment_post_processing: proc { |comments| comments },
custom_comment_generation: false,
env_sha: ENV['SHA'] || ENV['GERRIT_PATCHSET_REVISION'],
file_regex: /./,
generate_comment_proc: proc { },
gerrit_patchset: !!ENV['GERRIT_PATCHSET_REVISION'],
heavy_mode: false,
heavy_mode_proc: proc {},
include_git_dir_in_output: !!!ENV['GERRIT_PATCHSET_REVISION'],
plugin: ENV['GERRIT_PROJECT'],
skip_file_size_check: false,
skip_wips: false,
base_dir: nil
}.freeze
def initialize(options = {})
options = DEFAULT_OPTIONS.merge(options)
if options[:plugin] == 'canvas-lms'
options[:plugin] = nil
end
options.each do |key, value|
instance_variable_set("@#{key}", value)
end
end
def run
if git_dir && !Dir.exist?(git_dir)
puts "No plugin #{plugin} found"
return
end
if skip_wips && wip?
puts "WIP detected, #{linter_name} will not run."
return
end
if !skip_file_size_check && files.size == 0
puts "No #{file_regex} file changes found, skipping #{linter_name} check!"
return
end
if heavy_mode
heavy_mode_proc.call(files)
else
publish_comments
end
end
private
# TODO: generate from DEFAULT_OPTIONS
attr_reader :append_files_to_command,
:auto_correct,
:boyscout_mode,
:campsite_mode,
:command,
:comment_post_processing,
:default_boyscout_mode,
:custom_comment_generation,
:env_sha,
:file_regex,
:format,
:generate_comment_proc,
:gergich_capture,
:gerrit_patchset,
:heavy_mode,
:heavy_mode_proc,
:include_git_dir_in_output,
:linter_name,
:plugin,
:severe_levels,
:skip_file_size_check,
:skip_wips,
:base_dir
def git_dir
@git_dir ||= plugin && "gems/plugins/#{plugin}/"
end
def severe_levels
boyscout_mode ? %w(error warn info) : %w(error warn)
end
def dr_diff
@dr_diff ||= ::DrDiff::Manager.new(git_dir: git_dir, sha: env_sha, campsite: campsite_mode, base_dir: base_dir)
end
def wip?
dr_diff.wip?
end
def changes
dr_diff.changes
end
def files
@files ||= dr_diff.files(file_regex)
end
def full_command
if append_files_to_command
"#{command} #{files.join(' ')}"
else
command
end
end
def comments
@comments ||= dr_diff.comments(format: format,
command: full_command,
include_git_dir_in_output: include_git_dir_in_output,
severe_levels: severe_levels)
end
def generate_comments
if custom_comment_generation
generate_comment_proc.call(changes: changes, auto_correct: auto_correct)
else
comments
end
end
def publish_comments
processed_comments = comment_post_processing.call(generate_comments)
unless processed_comments.size > 0
puts "-- -- -- -- -- -- -- -- -- -- --"
puts "No relevant #{linter_name} errors found!"
puts "-- -- -- -- -- -- -- -- -- -- --"
end
if gerrit_patchset
publish_gergich_comments(processed_comments)
else
publish_local_comments(processed_comments)
if auto_correct
puts "Errors detected and possibly auto corrected."
puts "Fix and/or git add the corrections and try to commit again."
end
end
end
def publish_gergich_comments(comments)
require "gergich"
draft = Gergich::Draft.new
cover_comments, comments = comments.partition do |comment|
comment[:cover_message]
end
comments.each do |comment|
draft.add_comment comment[:path],
comment[:position],
comment[:message],
comment[:severity]
end
cover_comments.each do |cover_comment|
draft.add_message(cover_comment[:message])
end
end
def publish_local_comments(comments)
require 'colorize'
comments.each { |comment| pretty_comment(comment) }
end
def pretty_comment(comment)
message = ""
message += "[#{comment[:severity]}]".colorize(:yellow)
unless comment[:cover_message]
message += " #{comment[:path].colorize(:light_blue)}:#{comment[:position]}"
end
message += " => #{comment[:message].colorize(:green)}"
puts message
end
end