class Danger::Dangerfile

Attributes

defined_in_file[RW]

@return [Pathname] the path where the Dangerfile was loaded from. It is nil

if the Dangerfile was generated programmatically.
env[RW]
plugins[RW]
ui[RW]
verbose[RW]

Public Class Methods

core_plugin_classes() click to toggle source

These are the classes that are allowed to also use method_missing in order to provide broader plugin support

# File lib/danger/danger_core/dangerfile.rb, line 37
def self.core_plugin_classes
  [DangerfileMessagingPlugin]
end
essential_plugin_classes() click to toggle source

The ones that everything would break without

# File lib/danger/danger_core/dangerfile.rb, line 42
def self.essential_plugin_classes
  [DangerfileMessagingPlugin, DangerfileGitPlugin, DangerfileDangerPlugin, DangerfileGitHubPlugin, DangerfileGitLabPlugin, DangerfileBitbucketServerPlugin, DangerfileBitbucketCloudPlugin, DangerfileVSTSPlugin, DangerfileLocalOnlyPlugin]
end
new(env_manager, cork_board = nil) click to toggle source

cork_board not being set comes from plugins #585

# File lib/danger/danger_core/dangerfile.rb, line 77
def initialize(env_manager, cork_board = nil)
  @plugins = {}
  @core_plugins = []
  @ui = cork_board || Cork::Board.new(silent: false, verbose: false)

  # Triggers the core plugins
  @env = env_manager

  # Triggers local plugins from the root of a project
  Dir["./danger_plugins/*.rb"].each do |file|
    require File.expand_path(file)
  end

  refresh_plugins if env_manager.pr?
end

Public Instance Methods

core_dsl_attributes() click to toggle source
# File lib/danger/danger_core/dangerfile.rb, line 113
def core_dsl_attributes
  @core_plugins.map { |plugin| { plugin: plugin, methods: plugin.public_methods(false) } }
end
external_dsl_attributes() click to toggle source
# File lib/danger/danger_core/dangerfile.rb, line 117
def external_dsl_attributes
  plugins.values.reject { |plugin| @core_plugins.include? plugin }.map { |plugin| { plugin: plugin, methods: plugin.public_methods(false) } }
end
fail(*args, **kargs, &blk) click to toggle source
# File lib/danger/danger_core/dangerfile.rb, line 56
def fail(*args, **kargs, &blk)
  method_missing(:fail, *args, **kargs, &blk)
end
failed?() click to toggle source
# File lib/danger/danger_core/dangerfile.rb, line 244
def failed?
  violation_report[:errors].count > 0
end
init_plugins()
Alias for: refresh_plugins
method_missing(method_sym, *arguments, **keyword_arguments, &_block) click to toggle source

When an undefined method is called, we check to see if it’s something that the core DSLs have, then starts looking at plugins support.

Calls superclass method
# File lib/danger/danger_core/dangerfile.rb, line 63
def method_missing(method_sym, *arguments, **keyword_arguments, &_block)
  @core_plugins.each do |plugin|
    if plugin.public_methods(false).include?(method_sym)
      if keyword_arguments.empty?
        return plugin.send(method_sym, *arguments)
      else
        return plugin.send(method_sym, *arguments, **keyword_arguments)
      end
    end
  end
  super
end
method_values_for_plugin_hashes(plugin_hashes) click to toggle source
# File lib/danger/danger_core/dangerfile.rb, line 121
def method_values_for_plugin_hashes(plugin_hashes)
  plugin_hashes.flat_map do |plugin_hash|
    plugin = plugin_hash[:plugin]
    methods = plugin_hash[:methods].select { |name| plugin.method(name).parameters.empty? }

    methods.map do |method|
      case method
      when :api
        value = "Octokit::Client"

      when :pr_json, :mr_json
        value = "[Skipped JSON]"

      when :pr_diff, :mr_diff
        value = "[Skipped Diff]"

      else
        value = plugin.send(method)
        value = wrap_text(value.encode("utf-8")) if value.kind_of?(String)
        # So that we either have one value per row
        # or we have [] for an empty array
        value = value.join("\n") if value.kind_of?(Array) && value.count > 0
      end

      [method.to_s, value]
    end
  end
end
parse(path, contents = nil) click to toggle source

Parses the file at a path, optionally takes the content of the file for DI

