mirror of
https://github.com/nvbn/thefuck.git
synced 2025-03-14 06:38:32 +00:00
Merge branch 'master' into git-hook-bypass
This commit is contained in:
commit
b5f48be95d
@ -215,6 +215,7 @@ following rules are enabled by default:
|
||||
* `git_flag_after_filename` – fixes `fatal: bad flag '...' after filename`
|
||||
* `git_help_aliased` – fixes `git help <alias>` commands replacing <alias> with the aliased command;
|
||||
* `git_hook_bypass` – adds `--no-verify` flag previous to `git am`, `git commit`, or `git push` command;
|
||||
* `git_lfs_mistype` – fixes mistyped `git lfs <command>` commands;
|
||||
* `git_merge` – adds remote to branch names;
|
||||
* `git_merge_unrelated` – adds `--allow-unrelated-histories` when required
|
||||
* `git_not_command` – fixes wrong git commands like `git brnch`;
|
||||
|
@ -2,62 +2,54 @@
|
||||
|
||||
import pytest
|
||||
import os
|
||||
from collections import namedtuple
|
||||
from thefuck.rules.fix_file import match, get_new_command
|
||||
from thefuck.types import Command
|
||||
|
||||
FixFileTest = namedtuple('FixFileTest', ['script', 'file', 'line', 'col', 'output'])
|
||||
|
||||
# (script, file, line, col (or None), output)
|
||||
tests = (
|
||||
('gcc a.c', 'a.c', 3, 1,
|
||||
"""
|
||||
FixFileTest('gcc a.c', 'a.c', 3, 1, """
|
||||
a.c: In function 'main':
|
||||
a.c:3:1: error: expected expression before '}' token
|
||||
}
|
||||
^
|
||||
"""),
|
||||
|
||||
('clang a.c', 'a.c', 3, 1,
|
||||
"""
|
||||
FixFileTest('clang a.c', 'a.c', 3, 1, """
|
||||
a.c:3:1: error: expected expression
|
||||
}
|
||||
^
|
||||
"""),
|
||||
|
||||
('perl a.pl', 'a.pl', 3, None,
|
||||
"""
|
||||
FixFileTest('perl a.pl', 'a.pl', 3, None, """
|
||||
syntax error at a.pl line 3, at EOF
|
||||
Execution of a.pl aborted due to compilation errors.
|
||||
"""),
|
||||
|
||||
('perl a.pl', 'a.pl', 2, None,
|
||||
"""
|
||||
FixFileTest('perl a.pl', 'a.pl', 2, None, """
|
||||
Search pattern not terminated at a.pl line 2.
|
||||
"""),
|
||||
|
||||
('sh a.sh', 'a.sh', 2, None,
|
||||
"""
|
||||
FixFileTest('sh a.sh', 'a.sh', 2, None, """
|
||||
a.sh: line 2: foo: command not found
|
||||
"""),
|
||||
|
||||
('zsh a.sh', 'a.sh', 2, None,
|
||||
"""
|
||||
FixFileTest('zsh a.sh', 'a.sh', 2, None, """
|
||||
a.sh:2: command not found: foo
|
||||
"""),
|
||||
|
||||
('bash a.sh', 'a.sh', 2, None,
|
||||
"""
|
||||
FixFileTest('bash a.sh', 'a.sh', 2, None, """
|
||||
a.sh: line 2: foo: command not found
|
||||
"""),
|
||||
|
||||
('rustc a.rs', 'a.rs', 2, 5,
|
||||
"""
|
||||
FixFileTest('rustc a.rs', 'a.rs', 2, 5, """
|
||||
a.rs:2:5: 2:6 error: unexpected token: `+`
|
||||
a.rs:2 +
|
||||
^
|
||||
"""),
|
||||
|
||||
('cargo build', 'src/lib.rs', 3, 5,
|
||||
"""
|
||||
FixFileTest('cargo build', 'src/lib.rs', 3, 5, """
|
||||
Compiling test v0.1.0 (file:///tmp/fix-error/test)
|
||||
src/lib.rs:3:5: 3:6 error: unexpected token: `+`
|
||||
src/lib.rs:3 +
|
||||
@ -67,16 +59,14 @@ Could not compile `test`.
|
||||
To learn more, run the command again with --verbose.
|
||||
"""),
|
||||
|
||||
('python a.py', 'a.py', 2, None,
|
||||
"""
|
||||
FixFileTest('python a.py', 'a.py', 2, None, """
|
||||
File "a.py", line 2
|
||||
+
|
||||
^
|
||||
SyntaxError: invalid syntax
|
||||
"""),
|
||||
|
||||
('python a.py', 'a.py', 8, None,
|
||||
"""
|
||||
FixFileTest('python a.py', 'a.py', 8, None, """
|
||||
Traceback (most recent call last):
|
||||
File "a.py", line 8, in <module>
|
||||
match("foo")
|
||||
@ -89,8 +79,7 @@ Traceback (most recent call last):
|
||||
TypeError: first argument must be string or compiled pattern
|
||||
"""),
|
||||
|
||||
(u'python café.py', u'café.py', 8, None,
|
||||
u"""
|
||||
FixFileTest(u'python café.py', u'café.py', 8, None, u"""
|
||||
Traceback (most recent call last):
|
||||
File "café.py", line 8, in <module>
|
||||
match("foo")
|
||||
@ -103,57 +92,48 @@ Traceback (most recent call last):
|
||||
TypeError: first argument must be string or compiled pattern
|
||||
"""),
|
||||
|
||||
('ruby a.rb', 'a.rb', 3, None,
|
||||
"""
|
||||
FixFileTest('ruby a.rb', 'a.rb', 3, None, """
|
||||
a.rb:3: syntax error, unexpected keyword_end
|
||||
"""),
|
||||
|
||||
('lua a.lua', 'a.lua', 2, None,
|
||||
"""
|
||||
FixFileTest('lua a.lua', 'a.lua', 2, None, """
|
||||
lua: a.lua:2: unexpected symbol near '+'
|
||||
"""),
|
||||
|
||||
('fish a.sh', '/tmp/fix-error/a.sh', 2, None,
|
||||
"""
|
||||
FixFileTest('fish a.sh', '/tmp/fix-error/a.sh', 2, None, """
|
||||
fish: Unknown command 'foo'
|
||||
/tmp/fix-error/a.sh (line 2): foo
|
||||
^
|
||||
"""),
|
||||
|
||||
('./a', './a', 2, None,
|
||||
"""
|
||||
FixFileTest('./a', './a', 2, None, """
|
||||
awk: ./a:2: BEGIN { print "Hello, world!" + }
|
||||
awk: ./a:2: ^ syntax error
|
||||
"""),
|
||||
|
||||
('llc a.ll', 'a.ll', 1, 2,
|
||||
"""
|
||||
FixFileTest('llc a.ll', 'a.ll', 1, 2, """
|
||||
llc: a.ll:1:2: error: expected top-level entity
|
||||
+
|
||||
^
|
||||
"""),
|
||||
|
||||
('go build a.go', 'a.go', 1, 2,
|
||||
"""
|
||||
FixFileTest('go build a.go', 'a.go', 1, 2, """
|
||||
can't load package:
|
||||
a.go:1:2: expected 'package', found '+'
|
||||
"""),
|
||||
|
||||
('make', 'Makefile', 2, None,
|
||||
"""
|
||||
FixFileTest('make', 'Makefile', 2, None, """
|
||||
bidule
|
||||
make: bidule: Command not found
|
||||
Makefile:2: recipe for target 'target' failed
|
||||
make: *** [target] Error 127
|
||||
"""),
|
||||
|
||||
('git st', '/home/martin/.config/git/config', 1, None,
|
||||
"""
|
||||
FixFileTest('git st', '/home/martin/.config/git/config', 1, None, """
|
||||
fatal: bad config file line 1 in /home/martin/.config/git/config
|
||||
"""),
|
||||
|
||||
('node fuck.js asdf qwer', '/Users/pablo/Workspace/barebones/fuck.js', '2', 5,
|
||||
"""
|
||||
FixFileTest('node fuck.js asdf qwer', '/Users/pablo/Workspace/barebones/fuck.js', '2', 5, """
|
||||
/Users/pablo/Workspace/barebones/fuck.js:2
|
||||
conole.log(arg); // this should read console.log(arg);
|
||||
^
|
||||
@ -170,16 +150,14 @@ ReferenceError: conole is not defined
|
||||
at node.js:814:3
|
||||
"""),
|
||||
|
||||
('pep8', './tests/rules/test_systemctl.py', 17, 80,
|
||||
"""
|
||||
FixFileTest('pep8', './tests/rules/test_systemctl.py', 17, 80, """
|
||||
./tests/rules/test_systemctl.py:17:80: E501 line too long (93 > 79 characters)
|
||||
./tests/rules/test_systemctl.py:18:80: E501 line too long (103 > 79 characters)
|
||||
./tests/rules/test_whois.py:20:80: E501 line too long (89 > 79 characters)
|
||||
./tests/rules/test_whois.py:22:80: E501 line too long (83 > 79 characters)
|
||||
"""),
|
||||
|
||||
('py.test', '/home/thefuck/tests/rules/test_fix_file.py', 218, None,
|
||||
"""
|
||||
FixFileTest('py.test', '/home/thefuck/tests/rules/test_fix_file.py', 218, None, """
|
||||
monkeypatch = <_pytest.monkeypatch.monkeypatch object at 0x7fdb76a25b38>
|
||||
test = ('fish a.sh', '/tmp/fix-error/a.sh', 2, None, '', "\\nfish: Unknown command 'foo'\\n/tmp/fix-error/a.sh (line 2): foo\\n ^\\n")
|
||||
|
||||
@ -191,7 +169,7 @@ E NameError: name 'mocker' is not defined
|
||||
|
||||
/home/thefuck/tests/rules/test_fix_file.py:218: NameError
|
||||
"""),
|
||||
) # noqa
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('test', tests)
|
||||
@ -199,7 +177,7 @@ E NameError: name 'mocker' is not defined
|
||||
def test_match(mocker, monkeypatch, test):
|
||||
mocker.patch('os.path.isfile', return_value=True)
|
||||
monkeypatch.setenv('EDITOR', 'dummy_editor')
|
||||
assert match(Command('', test[4]))
|
||||
assert match(Command('', test.output))
|
||||
|
||||
|
||||
@pytest.mark.parametrize('test', tests)
|
||||
@ -209,7 +187,7 @@ def test_no_editor(mocker, monkeypatch, test):
|
||||
if 'EDITOR' in os.environ:
|
||||
monkeypatch.delenv('EDITOR')
|
||||
|
||||
assert not match(Command('', test[4]))
|
||||
assert not match(Command('', test.output))
|
||||
|
||||
|
||||
@pytest.mark.parametrize('test', tests)
|
||||
@ -218,7 +196,7 @@ def test_not_file(mocker, monkeypatch, test):
|
||||
mocker.patch('os.path.isfile', return_value=False)
|
||||
monkeypatch.setenv('EDITOR', 'dummy_editor')
|
||||
|
||||
assert not match(Command('', test[4]))
|
||||
assert not match(Command('', test.output))
|
||||
|
||||
|
||||
@pytest.mark.parametrize('test', tests)
|
||||
@ -234,12 +212,12 @@ def test_get_new_command_with_settings(mocker, monkeypatch, test, settings):
|
||||
mocker.patch('os.path.isfile', return_value=True)
|
||||
monkeypatch.setenv('EDITOR', 'dummy_editor')
|
||||
|
||||
cmd = Command(test[0], test[4])
|
||||
cmd = Command(test.script, test.output)
|
||||
settings.fixcolcmd = '{editor} {file} +{line}:{col}'
|
||||
|
||||
if test[3]:
|
||||
if test.col:
|
||||
assert (get_new_command(cmd) ==
|
||||
u'dummy_editor {} +{}:{} && {}'.format(test[1], test[2], test[3], test[0]))
|
||||
u'dummy_editor {} +{}:{} && {}'.format(test.file, test.line, test.col, test.script))
|
||||
else:
|
||||
assert (get_new_command(cmd) ==
|
||||
u'dummy_editor {} +{} && {}'.format(test[1], test[2], test[0]))
|
||||
u'dummy_editor {} +{} && {}'.format(test.file, test.line, test.script))
|
||||
|
29
tests/rules/test_git_lfs_mistype.py
Normal file
29
tests/rules/test_git_lfs_mistype.py
Normal file
@ -0,0 +1,29 @@
|
||||
import pytest
|
||||
|
||||
from thefuck.rules.git_lfs_mistype import match, get_new_command
|
||||
from thefuck.types import Command
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mistype_response():
|
||||
return """
|
||||
Error: unknown command "evn" for "git-lfs"
|
||||
|
||||
Did you mean this?
|
||||
env
|
||||
ext
|
||||
|
||||
Run 'git-lfs --help' for usage.
|
||||
"""
|
||||
|
||||
|
||||
def test_match(mistype_response):
|
||||
assert match(Command('git lfs evn', mistype_response))
|
||||
err_response = 'bash: git: command not found'
|
||||
assert not match(Command('git lfs env', err_response))
|
||||
assert not match(Command('docker lfs env', mistype_response))
|
||||
|
||||
|
||||
def test_get_new_command(mistype_response):
|
||||
assert (get_new_command(Command('git lfs evn', mistype_response))
|
||||
== ['git lfs env', 'git lfs ext'])
|
@ -71,7 +71,7 @@ def organize_commands(corrected_commands):
|
||||
without_duplicates,
|
||||
key=lambda corrected_command: corrected_command.priority)
|
||||
|
||||
logs.debug('Corrected commands: '.format(
|
||||
logs.debug(u'Corrected commands: {}'.format(
|
||||
', '.join(u'{}'.format(cmd) for cmd in [first_command] + sorted_commands)))
|
||||
|
||||
for command in sorted_commands:
|
||||
|
18
thefuck/rules/git_lfs_mistype.py
Normal file
18
thefuck/rules/git_lfs_mistype.py
Normal file
@ -0,0 +1,18 @@
|
||||
import re
|
||||
from thefuck.utils import get_all_matched_commands, replace_command
|
||||
from thefuck.specific.git import git_support
|
||||
|
||||
|
||||
@git_support
|
||||
def match(command):
|
||||
'''
|
||||
Match a mistyped command
|
||||
'''
|
||||
return 'lfs' in command.script and 'Did you mean this?' in command.output
|
||||
|
||||
|
||||
@git_support
|
||||
def get_new_command(command):
|
||||
broken_cmd = re.findall(r'Error: unknown command "([^"]*)" for "git-lfs"', command.output)[0]
|
||||
matched = get_all_matched_commands(command.output, ['Did you mean', ' for usage.'])
|
||||
return replace_command(command, broken_cmd, matched)
|
@ -122,7 +122,7 @@ class Rule(object):
|
||||
def __repr__(self):
|
||||
return 'Rule(name={}, match={}, get_new_command={}, ' \
|
||||
'enabled_by_default={}, side_effect={}, ' \
|
||||
'priority={}, requires_output)'.format(
|
||||
'priority={}, requires_output={})'.format(
|
||||
self.name, self.match, self.get_new_command,
|
||||
self.enabled_by_default, self.side_effect,
|
||||
self.priority, self.requires_output)
|
||||
|
Loading…
x
Reference in New Issue
Block a user