class ChefDK::Policyfile::Differ

Constants

FORMAT
INITIAL_FILE_LENGTH_DIFFERENCE
LINES_OF_CONTEXT
POLICY_SECTIONS

Attributes

new_lock[R]
new_name[R]
old_lock[R]
old_name[R]
ui[R]

Public Class Methods

new(old_name: nil, old_lock: nil, new_name: nil, new_lock: nil, ui: nil) click to toggle source
# File lib/chef-dk/policyfile/differ.rb, line 38
def initialize(old_name: nil, old_lock: nil, new_name: nil, new_lock: nil, ui: nil)
  @old_lock = old_lock
  @new_lock = new_lock
  @old_name = old_name
  @new_name = new_name
  @ui = ui

  @added_cookbooks    = nil
  @removed_cookbooks  = nil
  @modified_cookbooks = nil
end

Public Instance Methods

added_cookbooks() click to toggle source
# File lib/chef-dk/policyfile/differ.rb, line 166
def added_cookbooks
  detect_cookbook_changes if @added_cookbooks.nil?
  @added_cookbooks
end
different?() click to toggle source
# File lib/chef-dk/policyfile/differ.rb, line 68
def different?
  !updated_sections.empty?
end
lock_name() click to toggle source
# File lib/chef-dk/policyfile/differ.rb, line 50
def lock_name
  old_lock["name"]
end
modified_cookbooks() click to toggle source
# File lib/chef-dk/policyfile/differ.rb, line 176
def modified_cookbooks
  detect_cookbook_changes if @modified_cookbooks.nil?
  @modified_cookbooks
end
new_cookbook_locks() click to toggle source
# File lib/chef-dk/policyfile/differ.rb, line 58
def new_cookbook_locks
  new_lock["cookbook_locks"]
end
old_cookbook_locks() click to toggle source
# File lib/chef-dk/policyfile/differ.rb, line 54
def old_cookbook_locks
  old_lock["cookbook_locks"]
end
removed_cookbooks() click to toggle source
# File lib/chef-dk/policyfile/differ.rb, line 171
def removed_cookbooks
  detect_cookbook_changes if @removed_cookbooks.nil?
  @removed_cookbooks
end
report_added_cookbooks() click to toggle source
# File lib/chef-dk/policyfile/differ.rb, line 120
def report_added_cookbooks
  return nil if added_cookbooks.empty?

  h1("ADDED COOKBOOKS")
  added_cookbooks.each do |cb_name|
    ui.print("\n")
    old_lock = []
    new_lock = pretty_json(new_cookbook_locks[cb_name])
    h2(cb_name)
    diff_lines(old_lock, new_lock)
  end
end
report_default_attribute_changes() click to toggle source
# File lib/chef-dk/policyfile/differ.rb, line 146
def report_default_attribute_changes
  return nil unless updated_sections.include?("default_attributes")

  h1("DEFAULT ATTRIBUTES CHANGED")

  old_default = pretty_json(old_lock["default_attributes"])
  new_default = pretty_json(new_lock["default_attributes"])
  diff_lines(old_default, new_default)
end
report_modified_cookbooks() click to toggle source
# File lib/chef-dk/policyfile/differ.rb, line 133
def report_modified_cookbooks
  return nil if modified_cookbooks.empty?

  h1("MODIFIED COOKBOOKS")
  modified_cookbooks.each do |cb_name|
    ui.print("\n")
    old_lock = pretty_json(old_cookbook_locks[cb_name])
    new_lock = pretty_json(new_cookbook_locks[cb_name])
    h2(cb_name)
    diff_lines(old_lock, new_lock)
  end
end
report_override_attribute_changes() click to toggle source
# File lib/chef-dk/policyfile/differ.rb, line 156
def report_override_attribute_changes
  return nil unless updated_sections.include?("override_attributes")

  h1("OVERRIDE ATTRIBUTES CHANGED")

  old_override = pretty_json(old_lock["override_attributes"])
  new_override = pretty_json(new_lock["override_attributes"])
  diff_lines(old_override, new_override)
end
report_removed_cookbooks() click to toggle source
# File lib/chef-dk/policyfile/differ.rb, line 107
def report_removed_cookbooks
  return nil if removed_cookbooks.empty?

  h1("REMOVED COOKBOOKS")
  removed_cookbooks.each do |cb_name|
    ui.print("\n")
    old_lock = pretty_json(old_cookbook_locks[cb_name])
    new_lock = []
    h2(cb_name)
    diff_lines(old_lock, new_lock)
  end
