def test_added_file_not_in_pre_commits_list(temp_git_dir):
    with temp_git_dir.as_cwd():
        temp_git_dir.join('f.py').write("print('hello world')")
        cmd_output('git', 'add', 'f.py')

        # Should pass even with a size of 0
        assert find_large_added_files(['g.py'], 0) == 0
Exemple #2
0
def repository_pending_merge(tmpdir):
    # Make a (non-conflicting) merge
    repo1 = tmpdir.join('repo1')
    repo1_f1 = repo1.join('f1')
    repo2 = tmpdir.join('repo2')
    repo2_f1 = repo2.join('f1')
    repo2_f2 = repo2.join('f2')
    cmd_output('git', 'init', str(repo1))
    with repo1.as_cwd():
        repo1_f1.ensure()
        cmd_output('git', 'add', '.')
        git_commit('-m', 'commit1')

    cmd_output('git', 'clone', str(repo1), str(repo2))

    # Commit in master
    with repo1.as_cwd():
        repo1_f1.write('parent\n')
        git_commit('-am', 'master commit2')

    # Commit in clone and pull without committing
    with repo2.as_cwd():
        repo2_f2.write('child\n')
        cmd_output('git', 'add', '.')
        git_commit('-m', 'clone commit2')
        cmd_output('git', 'pull', '--no-commit', '--no-rebase')
        # We should end up in a pending merge
        assert repo2_f1.read() == 'parent\n'
        assert repo2_f2.read() == 'child\n'
        assert os.path.exists(os.path.join('.git', 'MERGE_HEAD'))
        yield repo2
Exemple #3
0
def main(argv: Optional[Sequence[str]] = None) -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument(
        '-r',
        '--report',
        help='where to store report',
    )
    parser.add_argument(
        '-c',
        '--config',
        help='location of config',
    )
    args = parser.parse_args(argv)

    report = args.report or None
    config = args.config or None
    cmd = "gitleaks --quiet --format=json --path=."
    if report:
        cmd += " --report={}".format(report)
    if config:
        cmd += " --config-path={}".format(config)
    try:
        cmd_output(*cmd.split())
    except CalledProcessError as excp:
        print(excp)
        return 1
    return
Exemple #4
0
def test_adding_something(temp_git_dir):
    with temp_git_dir.as_cwd():
        temp_git_dir.join('f.py').write("print('hello world')")
        cmd_output('git', 'add', 'f.py')

        # Should fail with max size of 0
        assert find_large_added_files(['f.py'], 0) == 1
Exemple #5
0
def test_added_file_not_in_pre_commits_list(temp_git_dir):
    with temp_git_dir.as_cwd():
        temp_git_dir.join('f.py').write("print('hello world')")
        cmd_output('git', 'add', 'f.py')

        # Should pass even with a size of 0
        assert find_large_added_files(['g.py'], 0) == 0
Exemple #6
0
def test_adding_file_with_conflicting_directory(temp_git_dir):
    with temp_git_dir.as_cwd():
        temp_git_dir.mkdir('dir').join('x').write('foo')
        temp_git_dir.join('DIR').write('foo')
        cmd_output('git', 'add', '-A')

        assert find_conflicting_filenames([]) == 1
def test_not_on_a_branch(temp_git_dir):
    with temp_git_dir.as_cwd():
        cmd_output('git', 'commit', '--no-gpg-sign', '--allow-empty', '-m1')
        head = cmd_output('git', 'rev-parse', 'HEAD').strip()
        cmd_output('git', 'checkout', head)
        # we're not on a branch!
        assert main(()) == 0
def test_adding_something(temp_git_dir):
    with temp_git_dir.as_cwd():
        temp_git_dir.join('f.py').write("print('hello world')")
        cmd_output('git', 'add', 'f.py')

        # Should fail with max size of 0
        assert find_large_added_files(['f.py'], 0) == 1
