commiti 1.3.0 → 1.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/lib/commiti.rb +1 -0
- data/lib/flows/commit_flow.rb +6 -4
- data/lib/services/git/commit/commit_execution.rb +8 -8
- data/lib/services/git/commit/commit_staging.rb +3 -3
- data/lib/services/helpers/spinner.rb +19 -11
- data/lib/services/helpers/terminal_ui.rb +58 -0
- data/lib/services/message_presenter.rb +10 -8
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 026566db469248936e47f40faa446650926b7bb893089246a6c23a45dfaa432a
|
|
4
|
+
data.tar.gz: 251995106b1883d61cb12c00f911a4e3158d6d47e9b9d1b434d2026234dd3c2f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c0d857c40f016686ee37b6b7f2d1109c5d7f79a7037c0ed41d0e49e1d3556ff57ce0db9f1da3f0f26e4956840e5a7ab0376a39799f359673068542e89a11480c
|
|
7
|
+
data.tar.gz: 677c08e9d0d5ae62723f7bb3fdea97c3c3799dd5a3775b133ca5520af32a102d924863c5f733794e005b3ff82c79a22d30a7aaee578985118ec0af31cd13c8ce
|
data/lib/commiti.rb
CHANGED
|
@@ -10,6 +10,7 @@ require_relative 'services/helpers/prompt_builder'
|
|
|
10
10
|
require_relative 'services/helpers/interactive_prompt'
|
|
11
11
|
require_relative 'services/git/pr/pr_opener'
|
|
12
12
|
require_relative 'services/helpers/clipboard'
|
|
13
|
+
require_relative 'services/helpers/terminal_ui'
|
|
13
14
|
require_relative 'services/helpers/spinner'
|
|
14
15
|
require_relative 'services/flow_context_builder'
|
|
15
16
|
require_relative 'services/message_generator'
|
data/lib/flows/commit_flow.rb
CHANGED
|
@@ -51,7 +51,8 @@ module Commiti
|
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
def run_single_group_context(context:, client:, model:)
|
|
54
|
-
|
|
54
|
+
message = 'Auto-split found a single connected change group. Falling back to single commit flow.'
|
|
55
|
+
puts "\n#{Commiti::TerminalUI.status(:info, message)}"
|
|
55
56
|
Commiti::MessagePresenter.print_summarization_notice(context[:summarized_result])
|
|
56
57
|
|
|
57
58
|
message = generate_message_for_context(context:, client:, model:)
|
|
@@ -63,7 +64,7 @@ module Commiti
|
|
|
63
64
|
groups = context[:change_groups]
|
|
64
65
|
run_stage('Unstaging current index for grouped commit execution') { Commiti::GitWriter.unstage_all! }
|
|
65
66
|
|
|
66
|
-
puts "\
|
|
67
|
+
puts "\n#{Commiti::TerminalUI.status(:info, "Auto-split detected #{groups.length} connected change groups.")}"
|
|
67
68
|
|
|
68
69
|
groups.each_with_index do |group, index|
|
|
69
70
|
break if process_group(group:, index:, total: groups.length, client:, model:) == :stop
|
|
@@ -74,7 +75,7 @@ module Commiti
|
|
|
74
75
|
run_stage("Staging files for group #{index + 1}/#{total}") { Commiti::GitWriter.stage_files!(group[:files]) }
|
|
75
76
|
return :continue unless run_stage('Checking staged changes') { Commiti::GitWriter.staged_changes? }
|
|
76
77
|
|
|
77
|
-
puts "\
|
|
78
|
+
puts "\n#{Commiti::TerminalUI.header("Group #{index + 1}/#{total} files")}:"
|
|
78
79
|
group[:files].each { |path| puts "- #{path}" }
|
|
79
80
|
|
|
80
81
|
group_context = build_context(diff: group_diff(group), client:, model:)
|
|
@@ -84,7 +85,8 @@ module Commiti
|
|
|
84
85
|
maybe_copy_to_clipboard(message)
|
|
85
86
|
return :continue if finalize(message) == :committed
|
|
86
87
|
|
|
87
|
-
|
|
88
|
+
stop_message = "Stopping auto-split flow at group #{index + 1} because commit was skipped."
|
|
89
|
+
puts Commiti::TerminalUI.status(:warn, stop_message)
|
|
88
90
|
run_stage('Restaging remaining uncommitted changes') { Commiti::GitWriter.stage_all! }
|
|
89
91
|
:stop
|
|
90
92
|
end
|
|
@@ -12,13 +12,13 @@ module Commiti
|
|
|
12
12
|
when :yes
|
|
13
13
|
errors = Commiti::InteractivePrompt.commit_message_errors(working_message)
|
|
14
14
|
unless errors.empty?
|
|
15
|
-
puts "\
|
|
15
|
+
puts "\n#{Commiti::TerminalUI.status(:warn, 'Current message needs fixes before commit:')}"
|
|
16
16
|
errors.each { |error| puts "- #{error}" }
|
|
17
17
|
|
|
18
18
|
if Commiti::InteractivePrompt.ask_yes_no('Open editor to fix now?', default: :yes)
|
|
19
19
|
edited = edit_message_until_valid(working_message)
|
|
20
20
|
if edited.nil?
|
|
21
|
-
puts "\
|
|
21
|
+
puts "\n#{Commiti::TerminalUI.status(:fail, 'Editor did not exit successfully. Commit skipped.')}\n\n"
|
|
22
22
|
return :skipped
|
|
23
23
|
end
|
|
24
24
|
|
|
@@ -27,25 +27,25 @@ module Commiti
|
|
|
27
27
|
next
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
puts "\
|
|
30
|
+
puts "\n#{Commiti::TerminalUI.status(:warn, 'Commit skipped.')}\n\n"
|
|
31
31
|
return :skipped
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
output = run_stage.call('Writing commit') { Commiti::GitWriter.commit_with_message_file(working_message) }
|
|
35
35
|
puts output unless output.to_s.strip.empty?
|
|
36
|
-
puts "\
|
|
36
|
+
puts "\n#{Commiti::TerminalUI.status(:success, 'Commit created.')}\n\n"
|
|
37
37
|
return :committed
|
|
38
38
|
when :edit
|
|
39
39
|
edited = edit_message_until_valid(working_message)
|
|
40
40
|
if edited.nil?
|
|
41
|
-
puts "\
|
|
41
|
+
puts "\n#{Commiti::TerminalUI.status(:fail, 'Editor did not exit successfully.')}\n\n"
|
|
42
42
|
next
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
working_message = edited
|
|
46
46
|
print_message.call(working_message)
|
|
47
47
|
else
|
|
48
|
-
puts "\
|
|
48
|
+
puts "\n#{Commiti::TerminalUI.status(:warn, 'Commit skipped.')}\n\n"
|
|
49
49
|
return :skipped
|
|
50
50
|
end
|
|
51
51
|
end
|
|
@@ -59,7 +59,7 @@ module Commiti
|
|
|
59
59
|
return nil if edited.nil?
|
|
60
60
|
|
|
61
61
|
if edited == working.to_s.strip
|
|
62
|
-
puts "\
|
|
62
|
+
puts "\n#{Commiti::TerminalUI.status(:info, 'No changes detected in editor.')}"
|
|
63
63
|
return edited unless Commiti::InteractivePrompt.ask_yes_no('Re-open editor now?', default: :yes)
|
|
64
64
|
|
|
65
65
|
next
|
|
@@ -68,7 +68,7 @@ module Commiti
|
|
|
68
68
|
errors = Commiti::InteractivePrompt.commit_message_errors(edited)
|
|
69
69
|
return edited if errors.empty?
|
|
70
70
|
|
|
71
|
-
puts "\
|
|
71
|
+
puts "\n#{Commiti::TerminalUI.status(:warn, 'Edited message needs fixes:')}"
|
|
72
72
|
errors.each { |error| puts "- #{error}" }
|
|
73
73
|
return edited unless Commiti::InteractivePrompt.ask_yes_no('Re-open editor now?', default: :yes)
|
|
74
74
|
|
|
@@ -11,11 +11,11 @@ module Commiti
|
|
|
11
11
|
status = run_stage.call('Reading git status') { Commiti::GitWriter.status_short }
|
|
12
12
|
raise 'No changes found in working tree.' if status.strip.empty?
|
|
13
13
|
|
|
14
|
-
puts "\
|
|
14
|
+
puts "\n#{Commiti::TerminalUI.header('Current git status')}\n\n#{status}"
|
|
15
15
|
return unless Commiti::InteractivePrompt.ask_yes_no('Run git add -A now?', default: :no)
|
|
16
16
|
|
|
17
17
|
run_stage.call('Staging changes (git add -A)') { Commiti::GitWriter.stage_all! }
|
|
18
|
-
puts "\
|
|
18
|
+
puts "\n#{Commiti::TerminalUI.status(:success, 'Staged changes with git add -A.')}\n"
|
|
19
19
|
end
|
|
20
20
|
private_class_method :maybe_stage_changes
|
|
21
21
|
|
|
@@ -26,7 +26,7 @@ module Commiti
|
|
|
26
26
|
if Commiti::InteractivePrompt.ask_yes_no('No staged changes found. Stage all changes now with git add -A?',
|
|
27
27
|
default: :yes)
|
|
28
28
|
run_stage.call('Staging changes (git add -A)') { Commiti::GitWriter.stage_all! }
|
|
29
|
-
puts "\
|
|
29
|
+
puts "\n#{Commiti::TerminalUI.status(:success, 'Staged changes with git add -A.')}\n"
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
staged = run_stage.call('Checking staged changes') { Commiti::GitWriter.staged_changes? }
|
|
@@ -5,13 +5,8 @@ module Commiti
|
|
|
5
5
|
FRAMES = ['|', '/', '-', '\\'].freeze
|
|
6
6
|
INTERVAL_SECONDS = 0.1
|
|
7
7
|
|
|
8
|
-
def self.run(message)
|
|
9
|
-
unless $stdout.tty?
|
|
10
|
-
puts "#{message}..."
|
|
11
|
-
result = yield
|
|
12
|
-
puts "[done] #{message}"
|
|
13
|
-
return result
|
|
14
|
-
end
|
|
8
|
+
def self.run(message, &block)
|
|
9
|
+
return run_without_spinner(message, &block) unless $stdout.tty?
|
|
15
10
|
|
|
16
11
|
done = false
|
|
17
12
|
error = nil
|
|
@@ -20,7 +15,7 @@ module Commiti
|
|
|
20
15
|
spinner_thread = Thread.new do
|
|
21
16
|
index = 0
|
|
22
17
|
until done
|
|
23
|
-
frame = FRAMES[index % FRAMES.length]
|
|
18
|
+
frame = Commiti::TerminalUI.color(FRAMES[index % FRAMES.length], :cyan)
|
|
24
19
|
print "\r#{frame} #{message}"
|
|
25
20
|
$stdout.flush
|
|
26
21
|
index += 1
|
|
@@ -29,15 +24,14 @@ module Commiti
|
|
|
29
24
|
end
|
|
30
25
|
|
|
31
26
|
begin
|
|
32
|
-
result =
|
|
27
|
+
result = block.call
|
|
33
28
|
rescue StandardError => e
|
|
34
29
|
error = e
|
|
35
30
|
ensure
|
|
36
31
|
done = true
|
|
37
32
|
spinner_thread.join
|
|
38
33
|
|
|
39
|
-
|
|
40
|
-
print "\r#{status} #{message}\n"
|
|
34
|
+
print "\r#{final_status_line(error, message)}\n"
|
|
41
35
|
$stdout.flush
|
|
42
36
|
end
|
|
43
37
|
|
|
@@ -45,5 +39,19 @@ module Commiti
|
|
|
45
39
|
|
|
46
40
|
result
|
|
47
41
|
end
|
|
42
|
+
|
|
43
|
+
def self.run_without_spinner(message, &block)
|
|
44
|
+
puts Commiti::TerminalUI.status(:info, "#{message}...")
|
|
45
|
+
result = block.call
|
|
46
|
+
puts Commiti::TerminalUI.status(:success, message)
|
|
47
|
+
result
|
|
48
|
+
end
|
|
49
|
+
private_class_method :run_without_spinner
|
|
50
|
+
|
|
51
|
+
def self.final_status_line(error, message)
|
|
52
|
+
kind = error.nil? ? :success : :fail
|
|
53
|
+
Commiti::TerminalUI.status(kind, message)
|
|
54
|
+
end
|
|
55
|
+
private_class_method :final_status_line
|
|
48
56
|
end
|
|
49
57
|
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Commiti
|
|
4
|
+
module TerminalUI
|
|
5
|
+
COLORS = {
|
|
6
|
+
green: 32,
|
|
7
|
+
red: 31,
|
|
8
|
+
yellow: 33,
|
|
9
|
+
blue: 34,
|
|
10
|
+
cyan: 36,
|
|
11
|
+
gray: 90,
|
|
12
|
+
bold: 1
|
|
13
|
+
}.freeze
|
|
14
|
+
|
|
15
|
+
SYMBOLS = {
|
|
16
|
+
success: '✅',
|
|
17
|
+
fail: '❌',
|
|
18
|
+
info: 'ℹ',
|
|
19
|
+
warn: '⚠'
|
|
20
|
+
}.freeze
|
|
21
|
+
|
|
22
|
+
def self.supports_ansi?
|
|
23
|
+
return false unless $stdout.tty?
|
|
24
|
+
return false if ENV.key?('NO_COLOR')
|
|
25
|
+
|
|
26
|
+
term = ENV.fetch('TERM', '').downcase
|
|
27
|
+
term != 'dumb'
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.color(text, *styles)
|
|
31
|
+
return text unless supports_ansi?
|
|
32
|
+
|
|
33
|
+
codes = styles.filter_map { |style| COLORS[style] }
|
|
34
|
+
return text if codes.empty?
|
|
35
|
+
|
|
36
|
+
"\e[#{codes.join(';')}m#{text}\e[0m"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def self.status(kind, text)
|
|
40
|
+
symbol = SYMBOLS.fetch(kind, '*')
|
|
41
|
+
color_style = case kind
|
|
42
|
+
when :success then :green
|
|
43
|
+
when :fail then :red
|
|
44
|
+
when :warn then :yellow
|
|
45
|
+
else :blue
|
|
46
|
+
end
|
|
47
|
+
"#{color(symbol, color_style)} #{text}"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def self.separator(length = 60)
|
|
51
|
+
color('─' * length, :gray)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def self.header(text)
|
|
55
|
+
color(text, :bold, :cyan)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -4,9 +4,9 @@ module Commiti
|
|
|
4
4
|
module MessagePresenter
|
|
5
5
|
def self.print_summarization_notice(summarized_result)
|
|
6
6
|
if summarized_result[:fallback_reason]
|
|
7
|
-
puts "\n#{summarized_result[:fallback_reason]}\n"
|
|
7
|
+
puts "\n#{Commiti::TerminalUI.status(:warn, summarized_result[:fallback_reason])}\n"
|
|
8
8
|
elsif summarized_result[:summarized]
|
|
9
|
-
puts "\
|
|
9
|
+
puts "\n#{Commiti::TerminalUI.status(:info, 'Diff is large — summarizing first to preserve prompt focus.')}\n"
|
|
10
10
|
end
|
|
11
11
|
end
|
|
12
12
|
|
|
@@ -19,7 +19,7 @@ module Commiti
|
|
|
19
19
|
print_candidates(candidates)
|
|
20
20
|
selected_index = Commiti::InteractivePrompt.ask_candidate_selection(candidates.length)
|
|
21
21
|
selected_message = candidates[selected_index]
|
|
22
|
-
puts "\
|
|
22
|
+
puts "\n#{Commiti::TerminalUI.status(:info, "Using candidate #{selected_index + 1}.")}"
|
|
23
23
|
print_message(selected_message)
|
|
24
24
|
selected_message
|
|
25
25
|
end
|
|
@@ -29,21 +29,23 @@ module Commiti
|
|
|
29
29
|
|
|
30
30
|
copied = run_stage.call('Copying output to clipboard') { Commiti::Clipboard.copy(message) }
|
|
31
31
|
if copied
|
|
32
|
-
puts "Copied to clipboard
|
|
32
|
+
puts "#{Commiti::TerminalUI.status(:success, 'Copied output to clipboard!')}\n\n"
|
|
33
33
|
else
|
|
34
|
-
puts "Clipboard
|
|
34
|
+
puts "#{Commiti::TerminalUI.status(:warn, 'Clipboard unavailable. Install xclip: sudo apt install xclip')}\n\n"
|
|
35
35
|
end
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
def self.print_message(message)
|
|
39
|
-
puts "\n#{
|
|
39
|
+
puts "\n#{Commiti::TerminalUI.separator}"
|
|
40
|
+
puts Commiti::TerminalUI.header('Generated output')
|
|
41
|
+
puts Commiti::TerminalUI.separator
|
|
40
42
|
puts message
|
|
41
|
-
puts "#{
|
|
43
|
+
puts "#{Commiti::TerminalUI.separator}\n"
|
|
42
44
|
end
|
|
43
45
|
|
|
44
46
|
def self.print_candidates(candidates)
|
|
45
47
|
candidates.each_with_index do |candidate, index|
|
|
46
|
-
puts "\
|
|
48
|
+
puts "\n#{Commiti::TerminalUI.header("Candidate #{index + 1}")}"
|
|
47
49
|
print_message(candidate)
|
|
48
50
|
end
|
|
49
51
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: commiti
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.3.
|
|
4
|
+
version: 1.3.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Setoju
|
|
@@ -71,6 +71,7 @@ files:
|
|
|
71
71
|
- lib/services/helpers/interactive_prompt.rb
|
|
72
72
|
- lib/services/helpers/prompt_builder.rb
|
|
73
73
|
- lib/services/helpers/spinner.rb
|
|
74
|
+
- lib/services/helpers/terminal_ui.rb
|
|
74
75
|
- lib/services/message_generator.rb
|
|
75
76
|
- lib/services/message_presenter.rb
|
|
76
77
|
homepage: https://github.com/setoju/commiti
|