churn_vs_complexity 1.0.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -1
- data/README.md +6 -1
- data/lib/churn_vs_complexity/churn.rb +8 -10
- data/lib/churn_vs_complexity/cli.rb +23 -16
- data/lib/churn_vs_complexity/concurrent_calculator.rb +16 -6
- data/lib/churn_vs_complexity/config.rb +31 -6
- data/lib/churn_vs_complexity/engine.rb +6 -5
- data/lib/churn_vs_complexity/file_selector.rb +11 -3
- data/lib/churn_vs_complexity/git_date.rb +59 -0
- data/lib/churn_vs_complexity/serializer.rb +50 -7
- data/lib/churn_vs_complexity/version.rb +1 -1
- data/lib/churn_vs_complexity.rb +1 -0
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d748bfb7d21087a5fbcb360dbc05dcd46b5ec05bf2c2fcc542e2e25368084d78
|
4
|
+
data.tar.gz: 0d160c582aee2696823061dd7623cf17e9b537d798ae31502eb30b065a61391d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f521d39fddad8e8adf05ab0f21d8b8adcc2460f9a57c553b90c73eb60451aafed19ab11977768d494987ff72838c856dd04c3910781ec0da34f53d82d18d9d4e
|
7
|
+
data.tar.gz: 3ab17db013540128bd428edb54cf0615f47ce50caa19d1ad418261c20efde494bb36ea8e84408e0ca330f7721013a9e8958f3cd5a16565636186508e59bf7360
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
1
|
## [1.0.0] - 2024-06-07
|
2
2
|
|
3
|
-
- Initial release
|
3
|
+
- Initial release
|
4
|
+
|
5
|
+
## [1.1.0] - 2024-09-20
|
6
|
+
|
7
|
+
- Introduce `--summary` flag to output summary statistics for churn and complexity
|
8
|
+
- Introduce `--month`, `--quarter`, and `--year` short-hand flags to calculate churn for different time periods relative to the most recent commit
|
9
|
+
|
10
|
+
## [1.2.0] - 2024-09-20
|
11
|
+
|
12
|
+
- Fix bug in CLI where new flags and `--since` would not be recognized
|
13
|
+
- Improve selection of observations included in the output
|
14
|
+
- Fixed calculation of churn that would never be zero
|
data/README.md
CHANGED
@@ -31,13 +31,17 @@ In order to use the `--java` flag, you must first install PMD manually, and the
|
|
31
31
|
Execute the `churn_vs_complexity` with the applicable arguments. Output in the requested format will be directed to stdout.
|
32
32
|
|
33
33
|
```
|
34
|
-
churn_vs_complexity [options] folder
|
34
|
+
Usage: churn_vs_complexity [options] folder
|
35
35
|
--java Check complexity of java classes
|
36
36
|
--ruby Check complexity of ruby files
|
37
37
|
--csv Format output as CSV
|
38
38
|
--graph Format output as HTML page with Churn vs Complexity graph
|
39
|
+
--summary Output summary statistics (mean and median) for churn and complexity
|
39
40
|
--excluded PATTERN Exclude file paths including this string. Can be used multiple times.
|
40
41
|
--since YYYY-MM-DD Calculate churn after this date
|
42
|
+
-m, --month Calculate churn for the month leading up to the most recent commit
|
43
|
+
-q, --quarter Calculate churn for the quarter leading up to the most recent commit
|
44
|
+
-y, --year Calculate churn for the year leading up to the most recent commit
|
41
45
|
-h, --help Display help
|
42
46
|
```
|
43
47
|
|
@@ -47,6 +51,7 @@ churn_vs_complexity [options] folder
|
|
47
51
|
|
48
52
|
`churn_vs_complexity --java --graph --exclude generated-sources --exclude generated-test-sources --since 2023-01-01 my_java_project > ~/Desktop/java-demo.html`
|
49
53
|
|
54
|
+
`churn_vs_complexity --ruby --summary -m my_ruby_project >> ~/Desktop/monthly-report.txt`
|
50
55
|
|
51
56
|
|
52
57
|
## Development
|
@@ -7,20 +7,18 @@ module ChurnVsComplexity
|
|
7
7
|
module GitCalculator
|
8
8
|
class << self
|
9
9
|
def calculate(folder:, file:, since:)
|
10
|
-
|
11
|
-
|
10
|
+
git_dir = File.join(folder, '.git')
|
11
|
+
formatted_date = since.strftime('%Y-%m-%d')
|
12
|
+
cmd = %Q(git --git-dir #{git_dir} --work-tree #{folder} log --format="%H" --follow --since="#{formatted_date}" -- #{file} | wc -l)
|
13
|
+
`#{cmd}`.to_i
|
12
14
|
end
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
-
def calculate_with_follow(folder, file, since)
|
17
|
-
# Format the date as "YYYY-MM-DD"
|
18
|
-
formatted_date = since.strftime('%Y-%m-%d')
|
19
|
-
# git log --follow --oneline --since="YYYY-MM-DD" <file_path> | wc -l
|
20
|
-
`git --git-dir #{File.join(folder,
|
21
|
-
'.git',)} --work-tree #{folder} log --follow --oneline --since=#{formatted_date} #{file} | wc -l`.to_i
|
16
|
+
def date_of_latest_commit(folder:)
|
17
|
+
repo(folder).log.first.date
|
22
18
|
end
|
23
19
|
|
20
|
+
private
|
21
|
+
|
24
22
|
def repo(folder)
|
25
23
|
repos[folder] ||= Git.open(folder)
|
26
24
|
end
|
@@ -9,7 +9,6 @@ module ChurnVsComplexity
|
|
9
9
|
def self.run!
|
10
10
|
# Create an options hash to store parsed options
|
11
11
|
options = { excluded: [] }
|
12
|
-
since = nil
|
13
12
|
|
14
13
|
# Initialize OptionParser
|
15
14
|
OptionParser.new do |opts|
|
@@ -31,13 +30,34 @@ module ChurnVsComplexity
|
|
31
30
|
options[:serializer] = :graph
|
32
31
|
end
|
33
32
|
|
33
|
+
opts.on('--summary', 'Output summary statistics (mean and median) for churn and complexity') do
|
34
|
+
options[:serializer] = :summary
|
35
|
+
end
|
36
|
+
|
34
37
|
opts.on('--excluded PATTERN',
|
35
38
|
'Exclude file paths including this string. Can be used multiple times.',) do |value|
|
36
39
|
options[:excluded] << value
|
37
40
|
end
|
38
41
|
|
39
42
|
opts.on('--since YYYY-MM-DD', 'Calculate churn after this date') do |value|
|
40
|
-
since = value
|
43
|
+
options[:since] = value
|
44
|
+
end
|
45
|
+
|
46
|
+
opts.on('-m', '--month', 'Calculate churn for the month leading up to the most recent commit') do
|
47
|
+
options[:since] = :month
|
48
|
+
end
|
49
|
+
|
50
|
+
opts.on('-q', '--quarter', 'Calculate churn for the quarter leading up to the most recent commit') do
|
51
|
+
options[:since] = :quarter
|
52
|
+
end
|
53
|
+
|
54
|
+
opts.on('-y', '--year', 'Calculate churn for the year leading up to the most recent commit') do
|
55
|
+
options[:since] = :year
|
56
|
+
end
|
57
|
+
|
58
|
+
opts.on('--dry-run', 'Echo the chosen options from the CLI') do
|
59
|
+
puts options
|
60
|
+
exit
|
41
61
|
end
|
42
62
|
|
43
63
|
opts.on('-h', '--help', 'Display help') do
|
@@ -56,24 +76,11 @@ module ChurnVsComplexity
|
|
56
76
|
|
57
77
|
raise Error, 'No options selected. Use --help for usage information.' if options.empty?
|
58
78
|
|
59
|
-
begin
|
60
|
-
if since.nil?
|
61
|
-
since = Time.at(0).to_date
|
62
|
-
options[:graph_title] = 'Churn vs Complexity'
|
63
|
-
else
|
64
|
-
date_string = since
|
65
|
-
since = Date.strptime(since, '%Y-%m-%d')
|
66
|
-
options[:graph_title] = "Churn vs Complexity since #{date_string}"
|
67
|
-
end
|
68
|
-
rescue StandardError
|
69
|
-
raise Error, "Invalid date #{since}, please use correct format, YYYY-MM-DD"
|
70
|
-
end
|
71
|
-
|
72
79
|
config = Config.new(**options)
|
73
80
|
|
74
81
|
config.validate!
|
75
82
|
|
76
|
-
puts config.to_engine.check(folder
|
83
|
+
puts config.to_engine.check(folder:)
|
77
84
|
end
|
78
85
|
end
|
79
86
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'etc'
|
4
|
+
|
3
5
|
module ChurnVsComplexity
|
4
6
|
class ConcurrentCalculator
|
5
7
|
CONCURRENCY = Etc.nprocessors
|
@@ -11,7 +13,9 @@ module ChurnVsComplexity
|
|
11
13
|
end
|
12
14
|
|
13
15
|
def calculate(folder:, files:, since:)
|
14
|
-
|
16
|
+
latest_commit_date = @churn.date_of_latest_commit(folder:)
|
17
|
+
@git_period = GitDate.git_period(since, latest_commit_date)
|
18
|
+
schedule_churn_calculation(folder, files[:included], @git_period.effective_start_date)
|
15
19
|
calculate_complexity(folder, files)
|
16
20
|
await_results
|
17
21
|
combine_results
|
@@ -22,9 +26,11 @@ module ChurnVsComplexity
|
|
22
26
|
def calculate_complexity(folder, files)
|
23
27
|
@complexity_results =
|
24
28
|
if @complexity.folder_based?
|
25
|
-
@complexity.calculate(folder:)
|
29
|
+
result = @complexity.calculate(folder:)
|
30
|
+
files[:explicitly_excluded].each { |file| result.delete(file) }
|
31
|
+
result
|
26
32
|
else
|
27
|
-
files.each_with_object({}) do |file, acc|
|
33
|
+
files[:included].each_with_object({}) do |file, acc|
|
28
34
|
acc.merge!(@complexity.calculate(file:))
|
29
35
|
end
|
30
36
|
end
|
@@ -51,10 +57,14 @@ module ChurnVsComplexity
|
|
51
57
|
end
|
52
58
|
|
53
59
|
def combine_results
|
54
|
-
|
55
|
-
|
56
|
-
|
60
|
+
result = {}
|
61
|
+
result[:values_by_file] = @complexity_results.keys.each_with_object({}) do |file, acc|
|
62
|
+
# File with complexity score might not have churned in queried period,
|
63
|
+
# set zero churn on miss
|
64
|
+
acc[file] = [@churn_results[file] || 0, @complexity_results[file]]
|
57
65
|
end
|
66
|
+
result[:git_period] = @git_period
|
67
|
+
result
|
58
68
|
end
|
59
69
|
end
|
60
70
|
end
|
@@ -6,21 +6,23 @@ module ChurnVsComplexity
|
|
6
6
|
language:,
|
7
7
|
serializer:,
|
8
8
|
excluded: [],
|
9
|
-
|
10
|
-
complexity_validator: ComplexityValidator
|
9
|
+
since: nil,
|
10
|
+
complexity_validator: ComplexityValidator,
|
11
|
+
since_validator: SinceValidator
|
11
12
|
)
|
12
13
|
@language = language
|
13
14
|
@serializer = serializer
|
14
15
|
@excluded = excluded
|
16
|
+
@since = since
|
15
17
|
@complexity_validator = complexity_validator
|
16
|
-
@
|
18
|
+
@since_validator = since_validator
|
17
19
|
end
|
18
20
|
|
19
21
|
def validate!
|
20
22
|
raise Error, "Unsupported language: #{@language}" unless %i[java ruby].include?(@language)
|
21
|
-
raise Error, "Unsupported serializer: #{@serializer}" unless %i[none csv graph].include?(@serializer)
|
22
|
-
raise Error, 'Please provide a title for the graph' if @serializer == :graph && @graph_title.nil?
|
23
|
+
raise Error, "Unsupported serializer: #{@serializer}" unless %i[none csv graph summary].include?(@serializer)
|
23
24
|
|
25
|
+
@since_validator.validate!(@since)
|
24
26
|
@complexity_validator.validate!(@language)
|
25
27
|
end
|
26
28
|
|
@@ -32,6 +34,7 @@ module ChurnVsComplexity
|
|
32
34
|
churn:,
|
33
35
|
file_selector: FileSelector::Java.excluding(@excluded),
|
34
36
|
serializer:,
|
37
|
+
since: @since,
|
35
38
|
)
|
36
39
|
when :ruby
|
37
40
|
Engine.concurrent(
|
@@ -39,6 +42,7 @@ module ChurnVsComplexity
|
|
39
42
|
churn:,
|
40
43
|
file_selector: FileSelector::Ruby.excluding(@excluded),
|
41
44
|
serializer:,
|
45
|
+
since: @since,
|
42
46
|
)
|
43
47
|
end
|
44
48
|
end
|
@@ -54,7 +58,9 @@ module ChurnVsComplexity
|
|
54
58
|
when :csv
|
55
59
|
Serializer::CSV
|
56
60
|
when :graph
|
57
|
-
Serializer::Graph.new
|
61
|
+
Serializer::Graph.new
|
62
|
+
when :summary
|
63
|
+
Serializer::Summary
|
58
64
|
end
|
59
65
|
end
|
60
66
|
|
@@ -66,5 +72,24 @@ module ChurnVsComplexity
|
|
66
72
|
end
|
67
73
|
end
|
68
74
|
end
|
75
|
+
|
76
|
+
module SinceValidator
|
77
|
+
def self.validate!(since)
|
78
|
+
# since can be nil, a date string or a keyword (:month, :quarter, :year)
|
79
|
+
return if since.nil?
|
80
|
+
|
81
|
+
if since.is_a?(Symbol)
|
82
|
+
raise Error, "Invalid since value #{since}" unless %i[month quarter year].include?(since)
|
83
|
+
elsif since.is_a?(String)
|
84
|
+
begin
|
85
|
+
Date.strptime(since, '%Y-%m-%d')
|
86
|
+
rescue StandardError
|
87
|
+
raise Error, "Invalid date #{since}, please use correct format, YYYY-MM-DD"
|
88
|
+
end
|
89
|
+
else
|
90
|
+
raise Error, "Invalid since value #{since}"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
69
94
|
end
|
70
95
|
end
|
@@ -2,20 +2,21 @@
|
|
2
2
|
|
3
3
|
module ChurnVsComplexity
|
4
4
|
class Engine
|
5
|
-
def initialize(file_selector:, calculator:, serializer:)
|
5
|
+
def initialize(file_selector:, calculator:, serializer:, since:)
|
6
6
|
@file_selector = file_selector
|
7
7
|
@calculator = calculator
|
8
8
|
@serializer = serializer
|
9
|
+
@since = since
|
9
10
|
end
|
10
11
|
|
11
|
-
def check(folder
|
12
|
+
def check(folder:)
|
12
13
|
files = @file_selector.select_files(folder)
|
13
|
-
result = @calculator.calculate(folder:, files:, since:)
|
14
|
+
result = @calculator.calculate(folder:, files:, since: @since)
|
14
15
|
@serializer.serialize(result)
|
15
16
|
end
|
16
17
|
|
17
|
-
def self.concurrent(complexity:, churn:, serializer: Serializer::None, file_selector: FileSelector::Any)
|
18
|
-
Engine.new(file_selector:, serializer:, calculator: ConcurrentCalculator.new(complexity:, churn:))
|
18
|
+
def self.concurrent(since:, complexity:, churn:, serializer: Serializer::None, file_selector: FileSelector::Any)
|
19
|
+
Engine.new(since:, file_selector:, serializer:, calculator: ConcurrentCalculator.new(complexity:, churn:))
|
19
20
|
end
|
20
21
|
end
|
21
22
|
end
|
@@ -4,7 +4,8 @@ module ChurnVsComplexity
|
|
4
4
|
module FileSelector
|
5
5
|
module Any
|
6
6
|
def self.select_files(folder)
|
7
|
-
Dir.glob("#{folder}/**/*").select { |f| File.file?(f) }
|
7
|
+
included = Dir.glob("#{folder}/**/*").select { |f| File.file?(f) }
|
8
|
+
{ explicitly_excluded: [], included: }
|
8
9
|
end
|
9
10
|
end
|
10
11
|
|
@@ -15,9 +16,16 @@ module ChurnVsComplexity
|
|
15
16
|
end
|
16
17
|
|
17
18
|
def select_files(folder)
|
18
|
-
|
19
|
-
|
19
|
+
were_excluded = []
|
20
|
+
were_included = []
|
21
|
+
Dir.glob("#{folder}/**/*").each do |f|
|
22
|
+
if has_excluded_pattern?(f)
|
23
|
+
were_excluded << f
|
24
|
+
elsif has_correct_extension?(f) && File.file?(f)
|
25
|
+
were_included << f
|
26
|
+
end
|
20
27
|
end
|
28
|
+
{ explicitly_excluded: were_excluded, included: were_included }
|
21
29
|
end
|
22
30
|
|
23
31
|
private
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ChurnVsComplexity
|
4
|
+
module GitDate
|
5
|
+
def self.git_period(cli_arg_since, latest_commit_date)
|
6
|
+
latest_commit_date = latest_commit_date.to_date
|
7
|
+
if cli_arg_since.nil?
|
8
|
+
NoStartGitPeriod.new(latest_commit_date)
|
9
|
+
elsif cli_arg_since.is_a?(Symbol)
|
10
|
+
AbsoluteGitPeriod.looking_back(relative_period: cli_arg_since, from: latest_commit_date)
|
11
|
+
elsif cli_arg_since.is_a?(String)
|
12
|
+
AbsoluteGitPeriod.between(cli_arg_since, latest_commit_date)
|
13
|
+
else
|
14
|
+
raise Error, "Unexpected since value #{cli_arg_since}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class NoStartGitPeriod
|
19
|
+
attr_reader :end_date
|
20
|
+
|
21
|
+
def initialize(end_date)
|
22
|
+
@end_date = end_date
|
23
|
+
end
|
24
|
+
|
25
|
+
def effective_start_date = Time.at(0)
|
26
|
+
|
27
|
+
def requested_start_date = nil
|
28
|
+
end
|
29
|
+
|
30
|
+
class AbsoluteGitPeriod
|
31
|
+
attr_reader :end_date
|
32
|
+
|
33
|
+
def self.between(cli_arg_since, latest_commit_date)
|
34
|
+
start_date = Date.strptime(cli_arg_since, '%Y-%m-%d')
|
35
|
+
new(start_date, latest_commit_date)
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.looking_back(relative_period:, from:)
|
39
|
+
shifter = case relative_period
|
40
|
+
when :month then 1
|
41
|
+
when :quarter then 3
|
42
|
+
when :year then 12
|
43
|
+
else raise Error, "Unexpected since value #{relative_period}"
|
44
|
+
end
|
45
|
+
start_date = from << shifter
|
46
|
+
new(start_date, from)
|
47
|
+
end
|
48
|
+
|
49
|
+
def initialize(start_date, end_date)
|
50
|
+
@start_date = start_date
|
51
|
+
@end_date = end_date
|
52
|
+
end
|
53
|
+
|
54
|
+
def effective_start_date = @start_date
|
55
|
+
|
56
|
+
def requested_start_date = @start_date
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -2,12 +2,55 @@
|
|
2
2
|
|
3
3
|
module ChurnVsComplexity
|
4
4
|
module Serializer
|
5
|
+
def self.title(result)
|
6
|
+
requested_start_date = result[:git_period].requested_start_date
|
7
|
+
end_date = result[:git_period].end_date
|
8
|
+
if requested_start_date.nil?
|
9
|
+
"Churn until #{end_date.strftime('%Y-%m-%d')} vs complexity"
|
10
|
+
else
|
11
|
+
"Churn between #{requested_start_date.strftime('%Y-%m-%d')} and #{end_date.strftime('%Y-%m-%d')} vs complexity"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
5
15
|
module None
|
6
|
-
def self.serialize(
|
16
|
+
def self.serialize(result) = result
|
17
|
+
end
|
18
|
+
|
19
|
+
module Summary
|
20
|
+
def self.serialize(result)
|
21
|
+
values_by_file = result[:values_by_file]
|
22
|
+
churn_values = values_by_file.map { |_, values| values[0].to_f }
|
23
|
+
complexity_values = values_by_file.map { |_, values| values[1].to_f }
|
24
|
+
|
25
|
+
mean_churn = churn_values.sum / churn_values.size
|
26
|
+
median_churn = churn_values.sort[churn_values.size / 2]
|
27
|
+
mean_complexity = complexity_values.sum / complexity_values.size
|
28
|
+
median_complexity = complexity_values.sort[complexity_values.size / 2]
|
29
|
+
|
30
|
+
product = values_by_file.map { |_, values| values[0].to_f * values[1].to_f }
|
31
|
+
mean_product = product.sum / product.size
|
32
|
+
median_product = product.sort[product.size / 2]
|
33
|
+
|
34
|
+
<<~SUMMARY
|
35
|
+
#{Serializer.title(result)}
|
36
|
+
|
37
|
+
Number of observations: #{values_by_file.size}
|
38
|
+
|
39
|
+
Churn:
|
40
|
+
Mean #{mean_churn}, Median #{median_churn}
|
41
|
+
|
42
|
+
Complexity:
|
43
|
+
Mean #{mean_complexity}, Median #{median_complexity}
|
44
|
+
|
45
|
+
Product of churn and complexity:
|
46
|
+
Mean #{mean_product}, Median #{median_product}
|
47
|
+
SUMMARY
|
48
|
+
end
|
7
49
|
end
|
8
50
|
|
9
51
|
module CSV
|
10
|
-
def self.serialize(
|
52
|
+
def self.serialize(result)
|
53
|
+
values_by_file = result[:values_by_file]
|
11
54
|
values_by_file.map do |file, values|
|
12
55
|
"#{file},#{values[0]},#{values[1]}\n"
|
13
56
|
end.join
|
@@ -15,16 +58,16 @@ module ChurnVsComplexity
|
|
15
58
|
end
|
16
59
|
|
17
60
|
class Graph
|
18
|
-
def initialize(
|
61
|
+
def initialize(template: Graph.load_template_file)
|
19
62
|
@template = template
|
20
|
-
@title = title
|
21
63
|
end
|
22
64
|
|
23
|
-
def serialize(
|
24
|
-
data = values_by_file.map do |file, values|
|
65
|
+
def serialize(result)
|
66
|
+
data = result[:values_by_file].map do |file, values|
|
25
67
|
"{ file_path: '#{file}', churn: #{values[0]}, complexity: #{values[1]} }"
|
26
68
|
end.join(",\n") + "\n"
|
27
|
-
|
69
|
+
title = Serializer.title(result)
|
70
|
+
@template.gsub("// INSERT DATA\n", data).gsub('INSERT TITLE', title)
|
28
71
|
end
|
29
72
|
|
30
73
|
def self.load_template_file
|
data/lib/churn_vs_complexity.rb
CHANGED
@@ -12,6 +12,7 @@ require_relative 'churn_vs_complexity/churn'
|
|
12
12
|
require_relative 'churn_vs_complexity/cli'
|
13
13
|
require_relative 'churn_vs_complexity/config'
|
14
14
|
require_relative 'churn_vs_complexity/serializer'
|
15
|
+
require_relative 'churn_vs_complexity/git_date'
|
15
16
|
|
16
17
|
module ChurnVsComplexity
|
17
18
|
class Error < StandardError; end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: churn_vs_complexity
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Erik T. Madsen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-09-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: flog
|
@@ -68,6 +68,7 @@ files:
|
|
68
68
|
- lib/churn_vs_complexity/config.rb
|
69
69
|
- lib/churn_vs_complexity/engine.rb
|
70
70
|
- lib/churn_vs_complexity/file_selector.rb
|
71
|
+
- lib/churn_vs_complexity/git_date.rb
|
71
72
|
- lib/churn_vs_complexity/serializer.rb
|
72
73
|
- lib/churn_vs_complexity/version.rb
|
73
74
|
- tmp/pmd-support/ruleset.xml
|
@@ -89,7 +90,7 @@ licenses:
|
|
89
90
|
- MIT
|
90
91
|
metadata:
|
91
92
|
source_code_uri: https://github.com/beatmadsen/churn_vs_complexity
|
92
|
-
changelog_uri: https://github.com/beatmadsen/churn_vs_complexity/CHANGELOG.md
|
93
|
+
changelog_uri: https://github.com/beatmadsen/churn_vs_complexity/blob/main/CHANGELOG.md
|
93
94
|
rubygems_mfa_required: 'true'
|
94
95
|
post_install_message:
|
95
96
|
rdoc_options: []
|