def check_author_identity(
    name_regexp=DEFAULT_NAME_REGEXP,
    email_regexp=DEFAULT_EMAIL_REGEXP,
):
    name = os.environ.get('GIT_AUTHOR_NAME')
    email = os.environ.get('GIT_AUTHOR_EMAIL')
    name = name or cmd_output(
        'git', 'config', '--get', 'user.name', retcode=None)
    email = email or cmd_output(
        'git', 'config', '--get', 'user.email', retcode=None)

    retv = 0
    if not name or not email:
        print('''name and/or email not configured!

Use the commands:
    git config --global user.name "Your Name"
    git config --global user.email "*****@*****.**"
to introduce yourself to Git before committing.
''')
        retv = 1
    elif not re.match(name_regexp, name):
        print('User name %r not match %r' % (name, name_regexp))
        retv = 2
    elif not re.match(email_regexp, email):
        print('User email %r not match %r' % (email, email_regexp))
        retv = 3

    return retv
def test_adding_something_with_conflict(temp_git_dir):
    with cwd(temp_git_dir):
        write_file('f.py', "print('hello world')")
        cmd_output('git', 'add', 'f.py')
        write_file('F.py', "print('hello world')")
        cmd_output('git', 'add', 'F.py')

        assert find_conflicting_filenames(['f.py', 'F.py']) == 1
def test_failing_cmdline_email_regexp(temp_git_dir):
    with temp_git_dir.as_cwd():
        cmd_output('git', 'config', '--add', 'user.name', 'test')
        cmd_output('git', 'config', '--add', 'user.email', '*****@*****.**')
        rc = main([
            '[email protected]',
        ])
        assert rc == 3
def test_filenames_ignored(temp_git_dir):
    with temp_git_dir.as_cwd():
        cmd_output('git', 'config', '--add', 'user.name', 'test')
        cmd_output('git', 'config', '--add', 'user.email', '*****@*****.**')
        rc = main([
            '.gitignore',
        ])
        assert rc == 0
Exemple #13
0
def test_adding_something_with_conflict(temp_git_dir):
    with temp_git_dir.as_cwd():
        temp_git_dir.join('f.py').write("print('hello world')")
        cmd_output('git', 'add', 'f.py')
        temp_git_dir.join('F.py').write("print('hello world')")
        cmd_output('git', 'add', 'F.py')

        assert find_conflicting_filenames(['f.py', 'F.py']) == 1
def test_adding_something_with_conflict(temp_git_dir):
    with temp_git_dir.as_cwd():
        temp_git_dir.join('f.py').write("print('hello world')")
        cmd_output('git', 'add', 'f.py')
        temp_git_dir.join('F.py').write("print('hello world')")
        cmd_output('git', 'add', 'F.py')

        assert find_conflicting_filenames(['f.py', 'F.py']) == 1
def test_passing_cmdline_name_regexp(temp_git_dir):
    with temp_git_dir.as_cwd():
        cmd_output('git', 'config', '--add', 'user.name', 'Test')
        cmd_output('git', 'config', '--add', 'user.email', '*****@*****.**')
        rc = main([
            '--name-regexp=[A-Z].+',
        ])
        assert rc == 0
Exemple #16
0
def test_file_conflicts_with_committed_dir(temp_git_dir):
    with temp_git_dir.as_cwd():
        temp_git_dir.mkdir('dir').join('x').write('foo')
        cmd_output('git', 'add', '-A')
        git_commit('-m', 'Add f.py')

        temp_git_dir.join('DIR').write('foo')
        cmd_output('git', 'add', '-A')

        assert find_conflicting_filenames([]) == 1
Exemple #17
0
def test_file_conflicts_with_committed_file(temp_git_dir):
    with temp_git_dir.as_cwd():
        temp_git_dir.join('f.py').write("print('hello world')")
        cmd_output('git', 'add', 'f.py')
        git_commit('-m', 'Add f.py')

        temp_git_dir.join('F.py').write("print('hello world')")
        cmd_output('git', 'add', 'F.py')

        assert find_conflicting_filenames(['F.py']) == 1
Exemple #18
0
def test_moves_with_gitlfs(temp_git_dir):  # pragma: no cover
    with temp_git_dir.as_cwd():
        cmd_output('git', 'lfs', 'install')
        cmd_output('git', 'lfs', 'track', 'a.bin', 'b.bin')
        # First add the file we're going to move
        temp_git_dir.join('a.bin').write('a' * 10000)
        cmd_output('git', 'add', '--', '.')
        cmd_output('git', 'commit', '--no-gpg-sign', '-am', 'foo')
        # Now move it and make sure the hook still succeeds
        cmd_output('git', 'mv', 'a.bin', 'b.bin')
        assert main(('--maxkb', '9', 'b.bin')) == 0
