git-recommend 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bd37e6d5a0899d26e9477ae487f378b70e823f00
4
- data.tar.gz: 2bf08d57c099aa33531424a8866f2a8506f78588
3
+ metadata.gz: 2b3bb536c881bc0b202f0abedb9a06375422634a
4
+ data.tar.gz: 605d94d353fb38ff29e1d4a05fd732ad82b1a1e2
5
5
  SHA512:
6
- metadata.gz: d73be1af4a07f28df93d165294d75b4a5099915b0b2145941beb43b137439006fd9429c2d8b147984f01a64599308ecaa003e00b813fd8d03be5d1dbcb4040da
7
- data.tar.gz: b927bed5b8af7e4c8e67504ad92cfe4a2b530cdcc72b603b4a2e890efb3e48727581768bf89e48f2ebe62a9fd7da189b1fd6cfdf57fb83cd059dfa5d880e20ad
6
+ metadata.gz: 055b3a5cc3a1013ce5d493429f7c97883e4b3424a5d987393f219858fc756350b788fde6296c5059bf04a86b8ff15869ce8f5283ace77ae24499d647c987b707
7
+ data.tar.gz: 253345f3bfe244c11be6ca1449334c226f9a4ecfe7e7715da5ad8b26f133917bebeed87cfadf85ba97764c37ff956e2068159caa29e8f88b63b842099ac61dac
data/.gitignore CHANGED
@@ -7,3 +7,4 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+ *~
data/bin/git-recommend CHANGED
@@ -1,108 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
- require 'thor'
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
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../lib/helper.rb'
3
+
4
+ GitTest.start(ARGV)
@@ -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
- require 'git/recommend/version'
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
@@ -0,0 +1,9 @@
1
+ require 'thor'
2
+ require 'evoc'
3
+ require 'vcs2json'
4
+ require 'highline'
5
+ require 'csv'
6
+ require 'set'
7
+
8
+ require 'git_recommend'
9
+ require 'git_test'
@@ -1,5 +1,5 @@
1
1
  module Git
2
2
  module Recommend
3
- VERSION = "0.1.0"
3
+ VERSION = "0.2.0"
4
4
  end
5
5
  end
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.1.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-14 00:00:00.000000000 Z
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/git/recommend.rb
132
- - lib/git/recommend/version.rb
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
data/lib/git/recommend.rb DELETED
@@ -1,7 +0,0 @@
1
- require "git/recommend/version"
2
-
3
- module Git
4
- module Recommend
5
- # Your code goes here...
6
- end
7
- end