Skip to content

Commit e4f5b4a

Browse files
author
Mike Foley
committed
Allow execution from scripts and GUI clients
If the Git hook is called from outside of a terminal, just fail on errors without trying to ask the user for input. This previously crashed because it assumed `/dev/tty` was present. This isn't the case when called from a GUI like RubyMine. Fixes #20
1 parent a2a8ae1 commit e4f5b4a

File tree

3 files changed

+54
-25
lines changed

3 files changed

+54
-25
lines changed

lib/fit_commit/runner.rb

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,30 @@ def run
2222
run_validators
2323
return EXIT_CODE_ALLOW_COMMIT if [errors, warnings].all?(&:empty?)
2424
print_results
25+
allow_commit = errors.empty? || ask_force_commit
2526

26-
allow_commit = errors.empty?
27-
unless allow_commit
28-
stderr.print "\nForce commit? [y/n] "
29-
return EXIT_CODE_REJECT_COMMIT unless stdin.gets =~ /y/i
30-
allow_commit = true
27+
if allow_commit
28+
stderr.print "\n"
29+
EXIT_CODE_ALLOW_COMMIT
30+
else
31+
EXIT_CODE_REJECT_COMMIT
3132
end
32-
33-
stderr.print "\n"
34-
allow_commit ? EXIT_CODE_ALLOW_COMMIT : EXIT_CODE_REJECT_COMMIT
3533
rescue Interrupt # Ctrl-c
3634
EXIT_CODE_REJECT_COMMIT
3735
end
3836

3937
private
4038

39+
def ask_force_commit
40+
return unless interactive?
41+
stderr.print "\nForce commit? [y/n] "
42+
stdin.gets =~ /y/i
43+
end
44+
45+
def interactive?
46+
stdin.tty?
47+
end
48+
4149
def run_validators
4250
validators.each do |validator|
4351
validator.validate(lines)

templates/hooks/commit-msg

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,4 @@
11
#!/usr/bin/env sh
2-
#
3-
# This hook will attempt to setup your environment before running checks.
4-
5-
if which rvm > /dev/null 2>&1
6-
then cmd="rvm default do ruby"
7-
elif which rbenv > /dev/null 2>&1
8-
then cmd="rbenv exec ruby"
9-
else cmd="ruby"
10-
fi
112

123
export COMMIT_MESSAGE_PATH=$1
134
if [ -z "$COMMIT_MESSAGE_PATH" ]; then
@@ -35,7 +26,19 @@ if [ -z "$GIT_BRANCH_NAME" ]; then
3526
exit 0
3627
fi
3728

38-
${cmd} -rrubygems -e '
29+
if which rvm > /dev/null 2>&1
30+
then cmd="rvm default do ruby"
31+
elif which rbenv > /dev/null 2>&1
32+
then cmd="rbenv exec ruby"
33+
else cmd="ruby"
34+
fi
35+
36+
# allow user input if running in a terminal
37+
if [ -t 1 ]; then
38+
exec < /dev/tty
39+
fi
40+
41+
$cmd -rrubygems -e '
3942
begin
4043
require "fit_commit"
4144
true
@@ -46,4 +49,4 @@ fit-commit: Did you set your Ruby version?
4649
MESSAGE
4750
false
4851
end and FitCommit.run
49-
' < /dev/tty
52+
'

test/unit/runner_test.rb

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,31 +65,49 @@ def call_runner
6565
describe "commit msg contains errors" do
6666
let(:commit_msg) { "foo.\nbar" }
6767

68-
def assert_error_output
68+
def assert_error_output(interactive: true)
6969
stderr_lines = stderr.read.lines.map(&:chomp)
70-
assert_equal 8, stderr_lines.size
70+
expected_lines = interactive ? 8 : 6
71+
assert_equal expected_lines, stderr_lines.size
7172
assert_equal commit_msg, stderr_lines[0..1].join("\n")
7273
assert_empty stderr_lines[2]
7374
assert_match(/\A1: Error: /, stderr_lines[3])
7475
assert_match(/\A1: Error: /, stderr_lines[4])
7576
assert_match(/\A2: Error: /, stderr_lines[5])
76-
assert_empty stderr_lines[6]
77-
assert_equal "Force commit? [y/n] ", stderr_lines[7]
77+
if interactive
78+
assert_empty stderr_lines[6]
79+
assert_equal "Force commit? [y/n] ", stderr_lines[7]
80+
end
81+
end
82+
83+
def fake_tty(text)
84+
StringIO.new(text).tap do |stringio|
85+
def stringio.tty?
86+
true
87+
end
88+
end
7889
end
7990

8091
describe "user does not force commit" do
81-
let(:stdin) { StringIO.new("n") }
92+
let(:stdin) { fake_tty("n") }
8293
it "prints errors to stderr and rejects commit" do
8394
assert_equal FitCommit::Runner::EXIT_CODE_REJECT_COMMIT, call_runner
8495
assert_error_output
8596
end
8697
end
8798
describe "user forces commit" do
88-
let(:stdin) { StringIO.new("y") }
99+
let(:stdin) { fake_tty("y") }
89100
it "prints errors to stderr and allows commit" do
90101
assert_equal FitCommit::Runner::EXIT_CODE_ALLOW_COMMIT, call_runner
91102
assert_error_output
92103
end
93104
end
105+
describe "TTY not available" do
106+
let(:stdin) { StringIO.new("") }
107+
it "prints errors to stderr and rejects commit" do
108+
assert_equal FitCommit::Runner::EXIT_CODE_REJECT_COMMIT, call_runner
109+
assert_error_output(interactive: false)
110+
end
111+
end
94112
end
95113
end

0 commit comments

Comments
 (0)