hotspots 0.1.1 → 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.
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
+ v0.2.0
2
+ ------
3
+
4
+ * Use default options when invoked as a library
5
+ * Restructure interfaces for Logger, ExitStrategy & Hotspots. The older classes, modules and methods are still available
6
+
1
7
  v0.1.1
2
- -------
8
+ ------
3
9
 
4
10
  * 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
5
11
  * Simplify Rakefile
data/README.md CHANGED
@@ -28,7 +28,7 @@ Specific options:
28
28
  -t, --time [TIME] Time in days to scan the repository for. Defaults to fifteen
29
29
  -r, --repository [PATH] Path to the repository to scan. Defaults to current path
30
30
  -f, --file-filter [REGEX] Regular expression to filtering file names. All files are allowed when not specified
31
- -m, --message-filter [PIPE SEPARATED] Values to filter files names against each commit message separated by pipe.
31
+ -m, --message-filter [PIPE SEPARATED] Pipe separated values to filter files names against each commit message.
32
32
  All files are allowed when not specified
33
33
  -c, --cutoff [CUTOFF] The minimum occurrence to consider for a file to appear in the list. Defaults to zero
34
34
  -v, --verbose Show verbose output
data/TODO.md CHANGED
@@ -1,4 +1,4 @@
1
1
  * Allow better use as a library - add documentation
2
- * Don't barf if not inside root directory of git
3
- * Hotspots#initialize validates presence of mandatory arguments - useful when used as library
2
+ * Reduce conditionals
4
3
  * Optional support for colors
4
+ * Remove compatibility layers in a major release
data/bin/hotspots CHANGED
@@ -2,4 +2,4 @@
2
2
 
3
3
  require 'hotspots'
4
4
 
5
- Hotspots::Main.new.execute!
5
+ Hotspots::Main.new.output
data/lib/hotspots.rb CHANGED
@@ -6,54 +6,73 @@ require 'hotspots/repository'
6
6
 
7
7
  module Hotspots
8
8
  class Main
9
- attr_reader :logger, :options, :repository, :verbose,
10
- :exit_strategy, :driver, :parser, :store
9
+ attr_reader :logger, :repository, :verbose,
10
+ :exit_strategy, :driver, :parser, :store,
11
+ :time, :message_filters, :file_filter, :cutoff
11
12
 
13
+ # TODO : change this signature - this method should get resolved options as parameters
14
+ # initialize is not responsible for invoking option parsing
12
15
  def initialize(opts = nil)
13
- @options = opts || Hotspots::OptionsParser.new.parse(*ARGV)
14
- @repository = options[:repository]
15
- @verbose = options[:verbose]
16
- @exit_strategy = options[:exit_strategy]
17
- @logger = Hotspots::Logger.new
16
+ options = opts.nil? ? Hotspots::OptionsParser.new.parse(*ARGV) : Hotspots::OptionsParser.default_options.merge(opts)
17
+
18
+ @logger = Hotspots::Logger.new
19
+ @repository = options[:repository]
20
+ @verbose = options[:verbose]
21
+ @exit_strategy = options[:exit_strategy]
22
+
23
+ @time = options[:time]
24
+ @message_filters = options[:message_filters]
25
+ @file_filter = options[:file_filter]
26
+ @cutoff = options[:cutoff]
18
27
  end
19
28
 
20
- def execute!
21
- validate!
29
+ def output
30
+ validate
22
31
  set
23
32
  run
24
33
  end
25
34
 
26
- def validate!
27
- validate_early_exit!
28
- validate_git_repository!
35
+ # TODO : this method should be private
36
+ def validate #:nodoc:
37
+ exit_if_options_are_for_help
38
+ exit_if_not_git_repository
29
39
  end
30
40
 
31
- def set
32
- set_logger
41
+ # TODO : this method should be private
42
+ def set #:nodoc:
43
+ set_logger_if_verbose
33
44
  set_path
34
45
  assign
35
46
  end
36
47
 
37
- def run
48
+ # TODO : this method should be private
49
+ def run #:nodoc:
38
50
  puts store.to_s
39
51
  end
40
52
 
53
+ # TODO : these methods should be private
54
+ # compatibility begin
55
+ alias_method :execute!, :output
56
+ alias_method :validate!, :validate
57
+ # compatibility end
58
+
41
59
  private
42
60
 
43
- def validate_early_exit!
61
+ def exit_if_options_are_for_help
44
62
  exit_strategy.perform
45
63
  end
