#!/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