pretty-git 0.1.4 → 0.1.6
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/CHANGELOG.md +84 -4
- data/README.md +78 -6
- data/README.ru.md +76 -3
- data/lib/pretty_git/analytics/languages.rb +61 -19
- data/lib/pretty_git/app.rb +22 -15
- data/lib/pretty_git/cli.rb +17 -6
- data/lib/pretty_git/cli_helpers.rb +148 -19
- data/lib/pretty_git/constants.rb +15 -0
- data/lib/pretty_git/filters.rb +41 -22
- data/lib/pretty_git/git/provider.rb +78 -15
- data/lib/pretty_git/logger.rb +20 -0
- data/lib/pretty_git/render/console_renderer.rb +25 -7
- data/lib/pretty_git/render/csv_renderer.rb +4 -15
- data/lib/pretty_git/render/markdown_renderer.rb +5 -15
- data/lib/pretty_git/render/report_schema.rb +39 -0
- data/lib/pretty_git/utils/path_utils.rb +30 -0
- data/lib/pretty_git/utils/time_utils.rb +39 -0
- data/lib/pretty_git/version.rb +1 -1
- metadata +6 -1
@@ -1,37 +1,26 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'csv'
|
4
|
+
require_relative 'report_schema'
|
4
5
|
|
5
6
|
module PrettyGit
|
6
7
|
module Render
|
7
8
|
# Renders CSV according to docs/output_formats.md and DR-001
|
8
9
|
class CsvRenderer
|
9
|
-
HEADERS = {
|
10
|
-
'activity' => %w[bucket timestamp commits additions deletions],
|
11
|
-
'authors' => %w[author author_email commits additions deletions avg_commit_size],
|
12
|
-
'files' => %w[path commits additions deletions changes],
|
13
|
-
'heatmap' => %w[dow hour commits],
|
14
|
-
'hotspots' => %w[path score commits additions deletions changes],
|
15
|
-
'churn' => %w[path churn commits additions deletions],
|
16
|
-
'ownership' => %w[path owner owner_share authors]
|
17
|
-
}.freeze
|
18
10
|
def initialize(io: $stdout)
|
19
11
|
@io = io
|
20
12
|
end
|
21
13
|
|
22
14
|
def call(report, result, _filters)
|
23
|
-
headers = headers_for(report, result)
|
15
|
+
headers = ReportSchema.headers_for(report, result)
|
24
16
|
write_csv(headers, result[:items])
|
25
17
|
end
|
26
18
|
|
27
19
|
private
|
28
20
|
|
29
21
|
def headers_for(report, result)
|
30
|
-
|
31
|
-
|
32
|
-
HEADERS.fetch(report) do
|
33
|
-
raise ArgumentError, "CSV output for report '#{report}' is not supported yet"
|
34
|
-
end
|
22
|
+
# Deprecated: use ReportSchema.headers_for instead
|
23
|
+
ReportSchema.headers_for(report, result)
|
35
24
|
end
|
36
25
|
|
37
26
|
def write_csv(headers, rows)
|
@@ -1,9 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'report_schema'
|
4
|
+
|
3
5
|
module PrettyGit
|
4
6
|
module Render
|
5
7
|
# Renders Markdown tables and sections per docs/output_formats.md
|
6
|
-
# rubocop:disable Metrics/ClassLength
|
7
8
|
class MarkdownRenderer
|
8
9
|
TITLES = {
|
9
10
|
'activity' => 'Activity',
|
@@ -16,15 +17,6 @@ module PrettyGit
|
|
16
17
|
'ownership' => 'Ownership'
|
17
18
|
}.freeze
|
18
19
|
|
19
|
-
HEADERS = {
|
20
|
-
'activity' => %w[bucket timestamp commits additions deletions],
|
21
|
-
'authors' => %w[author author_email commits additions deletions avg_commit_size],
|
22
|
-
'files' => %w[path commits additions deletions changes],
|
23
|
-
'heatmap' => %w[dow hour commits],
|
24
|
-
'hotspots' => %w[path score commits additions deletions changes],
|
25
|
-
'churn' => %w[path churn commits additions deletions],
|
26
|
-
'ownership' => %w[path owner owner_share authors]
|
27
|
-
}.freeze
|
28
20
|
def initialize(io: $stdout)
|
29
21
|
@io = io
|
30
22
|
end
|
@@ -32,7 +24,7 @@ module PrettyGit
|
|
32
24
|
def call(report, result, _filters)
|
33
25
|
return render_summary(result) if report == 'summary'
|
34
26
|
|
35
|
-
headers = headers_for(report, result)
|
27
|
+
headers = ReportSchema.headers_for(report, result)
|
36
28
|
title = title_for(report)
|
37
29
|
rows = sort_rows(report, result[:items], result)
|
38
30
|
render_table(title, headers, rows)
|
@@ -41,9 +33,8 @@ module PrettyGit
|
|
41
33
|
private
|
42
34
|
|
43
35
|
def headers_for(report, result)
|
44
|
-
|
45
|
-
|
46
|
-
HEADERS.fetch(report, [])
|
36
|
+
# Deprecated: use ReportSchema.headers_for instead
|
37
|
+
ReportSchema.headers_for(report, result)
|
47
38
|
end
|
48
39
|
|
49
40
|
def title_for(report)
|
@@ -131,6 +122,5 @@ module PrettyGit
|
|
131
122
|
(val || '').to_s
|
132
123
|
end
|
133
124
|
end
|
134
|
-
# rubocop:enable Metrics/ClassLength
|
135
125
|
end
|
136
126
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PrettyGit
|
4
|
+
module Render
|
5
|
+
# Centralized schema definitions for report headers and structure.
|
6
|
+
# Used by all renderers (CSV, Markdown, etc.) to ensure consistency.
|
7
|
+
module ReportSchema
|
8
|
+
# Standard headers for each report type
|
9
|
+
HEADERS = {
|
10
|
+
'activity' => %w[bucket timestamp commits additions deletions],
|
11
|
+
'authors' => %w[author author_email commits additions deletions avg_commit_size],
|
12
|
+
'files' => %w[path commits additions deletions changes],
|
13
|
+
'heatmap' => %w[dow hour commits],
|
14
|
+
'hotspots' => %w[path score commits additions deletions changes],
|
15
|
+
'churn' => %w[path churn commits additions deletions],
|
16
|
+
'ownership' => %w[path owner owner_share authors],
|
17
|
+
'summary' => %w[metric value] # not typically tabular but defined for completeness
|
18
|
+
}.freeze
|
19
|
+
|
20
|
+
module_function
|
21
|
+
|
22
|
+
# Returns headers for the given report type
|
23
|
+
# @param report [String] Report name
|
24
|
+
# @param result [Hash] Result hash (used for languages metric detection)
|
25
|
+
# @return [Array<String>] Array of header names
|
26
|
+
def headers_for(report, result = nil)
|
27
|
+
return languages_headers(result) if report == 'languages'
|
28
|
+
|
29
|
+
HEADERS[report] || raise(ArgumentError, "Unknown report type: #{report}")
|
30
|
+
end
|
31
|
+
|
32
|
+
# Languages report has dynamic headers based on metric
|
33
|
+
def languages_headers(result)
|
34
|
+
metric = result&.dig(:metric) || 'bytes'
|
35
|
+
['language', metric.to_s, 'percent', 'color']
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PrettyGit
|
4
|
+
module Utils
|
5
|
+
# Utilities for path/glob normalization and handling cross-platform quirks.
|
6
|
+
module PathUtils
|
7
|
+
module_function
|
8
|
+
|
9
|
+
# Normalize a string path or glob to Unicode NFC form.
|
10
|
+
# Returns nil if input is nil.
|
11
|
+
def normalize_nfc(str)
|
12
|
+
return nil if str.nil?
|
13
|
+
|
14
|
+
s = str.to_s
|
15
|
+
# Only normalize if supported in this Ruby build; otherwise return as-is
|
16
|
+
if s.respond_to?(:unicode_normalize)
|
17
|
+
s.unicode_normalize(:nfc)
|
18
|
+
else
|
19
|
+
s
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Normalize each entry in an Array-like collection to NFC and compact
|
24
|
+
# nils. Returns an Array.
|
25
|
+
def normalize_globs(collection)
|
26
|
+
Array(collection).compact.map { |p| normalize_nfc(p) }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'time'
|
4
|
+
|
5
|
+
module PrettyGit
|
6
|
+
module Utils
|
7
|
+
# Utilities for time parsing and ISO8601 normalization used by filters.
|
8
|
+
module TimeUtils
|
9
|
+
module_function
|
10
|
+
|
11
|
+
# Converts various time inputs to ISO8601 in UTC.
|
12
|
+
# Accepts Time, String(ISO8601), or String(YYYY-MM-DD) treated as UTC midnight.
|
13
|
+
# Returns nil for nil/blank input. Raises ArgumentError for invalid values.
|
14
|
+
def to_utc_iso8601(val)
|
15
|
+
return nil if val.nil? || val.to_s.strip.empty?
|
16
|
+
|
17
|
+
parse_to_time(val).utc.iso8601
|
18
|
+
rescue ArgumentError
|
19
|
+
raise ArgumentError, "Invalid datetime: #{val} (expected ISO8601 or YYYY-MM-DD)"
|
20
|
+
end
|
21
|
+
|
22
|
+
def parse_to_time(val)
|
23
|
+
return val if val.is_a?(Time)
|
24
|
+
return parse_date_only(val) if val.is_a?(String) && date_only?(val)
|
25
|
+
|
26
|
+
Time.parse(val.to_s)
|
27
|
+
end
|
28
|
+
|
29
|
+
def parse_date_only(str)
|
30
|
+
y, m, d = str.split('-').map(&:to_i)
|
31
|
+
Time.new(y, m, d, 0, 0, 0, '+00:00')
|
32
|
+
end
|
33
|
+
|
34
|
+
def date_only?(str)
|
35
|
+
!!(str =~ /^\d{4}-\d{2}-\d{2}$/)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/pretty_git/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pretty-git
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pretty Git Authors
|
@@ -74,17 +74,22 @@ files:
|
|
74
74
|
- lib/pretty_git/app.rb
|
75
75
|
- lib/pretty_git/cli.rb
|
76
76
|
- lib/pretty_git/cli_helpers.rb
|
77
|
+
- lib/pretty_git/constants.rb
|
77
78
|
- lib/pretty_git/filters.rb
|
78
79
|
- lib/pretty_git/git/provider.rb
|
80
|
+
- lib/pretty_git/logger.rb
|
79
81
|
- lib/pretty_git/render/console_renderer.rb
|
80
82
|
- lib/pretty_git/render/csv_renderer.rb
|
81
83
|
- lib/pretty_git/render/json_renderer.rb
|
82
84
|
- lib/pretty_git/render/languages_section.rb
|
83
85
|
- lib/pretty_git/render/markdown_renderer.rb
|
86
|
+
- lib/pretty_git/render/report_schema.rb
|
84
87
|
- lib/pretty_git/render/terminal_width.rb
|
85
88
|
- lib/pretty_git/render/xml_renderer.rb
|
86
89
|
- lib/pretty_git/render/yaml_renderer.rb
|
87
90
|
- lib/pretty_git/types.rb
|
91
|
+
- lib/pretty_git/utils/path_utils.rb
|
92
|
+
- lib/pretty_git/utils/time_utils.rb
|
88
93
|
- lib/pretty_git/version.rb
|
89
94
|
homepage: https://github.com/MikoMikocchi/pretty-git
|
90
95
|
licenses:
|