todidnt 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+ ruby '1.9.3'
3
+
4
+ group 'test' do
5
+ gem 'minitest'
6
+ gem 'mocha'
7
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,16 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ metaclass (0.0.1)
5
+ minitest (5.0.8)
6
+ mocha (0.14.0)
7
+ metaclass (~> 0.0.1)
8
+ trollop (2.0)
9
+
10
+ PLATFORMS
11
+ ruby
12
+
13
+ DEPENDENCIES
14
+ minitest
15
+ mocha
16
+ trollop
data/README ADDED
@@ -0,0 +1,9 @@
1
+ TODO:
2
+
3
+ - tests
4
+ - actual logging that is not putsing
5
+ - optimize blames
6
+ - html report?
7
+ - filter by person or time
8
+ - handle FIXME/XXX/custom
9
+ - stats
data/bin/todidnt ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+
5
+ require_relative '../lib/todidnt'
6
+
7
+ options = {:path => '.'}
8
+ ARGV.options do |opts|
9
+ opts.on('-p', '--path PATH', 'Git directory to run Todidnt in (default: current directory)') do |path|
10
+ options[:path] = path
11
+ end
12
+
13
+ opts.on_tail('-h', '--help', 'Show this message') do
14
+ puts opts
15
+ exit
16
+ end
17
+
18
+ opts.parse!
19
+ end
20
+
21
+ Todidnt::Runner.start(options)
@@ -0,0 +1,26 @@
1
+ module Todidnt
2
+ class GitCommand
3
+ def initialize(command, options)
4
+ @command = command
5
+ @options = options
6
+ end
7
+
8
+ def output_lines
9
+ run!.strip.split(/\n/)
10
+ end
11
+
12
+ def run!
13
+ `git #{command_with_options}`
14
+ end
15
+
16
+ def command_with_options
17
+ full_command = @command.to_s
18
+
19
+ for option in @options
20
+ full_command << " #{option.join(' ')}"
21
+ end
22
+
23
+ full_command
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,24 @@
1
+ module Todidnt
2
+ class GitRepo
3
+ def initialize(path)
4
+ expanded_path = File.expand_path(path)
5
+
6
+ if File.exist?(File.join(expanded_path, '.git'))
7
+ @working_dir = expanded_path
8
+ else
9
+ $stderr.puts "Whoops, #{expanded_path} is not a git repository!"
10
+ exit
11
+ end
12
+ end
13
+
14
+ def run(&blk)
15
+ unless Dir.pwd == @working_dir
16
+ Dir.chdir(@working_dir) do
17
+ yield @working_dir
18
+ end
19
+ else
20
+ yield
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,52 @@
1
+ module Todidnt
2
+ class TodoLine
3
+ IGNORE = %r{assets/js|third_?party|node_modules|jquery|Binary}
4
+
5
+ attr_reader :filename, :line_number, :content, :author
6
+
7
+ def self.all(expressions)
8
+ options = [['-n']]
9
+ expressions.each { |e| options << ['-e', e] }
10
+
11
+ grep = GitCommand.new(:grep, options)
12
+ grep.output_lines.map do |line|
13
+ filename, line_number, content = line.split(/:/, 3)
14
+ unless filename =~ IGNORE
15
+ lines = self.new(filename, line_number.to_i, content.strip[0..100])
16
+ end
17
+ end.compact
18
+ end
19
+
20
+ def initialize(filename, line_number, content)
21
+ @filename = filename
22
+ @line_number = line_number
23
+ @content = content
24
+ end
25
+
26
+ # TODO: This logic should probably be moved out somewhere else
27
+ def populate_blame
28
+ options = [
29
+ ['--line-porcelain'],
30
+ ['-L', "#{@line_number},#{@line_number}"],
31
+ [@filename]
32
+ ]
33
+
34
+ blame = GitCommand.new(:blame, options)
35
+ blame.output_lines.each do |line|
36
+ if (author = /author (.*)/.match(line))
37
+ @author = author[1]
38
+ elsif (author_time = /author-time (.*)/.match(line))
39
+ @timestamp = author_time[1].to_i
40
+ end
41
+ end
42
+ end
43
+
44
+ def pretty_time
45
+ Time.at(@timestamp).strftime('%F')
46
+ end
47
+
48
+ def pretty
49
+ "#{pretty_time} (#{author}, #{filename}:#{line_number}): #{content}"
50
+ end
51
+ end
52
+ end
data/lib/todidnt.rb ADDED
@@ -0,0 +1,25 @@
1
+ require_relative 'todidnt/git_repo'
2
+ require_relative 'todidnt/git_command'
3
+ require_relative 'todidnt/todo_line'
4
+
5
+ module Todidnt
6
+ class Runner
7
+ def self.start(options)
8
+ GitRepo.new(options[:path]).run do |path|
9
+ puts "Running in #{path || 'current directory'}..."
10
+ lines = TodoLine.all(["TODO"])
11
+ puts "Found #{lines.count} TODOs. Blaming..."
12
+
13
+ lines.each_with_index do |todo, i|
14
+ todo.populate_blame
15
+ $stdout.write "\rBlamed: #{i}/#{lines.count}"
16
+ end
17
+
18
+ puts "\nResults:"
19
+ lines.each do |line|
20
+ puts line.pretty
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
data/test/lib.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'minitest/spec'
2
+ require 'minitest/autorun'
3
+ require 'mocha/setup'
4
+
5
+ require_relative '../lib/todidnt'
6
+
7
+ class Test < MiniTest::Spec
8
+ end
data/test/todo_line.rb ADDED
@@ -0,0 +1,86 @@
1
+ require_relative 'lib'
2
+
3
+ class TestTodoLine < Test
4
+ before do
5
+ GitCommand.any_instance.stubs(:run!)
6
+ end
7
+
8
+ describe '.all' do
9
+ describe 'unit' do
10
+ it 'constructs the correct `git grep` command' do
11
+ grep = mock()
12
+ grep.stubs(:output_lines => [])
13
+
14
+ GitCommand.expects(:new).with(:grep, [['-n'], ['-e', 'hello']]).returns(grep)
15
+ TodoLine.all(['hello'])
16
+
17
+ GitCommand.expects(:new).with(:grep, [['-n'], ['-e', 'hello'], ['-e', 'goodbye']]).returns(grep)
18
+ TodoLine.all(['hello', 'goodbye'])
19
+ end
20
+
21
+ it 'creates a TodoLine object for each result line properly' do
22
+ GitCommand.any_instance.expects(:output_lines).returns(
23
+ [
24
+ 'filename.rb:12: content',
25
+ 'other_filename.rb:643: TODO'
26
+ ]
27
+ )
28
+
29
+ TodoLine.expects(:new).with('filename.rb', 12, 'content')
30
+ TodoLine.expects(:new).with('other_filename.rb', 643, 'TODO')
31
+
32
+ TodoLine.all(['anything'])
33
+ end
34
+ end
35
+
36
+ describe 'functional' do
37
+ it 'returns a list of TodoLine objects as matches' do
38
+ GitCommand.any_instance.expects(:output_lines).returns(
39
+ [
40
+ 'filename.rb:12: content',
41
+ 'other_filename.rb:643: TODO'
42
+ ]
43
+ )
44
+
45
+ todos = TodoLine.all(['anything'])
46
+ assert_equal 2, todos.count
47
+
48
+ assert_equal 'filename.rb', todos.first.filename
49
+ assert_equal 12, todos.first.line_number
50
+ assert_equal 'content', todos.first.content
51
+
52
+ assert_equal 'other_filename.rb', todos.last.filename
53
+ assert_equal 643, todos.last.line_number
54
+ assert_equal 'TODO', todos.last.content
55
+ end
56
+
57
+ it 'ignores lines matching IGNORE list' do
58
+ GitCommand.any_instance.expects(:output_lines).returns(
59
+ [
60
+ 'filename.rb:12: content',
61
+ 'thirdparty/other_filename.rb:643: TODO'
62
+ ]
63
+ )
64
+
65
+ todos = TodoLine.all(['anything'])
66
+ assert_equal 1, todos.count
67
+
68
+ assert_equal 'filename.rb', todos.first.filename
69
+ assert_equal 12, todos.first.line_number
70
+ assert_equal 'content', todos.first.content
71
+ end
72
+ end
73
+ end
74
+
75
+ describe '#populate_blame' do
76
+ it 'constructs the correct `git blame` command' do
77
+ # TODO
78
+ skip
79
+ end
80
+
81
+ it 'sets author, timestamp properties on the TodoLine object' do
82
+ # TODO
83
+ skip
84
+ end
85
+ end
86
+ end
data/todidnt.gemspec ADDED
@@ -0,0 +1,16 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'todidnt'
3
+ s.version = '0.0.0'
4
+ s.summary = 'Todidnt'
5
+ s.description = "Todidnt finds and dates todos in your git repository."
6
+ s.authors = ["Amber Feng"]
7
+ s.email = 'amber.feng@gmail.com'
8
+
9
+ s.add_development_dependency('minitest')
10
+ s.add_development_dependency('mocha')
11
+
12
+ s.files = `git ls-files`.split("\n")
13
+ s.test_files = `git ls-files -- test/*`.split("\n")
14
+ s.executables = ['todidnt']
15
+ s.require_paths = %w[lib]
16
+ end
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: todidnt
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Amber Feng
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-11-07 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: minitest
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: mocha
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: Todidnt finds and dates todos in your git repository.
47
+ email: amber.feng@gmail.com
48
+ executables:
49
+ - todidnt
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - Gemfile
54
+ - Gemfile.lock
55
+ - README
56
+ - bin/todidnt
57
+ - lib/todidnt.rb
58
+ - lib/todidnt/git_command.rb
59
+ - lib/todidnt/git_repo.rb
60
+ - lib/todidnt/todo_line.rb
61
+ - test/lib.rb
62
+ - test/todo_line.rb
63
+ - todidnt.gemspec
64
+ homepage:
65
+ licenses: []
66
+ post_install_message:
67
+ rdoc_options: []
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ! '>='
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ requirements: []
83
+ rubyforge_project:
84
+ rubygems_version: 1.8.23
85
+ signing_key:
86
+ specification_version: 3
87
+ summary: Todidnt
88
+ test_files:
89
+ - test/lib.rb
90
+ - test/todo_line.rb