def test_moves_with_gitlfs(temp_git_dir):  # pragma: no cover
    with temp_git_dir.as_cwd():
        cmd_output('git', 'lfs', 'install')
        cmd_output('git', 'lfs', 'track', 'a.bin', 'b.bin')
        # First add the file we're going to move
        temp_git_dir.join('a.bin').write('a' * 10000)
        cmd_output('git', 'add', '--', '.')
        cmd_output('git', 'commit', '--no-gpg-sign', '-am', 'foo')
        # Now move it and make sure the hook still succeeds
        cmd_output('git', 'mv', 'a.bin', 'b.bin')
        assert main(('--maxkb', '9', 'b.bin')) == 0
def test_check_git_filemode_failing(tmpdir):
    with tmpdir.as_cwd():
        cmd_output('git', 'init', '.')

        f = tmpdir.join('f').ensure()
        f.write('#!/usr/bin/env bash')
        f_path = str(f)
        cmd_output('git', 'add', f_path)

        files = (f_path, )
        assert _check_git_filemode(files) == 1
def fix_spaces_between_java_functions(argv=None):
    parser = argparse.ArgumentParser()
    parser.add_argument('filenames', nargs='*', help='Filenames to fix')
    args = parser.parse_args(argv)

    retv = 0
    print('eggs n bacon')
    cmd_output('eggs n bacon')
    for filename in args.filenames:
        print('Found file {0}'.format(filename))
    return retv
Exemple #22
0
def test_integration(temp_git_dir):
    with temp_git_dir.as_cwd():
        assert main(argv=[]) == 0

        temp_git_dir.join('f.py').write('a' * 10000)
        cmd_output('git', 'add', 'f.py')

        # Should not fail with default
        assert main(argv=['f.py']) == 0

        # Should fail with --maxkb
        assert main(argv=['--maxkb', '9', 'f.py']) == 1
def test_integration(temp_git_dir):
    with temp_git_dir.as_cwd():
        assert main(argv=[]) == 0

        temp_git_dir.join('f.py').write('a' * 10000)
        cmd_output('git', 'add', 'f.py')

        # Should not fail with default
        assert main(argv=['f.py']) == 0

        # Should fail with --maxkb
        assert main(argv=['--maxkb', '9', 'f.py']) == 1
def test_integration(temp_git_dir):
    with cwd(temp_git_dir):
        assert main(argv=[]) == 0

        write_file('f.py', "print('hello world')")
        cmd_output('git', 'add', 'f.py')

        assert main(argv=['f.py']) == 0

        write_file('F.py', "print('hello world')")
        cmd_output('git', 'add', 'F.py')

        assert main(argv=['F.py']) == 1
Exemple #25
0
def test_integration(temp_git_dir):
    with temp_git_dir.as_cwd():
        assert main(argv=[]) == 0

        temp_git_dir.join('f.py').write("print('hello world')")
        cmd_output('git', 'add', 'f.py')

        assert main(argv=['f.py']) == 0

        temp_git_dir.join('F.py').write("print('hello world')")
        cmd_output('git', 'add', 'F.py')

        assert main(argv=['F.py']) == 1
def test_integration(temp_git_dir):
    with temp_git_dir.as_cwd():
        assert main(argv=[]) == 0

        temp_git_dir.join('f.py').write("print('hello world')")
        cmd_output('git', 'add', 'f.py')

        assert main(argv=['f.py']) == 0

        temp_git_dir.join('F.py').write("print('hello world')")
        cmd_output('git', 'add', 'F.py')

        assert main(argv=['F.py']) == 1
Exemple #27
0
def test_worktree_merge_conflicts(f1_is_a_conflict_file, tmpdir):
    worktree = tmpdir.join('worktree')
    cmd_output('git', 'worktree', 'add', str(worktree))
    with worktree.as_cwd():
        cmd_output(
            'git',
            'pull',
            '--no-rebase',
            'origin',
            'master',
            retcode=None,
        )
        msg = f1_is_a_conflict_file.join('.git/worktrees/worktree/MERGE_MSG')
        assert msg.exists()
        test_merge_conflicts_git()
