#!/usr/bin/env ruby
# frozen_string_literal: true
require 'json'
require 'pathname'
require 'time'
require 'yaml'
require 'zlib'
CONFIG_PATH = 'config/solidus_compare.yml'
@config = {}
@cmd_options = {}
ARGV.each do |arg|
case arg
when '-h', '--help'
puts <<~HELP
Solidus Compare: a tool to detect changes between 2 repositories
Options:
-h or --help : show this help
-s or --summary : generate an XML summary of the files changed (used in CI)
-u or --update-ignore : update the config file setting the current hashes to ignore
HELP
exit 0
when '-s', '--summary'
@cmd_options[:summary] = true
when '-u', '--update-ignore'
@cmd_options[:update] = true
end
end
# ---------------------------------------------------------------------------- #
def generate_comparison(report)
report.each do |data|
conf = @config['ignore'].find { |cfg| cfg['path'] == data['path'] }
diffs = conf ? (conf['diffs'] || []) : []
data['diffs'].each do |result|
info = diffs.find { |diff| diff['file'] == result['file'] } || {}
if info['skip']
result['skip'] = true
result.delete 'hash'
next
elsif info['hash'] == result['hash']
next
end
puts result['diff']
end
end
update_ignore(report) if @cmd_options[:update]
end
def generate_summary(report) # rubocop:disable Metrics/MethodLength
summary = {}
report.each do |data|
path = data['path']
conf = @config['ignore'].find { |cfg| cfg['path'] == path }
diffs = conf ? (conf['diffs'] || []) : []
data['diffs'].each do |result|
info = diffs.find { |diff| diff['file'] == result['file'] } || {}
next if info['skip'] || info['hash'] == result['hash']
(summary[path] ||= {})[result['hash']] = result['file']
end
end
count = 0
testcases = summary.map do |file_path, value|
value.map do |hash, file|
count += 1
full_path = Pathname.new(file_path).join(file).to_s
"hash: #{hash}\nfile: #{file}"
end
end.join("\n")
output = <<~SUMMARY
#{testcases}
SUMMARY
puts output
exit 1 if count.positive?
end
def load_config
@config = YAML.load_file(CONFIG_PATH) if File.exist?(CONFIG_PATH)
@config ||= {}
@config['ignore'] ||= []
@config['project_paths'] ||= []
@config['source_repo'] ||= 'https://github.com/solidusio/solidus.git'
@config['source_name'] ||= 'solidus'
@config['source_branch'] ||= 'master'
@config['source_base_path'] ||= 'frontend/'
end
def solidus_compare
report = @config['project_paths'].map do |path|
remote_source = "remotes/#{@config['source_name']}/#{@config['source_branch']}"
remote_path = "#{@config['source_base_path']}#{path}"
result = `git diff "#{remote_source}" -- "#{remote_path}" "#{path}"`
puts("error with git diff #{path}") & exit if $?.exitstatus != 0
result.gsub!(/index\s[\w\d]+\.\.[\w\d]+\s[\w\d]+\n/, '')
diffs = result.split(/diff --git /)[1..-1]
next unless diffs
{
'path' => path,
'diffs' => diffs.map do |diff|
next if diff.include? 'similarity index 100%'
{
'hash' => Zlib.crc32(diff),
'file' => diff.match(%r{a/([^\s]+)})&.send(:[], 1),
'diff' => 'diff --git ' + diff
}
end.compact
}
# end
end.compact
@cmd_options[:summary] ? generate_summary(report) : generate_comparison(report)
end
def update_ignore(report)
report.each do |data|
data['diffs'].each do |result|
result.delete('diff')
end
end.compact
@config['ignore'] = report
File.open(CONFIG_PATH, 'w') { |f| f.puts(@config.to_yaml) }
end
def update_source
if `git remote`.split("\n").none? @config['source_name']
`git remote add -f #{@config['source_name']} #{@config['source_repo']}`
puts('error with git remote add') & exit if $?.exitstatus != 0
end
`git remote update > /dev/null 2>&1`
puts('error with git remote update') & exit if $?.exitstatus != 0
end
# ---------------------------------------------------------------------------- #
load_config
update_source
solidus_compare