git_auto 0.1.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +113 -0
- data/exe/git_auto +7 -0
- data/lib/git_auto/cli.rb +79 -0
- data/lib/git_auto/commands/commit_message_command.rb +315 -0
- data/lib/git_auto/commands/config_command.rb +175 -0
- data/lib/git_auto/commands/history_analysis_command.rb +87 -0
- data/lib/git_auto/commands/setup_command.rb +113 -0
- data/lib/git_auto/config/credential_store.rb +73 -0
- data/lib/git_auto/config/settings.rb +95 -0
- data/lib/git_auto/errors.rb +12 -0
- data/lib/git_auto/formatters/diff_formatter.rb +49 -0
- data/lib/git_auto/formatters/diff_summarizer.rb +99 -0
- data/lib/git_auto/formatters/message_formatter.rb +53 -0
- data/lib/git_auto/services/ai_service.rb +395 -0
- data/lib/git_auto/services/git_service.rb +115 -0
- data/lib/git_auto/services/history_service.rb +150 -0
- data/lib/git_auto/validators/commit_message_validator.rb +89 -0
- data/lib/git_auto/version.rb +5 -0
- data/lib/git_auto.rb +52 -0
- metadata +268 -0
@@ -0,0 +1,150 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
require "fileutils"
|
5
|
+
|
6
|
+
module GitAuto
|
7
|
+
module Services
|
8
|
+
class HistoryService
|
9
|
+
HISTORY_FILE = File.join(Config::Settings::CONFIG_DIR, "commit_history.json")
|
10
|
+
MAX_HISTORY_ENTRIES = 10
|
11
|
+
|
12
|
+
class Error < StandardError; end
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@settings = Config::Settings.new
|
16
|
+
ensure_history_file
|
17
|
+
end
|
18
|
+
|
19
|
+
def save_commit(message, metadata = {})
|
20
|
+
return unless @settings.get(:save_history)
|
21
|
+
|
22
|
+
history = load_history
|
23
|
+
history.unshift({
|
24
|
+
message: message,
|
25
|
+
timestamp: Time.now.iso8601,
|
26
|
+
metadata: metadata
|
27
|
+
})
|
28
|
+
|
29
|
+
# Keep only the last MAX_HISTORY_ENTRIES
|
30
|
+
history = history.take(MAX_HISTORY_ENTRIES)
|
31
|
+
|
32
|
+
save_history(history)
|
33
|
+
end
|
34
|
+
|
35
|
+
def get_recent_commits(limit = nil)
|
36
|
+
history = load_history
|
37
|
+
limit ? history.take(limit) : history
|
38
|
+
end
|
39
|
+
|
40
|
+
def analyze_patterns(limit = 50)
|
41
|
+
history = load_history.take(limit)
|
42
|
+
return {} if history.empty?
|
43
|
+
|
44
|
+
{
|
45
|
+
styles: analyze_styles(history),
|
46
|
+
scopes: analyze_scopes(history),
|
47
|
+
types: analyze_types(history),
|
48
|
+
common_phrases: analyze_phrases(history)
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def ensure_history_file
|
55
|
+
return if File.exist?(HISTORY_FILE)
|
56
|
+
|
57
|
+
FileUtils.mkdir_p(File.dirname(HISTORY_FILE))
|
58
|
+
save_history([])
|
59
|
+
end
|
60
|
+
|
61
|
+
def load_history
|
62
|
+
JSON.parse(File.read(HISTORY_FILE), symbolize_names: true)
|
63
|
+
rescue JSON::ParserError, Errno::ENOENT
|
64
|
+
[]
|
65
|
+
end
|
66
|
+
|
67
|
+
def save_history(history)
|
68
|
+
File.write(HISTORY_FILE, JSON.pretty_generate(history))
|
69
|
+
rescue StandardError => e
|
70
|
+
raise Error, "Failed to save commit history: #{e.message}"
|
71
|
+
end
|
72
|
+
|
73
|
+
def analyze_styles(history)
|
74
|
+
styles = history.each_with_object(Hash.new(0)) do |entry, counts|
|
75
|
+
style = detect_style(entry[:message])
|
76
|
+
counts[style] += 1
|
77
|
+
end
|
78
|
+
|
79
|
+
total = styles.values.sum.to_f
|
80
|
+
styles.transform_values { |count| (count / total * 100).round(1) }
|
81
|
+
end
|
82
|
+
|
83
|
+
def analyze_scopes(history)
|
84
|
+
scopes = history.each_with_object(Hash.new(0)) do |entry, counts|
|
85
|
+
scope = extract_scope(entry[:message])
|
86
|
+
counts[scope] += 1 if scope
|
87
|
+
end
|
88
|
+
|
89
|
+
# Return top 10 most used scopes
|
90
|
+
scopes.sort_by { |_, count| -count }.take(10).to_h
|
91
|
+
end
|
92
|
+
|
93
|
+
def analyze_types(history)
|
94
|
+
types = history.each_with_object(Hash.new(0)) do |entry, counts|
|
95
|
+
type = extract_type(entry[:message])
|
96
|
+
counts[type] += 1 if type
|
97
|
+
end
|
98
|
+
|
99
|
+
total = types.values.sum.to_f
|
100
|
+
types.transform_values { |count| (count / total * 100).round(1) }
|
101
|
+
end
|
102
|
+
|
103
|
+
def analyze_phrases(history)
|
104
|
+
phrases = history.each_with_object(Hash.new(0)) do |entry, counts|
|
105
|
+
extract_phrases(entry[:message]).each do |phrase|
|
106
|
+
counts[phrase] += 1
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# Return top 10 most used phrases
|
111
|
+
phrases.sort_by { |_, count| -count }.take(10).to_h
|
112
|
+
end
|
113
|
+
|
114
|
+
def detect_style(message)
|
115
|
+
if message.match?(/^(feat|fix|docs|style|refactor|test|chore)(\([^)]+\))?:/)
|
116
|
+
"conventional"
|
117
|
+
elsif message.include?("\n\n")
|
118
|
+
"detailed"
|
119
|
+
else
|
120
|
+
"simple"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def extract_scope(message)
|
125
|
+
if (match = message.match(/^[a-z]+\(([^)]+)\):/))
|
126
|
+
match[1]
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def extract_type(message)
|
131
|
+
if (match = message.match(/^([a-z]+)(\([^)]+\))?:/))
|
132
|
+
match[1]
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def extract_phrases(message)
|
137
|
+
# Extract common verb phrases from the message
|
138
|
+
# Ignore type/scope for conventional commits
|
139
|
+
content = message.sub(/^[a-z]+(\([^)]+\))?:\s*/, "")
|
140
|
+
words = content.downcase.split(/[^a-z]+/).reject(&:empty?)
|
141
|
+
|
142
|
+
# Get 2-3 word phrases
|
143
|
+
phrases = []
|
144
|
+
words.each_cons(2) { |phrase| phrases << phrase.join(" ") }
|
145
|
+
words.each_cons(3) { |phrase| phrases << phrase.join(" ") }
|
146
|
+
phrases
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GitAuto
|
4
|
+
module Validators
|
5
|
+
class CommitMessageValidator
|
6
|
+
HEADER_MAX_LENGTH = 72
|
7
|
+
|
8
|
+
# Conventional commit types and their descriptions
|
9
|
+
TYPES = {
|
10
|
+
"feat" => "A new feature",
|
11
|
+
"fix" => "A bug fix",
|
12
|
+
"docs" => "Documentation only changes",
|
13
|
+
"style" => "Changes that do not affect the meaning of the code",
|
14
|
+
"refactor" => "A code change that neither fixes a bug nor adds a feature",
|
15
|
+
"test" => "Adding missing tests or correcting existing tests",
|
16
|
+
"chore" => "Changes to the build process or auxiliary tools",
|
17
|
+
"perf" => "A code change that improves performance",
|
18
|
+
"ci" => "Changes to CI configuration files and scripts",
|
19
|
+
"build" => "Changes that affect the build system or external dependencies",
|
20
|
+
"revert" => "Reverts a previous commit"
|
21
|
+
}.freeze
|
22
|
+
|
23
|
+
CONVENTIONAL_COMMIT_PATTERN = %r{
|
24
|
+
^(?<type>#{TYPES.keys.join("|")}) # Commit type
|
25
|
+
(\((?<scope>[a-z0-9/_-]+)\))? # Optional scope in parentheses
|
26
|
+
:\s # Colon and space separator
|
27
|
+
(?<description>.+) # Commit description
|
28
|
+
}x
|
29
|
+
|
30
|
+
def validate(message)
|
31
|
+
errors = []
|
32
|
+
warnings = []
|
33
|
+
|
34
|
+
# Skip validation if message is empty
|
35
|
+
return { errors: ["Commit message cannot be empty"], warnings: [] } if message.nil? || message.strip.empty?
|
36
|
+
|
37
|
+
header_result = validate_header(message)
|
38
|
+
errors.concat(header_result[:errors])
|
39
|
+
warnings.concat(header_result[:warnings])
|
40
|
+
|
41
|
+
{ errors: errors, warnings: warnings }
|
42
|
+
end
|
43
|
+
|
44
|
+
def valid?(message)
|
45
|
+
result = validate(message)
|
46
|
+
result[:errors].empty?
|
47
|
+
end
|
48
|
+
|
49
|
+
def format_error(error)
|
50
|
+
"❌ #{error}".red
|
51
|
+
end
|
52
|
+
|
53
|
+
def format_warning(warning)
|
54
|
+
"⚠️ #{warning}".yellow
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def validate_header(message)
|
60
|
+
errors = []
|
61
|
+
warnings = []
|
62
|
+
|
63
|
+
lines = message.split("\n")
|
64
|
+
header = lines.first
|
65
|
+
|
66
|
+
# Validate header presence and length
|
67
|
+
if header.nil? || header.strip.empty?
|
68
|
+
errors << "Header (first line) cannot be empty"
|
69
|
+
return { errors: errors, warnings: warnings }
|
70
|
+
end
|
71
|
+
|
72
|
+
errors << "Header exceeds #{HEADER_MAX_LENGTH} characters" if header.length > HEADER_MAX_LENGTH
|
73
|
+
|
74
|
+
# Validate header format for conventional commits
|
75
|
+
valid_types = TYPES.keys.join('|')
|
76
|
+
pattern = %r{^(?:#{valid_types})\([a-z0-9/_-]+\)?: .+$}
|
77
|
+
|
78
|
+
unless pattern.match?(header)
|
79
|
+
errors << "Header must follow conventional commit format: <type>(<scope>): <description>"
|
80
|
+
end
|
81
|
+
|
82
|
+
# Suggest using lowercase for consistency
|
83
|
+
warnings << "Consider using lowercase for the commit message" if header =~ /[A-Z]/
|
84
|
+
|
85
|
+
{ errors: errors, warnings: warnings }
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
data/lib/git_auto.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "git_auto/version"
|
4
|
+
require "git_auto/errors"
|
5
|
+
require "git_auto/config/settings"
|
6
|
+
require "git_auto/config/credential_store"
|
7
|
+
require "git_auto/services/ai_service"
|
8
|
+
require "git_auto/services/git_service"
|
9
|
+
require "git_auto/services/history_service"
|
10
|
+
require "git_auto/commands/setup_command"
|
11
|
+
require "git_auto/commands/config_command"
|
12
|
+
require "git_auto/commands/commit_message_command"
|
13
|
+
require "git_auto/cli"
|
14
|
+
require "thor"
|
15
|
+
require "tty-prompt"
|
16
|
+
require "tty-spinner"
|
17
|
+
require "colorize"
|
18
|
+
require "http"
|
19
|
+
require "clipboard"
|
20
|
+
require "fileutils"
|
21
|
+
require_relative "git_auto/formatters/diff_formatter"
|
22
|
+
require_relative "git_auto/formatters/diff_summarizer"
|
23
|
+
require_relative "git_auto/formatters/message_formatter"
|
24
|
+
|
25
|
+
module GitAuto
|
26
|
+
class Error < StandardError; end
|
27
|
+
|
28
|
+
class << self
|
29
|
+
def root
|
30
|
+
File.expand_path("..", __dir__)
|
31
|
+
end
|
32
|
+
|
33
|
+
def install
|
34
|
+
# Create config directory if it doesn't exist
|
35
|
+
FileUtils.mkdir_p(Config::Settings::CONFIG_DIR)
|
36
|
+
end
|
37
|
+
|
38
|
+
def uninstall
|
39
|
+
# Remove config directory and all its contents if it exists
|
40
|
+
FileUtils.rm_rf(Config::Settings::CONFIG_DIR)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Register the hooks with RubyGems
|
46
|
+
Gem.post_install do |installer|
|
47
|
+
GitAuto.install if installer.spec.name == "git_auto"
|
48
|
+
end
|
49
|
+
|
50
|
+
Gem.pre_uninstall do |uninstaller|
|
51
|
+
GitAuto.uninstall if uninstaller.spec.name == "git_auto"
|
52
|
+
end
|
metadata
ADDED
@@ -0,0 +1,268 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: git_auto
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Guillermo Diaz
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-12-14 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: thor
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: tty-prompt
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.23'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.23'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: tty-spinner
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.9'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.9'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: colorize
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.1'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.1'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: http
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '5.1'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '5.1'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: clipboard
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.3'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.3'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rake
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '13.0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '13.0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rspec
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '3.0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '3.0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rubocop
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '1.21'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '1.21'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: rubocop-rake
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0.6'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0.6'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: rubocop-rspec
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - "~>"
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '2.22'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - "~>"
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '2.22'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: yard
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - "~>"
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0.9'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - "~>"
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0.9'
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: vcr
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - "~>"
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '6.1'
|
188
|
+
type: :development
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - "~>"
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '6.1'
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: webmock
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - "~>"
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '3.18'
|
202
|
+
type: :development
|
203
|
+
prerelease: false
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - "~>"
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '3.18'
|
209
|
+
description: GitAuto streamlines your git workflow by automatically generating meaningful
|
210
|
+
commit messages using AI. It analyzes staged changes and generates conventional
|
211
|
+
commit messages that are clear, consistent, and informative.
|
212
|
+
email:
|
213
|
+
- diazgdev@gmail.com
|
214
|
+
executables:
|
215
|
+
- git_auto
|
216
|
+
extensions: []
|
217
|
+
extra_rdoc_files: []
|
218
|
+
files:
|
219
|
+
- CHANGELOG.md
|
220
|
+
- LICENSE.txt
|
221
|
+
- README.md
|
222
|
+
- exe/git_auto
|
223
|
+
- lib/git_auto.rb
|
224
|
+
- lib/git_auto/cli.rb
|
225
|
+
- lib/git_auto/commands/commit_message_command.rb
|
226
|
+
- lib/git_auto/commands/config_command.rb
|
227
|
+
- lib/git_auto/commands/history_analysis_command.rb
|
228
|
+
- lib/git_auto/commands/setup_command.rb
|
229
|
+
- lib/git_auto/config/credential_store.rb
|
230
|
+
- lib/git_auto/config/settings.rb
|
231
|
+
- lib/git_auto/errors.rb
|
232
|
+
- lib/git_auto/formatters/diff_formatter.rb
|
233
|
+
- lib/git_auto/formatters/diff_summarizer.rb
|
234
|
+
- lib/git_auto/formatters/message_formatter.rb
|
235
|
+
- lib/git_auto/services/ai_service.rb
|
236
|
+
- lib/git_auto/services/git_service.rb
|
237
|
+
- lib/git_auto/services/history_service.rb
|
238
|
+
- lib/git_auto/validators/commit_message_validator.rb
|
239
|
+
- lib/git_auto/version.rb
|
240
|
+
homepage: https://github.com/diazgdev/git_auto
|
241
|
+
licenses:
|
242
|
+
- MIT
|
243
|
+
metadata:
|
244
|
+
allowed_push_host: https://rubygems.org
|
245
|
+
homepage_uri: https://github.com/diazgdev/git_auto
|
246
|
+
source_code_uri: https://github.com/diazgdev/git_auto
|
247
|
+
changelog_uri: https://github.com/diazgdev/git_auto/blob/main/CHANGELOG.md
|
248
|
+
rubygems_mfa_required: 'true'
|
249
|
+
post_install_message:
|
250
|
+
rdoc_options: []
|
251
|
+
require_paths:
|
252
|
+
- lib
|
253
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
254
|
+
requirements:
|
255
|
+
- - ">="
|
256
|
+
- !ruby/object:Gem::Version
|
257
|
+
version: 3.0.0
|
258
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
259
|
+
requirements:
|
260
|
+
- - ">="
|
261
|
+
- !ruby/object:Gem::Version
|
262
|
+
version: '0'
|
263
|
+
requirements: []
|
264
|
+
rubygems_version: 3.5.23
|
265
|
+
signing_key:
|
266
|
+
specification_version: 4
|
267
|
+
summary: AI-powered git commit message generator
|
268
|
+
test_files: []
|