Exemple #28
0
def find_destroyed_symlinks(files: Sequence[str]) -> List[str]:
    destroyed_links: List[str] = []
    if not files:
        return destroyed_links
    for line in zsplit(
            cmd_output('git', 'status', '--porcelain=v2', '-z', '--',
                       *files), ):
        splitted = line.split(' ')
        if splitted and splitted[0] == ORDINARY_CHANGED_ENTRIES_MARKER:
            # https://git-scm.com/docs/git-status#_changed_tracked_entries
            (
                _,
                _,
                _,
                mode_HEAD,
                mode_index,
                _,
                hash_HEAD,
                hash_index,
                *path_splitted,
            ) = splitted
            path = ' '.join(path_splitted)
            if (mode_HEAD == PERMS_LINK and mode_index != PERMS_LINK
                    and mode_index != PERMS_NONEXIST):
                if hash_HEAD == hash_index:
                    # if old and new hashes are equal, it's not needed to check
                    # anything more, we've found a destroyed symlink for sure
                    destroyed_links.append(path)
                else:
                    # if old and new hashes are *not* equal, it doesn't mean
                    # that everything is OK - new file may be altered
                    # by something like trailing-whitespace and/or
                    # mixed-line-ending hooks so we need to go deeper
                    SIZE_CMD = ('git', 'cat-file', '-s')
                    size_index = int(cmd_output(*SIZE_CMD, hash_index).strip())
                    size_HEAD = int(cmd_output(*SIZE_CMD, hash_HEAD).strip())

                    # in the worst case new file may have CRLF added
                    # so check content only if new file is bigger
                    # not more than 2 bytes compared to the old one
                    if size_index <= size_HEAD + 2:
                        head_content = subprocess.check_output(
                            ('git', 'cat-file', '-p', hash_HEAD), ).rstrip()
                        index_content = subprocess.check_output(
                            ('git', 'cat-file', '-p', hash_index), ).rstrip()
                        if head_content == index_content:
                            destroyed_links.append(path)
    return destroyed_links
def is_on_branch(protected):
    try:
        branch = cmd_output("git", "symbolic-ref", "HEAD")
    except CalledProcessError:
        return False
    chunks = branch.strip().split("/")
    return "/".join(chunks[2:]) == protected
def find_conflicting_filenames(filenames):
    repo_files = set(cmd_output("git", "ls-files").splitlines())
    relevant_files = set(filenames) | added_files()
    repo_files -= relevant_files
    retv = 0

    # new file conflicts with existing file
    conflicts = lower_set(repo_files) & lower_set(relevant_files)

    # new file conflicts with other new file
    lowercase_relevant_files = lower_set(relevant_files)
    for filename in set(relevant_files):
        if filename.lower() in lowercase_relevant_files:
            lowercase_relevant_files.remove(filename.lower())
        else:
            conflicts.add(filename.lower())

    if conflicts:
        conflicting_files = [
            x for x in repo_files | relevant_files if x.lower() in conflicts
        ]
        for filename in sorted(conflicting_files):
            print("Case-insensitivity conflict found: {}".format(filename))
        retv = 1

    return retv
def find_conflicting_filenames(filenames):
    repo_files = set(cmd_output('git', 'ls-files').splitlines())
    relevant_files = set(filenames) | added_files()
    repo_files -= relevant_files
    retv = 0

    # new file conflicts with existing file
    conflicts = lower_set(repo_files) & lower_set(relevant_files)

    # new file conflicts with other new file
    lowercase_relevant_files = lower_set(relevant_files)
    for filename in set(relevant_files):
        if filename.lower() in lowercase_relevant_files:
            lowercase_relevant_files.remove(filename.lower())
        else:
            conflicts.add(filename.lower())

    if conflicts:
        conflicting_files = [
            x for x in repo_files | relevant_files
            if x.lower() in conflicts
        ]
        for filename in sorted(conflicting_files):
            print('Case-insensitivity conflict found: {0}'.format(filename))
        retv = 1

    return retv