46
64
 
47
- def validate_git_repository!
48
- if not File.directory?(repository) or not File.directory?(File.join(repository, '.git'))
65
+ def exit_if_not_git_repository
66
+ output = `git status 2>&1`
67
+ unless $? == 0
49
68
  puts "'#{repository}' doesn't seem to be a git repository!"
50
69
  exit 10
51
70
  end
52
71
  end
53
72
 
54
- def set_logger
73
+ def set_logger_if_verbose
55
74
  if verbose
56
- logger.set_console
75
+ logger.as_console
57
76
  end
58
77
  end
59
78
 
@@ -62,9 +81,9 @@ module Hotspots
62
81
  end
63
82
 
64
83
  def assign
65
- @driver = Hotspots::Repository::Driver::Git.new logger
66
- @parser = Hotspots::Repository::Parser::Git.new driver, options.clone
67
- @store = Hotspots::Store.new parser.files, options.clone
84
+ @driver = Hotspots::Repository::Driver::Git.new logger
85
+ @parser = Hotspots::Repository::Parser::Git.new driver, :time => time, :message_filters => message_filters
86
+ @store = Hotspots::Store.new parser.files, :cutoff => cutoff, :file_filter => file_filter
68
87
  end
69
88
  end
70
89
  end
@@ -1,41 +1,13 @@
1
+ # compatibility begin
1
2
  module Hotspots
2
- class ExitStrategy
3
- attr_reader :code, :message
4
-
5
- def initialize(options)
6
- @message = options[:message]
7
- @code = options[:code]
8
- end
9
-
10
- def perform
11
- puts @message
12
- exit @code
13
- end
14
-
15
- class Safe
16
- attr_reader :code, :message
17
-
18
- def initialize(options)
19
- @message = options[:message]
20
- @code = 0
21
- end
22
-
23
- def perform
24
- puts @message
25
- exit @code
26
- end
27
- end
28
-
29
- class Null
30
- attr_reader :code, :message
31
-
32
- def initialize(options = {})
33
- @message = ""
34
- @code = nil
35
- end
36
-
37
- def perform
38
- end
39
- end
3
+ module OptionBasedExit #:nodoc: all
4
+ class Error; end
5
+ class Safe; end
6
+ class Noop; end
7
+
8
+ ExitStrategy = Error
9
+ ExitStrategy::Safe = Safe
10
+ ExitStrategy::Null = Noop
40
11
  end
41
12
  end
13
+ # compatibility end
@@ -1,5 +1,5 @@
1
1
  module Hotspots
2
- class Logger
2
+ class Logger #:nodoc: all
3
3
  class Console
4
4
  def self.<<(message)
5
5
  $stdout << message
@@ -16,10 +16,14 @@ module Hotspots
16
16
  @sink = Null
17
17
  end
18
18
 
19
- def set_console
19
+ def as_console
20
20
  @sink = Console
21
21
  end
22
22
 
23
+ # compatibility begin
24
+ alias_method :set_console, :as_console
25
+ # compatibility end
26
+
23
27
  def log(message)
24
28
  @sink << format(message)
25
29
  end
@@ -0,0 +1,47 @@
1
+ module Hotspots
2
+ module OptionBasedExit #:nodoc: all
3
+ class Error
4
+ attr_reader :code, :message
5
+
6
+ def initialize(options)
7
+ @message = options[:message]
8
+ @code = options[:code]
9
+ end
10
+
11
+ def perform
12
+ puts @message
13
+ exit @code
14
+ end
15
+ end
16
+
17
+ class Safe
18
+ attr_reader :code, :message
19
+
20
+ def initialize(options)
21
+ @message = options[:message]
22
+ @code = 0
23
+ end
24
+
25
+ def perform
26
+ puts @message
27
+ exit @code
28
+ end
29
+ end
30
+
31
+ class Noop
32
+ attr_reader :code, :message
33
+
34
+ def initialize(options = {})
35
+ @message = ""
36
+ @code = nil
37
+ end
38
+
39
+ def perform
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ # compatibility begin
46
+ require 'hotspots/exit_strategy'
47
+ # compatibility end
@@ -1,20 +1,26 @@
1
1
  require 'optparse'
2
2
 
3
3
  require 'hotspots/version'
4
- require 'hotspots/exit_strategy'
4
+ require 'hotspots/option_based_exit'
5
5
 
6
6
  module Hotspots
