hotspots 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +10 -1
- data/LICENSE +1 -1
- data/README.md +7 -15
- data/TODO.md +0 -2
- data/bin/hotspots +9 -3
- data/lib/hotspots/configuration.rb +36 -0
- data/lib/hotspots/{option_based_exit.rb → exit.rb} +4 -4
- data/lib/hotspots/options_parser.rb +21 -39
- data/lib/hotspots/repository/git.rb +17 -0
- data/lib/hotspots/repository/git_command.rb +38 -0
- data/lib/hotspots/repository/git_driver.rb +35 -0
- data/lib/hotspots/repository/git_parser.rb +25 -0
- data/lib/hotspots/repository.rb +5 -3
- data/lib/hotspots/store.rb +2 -2
- data/lib/hotspots/version.rb +1 -1
- data/lib/hotspots.rb +32 -53
- data/test/hotspots/configuration_test.rb +65 -0
- data/test/hotspots/options_parser_test.rb +91 -119
- data/test/hotspots/repository/git_command_test.rb +39 -0
- data/test/hotspots/repository/git_parser_test.rb +88 -0
- data/test/hotspots/store_test.rb +13 -13
- data/test/minitest_helper.rb +8 -5
- metadata +57 -73
- data/lib/hotspots/compatibility.rb +0 -4
- data/lib/hotspots/logger.rb +0 -58
- data/lib/hotspots/repository/command/git.rb +0 -40
- data/lib/hotspots/repository/command.rb +0 -1
- data/lib/hotspots/repository/driver/git.rb +0 -27
- data/lib/hotspots/repository/driver.rb +0 -1
- data/lib/hotspots/repository/parser/git.rb +0 -27
- data/lib/hotspots/repository/parser.rb +0 -1
- data/test/hotspots/repository/command/git_test.rb +0 -39
- data/test/hotspots/repository/parser/git_test.rb +0 -84
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7f43a6b0f28f054b6f4b3799ccabb18ebe2327f6709c325c4c7a2c07f16d0c8d
|
4
|
+
data.tar.gz: c165186a7d68e49e3bd6a3507d30f22ade3513d7f1182ba0f7b9eabcdc6739b0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 589499e787b881d179b267e3d2ff468db0af16b5d7aef558cd4799807288474d8cef5e1c3c4a2998cbd568d27681ace4cb8c409f3ca607d290a80136737b7d6f
|
7
|
+
data.tar.gz: 742faf60cca8d31eeda8e42e66f13d7a6d771bd75fd61cbc8820834a5423f1d12b15367da64ccc00084314d50c6c27a59f4d54a9b1f987fb45bc0c23b911eb68
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
v1.2.0
|
2
|
+
-------
|
3
|
+
|
4
|
+
* Use ruby's built-in logger instead of a custom one.
|
5
|
+
* Introduce the concept of Configuration. Configurations have defaults and are overridden by command-line options.
|
6
|
+
* Remove compatibility layers.
|
7
|
+
* Always enable colour for verbose output.
|
8
|
+
* Minimum supported version of ruby is 3.0.0.
|
9
|
+
|
1
10
|
v1.1.0
|
2
11
|
------
|
3
12
|
|
@@ -23,7 +32,7 @@ v0.2.0
|
|
23
32
|
v0.1.1
|
24
33
|
------
|
25
34
|
|
26
|
-
* Sort for an array of array via spaceship operator returns different result on each run on ruby 1.8.7. Store has a string representation breaks intermittently on 1.8.7. Tests fail intermittently on 1.8.7. So support for ruby 1.9.x only
|
35
|
+
* Sort for an array of array via spaceship operator returns different result on each run on ruby 1.8.7. Store has a string representation that breaks intermittently on 1.8.7. Tests fail intermittently on 1.8.7. So support for ruby 1.9.x only
|
27
36
|
* Simplify Rakefile
|
28
37
|
* Pull out a minitest_helper
|
29
38
|
* Allow gem to be used as a library
|
data/LICENSE
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright (c) 2011-
|
1
|
+
Copyright (c) 2011-2024 Chirantan Mitra
|
2
2
|
|
3
3
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
4
|
|
data/README.md
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
|
2
|
-
[![
|
1
|
+
![Build Status](https://github.com/chiku/r0man/actions/workflows/build.yml/badge.svg)
|
2
|
+
[![Gem Version](https://badge.fury.io/rb/hotspots.svg)](http://badge.fury.io/rb/hotspots)
|
3
3
|
|
4
4
|
Overview
|
5
5
|
--------
|
6
6
|
|
7
|
-
This program helps in identifying files with maximum churn in a git repository. The more the number of changes made to a file, the more likelyhood of the file being a source of
|
7
|
+
This program helps in identifying files with maximum churn in a git repository. The more the number of changes made to a file, the more likelyhood of the file being a source of bugs. If the same file is modified many times for bug fixes, it indicates that the file needs some refactoring or redesign love.
|
8
8
|
|
9
9
|
|
10
10
|
Dependencies
|
@@ -30,11 +30,12 @@ Specific options:
|
|
30
30
|
-r, --repository [PATH] Path to the repository to scan. Defaults to current path
|
31
31
|
-f, --file-filter [REGEX] Regular expression to filtering file names. All files are allowed when not specified
|
32
32
|
-m, --message-filter [PIPE SEPARATED] Pipe separated values to filter files names against each commit message.
|
33
|
-
All
|
33
|
+
All commit messages are allowed when not specified
|
34
34
|
-c, --cutoff [CUTOFF] The minimum occurrence to consider for a file to appear in the list. Defaults to zero
|
35
|
+
--log [LOG LEVEL] Log level (debug, info, warn, error, fatal)
|
35
36
|
-v, --verbose Show verbose output
|
36
|
-
-C, --colour, --color Show
|
37
|
-
--version Show version
|
37
|
+
-C, --colour, --color Show output in colours. The log level should be info or debug for colours
|
38
|
+
--version Show version
|
38
39
|
-h, --help Show this message
|
39
40
|
```
|
40
41
|
|
@@ -65,15 +66,6 @@ gem install simplecov
|
|
65
66
|
rake
|
66
67
|
```
|
67
68
|
|
68
|
-
Contributing
|
69
|
-
------------
|
70
|
-
|
71
|
-
* Fork the project.
|
72
|
-
* Make your feature addition or bug fix.
|
73
|
-
* Add tests for it. This is important so I don't break it in a future version unintentionally.
|
74
|
-
* Commit, but do not mess with the VERSION. If you want to have your own version, that is fine but bump the version in a commit by itself in another branch so I can ignore it when I pull.
|
75
|
-
* Send me a pull request.
|
76
|
-
|
77
69
|
License
|
78
70
|
-------
|
79
71
|
|
data/TODO.md
CHANGED
@@ -1,5 +1,3 @@
|
|
1
1
|
* Allow better use as a library - add documentation
|
2
|
-
* Use builtin logger instead of a custom one
|
3
2
|
* Reduce conditionals
|
4
|
-
* Split responsibilities of OptionsParser. It shouldn't be responsible for holding default options. It should just setting overrides.
|
5
3
|
* Group files based on their extensions
|
data/bin/hotspots
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
3
|
+
lib = File.expand_path(File.join("..", "..", "lib"), __FILE__)
|
4
|
+
$:.unshift lib unless $:.include?(lib)
|
4
5
|
|
5
|
-
|
6
|
+
require "logger"
|
7
|
+
require "hotspots"
|
6
8
|
|
7
|
-
Hotspots.new
|
9
|
+
default_configuration = Hotspots::Configuration.new
|
10
|
+
user_options = Hotspots::OptionsParser.new(:configuration => default_configuration)
|
11
|
+
overridden_configuration = user_options.parse(*ARGV)
|
12
|
+
|
13
|
+
Hotspots.new(overridden_configuration).output
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class Hotspots
|
2
|
+
class Configuration #:nodoc: all
|
3
|
+
attr_accessor :repository, :time, :message_filters, :file_filter, :cutoff
|
4
|
+
attr_accessor :logger
|
5
|
+
attr_accessor :exit_strategy
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
@repository = "."
|
9
|
+
@time = 15
|
10
|
+
@message_filters = [""]
|
11
|
+
@file_filter = ""
|
12
|
+
@cutoff = 0
|
13
|
+
@info_log_level = options[:info_log_level] || ::Logger::INFO
|
14
|
+
@error_log_level = options[:error_log_level] || ::Logger::ERROR
|
15
|
+
@logger = options[:logger] || default_logger
|
16
|
+
@exit_strategy = Exit::Noop.new
|
17
|
+
@logger.level = @error_log_level
|
18
|
+
end
|
19
|
+
|
20
|
+
def log_level
|
21
|
+
@logger.level
|
22
|
+
end
|
23
|
+
|
24
|
+
def enable_verbosity
|
25
|
+
@logger.level = @info_log_level
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def default_logger
|
31
|
+
::Logger.new(STDOUT).tap do |logger|
|
32
|
+
logger.formatter = proc { |severity, datetime, progname, msg| "#{datetime}: #{msg}\n" }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
class Hotspots
|
2
|
-
module
|
2
|
+
module Exit #:nodoc: all
|
3
3
|
class Error
|
4
4
|
attr_reader :code, :message
|
5
5
|
|
@@ -9,7 +9,7 @@ class Hotspots
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def perform
|
12
|
-
puts @message
|
12
|
+
$stderr.puts @message
|
13
13
|
exit @code
|
14
14
|
end
|
15
15
|
end
|
@@ -23,7 +23,7 @@ class Hotspots
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def perform
|
26
|
-
puts @message
|
26
|
+
$stdout.puts @message
|
27
27
|
exit @code
|
28
28
|
end
|
29
29
|
end
|
@@ -31,7 +31,7 @@ class Hotspots
|
|
31
31
|
class Noop
|
32
32
|
attr_reader :code, :message
|
33
33
|
|
34
|
-
def initialize
|
34
|
+
def initialize
|
35
35
|
@message = ""
|
36
36
|
@code = nil
|
37
37
|
end
|
@@ -1,37 +1,19 @@
|
|
1
|
-
require
|
2
|
-
|
3
|
-
require 'hotspots/version'
|
4
|
-
require 'hotspots/option_based_exit'
|
1
|
+
require "optparse"
|
5
2
|
|
6
3
|
class Hotspots
|
7
4
|
class OptionsParser #:nodoc: all
|
8
|
-
|
9
|
-
|
10
|
-
{
|
11
|
-
:time => 15,
|
12
|
-
:repository => ".",
|
13
|
-
:file_filter => "",
|
14
|
-
:message_filters => [""],
|
15
|
-
:cutoff => 0,
|
16
|
-
:verbose => false,
|
17
|
-
:exit_strategy => OptionBasedExit::Noop.new,
|
18
|
-
:colour => false,
|
19
|
-
}
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def initialize
|
24
|
-
@options = self.class.default_options
|
5
|
+
def initialize(opts)
|
6
|
+
@configuration = opts[:configuration].dup
|
25
7
|
end
|
26
8
|
|
27
9
|
def parse(*args)
|
28
10
|
parser = new_option_parser
|
29
11
|
begin
|
30
|
-
parser.parse
|
12
|
+
parser.parse(args)
|
31
13
|
rescue ::OptionParser::InvalidOption, ::OptionParser::InvalidArgument => ex
|
32
|
-
@
|
14
|
+
@configuration.exit_strategy = Exit::Error.new(:code => 1, :message => (ex.to_s + "\nUse -h for help\n"))
|
33
15
|
end
|
34
|
-
@
|
16
|
+
@configuration
|
35
17
|
end
|
36
18
|
|
37
19
|
private
|
@@ -47,7 +29,7 @@ class Hotspots
|
|
47
29
|
handle_message_filter_on(opts)
|
48
30
|
handle_cutoff_on(opts)
|
49
31
|
handle_verbosity_on(opts)
|
50
|
-
|
32
|
+
handle_version_on(opts)
|
51
33
|
handle_help_on(opts)
|
52
34
|
end
|
53
35
|
end
|
@@ -62,7 +44,7 @@ class Hotspots
|
|
62
44
|
opts.separator "Version #{::Hotspots::VERSION}"
|
63
45
|
opts.separator "Copyright (C) 2011-2013 Chirantan Mitra"
|
64
46
|
opts.separator ""
|
65
|
-
opts.separator "Usage:
|
47
|
+
opts.separator "Usage: hotspots [options]"
|
66
48
|
opts.separator ""
|
67
49
|
opts.separator "Specific options:"
|
68
50
|
end
|
@@ -70,14 +52,14 @@ class Hotspots
|
|
70
52
|
def handle_time_on(opts)
|
71
53
|
opts.on("-t", "--time [TIME]", OptionParser::DecimalInteger,
|
72
54
|
"Time in days to scan the repository for. Defaults to fifteen") do |o|
|
73
|
-
@
|
55
|
+
@configuration.time = o.to_i
|
74
56
|
end
|
75
57
|
end
|
76
58
|
|
77
59
|
def handle_path_on(opts)
|
78
60
|
opts.on("-r", "--repository [PATH]", String,
|
79
61
|
"Path to the repository to scan. Defaults to current path") do |o|
|
80
|
-
@
|
62
|
+
@configuration.repository = o.to_s
|
81
63
|
end
|
82
64
|
end
|
83
65
|
|
@@ -85,43 +67,43 @@ class Hotspots
|
|
85
67
|
opts.on("-f", "--file-filter [REGEX]", String,
|
86
68
|
"Regular expression to filtering file names.",
|
87
69
|
"All files are allowed when not specified") do |o|
|
88
|
-
@
|
70
|
+
@configuration.file_filter = o.to_s
|
89
71
|
end
|
90
72
|
end
|
91
73
|
|
92
74
|
def handle_message_filter_on(opts)
|
93
75
|
opts.on("-m", "--message-filter [PIPE SEPARATED]", String,
|
94
76
|
"Pipe separated values to filter files names against each commit message.",
|
95
|
-
"All
|
96
|
-
@
|
77
|
+
"All commit messages are allowed when not specified") do |o|
|
78
|
+
@configuration.message_filters = o.to_s.split("|")
|
97
79
|
end
|
98
80
|
end
|
99
81
|
|
100
82
|
def handle_cutoff_on(opts)
|
101
83
|
opts.on("-c", "--cutoff [CUTOFF]", OptionParser::DecimalInteger,
|
102
|
-
"The minimum
|
103
|
-
@
|
84
|
+
"The minimum occurrence to consider for a file to appear in the list. Defaults to zero") do |o|
|
85
|
+
@configuration.cutoff = o.to_i
|
104
86
|
end
|
105
87
|
end
|
106
88
|
|
107
89
|
def handle_verbosity_on(opts)
|
108
90
|
opts.on("-v", "--verbose",
|
109
91
|
"Show verbose output") do
|
110
|
-
@
|
92
|
+
@configuration.enable_verbosity
|
111
93
|
end
|
112
94
|
end
|
113
95
|
|
114
|
-
def
|
115
|
-
opts.
|
116
|
-
|
117
|
-
@
|
96
|
+
def handle_version_on(opts)
|
97
|
+
opts.on_tail("--version",
|
98
|
+
"Show version") do
|
99
|
+
@configuration.exit_strategy = Exit::Safe.new(:message => "hotspots #{::Hotspots::VERSION}\n")
|
118
100
|
end
|
119
101
|
end
|
120
102
|
|
121
103
|
def handle_help_on(opts)
|
122
104
|
opts.on_tail("-h", "--help",
|
123
105
|
"Show this message") do
|
124
|
-
@
|
106
|
+
@configuration.exit_strategy = Exit::Safe.new(:message => opts.to_s)
|
125
107
|
end
|
126
108
|
end
|
127
109
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class Hotspots
|
2
|
+
module Repository #:nodoc: all
|
3
|
+
module GitCommand
|
4
|
+
class Log
|
5
|
+
def initialize(options)
|
6
|
+
@since_days = options[:since_days]
|
7
|
+
@message_filter = options[:message_filter].to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
"git log --pretty=\"%H\" #{since_clause}#{grep_clause}"
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def since_clause
|
17
|
+
"--since=\"#{@since_days} days ago\""
|
18
|
+
end
|
19
|
+
|
20
|
+
def grep_clause
|
21
|
+
@message_filter.empty? ? "" : " --grep \"#{@message_filter}\""
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Show
|
26
|
+
attr_reader :commit_hash
|
27
|
+
|
28
|
+
def initialize(options)
|
29
|
+
@commit_hash = options[:commit_hash]
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_s
|
33
|
+
"git show --oneline --name-only #{commit_hash}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "ansi/code"
|
2
|
+
require "open3"
|
3
|
+
|
4
|
+
class Hotspots
|
5
|
+
module Repository #:nodoc: all
|
6
|
+
class GitDriver
|
7
|
+
def initialize(options)
|
8
|
+
@logger = options[:logger]
|
9
|
+
end
|
10
|
+
|
11
|
+
def pretty_log(options)
|
12
|
+
execute GitCommand::Log.new(:since_days => options[:since_days], :message_filter => options[:message_filter]).to_s
|
13
|
+
end
|
14
|
+
|
15
|
+
def show_one_line_names(options)
|
16
|
+
execute GitCommand::Show.new(:commit_hash => options[:commit_hash]).to_s
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def execute(command)
|
22
|
+
@logger.info { ::ANSI::Code.blue("[input]\n#{command}") }
|
23
|
+
output = ""
|
24
|
+
Open3.popen3(command) do |stdin, stdout, stderr, wait_thr|
|
25
|
+
error = stderr.gets(nil)
|
26
|
+
output = stdout.gets(nil)
|
27
|
+
@logger.error { ::ANSI::Code.red("[error]\n#{error}") } if error
|
28
|
+
@logger.info { ::ANSI::Code.green("[output]\n#{output}") } if output
|
29
|
+
Exit::Error.new(:message => "Error encountered while running git", :code => 1).perform unless wait_thr.value.success?
|
30
|
+
end
|
31
|
+
output || ""
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class Hotspots
|
2
|
+
module Repository #:nodoc: all
|
3
|
+
class GitParser
|
4
|
+
attr_reader :driver, :time, :message_filters
|
5
|
+
|
6
|
+
def initialize(driver, options)
|
7
|
+
@driver = driver
|
8
|
+
@time = options[:time]
|
9
|
+
@message_filters = options[:message_filters]
|
10
|
+
end
|
11
|
+
|
12
|
+
def files
|
13
|
+
filtered_commit_hashes.reduce([]) do |acc, commit_hash|
|
14
|
+
acc + driver.show_one_line_names({:commit_hash => commit_hash}).lines.map(&:strip)[1..-1]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def filtered_commit_hashes
|
19
|
+
message_filters.reduce([]) do |acc, filter|
|
20
|
+
acc + driver.pretty_log({:since_days => time, :message_filter => filter}).lines.map(&:strip)
|
21
|
+
end.uniq
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/hotspots/repository.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require "hotspots/repository/git"
|
2
|
+
require "hotspots/repository/git_command"
|
3
|
+
require "hotspots/repository/git_command"
|
4
|
+
require "hotspots/repository/git_driver"
|
5
|
+
require "hotspots/repository/git_parser"
|
data/lib/hotspots/store.rb
CHANGED
@@ -7,7 +7,7 @@ class Hotspots
|
|
7
7
|
@filter = options[:file_filter] || ""
|
8
8
|
|
9
9
|
@lines.map { |line| line.strip }.
|
10
|
-
select{ |line|
|
10
|
+
select{ |line| !line.empty? && line =~ Regexp.new(@filter) }.
|
11
11
|
each { |line| @store[line] += 1 }
|
12
12
|
end
|
13
13
|
|
@@ -23,7 +23,7 @@ class Hotspots
|
|
23
23
|
private
|
24
24
|
|
25
25
|
def sorted_array
|
26
|
-
@sorted_array ||= @store.sort do |(
|
26
|
+
@sorted_array ||= @store.sort do |(_, value1), (_, value2)|
|
27
27
|
value2 <=> value1
|
28
28
|
end
|
29
29
|
end
|
data/lib/hotspots/version.rb
CHANGED
data/lib/hotspots.rb
CHANGED
@@ -1,82 +1,61 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
1
|
+
require "hotspots/version"
|
2
|
+
require "hotspots/exit"
|
3
|
+
require "hotspots/configuration"
|
4
|
+
require "hotspots/store"
|
5
|
+
require "hotspots/options_parser"
|
6
|
+
require "hotspots/repository"
|
7
7
|
|
8
8
|
class Hotspots
|
9
|
-
attr_reader :
|
10
|
-
:exit_strategy, :driver, :parser, :store,
|
11
|
-
:time, :message_filters, :file_filter, :cutoff
|
9
|
+
attr_reader :configuration
|
12
10
|
|
13
|
-
def initialize(
|
14
|
-
|
15
|
-
|
16
|
-
@logger = Hotspots::Logger.new
|
17
|
-
@repository = options[:repository]
|
18
|
-
@verbose = options[:verbose]
|
19
|
-
@colour = options[:colour]
|
20
|
-
@exit_strategy = options[:exit_strategy]
|
21
|
-
|
22
|
-
@time = options[:time]
|
23
|
-
@message_filters = options[:message_filters]
|
24
|
-
@file_filter = options[:file_filter]
|
25
|
-
@cutoff = options[:cutoff]
|
11
|
+
def initialize(configuration)
|
12
|
+
@configuration = configuration
|
26
13
|
end
|
27
14
|
|
28
15
|
def output
|
29
16
|
validate
|
30
|
-
|
31
|
-
|
17
|
+
inside_repository do
|
18
|
+
run
|
19
|
+
end
|
32
20
|
end
|
33
21
|
|
34
22
|
private
|
35
23
|
|
36
|
-
def validate
|
37
|
-
|
38
|
-
|
24
|
+
def validate
|
25
|
+
configuration.exit_strategy.perform
|
26
|
+
ensure_git_installed
|
27
|
+
ensure_git_repository
|
39
28
|
end
|
40
29
|
|
41
|
-
def
|
42
|
-
|
43
|
-
set_path
|
44
|
-
assign
|
30
|
+
def inside_repository
|
31
|
+
yield Dir.chdir(repository)
|
45
32
|
end
|
46
33
|
|
47
|
-
def run
|
34
|
+
def run
|
48
35
|
puts store.to_s
|
49
36
|
end
|
50
37
|
|
51
|
-
def
|
52
|
-
|
38
|
+
def ensure_git_installed
|
39
|
+
Exit::Error.new(:message => "git not installed or not present in PATH!", :code => 10).perform unless Repository::Git.installed?
|
53
40
|
end
|
54
41
|
|
55
|
-
def
|
56
|
-
|
57
|
-
unless $? == 0
|
58
|
-
puts "'#{repository}' doesn't seem to be a git repository!"
|
59
|
-
exit 10
|
60
|
-
end
|
42
|
+
def ensure_git_repository
|
43
|
+
Exit::Error.new(:message => "'#{@repository}' doesn't seem to be a git repository!", :code => 10).perform unless Repository::Git.inside_valid_repository?
|
61
44
|
end
|
62
45
|
|
63
|
-
def
|
64
|
-
|
65
|
-
|
66
|
-
end
|
46
|
+
def repository
|
47
|
+
configuration.repository
|
48
|
+
end
|
67
49
|
|
68
|
-
|
69
|
-
|
70
|
-
end
|
50
|
+
def store
|
51
|
+
Store.new(parser.files, :cutoff => configuration.cutoff, :file_filter => configuration.file_filter)
|
71
52
|
end
|
72
53
|
|
73
|
-
def
|
74
|
-
|
54
|
+
def parser
|
55
|
+
Repository::GitParser.new(driver, :time => configuration.time, :message_filters => configuration.message_filters)
|
75
56
|
end
|
76
57
|
|
77
|
-
def
|
78
|
-
|
79
|
-
@parser = Hotspots::Repository::Parser::Git.new driver, :time => time, :message_filters => message_filters
|
80
|
-
@store = Hotspots::Store.new parser.files, :cutoff => cutoff, :file_filter => file_filter
|
58
|
+
def driver
|
59
|
+
Repository::GitDriver.new(:logger => configuration.logger)
|
81
60
|
end
|
82
61
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), '..', 'minitest_helper')
|
2
|
+
|
3
|
+
class Hotspots
|
4
|
+
class StubLogger
|
5
|
+
attr_accessor :level
|
6
|
+
def initialize
|
7
|
+
@level = :uninitialized
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "Configuration" do
|
12
|
+
describe "#initialize" do
|
13
|
+
let(:stub_logger) { StubLogger.new }
|
14
|
+
let(:configuration) { Configuration.new(:logger => stub_logger, :info_log_level => :info_level, :error_log_level => :error_level) }
|
15
|
+
|
16
|
+
it "defaults repository to the current path" do
|
17
|
+
expect(configuration.repository).must_equal "."
|
18
|
+
end
|
19
|
+
|
20
|
+
it "defaults time to 15" do
|
21
|
+
expect(configuration.time).must_equal 15
|
22
|
+
end
|
23
|
+
|
24
|
+
it "defaults file filter to empty string" do
|
25
|
+
expect(configuration.file_filter).must_equal ""
|
26
|
+
end
|
27
|
+
|
28
|
+
it "defaults message filters to array with an empty string" do
|
29
|
+
expect(configuration.message_filters).must_equal [""]
|
30
|
+
end
|
31
|
+
|
32
|
+
it "defaults cutoff to 0" do
|
33
|
+
expect(configuration.cutoff).must_equal 0
|
34
|
+
end
|
35
|
+
|
36
|
+
it "set a logger" do
|
37
|
+
expect(configuration.logger).wont_be :nil?
|
38
|
+
end
|
39
|
+
|
40
|
+
it "defaults the logger level to error" do
|
41
|
+
expect(configuration.logger.level).must_equal :error_level
|
42
|
+
end
|
43
|
+
|
44
|
+
it "defaults exit code to nil" do
|
45
|
+
expect(configuration.exit_strategy.code).must_be :nil?
|
46
|
+
end
|
47
|
+
|
48
|
+
it "defaults exit message to empty string" do
|
49
|
+
expect(configuration.exit_strategy.message).must_equal ""
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "#initialize without default logger" do
|
54
|
+
let(:configuration) { Configuration.new }
|
55
|
+
|
56
|
+
it "set a logger" do
|
57
|
+
expect(configuration.logger).wont_be :nil?
|
58
|
+
end
|
59
|
+
|
60
|
+
it "defaults the logger level to error" do
|
61
|
+
expect(configuration.logger.level).must_equal ::Logger::ERROR
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|