git-recommend 0.1.0 → 0.2.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 +4 -4
- data/.gitignore +1 -0
- data/bin/git-recommend +1 -104
- data/bin/git-test +4 -0
- data/git-recommend.gemspec +2 -2
- data/lib/git_recommend.rb +101 -0
- data/lib/git_test.rb +57 -0
- data/lib/helper.rb +9 -0
- data/lib/{git/recommend/version.rb → version.rb} +1 -1
- metadata +8 -4
- data/lib/git/recommend.rb +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2b3bb536c881bc0b202f0abedb9a06375422634a
|
4
|
+
data.tar.gz: 605d94d353fb38ff29e1d4a05fd732ad82b1a1e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 055b3a5cc3a1013ce5d493429f7c97883e4b3424a5d987393f219858fc756350b788fde6296c5059bf04a86b8ff15869ce8f5283ace77ae24499d647c987b707
|
7
|
+
data.tar.gz: 253345f3bfe244c11be6ca1449334c226f9a4ecfe7e7715da5ad8b26f133917bebeed87cfadf85ba97764c37ff956e2068159caa29e8f88b63b842099ac61dac
|
data/.gitignore
CHANGED
data/bin/git-recommend
CHANGED
@@ -1,108 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require 'evoc'
|
4
|
-
require 'vcs2json'
|
5
|
-
require 'highline'
|
6
|
-
|
7
|
-
class GitRecommend < Thor
|
8
|
-
|
9
|
-
DEFAULT_HISTORY = '.history'
|
10
|
-
@@in_git_repo = File.exist?('.git')
|
11
|
-
|
12
|
-
default_task :change
|
13
|
-
# history options
|
14
|
-
method_option :number, :aliases => '-n', type: :numeric, default: 10000, :desc => "The number of commits to dump"
|
15
|
-
# recommendation options
|
16
|
-
method_option :query, aliases: '-q', type: :array, required: false, desc: "Space separated list of query items"
|
17
|
-
method_option :query_from_file, aliases: '-f', type: :string, required: false, desc: "File with new-line separated list of query items"
|
18
|
-
method_option :staged, aliases: '-s', type: :boolean, required: false, desc: "Use staged files to generate recommendation"
|
19
|
-
method_option :unstaged, aliases: '-u', type: :boolean, required: false, desc: "Use unstaged files to generate recommendation"
|
20
|
-
method_option :history, :aliases => '-h', :type => :string, default: DEFAULT_HISTORY, :desc => "Path to change-history"
|
21
|
-
method_option :algorithm, :default => 'tarmaq0', :desc => "Which algorithm to use"
|
22
|
-
method_option :aggregator, :default => 'cg', :desc => "Which aggregator to use"
|
23
|
-
method_option :measures, aliases: '-m', type: :array, default: ['support','confidence'], desc: "Order rules on the given measures, presedence from left to right"
|
24
|
-
method_option :max_size, type: :numeric, default: 30, desc: "The maximum size of commits that should be considered when looking for patterns"
|
25
|
-
method_option :model_size, type: :numeric, default: 0, desc: "How many previous commits to consider when looking for patterns"
|
26
|
-
desc "change", ""
|
27
|
-
def change
|
28
|
-
# Initialize query
|
29
|
-
q = []
|
30
|
-
staged = (@@in_git_repo ? `git diff --cached --name-only`.split("\n") : [])
|
31
|
-
unstaged = (@@in_git_repo ? `git diff --name-only`.split("\n") : [])
|
32
|
-
from_command_line = (options[:query].nil? ? [] : options[:query])
|
33
|
-
from_file = if options[:query_from_file].nil?
|
34
|
-
[]
|
35
|
-
else
|
36
|
-
if File.exist?(options[:query_from_file])
|
37
|
-
File.read(options[:query_from_file]).split("\n")
|
38
|
-
else
|
39
|
-
$stderr.puts "No file found at #{options[:query_from_file]}"
|
40
|
-
[]
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
# default to locally changed files
|
45
|
-
if [:staged,:unstaged,:query,:query_from_file].all? {|k| options[k].nil?}
|
46
|
-
if @@in_git_repo
|
47
|
-
q = (staged | unstaged)
|
48
|
-
$stderr.puts "[default] Change recommendation based on the currently changed files\n"
|
49
|
-
end
|
50
|
-
else
|
51
|
-
staged = (options[:staged].nil? ? [] : staged)
|
52
|
-
unstaged = (options[:staged].nil? ? [] : unstaged)
|
53
|
-
q = (staged | unstaged | from_command_line | from_file)
|
54
|
-
end
|
55
|
-
|
56
|
-
# Initialize history
|
57
|
-
if !File.exists?(options[:history])
|
58
|
-
exit unless HighLine.new.agree("To recommend changes, a history cache needs to be generated, do you want to generate the default cache now? Run 'git recommend help update' for more options.")
|
59
|
-
GitRecommend.start(["update"])
|
60
|
-
end
|
61
|
-
# could do some validation here
|
62
|
-
h = Evoc::HistoryStore.initialize(path: options[:history])
|
63
|
-
if q.size > 0
|
64
|
-
$stderr.puts "Generating change recommendation for #{q.size} items"
|
65
|
-
q_tx = Evoc::Tx.new(id: 'query',date: Time.now, items: q)
|
66
|
-
h.base_history << q_tx
|
67
|
-
|
68
|
-
s = Evoc::Scenario.new({query: q_tx.items,
|
69
|
-
tx_index: q_tx.index,
|
70
|
-
tx_id: q_tx.id,
|
71
|
-
model_size: options[:model_size],
|
72
|
-
algorithm: options[:algorithm],
|
73
|
-
aggregator: options[:aggregator],
|
74
|
-
max_size: options[:max_size],
|
75
|
-
measures: options[:measures]})
|
76
|
-
s.call
|
77
|
-
s.print
|
78
|
-
else
|
79
|
-
$stderr.puts "No changed files detected. Change some files or run with --help for more options."
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
method_option :after, :aliases => '-a', :desc => "Only include commits after this date"
|
84
|
-
method_option :before, :aliases => '-b', :desc => "Only include commits before this date"
|
85
|
-
method_option :number, :aliases => '-n', type: :numeric, default: 10000, :desc => "The number of commits to dump"
|
86
|
-
method_option :fine_grained, type: :boolean, default: true, desc: "Include fine grained change information in output"
|
87
|
-
method_option :ignore_comments, type: :boolean, default: false, desc: "Ignore comments when calculating diffs. Only in effect for fine grained changes."
|
88
|
-
method_option :ignore_whitespace, type: :boolean, default: false, desc: "Ignore whitespace when calculating diffs. Only in effect for fine grained changes."
|
89
|
-
method_option :residuals, type: :boolean, default: true, desc: "Consider changes that happen outside of methods"
|
90
|
-
desc "update", "Update/Create the history used for generating recommendations"
|
91
|
-
def update
|
92
|
-
if @@in_git_repo
|
93
|
-
if File.exists?(DEFAULT_HISTORY)
|
94
|
-
exit unless HighLine.new.agree("History already exists, do you want to replace it?")
|
95
|
-
end
|
96
|
-
$stderr.puts "Generating new history cache to #{DEFAULT_HISTORY}, this may take a while."
|
97
|
-
old_stdout = $stdout # backup old stdout
|
98
|
-
$stdout.reopen(DEFAULT_HISTORY, 'w') # redirect stdout to file
|
99
|
-
Vcs2Json::Git.new(options).parse # write history
|
100
|
-
$stdout = STDOUT # restore stdout
|
101
|
-
else
|
102
|
-
$stderr.puts "Need to be in a git repository to generate history cache."
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
2
|
+
require_relative '../lib/helper.rb'
|
106
3
|
|
107
4
|
GitRecommend.start(ARGV)
|
108
5
|
|
data/bin/git-test
ADDED
data/git-recommend.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
lib = File.expand_path('../lib', __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
|
4
|
+
require_relative 'lib/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "git-recommend"
|
@@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
|
|
14
14
|
|
15
15
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
16
16
|
spec.bindir = "bin"
|
17
|
-
spec.executables = ["git-recommend"]
|
17
|
+
spec.executables = ["git-recommend","git-test"]
|
18
18
|
spec.require_paths = ["lib"]
|
19
19
|
|
20
20
|
spec.add_runtime_dependency "thor"
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class GitRecommend < Thor
|
4
|
+
|
5
|
+
DEFAULT_HISTORY = '.history'
|
6
|
+
@@in_git_repo = File.exist?('.git')
|
7
|
+
|
8
|
+
default_task :change
|
9
|
+
# history options
|
10
|
+
method_option :number, :aliases => '-n', type: :numeric, default: 10000, :desc => "The number of commits to dump"
|
11
|
+
# recommendation options
|
12
|
+
method_option :query, aliases: '-q', type: :array, required: false, desc: "Space separated list of query items"
|
13
|
+
method_option :query_from_file, aliases: '-f', type: :string, required: false, desc: "File with new-line separated list of query items"
|
14
|
+
method_option :staged, aliases: '-s', type: :boolean, required: false, desc: "Use staged files to generate recommendation"
|
15
|
+
method_option :unstaged, aliases: '-u', type: :boolean, required: false, desc: "Use unstaged files to generate recommendation"
|
16
|
+
method_option :history, :aliases => '-h', :type => :string, default: DEFAULT_HISTORY, :desc => "Path to change-history"
|
17
|
+
method_option :algorithm, :default => 'tarmaq0', :desc => "Which algorithm to use"
|
18
|
+
method_option :aggregator, :default => 'cg', :desc => "Which aggregator to use"
|
19
|
+
method_option :measures, aliases: '-m', type: :array, default: ['support','confidence'], desc: "Order rules on the given measures, presedence from left to right"
|
20
|
+
method_option :max_size, type: :numeric, default: 30, desc: "The maximum size of commits that should be considered when looking for patterns"
|
21
|
+
method_option :model_size, type: :numeric, default: 0, desc: "How many previous commits to consider when looking for patterns"
|
22
|
+
desc "change", ""
|
23
|
+
def change
|
24
|
+
# Initialize query
|
25
|
+
q = []
|
26
|
+
staged = (@@in_git_repo ? `git diff --cached --name-only`.split("\n") : [])
|
27
|
+
unstaged = (@@in_git_repo ? `git diff --name-only`.split("\n") : [])
|
28
|
+
from_command_line = (options[:query].nil? ? [] : options[:query])
|
29
|
+
from_file = if options[:query_from_file].nil?
|
30
|
+
[]
|
31
|
+
else
|
32
|
+
if File.exist?(options[:query_from_file])
|
33
|
+
File.read(options[:query_from_file]).split("\n")
|
34
|
+
else
|
35
|
+
$stderr.puts "No file found at #{options[:query_from_file]}"
|
36
|
+
[]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# default to locally changed files
|
41
|
+
if [:staged,:unstaged,:query,:query_from_file].all? {|k| options[k].nil?}
|
42
|
+
if @@in_git_repo
|
43
|
+
q = (staged | unstaged)
|
44
|
+
$stderr.puts "[default] Change recommendation based on the currently changed files\n"
|
45
|
+
end
|
46
|
+
else
|
47
|
+
staged = (options[:staged].nil? ? [] : staged)
|
48
|
+
unstaged = (options[:staged].nil? ? [] : unstaged)
|
49
|
+
q = (staged | unstaged | from_command_line | from_file)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Initialize history
|
53
|
+
if !File.exists?(options[:history])
|
54
|
+
exit unless HighLine.new.agree("To recommend changes, a history cache needs to be generated, do you want to generate the default cache now? Run 'git recommend help update' for more options.")
|
55
|
+
GitRecommend.start(["update"])
|
56
|
+
end
|
57
|
+
# could do some validation here
|
58
|
+
h = Evoc::HistoryStore.initialize(path: options[:history])
|
59
|
+
if q.size > 0
|
60
|
+
$stderr.puts "Generating change recommendation for #{q.size} items"
|
61
|
+
q_tx = Evoc::Tx.new(id: 'query',date: Time.now, items: q)
|
62
|
+
h.base_history << q_tx
|
63
|
+
|
64
|
+
s = Evoc::Scenario.new({query: q_tx.items,
|
65
|
+
tx_index: q_tx.index,
|
66
|
+
tx_id: q_tx.id,
|
67
|
+
model_size: options[:model_size],
|
68
|
+
algorithm: options[:algorithm],
|
69
|
+
aggregator: options[:aggregator],
|
70
|
+
max_size: options[:max_size],
|
71
|
+
measures: options[:measures]})
|
72
|
+
s.call
|
73
|
+
s.print
|
74
|
+
else
|
75
|
+
$stderr.puts "No changed files detected. Change some files or run with --help for more options."
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
method_option :after, :aliases => '-a', :desc => "Only include commits after this date"
|
80
|
+
method_option :before, :aliases => '-b', :desc => "Only include commits before this date"
|
81
|
+
method_option :number, :aliases => '-n', type: :numeric, default: 10000, :desc => "The number of commits to dump"
|
82
|
+
method_option :fine_grained, type: :boolean, default: true, desc: "Include fine grained change information in output"
|
83
|
+
method_option :ignore_comments, type: :boolean, default: false, desc: "Ignore comments when calculating diffs. Only in effect for fine grained changes."
|
84
|
+
method_option :ignore_whitespace, type: :boolean, default: false, desc: "Ignore whitespace when calculating diffs. Only in effect for fine grained changes."
|
85
|
+
method_option :residuals, type: :boolean, default: true, desc: "Consider changes that happen outside of methods"
|
86
|
+
desc "update", "Update/Create the history used for generating recommendations"
|
87
|
+
def update
|
88
|
+
if @@in_git_repo
|
89
|
+
if File.exists?(DEFAULT_HISTORY)
|
90
|
+
exit unless HighLine.new.agree("History already exists, do you want to replace it?")
|
91
|
+
end
|
92
|
+
$stderr.puts "Generating new history cache to #{DEFAULT_HISTORY}, this may take a while."
|
93
|
+
old_stdout = $stdout # backup old stdout
|
94
|
+
$stdout.reopen(DEFAULT_HISTORY, 'w') # redirect stdout to file
|
95
|
+
Vcs2Json::Git.new(options).parse # write history
|
96
|
+
$stdout = STDOUT # restore stdout
|
97
|
+
else
|
98
|
+
$stderr.puts "Need to be in a git repository to generate history cache."
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
data/lib/git_test.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class GitTest < Thor
|
4
|
+
default_task :test
|
5
|
+
|
6
|
+
method_option :mapping, aliases: '-m', type: :string, required: true, desc: "Path to test<->code mapping file"
|
7
|
+
method_option :change_recommendation, aliases: '-c', type: :string, required: true ,desc: "Path to change recommendation"
|
8
|
+
method_option :output, aliases: '-o', enum: ['csv','dot'], default: 'csv', desc: "The output format of the test recommendation"
|
9
|
+
desc "test", ""
|
10
|
+
def test
|
11
|
+
begin
|
12
|
+
mapping = CSV.read(options[:mapping], headers: true)
|
13
|
+
change_rec = CSV.read(options[:change_recommendation], headers: true)
|
14
|
+
rescue CSV::MalformedCSVError => e
|
15
|
+
$stderr.puts "An error occured when parsing the mapping file:\n #{e}"
|
16
|
+
end
|
17
|
+
|
18
|
+
test_plan = Hash.new
|
19
|
+
covered = Set.new
|
20
|
+
uniq_impacted_items = change_rec.map {|row| row["rhs"]}.to_set
|
21
|
+
|
22
|
+
change_rec.each do |row|
|
23
|
+
lhs = row["lhs"]
|
24
|
+
rhs = row["rhs"]
|
25
|
+
support = row["support"].to_r.to_f
|
26
|
+
mapping.each do |mapping_row|
|
27
|
+
pattern = Regexp.new(mapping_row["pattern"], Regexp::IGNORECASE)
|
28
|
+
test = mapping_row["test"]
|
29
|
+
if rhs =~ pattern
|
30
|
+
covered << rhs
|
31
|
+
if test_plan[test].nil?
|
32
|
+
test_plan[test] = {impact: support, covers: 1}
|
33
|
+
else
|
34
|
+
test_plan[test][:impact] += support
|
35
|
+
test_plan[test][:covers] += 1
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
# print warnings to stderr if any
|
41
|
+
if covered.size < uniq_impacted_items.size
|
42
|
+
uncovered = uniq_impacted_items - covered
|
43
|
+
if uncovered.size < 11
|
44
|
+
$stderr.puts "The following potentially impacted items were not covered by at least 1 test:\n #{uncovered.to_a.join("\n")}"
|
45
|
+
else
|
46
|
+
$stderr.puts "#{uncovered.size} potentially impacted items were not covered by at least 1 test. The first 10 were: \n #{uncovered.take(10).join("\n")}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# print testplan to stdout
|
51
|
+
$stdout.puts "test,impact,covers"
|
52
|
+
test_plan.sort_by {|k,v| -v[:impact]}.each do |test,relevance|
|
53
|
+
$stdout.puts "#{test},#{relevance[:impact]},#{relevance[:covers]}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
data/lib/helper.rb
ADDED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: git-recommend
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thomas Rolfsnes
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-12-
|
11
|
+
date: 2016-12-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -113,6 +113,7 @@ email:
|
|
113
113
|
- mail@thomasrolfsnes.com
|
114
114
|
executables:
|
115
115
|
- git-recommend
|
116
|
+
- git-test
|
116
117
|
extensions: []
|
117
118
|
extra_rdoc_files: []
|
118
119
|
files:
|
@@ -126,10 +127,13 @@ files:
|
|
126
127
|
- Rakefile
|
127
128
|
- bin/console
|
128
129
|
- bin/git-recommend
|
130
|
+
- bin/git-test
|
129
131
|
- bin/setup
|
130
132
|
- git-recommend.gemspec
|
131
|
-
- lib/
|
132
|
-
- lib/
|
133
|
+
- lib/git_recommend.rb
|
134
|
+
- lib/git_test.rb
|
135
|
+
- lib/helper.rb
|
136
|
+
- lib/version.rb
|
133
137
|
homepage:
|
134
138
|
licenses:
|
135
139
|
- MIT
|