7
- class OptionsParser
7
+ class OptionsParser #:nodoc: all
8
+ class << self
9
+ def default_options
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
+ }
19
+ end
20
+ end
21
+
8
22
  def initialize
9
- @options = {
10
- :time => 15,
11
- :repository => ".",
12
- :file_filter => "",
13
- :message_filters => [""],
14
- :cutoff => 0,
15
- :verbose => false,
16
- :exit_strategy => ExitStrategy::Null.new
17
- }
23
+ @options = self.class.default_options
18
24
  end
19
25
 
20
26
  def parse(*args)
@@ -22,7 +28,7 @@ module Hotspots
22
28
  begin
23
29
  parser.parse args
24
30
  rescue ::OptionParser::InvalidOption, ::OptionParser::InvalidArgument => ex
25
- @options[:exit_strategy] = ExitStrategy.new(:code => 1, :message => (ex.to_s << "\nUse -h for help\n"))
31
+ @options[:exit_strategy] = OptionBasedExit::Error.new(:code => 1, :message => (ex.to_s << "\nUse -h for help\n"))
26
32
  end
27
33
  @options
28
34
  end
@@ -83,7 +89,7 @@ module Hotspots
83
89
 
84
90
  def handle_message_filter_on(opts)
85
91
  opts.on("-m", "--message-filter [PIPE SEPARATED]", String,
86
- "Pipe separated values to filter files names against each commit message separated by pipe.",
92
+ "Pipe separated values to filter files names against each commit message.",
87
93
  "All files are allowed when not specified") do |o|
88
94
  @options[:message_filters] = o.to_s.split("|")
89
95
  end
@@ -106,7 +112,7 @@ module Hotspots
106
112
  def handle_help_on(opts)
107
113
  opts.on_tail("-h", "--help",
108
114
  "Show this message") do
109
- @options[:exit_strategy] = ExitStrategy::Safe.new(:message => opts.to_s)
115
+ @options[:exit_strategy] = OptionBasedExit::Safe.new(:message => opts.to_s)
110
116
  end
111
117
  end
112
118
  end
@@ -1,2 +1,3 @@
1
+ require 'hotspots/repository/command'
1
2
  require 'hotspots/repository/driver'
2
3
  require 'hotspots/repository/parser'
@@ -0,0 +1 @@
1
+ require 'hotspots/repository/command/git'
@@ -0,0 +1,40 @@
1
+ module Hotspots
2
+ module Repository #:nodoc: all
3
+ module Command
4
+ module Git
5
+ class Log
6
+ attr_reader :since_days, :message_filter
7
+
8
+ def initialize(options)
9
+ @since_days = options[:since_days]
10
+ @message_filter = options[:message_filter].to_s
11
+ end
12
+
13
+ def build
14
+ "git log --pretty=\"%H\" #{since_clause}#{grep_clause}"
15
+ end
16
+
17
+ def since_clause
18
+ "--since=\"#{since_days} days ago\""
19
+ end
20
+
21
+ def grep_clause
22
+ message_filter.empty? ? "" : " --grep \"#{message_filter}\""
23
+ end
24
+ end
25
+
26
+ class Show
27
+ attr_reader :commit_hash
28
+
29
+ def initialize(options)
30
+ @commit_hash = options[:commit_hash]
31
+ end
32
+
33
+ def build
34
+ "git show --oneline --name-only #{commit_hash}"
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,5 +1,5 @@
1
1
  module Hotspots
2
- module Repository
2
+ module Repository #:nodoc: all
3
3
  module Driver
4
4
  class Git
5
5
  attr_reader :logger
@@ -8,19 +8,20 @@ module Hotspots
8
8
  @logger = logger
9
9
  end
10
10
 
11
+ # Input and output should be optionally coloured
11
12
  def pretty_log(options)