def main(argv=None):  # type: (Optional[Sequence[str]]) -> int
    # `argv` is ignored, pre-commit will send us a list of files that we
    # don't care about
    added_diff = cmd_output(
        'git',
        'diff',
        '--staged',
        '--diff-filter=A',
        '--raw',
    )
    retv = 0
    for line in added_diff.splitlines():
        metadata, filename = line.split('\t', 1)
        new_mode = metadata.split(' ')[1]
        if new_mode == '160000':
            print('{}: new submodule introduced'.format(filename))
            retv = 1

    if retv:
        print()
        print('This commit introduces new submodules.')
        print('Did you unintentionally `git add .`?')
        print('To fix: git rm {thesubmodule}  # no trailing slash')
        print('Also check .gitmodules')

    return retv
def is_on_branch(protected):
    try:
        branch = cmd_output('git', 'symbolic-ref', 'HEAD')
    except CalledProcessError:
        return False
    chunks = branch.strip().split('/')
    return '/'.join(chunks[2:]) in protected
def is_on_branch(protected):
    try:
        branch = cmd_output('git', 'symbolic-ref', 'HEAD')
    except CalledProcessError:
        return False
    chunks = branch.strip().split('/')
    return '/'.join(chunks[2:]) == protected
Exemple #35
0
def find_conflicting_filenames(filenames: Sequence[str]) -> int:
    repo_files = set(cmd_output('git', 'ls-files').splitlines())
    repo_files |= directories_for(repo_files)
    relevant_files = set(filenames) | added_files()
    relevant_files |= directories_for(relevant_files)
    repo_files -= relevant_files
    retv = 0

    # new file conflicts with existing file
    conflicts = lower_set(repo_files) & lower_set(relevant_files)

    # new file conflicts with other new file
    lowercase_relevant_files = lower_set(relevant_files)
    for filename in set(relevant_files):
        if filename.lower() in lowercase_relevant_files:
            lowercase_relevant_files.remove(filename.lower())
        else:
            conflicts.add(filename.lower())

    if conflicts:
        conflicting_files = [
            x for x in repo_files | relevant_files if x.lower() in conflicts
        ]
        for filename in sorted(conflicting_files):
            print(f'Case-insensitivity conflict found: {filename}')
        retv = 1

    return retv
def test_add_something_giant(temp_git_dir):
    with temp_git_dir.as_cwd():
        temp_git_dir.join('f.py').write('a' * 10000)

        # Should not fail when not added
        assert find_large_added_files(['f.py'], 0) == 0

        cmd_output('git', 'add', 'f.py')

        # Should fail with strict bound
        assert find_large_added_files(['f.py'], 0) == 1

        # Should also fail with actual bound
        assert find_large_added_files(['f.py'], 9) == 1

        # Should pass with higher bound
        assert find_large_added_files(['f.py'], 10) == 0
Exemple #37
0
def test_add_something_giant(temp_git_dir):
    with temp_git_dir.as_cwd():
        temp_git_dir.join('f.py').write('a' * 10000)

        # Should not fail when not added
        assert find_large_added_files(['f.py'], 0) == 0

        cmd_output('git', 'add', 'f.py')

        # Should fail with strict bound
        assert find_large_added_files(['f.py'], 0) == 1

        # Should also fail with actual bound
        assert find_large_added_files(['f.py'], 9) == 1

        # Should pass with higher bound
        assert find_large_added_files(['f.py'], 10) == 0
Exemple #38
0
def lfs_files():
    try:
        # Introduced in git-lfs 2.2.0, first working in 2.2.1
        lfs_ret = cmd_output('git', 'lfs', 'status', '--json')
    except CalledProcessError:  # pragma: no cover (with git-lfs)
        lfs_ret = '{"files":{}}'

    return set(json.loads(lfs_ret)['files'])
Exemple #39
0
def lfs_files():
    try:
        # Introduced in git-lfs 2.2.0, first working in 2.2.1
        lfs_ret = cmd_output("git", "lfs", "status", "--json")
    except CalledProcessError:  # pragma: no cover (with git-lfs)
        lfs_ret = '{"files":{}}'

    return set(json.loads(lfs_ret)["files"])
