repo-compare 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 773b51d17d77a75045e4ef688366a80c4c00dc5de265792789c50c1797cf446d
4
+ data.tar.gz: 54fdb63bf82c42bf11aefa6cb3bd7565d8184a6744bd59efdbb8fed718117a55
5
+ SHA512:
6
+ metadata.gz: be45085c8b9118870b9493633ecbed8d536b17296225ed8c258b40e33cc0161c5aab23a22d63284f749497187f4852e37a27634e82ef4e1a2ff97954dc0e80cb
7
+ data.tar.gz: 3a1c720c912fdf315bc8492d9ac329004ca88cc984967b1ddb04f72e046820dc52b9dc80347036750601ae32701b08608b045708db4f7928daeb4f7845332763
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2021 Mattia Roccoberton
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,57 @@
1
+ # Repo Compare
2
+
3
+ Track changes of another repository.
4
+
5
+ Features:
6
+ - check multiple paths of a repo;
7
+ - create a summary of the changes using git compare (`-s` option);
8
+ - create a detailed list of diffs;
9
+ - ignore some changes to a specific file, saving hashes locally (`-u` option).
10
+
11
+ It can be useful keep track of the changes of a master repo from a forked project, eventually preparing a check in the CI.
12
+
13
+ **IMPORTANT**: the tool will add the other repository as remote source.
14
+
15
+ ## Installation
16
+
17
+ - Add to your Gemfile: `gem 'repo-compare', require: false` (and execute `bundle`)
18
+ - Create a config file in the root of your project (`.repo-compare.yml`):
19
+
20
+ ```yml
21
+ ---
22
+ source_name: REPO_NAME
23
+ source_branch: master
24
+ source_base_path: OPTIONAL_INTERNAL_PATH
25
+ source_repo: https://github.com/ACCOUNT_NAME/REPO_NAME.git
26
+ paths:
27
+ - PATH1
28
+ - PATH2
29
+ - PATH3
30
+ - ...
31
+ ```
32
+
33
+ - Execute the binary: `bundle exec repo-compare`
34
+
35
+ Alternative option, install it at system level: `gem install repo-compare`
36
+
37
+ ## Usage
38
+
39
+ The tool accepts some command line option:
40
+
41
+ - `-h` or `--help` : show this help
42
+ - `-s` or `--summary` : generate an XML summary of the files changed (useful for CI)
43
+ - `-u` or `--update` : update the config file setting the current hashes to ignore
44
+
45
+ ## Do you like it? Star it!
46
+
47
+ If you use this component just star it. A developer is more motivated to improve a project when there is some interest.
48
+
49
+ Or consider offering me a coffee, it's a small thing but it is greatly appreciated: [about me](https://www.blocknot.es/about-me).
50
+
51
+ ## Contributors
52
+
53
+ - [Mattia Roccoberton](https://blocknot.es/): author
54
+
55
+ ## License
56
+
57
+ The gem is available as open source under the terms of the [MIT License](MIT-LICENSE).
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+
5
+ begin
6
+ require 'rspec/core/rake_task'
7
+
8
+ RSpec::Core::RakeTask.new(:spec) do |t|
9
+ # t.ruby_opts = %w[-w]
10
+ t.rspec_opts = ['--color', '--format documentation']
11
+ end
12
+
13
+ task default: :spec
14
+ rescue LoadError
15
+ puts '! LoadError: no RSpec available'
16
+ end
data/bin/repo-compare ADDED
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'repo-compare/config'
5
+ require 'repo-compare/git_remote_update'
6
+ require 'repo-compare/git_diff'
7
+ require 'repo-compare/git_diff_raw'
8
+ require 'repo-compare/summary'
9
+
10
+ # Check the arguments
11
+ action = nil
12
+ ARGV.each do |arg|
13
+ case arg
14
+ when '-h', '--help'
15
+ puts <<~HELP
16
+ Repo Compare: a tool to detect changes between 2 repositories
17
+
18
+ Options:
19
+ -h or --help : show this help
20
+ -s or --summary : generate an XML summary of the files changed (useful for CI)
21
+ -u or --update : update the config file setting the current hashes to ignore
22
+ HELP
23
+ exit 0
24
+ when '-s', '--summary'
25
+ action = :summary
26
+ when '-u', '--update'
27
+ action = :update
28
+ end
29
+ end
30
+
31
+ # Load the config options
32
+ config = RepoCompare::Config.new
33
+ config_hash = config.to_h
34
+
35
+ # Update the remote source
36
+ RepoCompare::GitRemoteUpdate.new(config_hash).call
37
+
38
+ # Compare paths
39
+ results = config_hash['paths'].map do |path|
40
+ RepoCompare::GitDiffRaw.new(config_hash, path).call.merge(src: path)
41
+ end
42
+
43
+ if action == :summary
44
+ # Prepare a summary
45
+ puts RepoCompare::Summary.new(results).to_xml
46
+ else
47
+ # Prepare a detailed diff
48
+ results.each do |res|
49
+ diff = RepoCompare::GitDiff.new(config_hash, res).call
50
+ puts diff unless diff.empty?
51
+ end
52
+ end
53
+
54
+ # Update the config
55
+ config.update(results) if action == :update
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+
5
+ module RepoCompare
6
+ # Load configuration
7
+ class Config
8
+ CONFIG_PATH = '.repo-compare.yml'
9
+
10
+ def initialize
11
+ @config = File.exist?(CONFIG_PATH) ? YAML.load_file(CONFIG_PATH) : {}
12
+ @config['paths'] ||= []
13
+ @config['ignore'] ||= {}
14
+ @config['source_branch'] ||= 'master'
15
+ end
16
+
17
+ def to_h
18
+ @config.to_h
19
+ end
20
+
21
+ def update(results)
22
+ results.each do |result|
23
+ @config['ignore'][result[:src]] ||= {}
24
+ update_conf_path(@config['ignore'][result[:src]], result[:results])
25
+ end
26
+ File.open(CONFIG_PATH, 'w') { |f| f.puts(@config.to_yaml) }
27
+ end
28
+
29
+ private
30
+
31
+ def update_conf_path(conf, results)
32
+ results.each do |path, hash|
33
+ # require 'pry'; binding.pry
34
+ if conf[path]
35
+ # TODO: update...
36
+ else
37
+ conf[path] = hash
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RepoCompare
4
+ # Compare 2 repos
5
+ class GitDiff
6
+ def initialize(config, result)
7
+ @config = config
8
+ @result = result
9
+ end
10
+
11
+ def call
12
+ @result[:results].map do |paths, _hash|
13
+ diff(paths)
14
+ end.join("\n")
15
+ end
16
+
17
+ private
18
+
19
+ def diff(paths)
20
+ src, dst = paths.split("\t")
21
+ dst ||= src
22
+ `git diff 'remotes/#{@config['source_name']}/#{@config['source_branch']}' -- '#{src}' '#{dst}'`
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RepoCompare
4
+ # Compare 2 repos
5
+ class GitDiffRaw
6
+ DIFF_OPTIONS = '--cc --raw'
7
+ EXP = /:\w+ \w+ (?<src>\w+) (?<dst>\w+) (?<status>\w+)\t(?<path>.+)/.freeze
8
+
9
+ def initialize(config, path)
10
+ @config = config
11
+ @context = { output: [] }
12
+ @path = path
13
+ end
14
+
15
+ def call
16
+ compare_repos
17
+ filter_changes
18
+ extract_results
19
+ @context.merge!(success?: true)
20
+ end
21
+
22
+ private
23
+
24
+ def compare_repos
25
+ cmd = "git diff #{DIFF_OPTIONS} 'remotes/#{@config['source_name']}/#{@config['source_branch']}' -- "
26
+ cmd += "'#{@config['source_base_path']}/#{@path}' '#{@path}'"
27
+ @context[:output] = `#{cmd}`.scan(EXP)
28
+ @context
29
+ end
30
+
31
+ def extract_results
32
+ @context[:output].sort_by! { |item| item[3] }
33
+ @context[:results] = {}
34
+ @context[:output].each_with_object(@context[:results]) do |item, ret|
35
+ ret[item[3]] = item[0]
36
+ end
37
+ @context
38
+ end
39
+
40
+ def filter_changes
41
+ ignore = @config['ignore'][@path] || []
42
+ @context[:output].reject! { |line| line[0] == line[1] || ignore_changes?(ignore, line) }
43
+ @context
44
+ end
45
+
46
+ def ignore_changes?(ignore, line)
47
+ path = line[3]
48
+ ignore[path] == '-' || ignore[path] == line[0]
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RepoCompare
4
+ # Update the remote source
5
+ class GitRemoteUpdate
6
+ def initialize(config)
7
+ @config = config
8
+ end
9
+
10
+ def call
11
+ if `git remote`.split("\n").none? @config['source_name']
12
+ `git remote add -f #{@config['source_name']} #{@config['source_repo']}`
13
+ puts('error with git remote add') & exit if $?.exitstatus != 0
14
+ end
15
+
16
+ `git remote update > /dev/null 2>&1`
17
+ puts('error with git remote update') & exit if $?.exitstatus != 0
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+
5
+ module RepoCompare
6
+ # Create a diff summary
7
+ class Summary
8
+ def initialize(results)
9
+ @count = 0
10
+ @results = results || []
11
+ end
12
+
13
+ def to_xml
14
+ <<~SUMMARY
15
+ <?xml version="1.0" encoding="UTF-8"?>
16
+ <testsuite name="solidus_compare" tests="#{@count}" skipped="0" failures="#{@count}" errors="#{@count}" time="1" timestamp="#{DateTime.now.iso8601}">
17
+ #{testcases}</testsuite>
18
+ SUMMARY
19
+ end
20
+
21
+ private
22
+
23
+ def testcases
24
+ @results.map do |result|
25
+ result[:results].map do |paths, hash|
26
+ @count += 1
27
+ # result[:src]
28
+ name = paths.gsub(/\t/, ' - ')
29
+ file = paths.split("\t")[-1]
30
+ "<testcase name=\"#{name}\" file=\"#{file}\" time=\"0\"><failure>hash: #{hash}\nfile: #{paths}</failure></testcase>"
31
+ end.join("\n")
32
+ end.join("\n")
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RepoCompare
4
+ VERSION = '0.1.0'
5
+ end
metadata ADDED
@@ -0,0 +1,54 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: repo-compare
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Mattia Roccoberton
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-06-06 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Track changes of another repo.
14
+ email:
15
+ - mat@blocknot.es
16
+ executables:
17
+ - repo-compare
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - MIT-LICENSE
22
+ - README.md
23
+ - Rakefile
24
+ - bin/repo-compare
25
+ - lib/repo-compare/config.rb
26
+ - lib/repo-compare/git_diff.rb
27
+ - lib/repo-compare/git_diff_raw.rb
28
+ - lib/repo-compare/git_remote_update.rb
29
+ - lib/repo-compare/summary.rb
30
+ - lib/repo-compare/version.rb
31
+ homepage: https://github.com/blocknotes/repo-compare
32
+ licenses:
33
+ - MIT
34
+ metadata: {}
35
+ post_install_message:
36
+ rdoc_options: []
37
+ require_paths:
38
+ - lib
39
+ required_ruby_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ required_rubygems_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ requirements: []
50
+ rubygems_version: 3.1.4
51
+ signing_key:
52
+ specification_version: 4
53
+ summary: Repo Compare
54
+ test_files: []