# File lib/danger/danger_core/dangerfile.rb, line 178
def parse(path, contents = nil)
  print_known_info if verbose

  contents ||= File.open(path, "r:utf-8", &:read)

  # Work around for Rubinius incomplete encoding in 1.9 mode
  if contents.respond_to?(:encoding) && contents.encoding.name != "UTF-8"
    contents.encode!("UTF-8")
  end

  if contents.tr!("“”‘’‛", %(""'''))
    # Changes have been made
    ui.puts "Your #{path.basename} has had smart quotes sanitised. " \
      "To avoid issues in the future, you should not use " \
      "TextEdit for editing it. If you are not using TextEdit, " \
      "you should turn off smart quotes in your editor of choice.".red
  end

  if contents.include?("puts")
    ui.puts "You used `puts` in your Dangerfile. To print out text to GitHub use `message` instead"
  end

  self.defined_in_file = path
  instance_eval do
    # rubocop:disable Lint/RescueException

    eval_file(contents, path)
  rescue Exception => e
    message = "Invalid `#{path.basename}` file: #{e.message}"
    raise DSLError.new(message, path, e.backtrace, contents)

    # rubocop:enable Lint/RescueException
  end
end
post_results(danger_id, new_comment, remove_previous_comments) click to toggle source
# File lib/danger/danger_core/dangerfile.rb, line 248
def post_results(danger_id, new_comment, remove_previous_comments)
  violations = violation_report
  report = {
      warnings: violations[:warnings].uniq,
      errors: violations[:errors].uniq,
      messages: violations[:messages].uniq,
      markdowns: status_report[:markdowns].uniq,
      danger_id: danger_id
  }

  if env.request_source.respond_to?(:update_pr_by_line!) && ENV["DANGER_MESSAGE_AGGREGATION"]
    env.request_source.update_pr_by_line!(message_groups: MessageAggregator.aggregate(**report),
                                          new_comment: new_comment,
                                          remove_previous_comments: remove_previous_comments,
                                          danger_id: report[:danger_id])
  else
    env.request_source.update_pull_request!(
      **report,
      new_comment: new_comment,
      remove_previous_comments: remove_previous_comments
    )
  end
end
print_known_info() click to toggle source

Iterates through the DSL’s attributes, and table’s the output

print_results() click to toggle source
refresh_plugins() click to toggle source

Iterate through available plugin classes and initialize them with a reference to this Dangerfile

# File lib/danger/danger_core/dangerfile.rb, line 95
def refresh_plugins
  plugins = Plugin.all_plugins
  plugins.each do |klass|
    next if klass.respond_to?(:singleton_class?) && klass.singleton_class?

    plugin = klass.new(self)
    next if plugin.nil? || @plugins[klass]

    name = plugin.class.instance_name
    self.class.send(:attr_reader, name)
    instance_variable_set("@#{name}", plugin)

    @plugins[klass] = plugin
    @core_plugins << plugin if self.class.core_plugin_classes.include? klass
  end
end
Also aliased as: init_plugins
run(base_branch, head_branch, dangerfile_path, danger_id, new_comment, remove_previous_comments, report_results = true) click to toggle source
# File lib/danger/danger_core/dangerfile.rb, line 277
def run(base_branch, head_branch, dangerfile_path, danger_id, new_comment, remove_previous_comments, report_results = true)
  # Setup internal state
  init_plugins
  env.fill_environment_vars

  begin
    # Sets up the git environment
    setup_for_running(base_branch, head_branch)

    # Parse the local Dangerfile
    parse(Pathname.new(dangerfile_path))

    # Push results to the API
    # Pass along the details of the run to the request source
    # to send back to the code review site.
    post_results(danger_id, new_comment, remove_previous_comments) if report_results

    # Print results in the terminal
    print_results
  rescue DSLError => e
    # Push exception to the API and re-raise
    post_exception(e, danger_id, new_comment) unless danger_id.nil?
    raise
  ensure
    # Makes sure that Danger specific git branches are cleaned
    env.clean_up
  end

  failed?
end
setup_for_running(base_branch, head_branch) click to toggle source
# File lib/danger/danger_core/dangerfile.rb, line 272
def setup_for_running(base_branch, head_branch)
  env.ensure_danger_branches_are_setup
  env.scm.diff_for_folder(".".freeze, from: base_branch, to: head_branch, lookup_top_level: true)
end
to_s() click to toggle source

@return [String] a string useful to represent the Dangerfile in a message

presented to the user.
# File lib/danger/danger_core/dangerfile.rb, line 31
def to_s
  "Dangerfile"
end
warn(*args, **kargs, &blk) click to toggle source

Both of these methods exist on all objects ruby-doc.org/core-2.2.3/Kernel.html#method-i-warn ruby-doc.org/core-2.2.3/Kernel.html#method-i-fail However, as we’re using using them in the DSL, they won’t get method_missing called correctly without overriding them.

# File lib/danger/danger_core/dangerfile.rb, line 52
def warn(*args, **kargs, &blk)
  method_missing(:warn, *args, **kargs, &blk)
end

Private Instance Methods

eval_file(contents, path) click to toggle source
# File lib/danger/danger_core/dangerfile.rb, line 310
def eval_file(contents, path)
  eval(contents, nil, path.to_s) # rubocop:disable Security/Eval
end
post_exception(ex, danger_id, new_comment) click to toggle source
# File lib/danger/danger_core/dangerfile.rb, line 337
def post_exception(ex, danger_id, new_comment)
  return if ENV["DANGER_DO_NOT_POST_INVALID_DANGERFILE_ERROR"]
  return if danger_id.nil?

  env.request_source.update_pull_request!(
    danger_id: danger_id,
    new_comment: new_comment,
    markdowns: [ex.to_markdown]
  )
end
print_list(title, rows) click to toggle source
wrap_text(text, width = 80) click to toggle source
# File lib/danger/danger_core/dangerfile.rb, line 330
def wrap_text(text, width = 80)
  text.gsub(/.{,#{width}}/) do |line|
    line.strip!
    "#{line}\n"
  end
end