def test_allows_gitlfs(temp_git_dir):  # pragma: no cover
    with cwd(temp_git_dir):
        # Work around https://github.com/github/git-lfs/issues/913
        cmd_output('git', 'commit', '--allow-empty', '-m', 'foo')
        cmd_output('git', 'lfs', 'install')
        write_file('f.py', 'a' * 10000)
        cmd_output('git', 'lfs', 'track', 'f.py')
        cmd_output('git', 'add', '.')
        # Should succeed
        assert main(('--maxkb', '9', 'f.py')) == 0
def test_allows_gitlfs(temp_git_dir):  # pragma: no cover
    with cwd(temp_git_dir):
        # Work around https://github.com/github/git-lfs/issues/913
        cmd_output('git', 'commit', '--allow-empty', '-m', 'foo')
        cmd_output('git', 'lfs', 'install')
        write_file('f.py', 'a' * 10000)
        cmd_output('git', 'lfs', 'track', 'f.py')
        cmd_output('git', 'add', '.')
        # Should succeed
        assert main(('--maxkb', '9', 'f.py')) == 0
def is_on_branch(protected, patterns=frozenset()):
    # type: (AbstractSet[str], AbstractSet[str]) -> bool
    try:
        ref_name = cmd_output('git', 'symbolic-ref', 'HEAD')
    except CalledProcessError:
        return False
    chunks = ref_name.strip().split('/')
    branch_name = '/'.join(chunks[2:])
    return branch_name in protected or any(
        re.match(p, branch_name) for p in patterns
    )
def add_middle_whitespace(argv=None):
    parser = argparse.ArgumentParser()
    parser.add_argument(
        '--no-markdown-linebreak-ext',
        action='store_const',
        const=[],
        default=argparse.SUPPRESS,
        dest='markdown_linebreak_ext',
        help='Do not preserve linebreak spaces in Markdown'
    )
    parser.add_argument(
        '--markdown-linebreak-ext',
        action='append',
        const='',
        default=['md,markdown'],
        metavar='*|EXT[,EXT,...]',
        nargs='?',
        help='Markdown extensions (or *) for linebreak spaces'
    )
    parser.add_argument('filenames', nargs='*', help='Filenames to fix')
    args = parser.parse_args(argv)

    bad_whitespace_files = cmd_output(
        'grep', '-l', '[[:space:]]$', *args.filenames, retcode=None
    ).strip().splitlines()

    md_args = args.markdown_linebreak_ext
    if '' in md_args:
        parser.error('--markdown-linebreak-ext requires a non-empty argument')
    all_markdown = '*' in md_args
    # normalize all extensions; split at ',', lowercase, and force 1 leading '.'
    md_exts = ['.' + x.lower().lstrip('.')
               for x in ','.join(md_args).split(',')]

    # reject probable "eaten" filename as extension (skip leading '.' with [1:])
    for ext in md_exts:
        if any(c in ext[1:] for c in r'./\:'):
            parser.error(
                "bad --markdown-linebreak-ext extension '{0}' (has . / \\ :)\n"
                "  (probably filename; use '--markdown-linebreak-ext=EXT')"
                .format(ext)
            )

    if bad_whitespace_files:
        for bad_whitespace_file in bad_whitespace_files:
            print('Fixing {0}'.format(bad_whitespace_file))
            _, extension = os.path.splitext(bad_whitespace_file.lower())
            _fix_file(bad_whitespace_file, all_markdown or extension in md_exts)
        return 1
    else:
        return 0
def test_allows_gitlfs(temp_git_dir):  # pragma: no cover
    with temp_git_dir.as_cwd():
        cmd_output('git', 'lfs', 'install')
        temp_git_dir.join('f.py').write('a' * 10000)
        cmd_output('git', 'lfs', 'track', 'f.py')
        cmd_output('git', 'add', '--', '.')
        # Should succeed
        assert main(('--maxkb', '9', 'f.py')) == 0
def fix_comma_whitespace(argv=None):
    parser = argparse.ArgumentParser()
    args = parser.parse_args(argv)

    bad_comma_whitespace_files = cmd_output(
        'grep', '-l', ',^[[:space:]]', *args.filenames, retcode=None
    ).strip().splitlines()

    if bad_comma_whitespace_files:
        for bad_comma_whitespace_file in bad_comma_whitespace_files:
            print('Fixing {0}'.format(bad_comma_whitespace_file))
            _fix_file(bad_comma_whitespace_file)
        return 1
    else:
        return 0
