debtective 0.2.2 → 0.2.3.1
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/bin/debtective +9 -0
- data/lib/debtective/build_todo.rb +67 -0
- data/lib/debtective/{end_of_statement.rb → find_end_of_statement.rb} +13 -12
- data/lib/debtective/find_todos.rb +41 -0
- data/lib/debtective/git_commit.rb +66 -0
- data/lib/debtective/output_todos.rb +62 -0
- data/lib/debtective/print_table.rb +87 -0
- data/lib/debtective/todo.rb +45 -13
- data/lib/debtective/todo_list.rb +30 -23
- data/lib/debtective/version.rb +1 -1
- data/lib/tasks/debtective/todo_list.rake +8 -37
- metadata +25 -9
- data/MIT-LICENSE +0 -20
- data/README.md +0 -53
- data/Rakefile +0 -12
- data/lib/debtective/file_todos.rb +0 -60
- data/lib/debtective/todo_list_counts.rb +0 -29
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5337f50843d65198958e3c2a2f63b1b618f69070ec5445203c2615cc548ce833
|
|
4
|
+
data.tar.gz: 128f58647d0da0046a99088fa1e7cd0c06c8fe0a557a8e1e3304e0f84a2644b3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 34e11cc316b6a64489873769db16d2125a61643c8f70abf602f399df51d033a2e57df267520ca46caf2b4186600f38b9c00b8cc23159d8729316c25dfafb81d5
|
|
7
|
+
data.tar.gz: 74a9440b99fb2b9d4888b19e64efa5c6de67742cdad82e8c89b706293074a902292b7826f0e5092ec31cbd45f863aa5ea14878b30c988d5922d14dd9acc47505
|
data/bin/debtective
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "debtective"
|
|
5
|
+
require "debtective/output_todos"
|
|
6
|
+
|
|
7
|
+
user_name = `git config user.name`.strip if ARGV.include?("--me")
|
|
8
|
+
quiet = ARGV.include?("--quiet")
|
|
9
|
+
Debtective::OutputTodos.new(user_name, quiet: quiet).call
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "pathname"
|
|
4
|
+
require "debtective/todo"
|
|
5
|
+
require "debtective/find_end_of_statement"
|
|
6
|
+
|
|
7
|
+
module Debtective
|
|
8
|
+
# Find the todos comments and their boundaries
|
|
9
|
+
class BuildTodo
|
|
10
|
+
BEFORE_LINE_TODO_REGEX = /^\s*#\sTODO:\s/
|
|
11
|
+
INLINE_TODO_REGEX = /\s*#\sTODO:\s/
|
|
12
|
+
COMMENT_REGEX = /\s*#/
|
|
13
|
+
|
|
14
|
+
# @param pathname [Pathname]
|
|
15
|
+
# @param index [Integer]
|
|
16
|
+
def initialize(pathname, index)
|
|
17
|
+
@pathname = pathname
|
|
18
|
+
@index = index
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @return [Debtective::Todo]
|
|
22
|
+
def call
|
|
23
|
+
Todo.new(
|
|
24
|
+
@pathname,
|
|
25
|
+
lines,
|
|
26
|
+
todo_boundaries,
|
|
27
|
+
statement_boundaries
|
|
28
|
+
)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
# @return [Array<String>]
|
|
34
|
+
def lines
|
|
35
|
+
@lines ||= @pathname.readlines
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @return [Range]
|
|
39
|
+
def todo_boundaries
|
|
40
|
+
@index..([@index, statement_boundaries.min - 1].max)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# range of the concerned code
|
|
44
|
+
# @return [Range]
|
|
45
|
+
def statement_boundaries
|
|
46
|
+
@statement_boundaries ||=
|
|
47
|
+
case lines[@index]
|
|
48
|
+
when BEFORE_LINE_TODO_REGEX
|
|
49
|
+
first_line_index = statement_start
|
|
50
|
+
last_line_index = FindEndOfStatement.new(lines, first_line_index).call
|
|
51
|
+
first_line_index..last_line_index
|
|
52
|
+
when INLINE_TODO_REGEX
|
|
53
|
+
@index..@index
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# start index of the concerned code (i.e. below the TODO comment)
|
|
58
|
+
# @return [Integer]
|
|
59
|
+
def statement_start
|
|
60
|
+
lines.index.with_index do |line, i|
|
|
61
|
+
i > @index &&
|
|
62
|
+
!line.strip.empty? &&
|
|
63
|
+
!line.match?(COMMENT_REGEX)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -5,19 +5,20 @@ require "debtective/stderr_helper"
|
|
|
5
5
|
module Debtective
|
|
6
6
|
# Find the index of the line ending a statement
|
|
7
7
|
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
8
|
+
# @example
|
|
9
|
+
# FindEndOfStatement.new(
|
|
10
|
+
# [
|
|
11
|
+
# "class User",
|
|
12
|
+
# " def example",
|
|
13
|
+
# " x + y",
|
|
14
|
+
# " end"
|
|
15
|
+
# "end"
|
|
16
|
+
# ],
|
|
17
|
+
# 1
|
|
18
|
+
# ).call
|
|
19
|
+
# => 3
|
|
19
20
|
#
|
|
20
|
-
class
|
|
21
|
+
class FindEndOfStatement
|
|
21
22
|
include StderrHelper
|
|
22
23
|
|
|
23
24
|
# @param lines [Array<String>] lines of code
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "pathname"
|
|
4
|
+
require "debtective/build_todo"
|
|
5
|
+
|
|
6
|
+
module Debtective
|
|
7
|
+
# Find and investigate todo comments and return a list of todos
|
|
8
|
+
class FindTodos
|
|
9
|
+
TODO_REGEX = /#\sTODO:/
|
|
10
|
+
|
|
11
|
+
# @param paths [Array<String>]
|
|
12
|
+
def initialize(paths)
|
|
13
|
+
@paths = paths
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @return [Array<Debtective::Todo>]
|
|
17
|
+
def call
|
|
18
|
+
ruby_pathnames.flat_map { pathname_todos(_1) }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
# @return [Array<Pathname>] only pathes to ruby files
|
|
24
|
+
def ruby_pathnames
|
|
25
|
+
@paths
|
|
26
|
+
.flat_map { Dir[_1] }
|
|
27
|
+
.map { Pathname(_1) }
|
|
28
|
+
.select { _1.file? && _1.extname == ".rb" }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# return todos in the pathname
|
|
32
|
+
# @return [Array<Debtective::Todo>]
|
|
33
|
+
def pathname_todos(pathname)
|
|
34
|
+
pathname.readlines.filter_map.with_index do |line, index|
|
|
35
|
+
next unless line.match?(TODO_REGEX)
|
|
36
|
+
|
|
37
|
+
Todo.build(pathname, index)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "git"
|
|
4
|
+
require "open3"
|
|
5
|
+
|
|
6
|
+
module Debtective
|
|
7
|
+
# find the commit that introduced a line of code
|
|
8
|
+
class GitCommit
|
|
9
|
+
Author = Struct.new(:email, :name)
|
|
10
|
+
Commit = Struct.new(:sha, :author, :time)
|
|
11
|
+
|
|
12
|
+
SPECIAL_CHARACTER_REGEX = /(?!\w|\s|#|:).+/
|
|
13
|
+
|
|
14
|
+
# @param pathname [Pathname] file path
|
|
15
|
+
# @param code [String] line of code
|
|
16
|
+
def initialize(pathname, code)
|
|
17
|
+
@pathname = pathname
|
|
18
|
+
@code = code
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @return [Debtective::GitCommit::Commit]
|
|
22
|
+
def call
|
|
23
|
+
Commit.new(sha, author, time)
|
|
24
|
+
rescue Git::GitExecuteError
|
|
25
|
+
author = Author.new(nil, nil)
|
|
26
|
+
Commit.new(nil, author, nil)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# @return [Debtective::GitCommit::Author]
|
|
30
|
+
def author
|
|
31
|
+
Author.new(commit.author.email, commit.author.name)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# @return [Time]
|
|
35
|
+
def time
|
|
36
|
+
commit.date
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# @return [Git::Base]
|
|
40
|
+
def git
|
|
41
|
+
Git.open(".")
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# @return [Git::Object::Commit]
|
|
45
|
+
def commit
|
|
46
|
+
git.gcommit(sha)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# commit sha
|
|
50
|
+
# @return [String]
|
|
51
|
+
def sha
|
|
52
|
+
@sha ||=
|
|
53
|
+
begin
|
|
54
|
+
cmd = "git log -S \"#{safe_code}\" #{@pathname}"
|
|
55
|
+
stdout, _stderr, _status = ::Open3.capture3(cmd)
|
|
56
|
+
stdout[/commit (\w{40})\n/, 1]
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# characters " and ` can break the git command
|
|
61
|
+
# @return [String]
|
|
62
|
+
def safe_code
|
|
63
|
+
@code.gsub(/"/, "\\\"").gsub("`", "\\\\`")
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "debtective/print_table"
|
|
5
|
+
require "pry"
|
|
6
|
+
|
|
7
|
+
module Debtective
|
|
8
|
+
# Generate todolist
|
|
9
|
+
class OutputTodos
|
|
10
|
+
FILE_PATH = "todos.json"
|
|
11
|
+
|
|
12
|
+
# @param user_name [String] git user email to filter
|
|
13
|
+
def initialize(user_name = nil, quiet: false)
|
|
14
|
+
@user_name = user_name
|
|
15
|
+
@quiet = quiet
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @return [void]
|
|
19
|
+
def call
|
|
20
|
+
@todo_list = log_table
|
|
21
|
+
@todo_list ||= Debtective::TodoList.new(Debtective.configuration&.paths || ["./**/*"])
|
|
22
|
+
filter_todo_list!
|
|
23
|
+
log_counts
|
|
24
|
+
update_json_file
|
|
25
|
+
puts FILE_PATH
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
# @return [void]
|
|
31
|
+
def log_table
|
|
32
|
+
return if @quiet
|
|
33
|
+
|
|
34
|
+
Debtective::PrintTable.new(@user_name).call
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# @return [void]
|
|
38
|
+
def filter_todo_list!
|
|
39
|
+
!@user_name.nil? && @todo_list.todos.select! { _1.commit.author.name == @user_name }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# @return [void]
|
|
43
|
+
def log_counts
|
|
44
|
+
@return if @quiet
|
|
45
|
+
|
|
46
|
+
puts "total: #{@todo_list.todos.count}"
|
|
47
|
+
puts "combined lines count: #{@todo_list.combined_count}"
|
|
48
|
+
puts "extended lines count: #{@todo_list.extended_count}"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# @return [void]
|
|
52
|
+
def update_json_file
|
|
53
|
+
File.open(FILE_PATH, "w") do |file|
|
|
54
|
+
file.puts(
|
|
55
|
+
JSON.pretty_generate(
|
|
56
|
+
@todo_list.todos.map(&:to_h)
|
|
57
|
+
)
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "debtective/todo_list"
|
|
4
|
+
|
|
5
|
+
module Debtective
|
|
6
|
+
# Print todos as a table in the stdout
|
|
7
|
+
class PrintTable
|
|
8
|
+
# @param user_name [String] git user email to filter
|
|
9
|
+
def initialize(user_name = nil)
|
|
10
|
+
@user_name = user_name
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# @return [Debtective::TodoList]
|
|
14
|
+
def call
|
|
15
|
+
log_table_headers
|
|
16
|
+
log_table_rows
|
|
17
|
+
todo_list
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
# @return [void]
|
|
23
|
+
def log_table_headers
|
|
24
|
+
puts separator
|
|
25
|
+
puts table_row("location", "author", "days", "size")
|
|
26
|
+
puts separator
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# @return [void]
|
|
30
|
+
def log_table_rows
|
|
31
|
+
trace.enable
|
|
32
|
+
todo_list.todos
|
|
33
|
+
trace.disable
|
|
34
|
+
puts separator
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# use a trace to log each todo as soon as it is found
|
|
38
|
+
# @return [Tracepoint]
|
|
39
|
+
def trace
|
|
40
|
+
TracePoint.new(:return) do |trace_point|
|
|
41
|
+
next unless trace_point.defined_class == Debtective::BuildTodo && trace_point.method_id == :call
|
|
42
|
+
|
|
43
|
+
todo = trace_point.return_value
|
|
44
|
+
log_todo(todo)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# if a user_name is given and is not the commit author
|
|
49
|
+
# the line is temporary and will be replaced by the next one
|
|
50
|
+
# @return [void]
|
|
51
|
+
def log_todo(todo)
|
|
52
|
+
row = table_row(
|
|
53
|
+
todo.location,
|
|
54
|
+
todo.commit.author.name || "?",
|
|
55
|
+
todo.days || "?",
|
|
56
|
+
todo.size
|
|
57
|
+
)
|
|
58
|
+
if @user_name.nil? || @user_name == todo.commit.author.name
|
|
59
|
+
puts row
|
|
60
|
+
else
|
|
61
|
+
print "#{row}\r"
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# @return [Debtective::Todo]
|
|
66
|
+
def todo_list
|
|
67
|
+
@todo_list ||= Debtective::TodoList.new(
|
|
68
|
+
Debtective.configuration&.paths || ["./**/*"]
|
|
69
|
+
)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# @return [String]
|
|
73
|
+
def table_row(location, author, days, size)
|
|
74
|
+
[
|
|
75
|
+
format("%-80.80s", location),
|
|
76
|
+
format("%-20.20s", author),
|
|
77
|
+
format("%-12.12s", days),
|
|
78
|
+
format("%-12.12s", size)
|
|
79
|
+
].join(" | ")
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# @return [String]
|
|
83
|
+
def separator
|
|
84
|
+
@separator ||= Array.new(table_row(nil, nil, nil, nil).size) { "-" }.join
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
data/lib/debtective/todo.rb
CHANGED
|
@@ -1,37 +1,69 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "debtective/
|
|
3
|
+
require "debtective/git_commit"
|
|
4
4
|
|
|
5
5
|
module Debtective
|
|
6
6
|
# Hold todo information
|
|
7
7
|
class Todo
|
|
8
|
-
|
|
8
|
+
class << self
|
|
9
|
+
# @return [Debtective::Todo]
|
|
10
|
+
def build(pathname, index)
|
|
11
|
+
BuildTodo.new(pathname, index).call
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
attr_accessor :pathname, :todo_boundaries, :statement_boundaries
|
|
9
16
|
|
|
10
17
|
# @param pathname [Pathname]
|
|
11
|
-
# @param
|
|
12
|
-
# @param
|
|
13
|
-
|
|
18
|
+
# @param lines [Array<String>]
|
|
19
|
+
# @param todo_boundaries [Range]
|
|
20
|
+
# @param statement_boundaries [Range]
|
|
21
|
+
def initialize(pathname, lines, todo_boundaries, statement_boundaries)
|
|
14
22
|
@pathname = pathname
|
|
15
|
-
@
|
|
16
|
-
@
|
|
23
|
+
@lines = lines
|
|
24
|
+
@todo_boundaries = todo_boundaries
|
|
25
|
+
@statement_boundaries = statement_boundaries
|
|
17
26
|
end
|
|
18
27
|
|
|
19
28
|
# location in the codebase
|
|
20
29
|
# @return [String]
|
|
21
30
|
def location
|
|
22
|
-
"#{pathname}:#{
|
|
31
|
+
"#{@pathname}:#{@todo_boundaries.min + 1}"
|
|
23
32
|
end
|
|
24
33
|
|
|
25
34
|
# size of the todo code
|
|
26
35
|
# @return [Integer]
|
|
27
36
|
def size
|
|
28
|
-
|
|
37
|
+
@statement_boundaries.size
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# return commit that introduced the todo
|
|
41
|
+
# @return [Git::Object::Commit]
|
|
42
|
+
def commit
|
|
43
|
+
@commit ||= Debtective::GitCommit.new(@pathname, @lines[@todo_boundaries.min]).call
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @return [Integer]
|
|
47
|
+
def days
|
|
48
|
+
return if commit.time.nil?
|
|
49
|
+
|
|
50
|
+
((Time.now - commit.time) / (24 * 60 * 60)).round
|
|
29
51
|
end
|
|
30
52
|
|
|
31
|
-
#
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
53
|
+
# @return [Hash]
|
|
54
|
+
def to_h
|
|
55
|
+
{
|
|
56
|
+
pathname: pathname,
|
|
57
|
+
location: location,
|
|
58
|
+
todo_boundaries: todo_boundaries.minmax,
|
|
59
|
+
statement_boundaries: statement_boundaries.minmax,
|
|
60
|
+
size: size,
|
|
61
|
+
commit: {
|
|
62
|
+
sha: commit.sha,
|
|
63
|
+
author: commit.author.to_h,
|
|
64
|
+
time: commit.time
|
|
65
|
+
}
|
|
66
|
+
}
|
|
35
67
|
end
|
|
36
68
|
end
|
|
37
69
|
end
|
data/lib/debtective/todo_list.rb
CHANGED
|
@@ -1,37 +1,33 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "debtective/
|
|
3
|
+
require "debtective/find_todos"
|
|
4
4
|
|
|
5
5
|
module Debtective
|
|
6
|
-
#
|
|
6
|
+
# Information about the todos in the codebase
|
|
7
7
|
class TodoList
|
|
8
|
-
|
|
8
|
+
Author = Struct.new(:email, :name, :todos)
|
|
9
9
|
|
|
10
|
-
# @
|
|
11
|
-
def
|
|
12
|
-
|
|
13
|
-
.flat_map { FileTodos.new(_1).call }
|
|
10
|
+
# @param paths [Array<String>]
|
|
11
|
+
def initialize(paths)
|
|
12
|
+
@paths = paths
|
|
14
13
|
end
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def paths
|
|
20
|
-
Debtective.configuration&.paths || DEFAULT_PATHS
|
|
15
|
+
# @return [Array<Debtective::Todo>]
|
|
16
|
+
def todos
|
|
17
|
+
@todos ||= Debtective::FindTodos.new(@paths).call
|
|
21
18
|
end
|
|
22
19
|
|
|
23
|
-
# @return [Array<
|
|
24
|
-
def
|
|
25
|
-
|
|
26
|
-
.
|
|
27
|
-
.
|
|
28
|
-
.
|
|
20
|
+
# @return [Array<TodoList::Author>]
|
|
21
|
+
def authors
|
|
22
|
+
todos
|
|
23
|
+
.map { [_1.commit.author.email, _1.commit.author.name] }
|
|
24
|
+
.uniq
|
|
25
|
+
.map { author(_1) }
|
|
29
26
|
end
|
|
30
27
|
|
|
31
28
|
# @return [Integer]
|
|
32
29
|
def extended_count
|
|
33
|
-
todos
|
|
34
|
-
.sum { _1.boundaries.size }
|
|
30
|
+
todos.sum(&:size)
|
|
35
31
|
end
|
|
36
32
|
|
|
37
33
|
# @return [Integer]
|
|
@@ -39,12 +35,23 @@ module Debtective
|
|
|
39
35
|
todos
|
|
40
36
|
.group_by(&:pathname)
|
|
41
37
|
.values
|
|
42
|
-
.sum do |
|
|
43
|
-
|
|
44
|
-
.map { _1.
|
|
38
|
+
.sum do |pathname_todos|
|
|
39
|
+
pathname_todos
|
|
40
|
+
.map { _1.statement_boundaries.to_a }
|
|
45
41
|
.reduce(:|)
|
|
46
42
|
.length
|
|
47
43
|
end
|
|
48
44
|
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
# @param email_and_name [Array<String>]
|
|
49
|
+
# @return [TodoList::Author]
|
|
50
|
+
def author(email_and_name)
|
|
51
|
+
Author.new(
|
|
52
|
+
*email_and_name,
|
|
53
|
+
todos.select { email_and_name == [_1.commit.author.email, _1.commit.author.name] }
|
|
54
|
+
)
|
|
55
|
+
end
|
|
49
56
|
end
|
|
50
57
|
end
|
data/lib/debtective/version.rb
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "debtective/
|
|
4
|
-
require "debtective/todo_list_counts"
|
|
3
|
+
require "debtective/output_todos"
|
|
5
4
|
|
|
6
5
|
begin
|
|
7
6
|
require "#{Rails.root}/config/initializers/debtective" if defined?(Rails)
|
|
@@ -12,40 +11,12 @@ end
|
|
|
12
11
|
namespace :debtective do
|
|
13
12
|
desc "Todo List"
|
|
14
13
|
task :todo_list do
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
separator = Array.new(array_row.call(nil, nil, nil).size) { "-" }.join
|
|
25
|
-
|
|
26
|
-
todo_list = Debtective::TodoList.new.call
|
|
27
|
-
todos = todo_list.sort_by { _1.boundaries.size }.reverse
|
|
28
|
-
todo_list_counts = Debtective::TodoListCounts.new(todos)
|
|
29
|
-
|
|
30
|
-
puts separator
|
|
31
|
-
puts "todo list"
|
|
32
|
-
puts separator
|
|
33
|
-
puts array_row.call("pathname", "line numbers", "lines count")
|
|
34
|
-
puts separator
|
|
35
|
-
todos.each { puts array_row.call(_1.location, _1.line_numbers, _1.size) }
|
|
36
|
-
|
|
37
|
-
puts separator
|
|
38
|
-
puts "todos count"
|
|
39
|
-
puts todos.count
|
|
40
|
-
|
|
41
|
-
puts separator
|
|
42
|
-
puts "combined lines count"
|
|
43
|
-
puts todo_list_counts.combined_count
|
|
44
|
-
|
|
45
|
-
puts separator
|
|
46
|
-
puts "extended lines count"
|
|
47
|
-
puts todo_list_counts.extended_count
|
|
48
|
-
|
|
49
|
-
puts separator
|
|
14
|
+
if ARGV.include?("--me")
|
|
15
|
+
user_name = `git config user.name`.strip
|
|
16
|
+
puts "Searching TODOs from #{user_name}..."
|
|
17
|
+
else
|
|
18
|
+
puts "Searching TODOs..."
|
|
19
|
+
end
|
|
20
|
+
Debtective::OutputTodos.new(user_name, quiet: ARGV.include?("--quiet")).call
|
|
50
21
|
end
|
|
51
22
|
end
|
metadata
CHANGED
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: debtective
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.3.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Edouard Piron
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2023-02-
|
|
11
|
+
date: 2023-02-16 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: git
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0'
|
|
13
27
|
- !ruby/object:Gem::Dependency
|
|
14
28
|
name: rake
|
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -97,22 +111,24 @@ dependencies:
|
|
|
97
111
|
description: Find TODOs and compute debt size
|
|
98
112
|
email:
|
|
99
113
|
- ed.piron@gmail.com
|
|
100
|
-
executables:
|
|
114
|
+
executables:
|
|
115
|
+
- debtective
|
|
101
116
|
extensions: []
|
|
102
117
|
extra_rdoc_files: []
|
|
103
118
|
files:
|
|
104
|
-
-
|
|
105
|
-
- README.md
|
|
106
|
-
- Rakefile
|
|
119
|
+
- bin/debtective
|
|
107
120
|
- lib/debtective.rb
|
|
121
|
+
- lib/debtective/build_todo.rb
|
|
108
122
|
- lib/debtective/configuration.rb
|
|
109
|
-
- lib/debtective/
|
|
110
|
-
- lib/debtective/
|
|
123
|
+
- lib/debtective/find_end_of_statement.rb
|
|
124
|
+
- lib/debtective/find_todos.rb
|
|
125
|
+
- lib/debtective/git_commit.rb
|
|
126
|
+
- lib/debtective/output_todos.rb
|
|
127
|
+
- lib/debtective/print_table.rb
|
|
111
128
|
- lib/debtective/railtie.rb
|
|
112
129
|
- lib/debtective/stderr_helper.rb
|
|
113
130
|
- lib/debtective/todo.rb
|
|
114
131
|
- lib/debtective/todo_list.rb
|
|
115
|
-
- lib/debtective/todo_list_counts.rb
|
|
116
132
|
- lib/debtective/version.rb
|
|
117
133
|
- lib/tasks/debtective/todo_list.rake
|
|
118
134
|
homepage: https://github.com/BigBigDoudou/debtective
|
data/MIT-LICENSE
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
Copyright 2021 Edouard Piron
|
|
2
|
-
|
|
3
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
-
a copy of this software and associated documentation files (the
|
|
5
|
-
"Software"), to deal in the Software without restriction, including
|
|
6
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
-
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
-
the following conditions:
|
|
10
|
-
|
|
11
|
-
The above copyright notice and this permission notice shall be
|
|
12
|
-
included in all copies or substantial portions of the Software.
|
|
13
|
-
|
|
14
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
# Debtective
|
|
2
|
-
|
|
3
|
-
Find todos in your codebase so you don't forget to pay off your debts! 💰
|
|
4
|
-
|
|
5
|
-
## Usage
|
|
6
|
-
|
|
7
|
-
Run the task with:
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
bundle exec rake debtective:todo_list
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
It outputs the todos positions with the concerned lines of code and some counts.
|
|
14
|
-
|
|
15
|
-
## Installation
|
|
16
|
-
|
|
17
|
-
Add this line to your application's Gemfile:
|
|
18
|
-
|
|
19
|
-
```ruby
|
|
20
|
-
group :development do
|
|
21
|
-
gem "debtective"
|
|
22
|
-
end
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
And then execute:
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
$ bundle
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
Or install it yourself as:
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
$ gem install debtective
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
Configure the paths that should be analyzed (all by default):
|
|
38
|
-
|
|
39
|
-
```ruby
|
|
40
|
-
# config/initializers/debtective.rb
|
|
41
|
-
|
|
42
|
-
Debtective.configure do |config|
|
|
43
|
-
config.paths = ["app/**/*", "lib/**/*"]
|
|
44
|
-
end
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## Contributing
|
|
48
|
-
|
|
49
|
-
This gem is still a work in progress. You can use GitHub issue to start a discussion.
|
|
50
|
-
|
|
51
|
-
## License
|
|
52
|
-
|
|
53
|
-
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "debtective/todo"
|
|
4
|
-
require "debtective/end_of_statement"
|
|
5
|
-
|
|
6
|
-
module Debtective
|
|
7
|
-
# Find the todos comments and their boundaries
|
|
8
|
-
class FileTodos
|
|
9
|
-
BEFORE_LINE_TODO_REGEX = /^\s*#\sTODO:\s/
|
|
10
|
-
INLINE_TODO_REGEX = /\s*#\sTODO:\s/
|
|
11
|
-
COMMENT_REGEX = /\s*#/
|
|
12
|
-
|
|
13
|
-
# @param pathname [Pathname]
|
|
14
|
-
def initialize(pathname)
|
|
15
|
-
@pathname = pathname
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
# @return [Array<FileTodos::Result>]
|
|
19
|
-
def call
|
|
20
|
-
lines.filter_map.with_index do |line, index|
|
|
21
|
-
boundaries = boundaries(line, index)
|
|
22
|
-
next if boundaries.nil?
|
|
23
|
-
|
|
24
|
-
Todo.new(@pathname, index, boundaries)
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
private
|
|
29
|
-
|
|
30
|
-
# return todo boundaries if there is a todo
|
|
31
|
-
# @param line [String]
|
|
32
|
-
# @param index [Integer]
|
|
33
|
-
# @return [Range, nil]
|
|
34
|
-
def boundaries(line, index)
|
|
35
|
-
case line
|
|
36
|
-
when BEFORE_LINE_TODO_REGEX
|
|
37
|
-
first_line_index = statement_first_line_index(index)
|
|
38
|
-
last_line_index = EndOfStatement.new(@lines, first_line_index).call
|
|
39
|
-
first_line_index..last_line_index
|
|
40
|
-
when INLINE_TODO_REGEX
|
|
41
|
-
index..index
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
# @return [Array<String>]
|
|
46
|
-
def lines
|
|
47
|
-
@lines ||= @pathname.readlines
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
# @param todo_index [Integer]
|
|
51
|
-
# @return [Integer]
|
|
52
|
-
def statement_first_line_index(todo_index)
|
|
53
|
-
@lines.index.with_index do |line, i|
|
|
54
|
-
i > todo_index &&
|
|
55
|
-
!line.strip.empty? &&
|
|
56
|
-
!line.match?(COMMENT_REGEX)
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
end
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Debtective
|
|
4
|
-
# Apply calculations on a todo list
|
|
5
|
-
class TodoListCounts
|
|
6
|
-
# @param todo_list [Array<Debtective::Todo>]
|
|
7
|
-
def initialize(todos)
|
|
8
|
-
@todos = todos
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
# @return [Integer]
|
|
12
|
-
def extended_count
|
|
13
|
-
@todos.sum(&:size)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
# @return [Integer]
|
|
17
|
-
def combined_count
|
|
18
|
-
@todos
|
|
19
|
-
.group_by(&:pathname)
|
|
20
|
-
.values
|
|
21
|
-
.sum do |pathname_todos|
|
|
22
|
-
pathname_todos
|
|
23
|
-
.map { _1.boundaries.to_a }
|
|
24
|
-
.reduce(:|)
|
|
25
|
-
.length
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|