12
- grep_clause = options[:message_filter].empty? ? "" : " --grep \"#{options[:message_filter]}\""
13
- command = %Q(git log --pretty="%H" --since="#{options[:since_days]} days ago" #{grep_clause}).
14
- tap {|raw| logger.log "<Input>\n#{raw}\n</Input>"}
15
- %x(#{command}).
16
- tap {|raw| logger.log "<Output>\n#{raw}\n</Output>"}
13
+ command = log_with_tag("Input") { Command::Git::Log.new(:since_days => options[:since_days], :message_filter => options[:message_filter]).build }
14
+ log_with_tag("Output") { %x(#{command}) }
17
15
  end
18
16
 
17
+ # Input and output should be optionally coloured
19
18
  def show_one_line_names(options)
20
- command = %Q(git show --oneline --name-only #{options[:commit_hash]}).
21
- tap {|raw| logger.log "<Input>\n#{raw}\n</Input>"}
22
- %x(#{command}).
23
- tap {|raw| logger.log "<Output>\n#{raw}\n</Output>"}
19
+ command = log_with_tag("Input") { Command::Git::Show.new(:commit_hash => options[:commit_hash]).build }
20
+ log_with_tag("Output") { %x(#{command}) }
21
+ end
22
+
23
+ def log_with_tag(tag, &block)
24
+ yield.tap { |raw| logger.log "<#{tag}>\n#{raw}<#{tag}/>" }
24
25
  end
25
26
  end
26
27
  end
@@ -1,25 +1,29 @@
1
1
  module Hotspots
2
- module Repository
2
+ module Repository #:nodoc: all
3
3
  module Parser
4
4
  class Git
5
+ attr_reader :driver, :time, :message_filters
6
+
5
7
  def initialize(driver, options)
6
8
  @driver = driver
7
9
  @time = options[:time]
8
10
  @message_filters = options[:message_filters]
9
11
  end
10
12
 
13
+ # TODO : replace with each_line
11
14
  def files
12
15
  filtered_commit_hashes.map do |commit_hash|
13
- @driver.show_one_line_names(:commit_hash => commit_hash).
16
+ driver.show_one_line_names(:commit_hash => commit_hash).
14
17
  gsub("\r\n", "\n").
15
18
  gsub("\r", "\n").
16
19
  split("\n")[1..-1]
17
20
  end.flatten
18
21
  end
19
22
 
23
+ # TODO : replace with each_line
20
24
  def filtered_commit_hashes
21
- @message_filters.map do |filter|
22
- @driver.pretty_log(:since_days => @time, :message_filter => filter).
25
+ message_filters.map do |filter|
26
+ driver.pretty_log(:since_days => time, :message_filter => filter).
23
27
  gsub("\r\n", "\n").
24
28
  gsub("\r", "\n").
25
29
  split("\n")
@@ -1,5 +1,5 @@
1
1
  module Hotspots
2
- class Store
2
+ class Store #:nodoc: all
3
3
  def initialize(lines, options = {})
4
4
  @lines = lines
5
5
  @store = Hash.new(0)
@@ -1,3 +1,3 @@
1
1
  module Hotspots
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -1,6 +1,3 @@
1
- require File.join(File.expand_path(File.dirname(__FILE__)), '..', '..', 'lib', 'hotspots', 'exit_strategy')
2
- require File.join(File.expand_path(File.dirname(__FILE__)), '..', '..', 'lib', 'hotspots', 'options_parser')
3
-
4
1
  require File.join(File.expand_path(File.dirname(__FILE__)), '..', 'minitest_helper')
5
2
 
6
3
  module Hotspots
@@ -123,7 +120,7 @@ module Hotspots
123
120
  end
124
121
  end
125
122
 
126
- describe "on a invalid option" do
123
+ describe "on an invalid option" do
127
124
  before do
128
125
  @options = @parser.parse("--invalid-option")
129
126
  end
@@ -137,7 +134,7 @@ module Hotspots
137
134
  end
138
135
  end
139
136
 
140
- describe "on a invalid argument" do
137
+ describe "on an invalid argument" do
141
138
  before do
142
139
  @options = @parser.parse("--repo", "")
143
140
  end
@@ -0,0 +1,39 @@
1
+ require File.join(File.expand_path(File.dirname(__FILE__)), '..', '..', '..', 'minitest_helper')
2
+
3
+ module Hotspots::Repository
4
+ describe "Command::Git" do
5
+ describe "Log" do
6
+ describe "#build" do
7
+ describe "when message filter exists" do
8
+ it "includes a grep clause" do
9
+ log_command = Command::Git::Log.new :since_days => 20, :message_filter => "Foo|Bar"
10
+ log_command.build.must_equal 'git log --pretty="%H" --since="20 days ago" --grep "Foo|Bar"'
11
+ end
12
+ end
13
+
14
+ describe "when message filter doesn't exist" do
15
+ it "doesn't have a grep clause" do
16
+ log_command = Command::Git::Log.new :since_days => 20
17
+ log_command.build.must_equal 'git log --pretty="%H" --since="20 days ago"'
18
+ end
19
+ end
20
+
21
+ describe "when message filter is set to an empty string" do
22
+ it "grep clause is ignored" do
23
+ log_command = Command::Git::Log.new :since_days => 20, :message_filter => ""
24
+ log_command.build.must_equal 'git log --pretty="%H" --since="20 days ago"'
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ describe "Show" do
31
+ describe "#build" do
32
+ it "constructs a git show with one-line format" do
33
+ show_command = Command::Git::Show.new :commit_hash => "abc123"
34
+ show_command.build.must_equal 'git show --oneline --name-only abc123'
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -1,5 +1,3 @@
1
- require File.join(File.expand_path(File.dirname(__FILE__)), '..', '..', '..', '..', 'lib', 'hotspots', 'repository', 'parser', 'git')
2
-
3
1
  require File.join(File.expand_path(File.dirname(__FILE__)), '..', '..', '..', 'minitest_helper')
4
2
 
5
3
  module Hotspots::Repository
@@ -1,5 +1,3 @@
1
- require File.join(File.expand_path(File.dirname(__FILE__)), '..', '..', 'lib', 'hotspots', 'store')
2
-
3
1
  require File.join(File.expand_path(File.dirname(__FILE__)), '..', 'minitest_helper')
4
2
 
5
3
  module Hotspots
@@ -1,10 +1,15 @@
1
- begin
2
- require 'simplecov'
3
- SimpleCov.start do
4
- add_filter "/test/"
1
+ lib = File.expand_path('../../lib/', __FILE__)
2
+ $:.unshift lib unless $:.include?(lib)
3
+
4
+ if ENV["coverage"] == "true"
5
+ begin
6
+ require 'simplecov'
7
+ SimpleCov.start do
8
+ add_filter "/test/"
9
+ end
10
+ rescue LoadError
11
+ puts "\nPlease install simplecov to generate coverage report!\n\n"
5
12
  end
6
- rescue LoadError
7
- puts "\nPlease install simplecov to generate coverage report!\n\n"
8
13
  end
9
14
 
10
15
  # eager load all files
@@ -12,6 +17,7 @@ Dir["lib/**/*.rb"].each do |file|
12
17
  require File.expand_path(file)
13
18
  end
14
19
 
20
+ require_relative "../lib/hotspots"
15
21
 
16
22
  require 'minitest/autorun'
17
23
  require 'minitest/spec'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hotspots
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-22 00:00:00.000000000 Z
12
+ date: 2012-12-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -77,7 +77,10 @@ extra_rdoc_files: []
77
77
  files:
78
78
  - lib/hotspots/exit_strategy.rb
79
79
  - lib/hotspots/logger.rb
80
+ - lib/hotspots/option_based_exit.rb
80
81
  - lib/hotspots/options_parser.rb
82
+ - lib/hotspots/repository/command/git.rb
83
+ - lib/hotspots/repository/command.rb
81
84
  - lib/hotspots/repository/driver/git.rb
82
85
  - lib/hotspots/repository/driver.rb
83
86
  - lib/hotspots/repository/parser/git.rb
@@ -88,6 +91,7 @@ files:
88
91
  - lib/hotspots.rb
89
92
  - bin/hotspots
90
93
  - test/hotspots/options_parser_test.rb
94
+ - test/hotspots/repository/command/git_test.rb
91
95
  - test/hotspots/repository/parser/git_test.rb
92
96
  - test/hotspots/store_test.rb
93
97
  - test/minitest_helper.rb
@@ -107,12 +111,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
107
111
  - - ! '>='
108
112
  - !ruby/object:Gem::Version
109
113
  version: '0'
114
+ segments:
115
+ - 0
116
+ hash: 1394833690291643919
110
117
  required_rubygems_version: !ruby/object:Gem::Requirement
111
118
  none: false
112
119
  requirements:
113
120
  - - ! '>='
114
121
  - !ruby/object:Gem::Version
115
122
  version: '0'
123
+ segments:
124
+ - 0
125
+ hash: 1394833690291643919
116
126
  requirements: []
117
127
  rubyforge_project: hotspots
118
128
  rubygems_version: 1.8.24
@@ -121,6 +131,7 @@ specification_version: 3
121
131
  summary: Find all files that changed over the past in a git repository based on conditions
122
132
  test_files:
123
133
  - test/hotspots/options_parser_test.rb
134
+ - test/hotspots/repository/command/git_test.rb
124
135
  - test/hotspots/repository/parser/git_test.rb
125
136
  - test/hotspots/store_test.rb
126
137
  - test/minitest_helper.rb