def test_file_conflicts_with_committed_file(temp_git_dir):
    with cwd(temp_git_dir):
        write_file('f.py', "print('hello world')")
        cmd_output('git', 'add', 'f.py')
        cmd_output('git', 'commit', '--no-verify', '-m', 'Add f.py')

        write_file('F.py', "print('hello world')")
        cmd_output('git', 'add', 'F.py')

        assert find_conflicting_filenames(['F.py']) == 1
def test_file_conflicts_with_committed_file(temp_git_dir):
    with temp_git_dir.as_cwd():
        temp_git_dir.join('f.py').write("print('hello world')")
        cmd_output('git', 'add', 'f.py')
        cmd_output('git', 'commit', '--no-gpg-sign', '-n', '-m', 'Add f.py')

        temp_git_dir.join('F.py').write("print('hello world')")
        cmd_output('git', 'add', 'F.py')

        assert find_conflicting_filenames(['F.py']) == 1
def fix_trailing_whitespace(argv=None):
    parser = argparse.ArgumentParser()
    parser.add_argument('filenames', nargs='*', help='Filenames to fix')
    args = parser.parse_args(argv)

    bad_whitespace_files = cmd_output(
        'grep', '-l', '[[:space:]]$', *args.filenames, retcode=None
    ).strip().splitlines()

    if bad_whitespace_files:
        for bad_whitespace_file in bad_whitespace_files:
            print('Fixing {0}'.format(bad_whitespace_file))
            _fix_file(bad_whitespace_file)
        return 1
    else:
        return 0
def lfs_files():
    try:  # pragma: no cover (no git-lfs)
        lines = cmd_output('git', 'lfs', 'status', '--porcelain').splitlines()
    except CalledProcessError:
        lines = []

    modes_and_fileparts = [
        (line[:3].strip(), line[3:].rpartition(' ')[0]) for line in lines
    ]

    def to_file_part(mode, filepart):  # pragma: no cover (no git-lfs)
        assert mode in ('A', 'R')
        return filepart if mode == 'A' else filepart.split(' -> ')[1]

    return set(
        to_file_part(mode, filepart) for mode, filepart in modes_and_fileparts
        if mode in ('A', 'R')
    )
def main(argv=None):  # type: (Optional[Sequence[str]]) -> int
    # `argv` is ignored, pre-commit will send us a list of files that we
    # don't care about
    added_diff = cmd_output(
        'git', 'diff', '--staged', '--diff-filter=A', '--raw',
    )
    retv = 0
    for line in added_diff.splitlines():
        metadata, filename = line.split('\t', 1)
        new_mode = metadata.split(' ')[1]
        if new_mode == '160000':
            print('{}: new submodule introduced'.format(filename))
            retv = 1

    if retv:
        print()
        print('This commit introduces new submodules.')
        print('Did you unintentionally `git add .`?')
        print('To fix: git rm {thesubmodule}  # no trailing slash')
        print('Also check .gitmodules')

    return retv
def test_main_default_call(temp_git_dir):
    with temp_git_dir.as_cwd():
        cmd_output('git', 'checkout', '-b', 'anotherbranch')
        assert main(()) == 0
def test_forbid_multiple_branches(temp_git_dir, branch_name):
    with temp_git_dir.as_cwd():
        cmd_output('git', 'checkout', '-b', branch_name)
        assert main(('--branch', 'b1', '--branch', 'b2'))
def test_main_branch_call(temp_git_dir):
    with temp_git_dir.as_cwd():
        cmd_output('git', 'checkout', '-b', 'other')
        assert main(('--branch', 'other')) == 1
def test_multi_branch_fail(temp_git_dir):
    with temp_git_dir.as_cwd():
        cmd_output('git', 'checkout', '-b', 'another/branch')
        assert is_on_branch({'another/branch'}) is True
def test_multi_branch(temp_git_dir):
    with temp_git_dir.as_cwd():
        cmd_output('git', 'checkout', '-b', 'another/branch')
        assert is_on_branch({'master'}) is False
def has_gitlfs():
    output = cmd_output('git', 'lfs', retcode=None, stderr=subprocess.STDOUT)
    return 'git lfs status' in output