end
report_rev_id_changes() click to toggle source
# File lib/chef-dk/policyfile/differ.rb, line 89
def report_rev_id_changes
  h1("REVISION ID CHANGED")
  old_rev = old_lock["revision_id"]
  new_rev = new_lock["revision_id"]
  diff_lines([ old_rev ], [ new_rev ])
end
report_run_list_changes() click to toggle source
# File lib/chef-dk/policyfile/differ.rb, line 96
def report_run_list_changes
  return nil unless updated_sections.include?("run_list")

  h1("RUN LIST CHANGED")

  old_run_list = old_lock["run_list"]
  new_run_list = new_lock["run_list"]

  diff_lines(old_run_list, new_run_list)
end
run_report() click to toggle source
# File lib/chef-dk/policyfile/differ.rb, line 72
def run_report
  unless different?
    ui.err("No changes for policy lock '#{lock_name}' between '#{old_name}' and '#{new_name}'")
    return true
  end

  ui.print("Policy lock '#{lock_name}' differs between '#{old_name}' and '#{new_name}':\n\n")

  report_rev_id_changes
  report_run_list_changes
  report_added_cookbooks
  report_removed_cookbooks
  report_modified_cookbooks
  report_default_attribute_changes
  report_override_attribute_changes
end
updated_sections() click to toggle source
# File lib/chef-dk/policyfile/differ.rb, line 62
def updated_sections
  @updated_sections ||= POLICY_SECTIONS.select do |key|
    old_lock[key] != new_lock[key]
  end
end

Private Instance Methods

color_for_line(line) click to toggle source
# File lib/chef-dk/policyfile/differ.rb, line 224
def color_for_line(line)
  case line[0].chr
  when "+"
    :green
  when "-"
    :red
  when "@"
    line[1].chr == "@" ? :blue : nil
  else
    nil
  end
end
detect_cookbook_changes() click to toggle source
# File lib/chef-dk/policyfile/differ.rb, line 241
def detect_cookbook_changes
  all_locked_cookbooks = old_cookbook_locks.keys | new_cookbook_locks.keys

  @added_cookbooks = []
  @removed_cookbooks = []
  @modified_cookbooks = []

  all_locked_cookbooks.each do |cb_name|
    if old_cookbook_locks.key?(cb_name) && new_cookbook_locks.key?(cb_name)
      old_cb_lock = old_cookbook_locks[cb_name]
      new_cb_lock = new_cookbook_locks[cb_name]
      if old_cb_lock != new_cb_lock
        @modified_cookbooks << cb_name
      end
    elsif old_cookbook_locks.key?(cb_name)
      @removed_cookbooks << cb_name
    elsif new_cookbook_locks.key?(cb_name)
      @added_cookbooks << cb_name
    else
      raise "Bug: cookbook lock #{cb_name} cannot be determined as new/removed/modified/unmodified"
    end
  end
end
diff_lines(old_lines, new_lines) click to toggle source
# File lib/chef-dk/policyfile/differ.rb, line 193
def diff_lines(old_lines, new_lines)
  file_length_difference = INITIAL_FILE_LENGTH_DIFFERENCE

  previous_hunk = nil

  diffs = Diff::LCS.diff(old_lines, new_lines)

  ui.print("\n")

  diffs.each do |piece|
    hunk = Diff::LCS::Hunk.new(old_lines, new_lines, piece, LINES_OF_CONTEXT, file_length_difference)

    file_length_difference = hunk.file_length_difference

    maybe_contiguous_hunks = (previous_hunk.nil? || hunk.merge(previous_hunk))

    unless maybe_contiguous_hunks
      print_color_diff("#{previous_hunk.diff(FORMAT)}\n")
    end
    previous_hunk = hunk
  end
  print_color_diff("#{previous_hunk.diff(FORMAT)}\n") unless previous_hunk.nil?
  ui.print("\n")
end
h1(str) click to toggle source
# File lib/chef-dk/policyfile/differ.rb, line 183
def h1(str)
  ui.msg(str)
  ui.msg("=" * str.size)
end
h2(str) click to toggle source
# File lib/chef-dk/policyfile/differ.rb, line 188
def h2(str)
  ui.msg(str)
  ui.msg("-" * str.size)
end
pretty_json(data) click to toggle source
# File lib/chef-dk/policyfile/differ.rb, line 237
def pretty_json(data)
  FFI_Yajl::Encoder.encode(data, pretty: true).lines.map(&:chomp)
end
print_color_diff(hunk) click to toggle source