Example #1
0
    def test_run_shell_command_kwargs_delegation(self):
        with self.assertRaises(TypeError):
            run_shell_command("super-cool-command", weird_parameter2="abc")

        # Test one of the forbidden parameters.
        with self.assertRaises(TypeError):
            run_shell_command("super-cool-command", universal_newlines=False)
Example #2
0
def handle_thread(thread):
    """
    Handler for notification thread

    :param thread: Thread object of where coafile mention is made
    :return: coafile string
    """
    post_comment(
        thread, 'Greetings! I\'m the coafile bot and I\'m here to get your coafile ready. Sit Tight!')

    clone_url = 'https://github.com/' + thread.repository.full_name + '.git'
    cmd = ['git', 'clone', '--depth=100', clone_url]

    directory = tempfile.mkdtemp(dir=TEMP_DIR)
    run_shell_command(cmd, cwd=directory)

    quickstart_cmd = ["coala-quickstart", "--ci"]
    run_shell_command(quickstart_cmd, cwd=directory)

    with open(directory + os.sep + '.coafile', 'r') as pointer:
        coafile = pointer.read()
        pointer.close()

    shutil.rmtree(directory)

    return coafile
Example #3
0
    def test_run_shell_command_kwargs_delegation(self):
        with self.assertRaises(TypeError):
            run_shell_command("super-cool-command", weird_parameter2="abc")

        # Test one of the forbidden parameters.
        with self.assertRaises(TypeError):
            run_shell_command("super-cool-command", universal_newlines=False)
 def test_get_head_commit_sha(self):
     exception_msg = r'The directory is not a git repository.'
     Path('testfile.txt').touch()
     run_shell_command('git add testfile.txt')
     run_shell_command('git commit -m "Add testfile"')
     with self.assertRaisesRegex(RuntimeError, exception_msg):
         self.uut.get_head_commit_sha()
Example #5
0
    def analyze_commit(self, head_commit_sha):
        commit_type = COMMIT_TYPE.simple_commit

        command = 'git log -1 --pretty=%B ' + head_commit_sha
        head_commit = run_shell_command(command)[0]

        get_parent_commits = 'git log --pretty=%P -n 1 ' + head_commit_sha
        all_parent_commits = run_shell_command(get_parent_commits)[0]
        parent_commits_list = all_parent_commits.split(' ')

        if len(parent_commits_list) >= 2:
            commit_type |= COMMIT_TYPE.merge_commit

        get_all_committed_files = ('git show --pretty="" --name-status ' +
                                   head_commit_sha)
        all_committed_files = run_shell_command(get_all_committed_files)[0]
        all_committed_files = all_committed_files.split('\n')

        modified_files_list = []
        added_files_list = []
        deleted_files_list = []

        for line in all_committed_files:
            pos = line.find('\t')
            change = line[:pos]
            if change == 'M':
                modified_files_list.append(line[pos+1:])
            elif change == 'A':
                added_files_list.append(line[pos+1:])
            elif change == 'D':
                deleted_files_list.append(line[pos+1:])

        yield (head_commit, head_commit_sha, parent_commits_list,
               commit_type, modified_files_list, added_files_list,
               deleted_files_list)
Example #6
0
    def get_head_commit(self):
        with change_directory(self.get_config_dir() or os.getcwd()):
            command = self.check_github_pull_request_temporary_merge_commit()
            if command:
                return run_shell_command(command)

            return run_shell_command('git log -1 --pretty=%B')
    def test_hg_failure(self):
        # The only case where hg log gives error is in case its not a repo
        # so do a log on non-existent repo to perform failure check
        run_shell_command('mv .hg .hgback')
        self.assertEqual(self.run_uut(), [])
        run_shell_command('mv .hgback .hg')

        hg_error = self.msg_queue.get().message
        self.assertEqual(hg_error[:3], 'hg:')

        self.assert_no_msgs()
Example #8
0
    def test_hg_failure(self):
        # The only case where hg log gives error is in case its not a repo
        # so do a log on non-existent repo to perform failure check
        run_shell_command('mv .hg .hgback')
        self.assertEqual(self.run_uut(), [])
        run_shell_command('mv .hgback .hg')

        hg_error = self.msg_queue.get().message
        self.assertEqual(hg_error[:3], 'hg:')

        self.assert_no_msgs()
Example #9
0
    def test_run_shell_command_with_stdin(self):
        command = RunShellCommandTest.construct_testscript_command(
            "test_input_program.py")

        stdout, stderr = run_shell_command(command, "1  4  10  22")

        self.assertEqual(stdout, "37\n")
        self.assertEqual(stderr, "")

        stdout, stderr = run_shell_command(command, "1 p 5")

        self.assertEqual(stdout, "")
        self.assertEqual(stderr, "INVALID INPUT\n")
Example #10
0
    def test_run_shell_command_with_stdin(self):
        command = RunShellCommandTest.construct_testscript_command(
            'test_input_program.py')

        stdout, stderr = run_shell_command(command, '1  4  10  22')

        self.assertEqual(stdout, '37\n')
        self.assertEqual(stderr, '')

        stdout, stderr = run_shell_command(command, '1 p 5')

        self.assertEqual(stdout, '')
        self.assertEqual(stderr, 'INVALID INPUT\n')
Example #11
0
    def test_run_shell_command_with_stdin(self):
        command = RunShellCommandTest.construct_testscript_command(
            "test_input_program.py")

        stdout, stderr = run_shell_command(command, "1  4  10  22")

        self.assertEqual(stdout, "37\n")
        self.assertEqual(stderr, "")

        stdout, stderr = run_shell_command(command, "1 p 5")

        self.assertEqual(stdout, "")
        self.assertEqual(stderr, "INVALID INPUT\n")
Example #12
0
    def test_run_shell_command_with_stdin(self):
        command = RunShellCommandTest.construct_testscript_command(
            'test_input_program.py')

        stdout, stderr = run_shell_command(command, '1  4  10  22')

        self.assertEqual(stdout, '37\n')
        self.assertEqual(stderr, '')

        stdout, stderr = run_shell_command(command, '1 p 5')

        self.assertEqual(stdout, '')
        self.assertEqual(stderr, 'INVALID INPUT\n')
Example #13
0
    def setUp(self):
        self.msg_queue = Queue()
        self.section = Section('')
        self.uut = HgCommitBear(None, self.section, self.msg_queue)

        self._old_cwd = os.getcwd()
        self.hgdir = mkdtemp()
        os.chdir(self.hgdir)
        self.run_hg_command('init')
        run_shell_command('touch ' + HgCommitBearTest.test_file)
        self.run_hg_command('add', HgCommitBearTest.test_file)
        new_config_file = ('[ui]\n' 'username = user.email <*****@*****.**>')
        self.changeHgConfig(new_config_file)
        self.run_hg_command('commit -m "testInit Commit"')
    def setUp(self):
        self.msg_queue = Queue()
        self.section = Section('')
        self.uut = HgCommitBear(None, self.section, self.msg_queue)

        self._old_cwd = os.getcwd()
        self.hgdir = mkdtemp()
        os.chdir(self.hgdir)
        self.run_hg_command('init')
        run_shell_command('touch ' + HgCommitBearTest.test_file)
        self.run_hg_command('add', HgCommitBearTest.test_file)
        new_config_file = ('[ui]\n'
                           'username = user.email <*****@*****.**>')
        self.changeHgConfig(new_config_file)
        self.run_hg_command('commit -m "testInit Commit"')
Example #15
0
    def check_github_pull_request_temporary_merge_commit(self):
        """
        This function creates a git command to fetch the
        unmerged parent commit shortlog from a commit generated
        by GitHub in a refs/pull/(\\d+)/merge git remote reference.
        Visit https://github.com/travis-ci/travis-ci/issues/8400
        for more details.

        :return: A git command (str) to fetch the unmerged parent
                 commit if HEAD commit is a GitHub PR temporary
                 merge commit, otherwise None"
        """
        stdout, _ = run_shell_command('git log -1 --pretty=%B')

        pos = stdout.find('\n')
        shortlog = stdout[:pos] if pos != -1 else stdout

        github_pull_request_temporary_merge_commit_regex = re.compile(
            r'^Merge ([0-9a-f]{40}) into ([0-9a-f]{40})$')
        match = re.fullmatch(github_pull_request_temporary_merge_commit_regex,
                             shortlog)

        if match:
            unmerged_commit_sha = match.group(1)

            command = ('git log -n 1 --pretty=%B ' + unmerged_commit_sha)

            return command
Example #16
0
    def run(self, allow_empty_commit_message: bool = False, **kwargs):
        """
        Check the current git commit message at HEAD.

        This bear ensures automatically that the shortlog and body do not
        exceed a given line-length and that a newline lies between them.

        :param allow_empty_commit_message: Whether empty commit messages are
                                           allowed or not.
        """
        with change_directory(self.get_config_dir() or os.getcwd()):
            stdout, stderr = run_shell_command("git log -1 --pretty=%B")

        if stderr:
            self.err("git:", repr(stderr))
            return

        stdout = stdout.rstrip("\n").splitlines()

        if len(stdout) == 0:
            if not allow_empty_commit_message:
                yield Result(self, "HEAD commit has no message.")
            return

        yield from self.check_shortlog(
            stdout[0],
            **self.get_shortlog_checks_metadata().filter_parameters(kwargs))
        yield from self.check_body(
            stdout[1:],
            **self.get_body_checks_metadata().filter_parameters(kwargs))
Example #17
0
File: Lint.py Project: kipawa/coala
    def lint(self, filename=None, file=None):
        """
        Takes a file and lints it using the linter variables defined apriori.

        :param filename:  The name of the file to execute.
        :param file:      The contents of the file as a list of strings.
        """
        assert ((self.use_stdin and file is not None) or
                (not self.use_stdin and filename is not None))

        config_file = self.generate_config_file()
        self.command = self._create_command(filename=filename,
                                            config_file=config_file)

        stdin_input = "".join(file) if self.use_stdin else None
        stdout_output, stderr_output = run_shell_command(self.command,
                                                         stdin=stdin_input)
        self.stdout_output = tuple(stdout_output.splitlines(keepends=True))
        self.stderr_output = tuple(stderr_output.splitlines(keepends=True))
        results_output = (self.stderr_output if self.use_stderr
                          else self.stdout_output)
        results = self.process_output(results_output, filename, file)
        if not self.use_stderr:
            self._print_errors(self.stderr_output)

        if config_file:
            os.remove(config_file)

        return results
Example #18
0
        def run(self, filename, file, **kwargs):
            # Get the **kwargs params to forward to `generate_config()`
            # (from `_create_config()`).
            generate_config_kwargs = FunctionMetadata.filter_parameters(
                self._get_generate_config_metadata(), kwargs)

            with self._create_config(
                    filename,
                    file,
                    **generate_config_kwargs) as config_file:
                # And now retrieve the **kwargs for `create_arguments()`.
                create_arguments_kwargs = (
                    FunctionMetadata.filter_parameters(
                        self._get_create_arguments_metadata(), kwargs))

                arguments = (self.get_executable(),) + tuple(
                    self.create_arguments(
                        filename, file, config_file,
                        **create_arguments_kwargs))
                self.debug("Running '{}'".format(' '.join(arguments)))

                output = run_shell_command(
                    arguments,
                    stdin="".join(file) if options["use_stdin"] else None)

                output = tuple(compress(
                    output,
                    (options["use_stdout"], options["use_stderr"])))
                if len(output) == 1:
                    output = output[0]

                process_output_kwargs = FunctionMetadata.filter_parameters(
                    self._get_process_output_metadata(), kwargs)
                return self.process_output(output, filename, file,
                                           **process_output_kwargs)
Example #19
0
    def run(self, allow_empty_commit_message: bool = False, **kwargs):
        """
        Check the current git commit message at HEAD.

        This bear ensures automatically that the shortlog and body do not
        exceed a given line-length and that a newline lies between them.

        :param allow_empty_commit_message: Whether empty commit messages are
                                           allowed or not.
        """
        with change_directory(self.get_config_dir() or os.getcwd()):
            stdout, stderr = run_shell_command("git log -1 --pretty=%B")

        if stderr:
            self.err("git:", repr(stderr))
            return

        stdout = stdout.rstrip("\n").splitlines()

        if len(stdout) == 0:
            if not allow_empty_commit_message:
                yield Result(self, "HEAD commit has no message.")
            return

        yield from self.check_shortlog(
            stdout[0],
            **self.get_shortlog_checks_metadata().filter_parameters(kwargs))
        yield from self.check_body(
            stdout[1:],
            **self.get_body_checks_metadata().filter_parameters(kwargs))
Example #20
0
    def lint(self, filename=None, file=None):
        """
        Takes a file and lints it using the linter variables defined apriori.

        :param filename:  The name of the file to execute.
        :param file:      The contents of the file as a list of strings.
        """
        assert ((self.use_stdin and file is not None)
                or (not self.use_stdin and filename is not None))

        config_file = self.generate_config_file()
        self.command = self._create_command(filename=filename,
                                            config_file=config_file)

        stdin_input = "".join(file) if self.use_stdin else None
        stdout_output, stderr_output = run_shell_command(self.command,
                                                         stdin=stdin_input,
                                                         shell=True)
        self.stdout_output = tuple(stdout_output.splitlines(keepends=True))
        self.stderr_output = tuple(stderr_output.splitlines(keepends=True))
        results_output = (self.stderr_output
                          if self.use_stderr else self.stdout_output)
        results = self.process_output(results_output, filename, file)
        if not self.use_stderr:
            self._print_errors(self.stderr_output)

        if config_file:
            os.remove(config_file)

        return results
Example #21
0
    def run(self,
            shortlog_length: int=50,
            body_line_length: int=73,
            force_body: bool=False,
            allow_empty_commit_message: bool=False,
            shortlog_regex: str="",
            shortlog_trailing_period: bool=None):
        """
        Checks the current git commit message at HEAD.

        This bear ensures that the shortlog and body do not exceed a given
        line-length and that a newline lies between them.

        :param shortlog_length:            The maximum length of the shortlog.
                                           The shortlog is the first line of
                                           the commit message. The newline
                                           character at end does not count to
                                           the length.
        :param body_line_length:           The maximum line-length of the body.
                                           The newline character at each line
                                           end does not count to the length.
        :param force_body:                 Whether a body shall exist or not.
        :param allow_empty_commit_message: Whether empty commit messages are
                                           allowed or not.
        :param shortlog_regex:             A regex to check the shortlog with.
                                           A full match of this regex is then
                                           required. Passing an empty string
                                           disable the regex-check.
        :param shortlog_trailing_period:   Whether a dot shall be enforced at
                                           the end of the shortlog line.
                                           Providing ``None`` means
                                           "doesn't care".
        """
        config_dir = self.get_config_dir()
        old_dir = os.getcwd()
        if config_dir:
            os.chdir(config_dir)
        stdout, stderr = run_shell_command(self._git_command)

        if stderr:
            self.err("git:", repr(stderr))
            return

        # git automatically removes trailing whitespaces. Also we need to
        # remove the last \n printed to align the prompt onto the next line.
        stdout = stdout.splitlines()[:-1]

        if len(stdout) == 0:
            if not allow_empty_commit_message:
                yield Result(self, "HEAD commit has no message.")
            return

        yield from self.check_shortlog(shortlog_length,
                                       shortlog_regex,
                                       shortlog_trailing_period,
                                       stdout[0])
        yield from self.check_body(body_line_length, force_body, stdout[1:])

        os.chdir(old_dir)
Example #22
0
        def run(self, filename=None, file=None, **kwargs):
            """
            Runs the wrapped tool.

            :param filename:
                The filename of the file being linted. ``None`` for project
                scope.
            :param file:
                The content of the file being linted. ``None`` for project
                scope.
            """
            # Get the **kwargs params to forward to `generate_config()`
            # (from `_create_config()`).
            generate_config_kwargs = FunctionMetadata.filter_parameters(
                self._get_generate_config_metadata(), kwargs)

            with self._create_config(filename, file,
                                     **generate_config_kwargs) as config_file:
                # And now retrieve the **kwargs for `create_arguments()`.
                create_arguments_kwargs = (FunctionMetadata.filter_parameters(
                    self._get_create_arguments_metadata(), kwargs))

                # The interface of create_arguments is different for local
                # and global bears, therefore we must check here, what kind
                # of bear we have.
                if isinstance(self, LocalBear):
                    args = self.create_arguments(filename, file, config_file,
                                                 **create_arguments_kwargs)
                else:
                    args = self.create_arguments(config_file,
                                                 **create_arguments_kwargs)

                try:
                    args = tuple(args)
                except TypeError:
                    self.err('The given arguments '
                             '{!r} are not iterable.'.format(args))
                    return

                arguments = (self.get_executable(), ) + args
                self.debug("Running '{}'".format(' '.join(
                    str(arg) for arg in arguments)))

                output = run_shell_command(
                    arguments,
                    stdin=''.join(file) if options['use_stdin'] else None,
                    cwd=self.get_config_dir())

                output = tuple(
                    compress(output,
                             (options['use_stdout'], options['use_stderr'])))
                if options['strip_ansi']:
                    output = tuple(map(strip_ansi, output))
                if len(output) == 1:
                    output = output[0]
                process_output_kwargs = FunctionMetadata.filter_parameters(
                    self._get_process_output_metadata(), kwargs)
                return self.process_output(output, filename, file,
                                           **process_output_kwargs)
Example #23
0
    def run(self,
            shortlog_length: int = 50,
            body_line_length: int = 73,
            force_body: bool = False,
            allow_empty_commit_message: bool = False,
            shortlog_regex: str = "",
            shortlog_trailing_period: bool = None):
        """
        Checks the current git commit message at HEAD.

        This bear ensures that the shortlog and body do not exceed a given
        line-length and that a newline lies between them.

        :param shortlog_length:            The maximum length of the shortlog.
                                           The shortlog is the first line of
                                           the commit message. The newline
                                           character at end does not count to
                                           the length.
        :param body_line_length:           The maximum line-length of the body.
                                           The newline character at each line
                                           end does not count to the length.
        :param force_body:                 Whether a body shall exist or not.
        :param allow_empty_commit_message: Whether empty commit messages are
                                           allowed or not.
        :param shortlog_regex:             A regex to check the shortlog with.
                                           A full match of this regex is then
                                           required. Passing an empty string
                                           disable the regex-check.
        :param shortlog_trailing_period:   Whether a dot shall be enforced at
                                           the end of the shortlog line.
                                           Providing ``None`` means
                                           "doesn't care".
        """
        config_dir = self.get_config_dir()
        old_dir = os.getcwd()
        if config_dir:
            os.chdir(config_dir)
        stdout, stderr = run_shell_command(self._git_command)

        if stderr:
            self.err("git:", repr(stderr))
            return

        # git automatically removes trailing whitespaces. Also we need to
        # remove the last \n printed to align the prompt onto the next line.
        stdout = stdout.splitlines()[:-1]

        if len(stdout) == 0:
            if not allow_empty_commit_message:
                yield Result(self, "HEAD commit has no message.")
            return

        yield from self.check_shortlog(shortlog_length, shortlog_regex,
                                       shortlog_trailing_period, stdout[0])
        yield from self.check_body(body_line_length, force_body, stdout[1:])

        os.chdir(old_dir)
Example #24
0
    def is_installed(self):
        """
        Checks if the dependency is installed.

        :param return: True if dependency is installed, false otherwise.
        """
        return True if run_shell_command(
                ('R -e \'library(\"{}\", quietly=TRUE)\''
                 .format(self.package)))[1] is '' else False
    def is_installed(self):
        """
        Checks if the dependency is installed.

        :param return: True if dependency is installed, false otherwise.
        """
        return True if run_shell_command(
            ('R -e \'library(\"{}\", quietly=TRUE)\''.format(
                self.package)))[1] is '' else False
 def test_analyze_git_revert_commit(self):
     Path('testfile3.txt').touch()
     run_shell_command('git add testfile3.txt')
     run_shell_command('git commit -m "another commit [skip ci]"')
     test_sha3 = run_shell_command('git rev-parse HEAD')[0].strip('\n')
     run_shell_command('git revert HEAD --no-edit')
     test_sha4 = run_shell_command('git rev-parse HEAD')[0].strip('\n')
     get_parents = 'git log --pretty=%P -n 1 ' + test_sha4
     parents = run_shell_command(get_parents)[0].split(' ')
     test_raw_commit_msg = ('Revert "another commit [skip ci]"\n\n'
                            'This reverts commit %s.\n\n' % (test_sha3))
     self.assertEqual(
         self.run_uut(),
         [(test_raw_commit_msg, test_sha4, parents,
           COMMIT_TYPE.simple_commit, [], [], ['testfile3.txt'])])
Example #27
0
    def get_ignored_files():
        """
        This function checks for the files that are being tracked
        but are ignored in .gitignore file.
        Visit https://github.com/coala/coala-bears/issues/2610
        for more details.

        :return:
            A list of details of tracked files that are
            ignored in .gitignore file.
        """
        files, _ = run_shell_command('git ls-files')
        files = files.strip().split('\n')
        ignored = list(
            map(
                lambda file: run_shell_command(
                    'git check-ignore --no-index -v {}'.format(file))[0].strip(
                    ), files))
        return list(filter(lambda f: f != '', ignored))
Example #28
0
    def get_head_commit_sha(self):
        with change_directory(self.get_config_dir() or os.getcwd()):
            (stdout, stderr) = run_shell_command('git rev-parse HEAD')

            if stderr:
                vcs_name = list(self.LANGUAGES)[0].lower()+':'
                self.err(vcs_name, repr(stderr))
                raise RuntimeError('The directory is not a git repository.')

            head_commit_sha = stdout.strip('\n')
            return head_commit_sha
Example #29
0
    def test_run_shell_command_without_stdin(self):
        command = RunShellCommandTest.construct_testscript_command(
            'test_program.py')

        stdout, stderr = run_shell_command(command)

        expected = ('test_program Z\n'
                    'non-interactive mode.\n'
                    'Exiting...\n')
        self.assertEqual(stdout, expected)
        self.assertEqual(stderr, '')
Example #30
0
    def test_run_shell_command_without_stdin(self):
        command = RunShellCommandTest.construct_testscript_command(
            "test_program.py")

        stdout, stderr = run_shell_command(command)

        expected = ("test_program Z\n"
                    "non-interactive mode.\n"
                    "Exiting...\n")
        self.assertEqual(stdout, expected)
        self.assertEqual(stderr, "")
 def test_check_revert_commit_not_allowed(self):
     Path('testfile1.txt').touch()
     run_shell_command('git add testfile1.txt')
     run_shell_command('git commit -m "Add testfile1"')
     run_shell_command('git revert HEAD --no-edit')
     self.assertEqual(self.run_uut(allow_git_revert_commit=False),
                      ['Revert commit is not allowed.'])
Example #32
0
    def run(self,
            shortlog_length: int=50,
            body_line_length: int=73,
            force_body: bool=False,
            allow_empty_commit_message: bool=False,
            shortlog_regex: str="",
            shortlog_trailing_period: bool=None):
        """
        Checks the current git commit message at HEAD.

        This bear ensures that the shortlog and body do not exceed a given
        line-length and that a newline lies between them.

        :param shortlog_length:            The maximum length of the shortlog.
                                           The shortlog is the first line of
                                           the commit message. The newline
                                           character at end does not count to
                                           the length.
        :param body_line_length:           The maximum line-length of the body.
                                           The newline character at each line
                                           end does not count to the length.
        :param force_body:                 Whether a body shall exist or not.
        :param allow_empty_commit_message: Whether empty commit messages are
                                           allowed or not.
        :param shortlog_regex:             A regex to check the shortlog with.
                                           A full match of this regex is then
                                           required. Passing an empty string
                                           disable the regex-check.
        :param shortlog_trailing_period:   Whether a dot shall be enforced at
                                           the end of the shortlog line.
                                           Providing ``None`` means
                                           "doesn't care".
        """
        with change_directory(self.get_config_dir() or os.getcwd()):
            stdout, stderr = run_shell_command("git log -1 --pretty=%B")

        if stderr:
            self.err("git:", repr(stderr))
            return

        stdout = stdout.rstrip("\n").splitlines()

        if len(stdout) == 0:
            if not allow_empty_commit_message:
                yield Result(self, "HEAD commit has no message.")
            return

        yield from self.check_shortlog(shortlog_length,
                                       shortlog_regex,
                                       shortlog_trailing_period,
                                       stdout[0])
        yield from self.check_body(body_line_length, force_body, stdout[1:])
    def test_github_pull_request_temporary_merge_commit_check(self):
        self.run_git_command('remote', 'add', 'upstream',
                             'https://github.com/coala/coala-quickstart.git')
        run_shell_command('git fetch upstream pull/259/merge:pytest36')
        run_shell_command('git checkout pytest36')
        self.assertEqual(self.run_uut(), [])

        run_shell_command('git fetch upstream pull/257/merge:patch-1')
        run_shell_command('git checkout patch-1')
        self.assertEqual(self.run_uut(),
                         ["Shortlog of HEAD commit isn't in imperative"
                          " mood! Bad words are 'Fixed'"])

        self.git_commit('Simple git commit')
        self.assertEqual(self.run_uut(), [])
 def test_check_revert_commit_not_allowed(self):
     Path('testfile1.txt').touch()
     run_shell_command('git add testfile1.txt')
     run_shell_command('git commit -m "Add testfile1"')
     run_shell_command('git revert HEAD --no-edit')
     self.assertEqual(self.run_uut(
         allow_git_revert_commit=False),
         ['Revert commit is not allowed.'])
Example #35
0
    def test_github_pull_request_temporary_merge_commit_check(self):
        self.run_git_command('remote', 'add', 'upstream',
                             'https://github.com/coala/coala-quickstart.git')
        run_shell_command('git fetch upstream pull/259/merge:pytest36')
        run_shell_command('git checkout pytest36')
        self.assertEqual(self.run_uut(), [])

        run_shell_command('git fetch upstream pull/257/merge:patch-1')
        run_shell_command('git checkout patch-1')
        self.assertEqual(self.run_uut(),
                         ["Shortlog of HEAD commit isn't in imperative"
                          " mood! Bad words are 'Fixed'"])

        self.git_commit('Simple git commit')
        self.assertEqual(self.run_uut(), [])
Example #36
0
    def run(self,
            shortlog_length: int = 50,
            body_line_length: int = 73,
            force_body: bool = False,
            allow_empty_commit_message: bool = False,
            shortlog_regex: str = "",
            shortlog_trailing_period: bool = None):
        """
        Checks the current git commit message at HEAD.

        This bear ensures that the shortlog and body do not exceed a given
        line-length and that a newline lies between them.

        :param shortlog_length:            The maximum length of the shortlog.
                                           The shortlog is the first line of
                                           the commit message. The newline
                                           character at end does not count to
                                           the length.
        :param body_line_length:           The maximum line-length of the body.
                                           The newline character at each line
                                           end does not count to the length.
        :param force_body:                 Whether a body shall exist or not.
        :param allow_empty_commit_message: Whether empty commit messages are
                                           allowed or not.
        :param shortlog_regex:             A regex to check the shortlog with.
                                           A full match of this regex is then
                                           required. Passing an empty string
                                           disable the regex-check.
        :param shortlog_trailing_period:   Whether a dot shall be enforced at
                                           the end of the shortlog line.
                                           Providing ``None`` means
                                           "doesn't care".
        """
        with change_directory(self.get_config_dir() or os.getcwd()):
            stdout, stderr = run_shell_command("git log -1 --pretty=%B")

        if stderr:
            self.err("git:", repr(stderr))
            return

        stdout = stdout.rstrip("\n").splitlines()

        if len(stdout) == 0:
            if not allow_empty_commit_message:
                yield Result(self, "HEAD commit has no message.")
            return

        yield from self.check_shortlog(shortlog_length, shortlog_regex,
                                       shortlog_trailing_period, stdout[0])
        yield from self.check_body(body_line_length, force_body, stdout[1:])
Example #37
0
    def get_host_from_remotes():
        """
        Retrieve the first host from the list of git remotes.
        """
        remotes, _ = run_shell_command(
            "git config --get-regex '^remote.*.url$'")

        remotes = [url.split()[-1] for url in remotes.splitlines()]
        if len(remotes) == 0:
            return None

        url = remotes[0]
        parsed_url = parse(url)
        netloc = parsed_url.host
        return netloc.split('.')[0]
Example #38
0
        def run(self, filename, file, **settings):
            self._prepare_settings(settings)
            json_string = json.dumps({"filename": filename, "file": file, "settings": settings})

            args = self.create_arguments()
            try:
                args = tuple(args)
            except TypeError:
                self.err("The given arguments " "{!r} are not iterable.".format(args))
                return

            shell_command = (self.get_executable(),) + args
            out, err = run_shell_command(shell_command, json_string)

            return self.parse_output(out, filename)
    def setUp(self):
        self.msg_queue = Queue()
        self.section = Section('')
        self.uut = GitCommitMetadataBear(None, self.section, self.msg_queue)

        self._old_cwd = os.getcwd()
        self.gitdir = mkdtemp()
        os.chdir(self.gitdir)
        run_shell_command('git init')
        run_shell_command('git config -- user.email [email protected]')
        run_shell_command('git config -- user.name coala')
Example #40
0
    def run(self):
        """
        Check Python code for unused variables and functions using `vulture`.

        See <https://bitbucket.org/jendrikseipp/vulture> for more information.
        """
        stdout_output, _ = run_shell_command(
            (self.EXECUTABLE,) +
            tuple(filename for filename in self.file_dict.keys()),
            cwd=self.get_config_dir())

        for match in re.finditer(self.OUTPUT_REGEX, stdout_output):
            groups = match.groupdict()
            yield Result.from_values(origin=self,
                                     message=groups['message'],
                                     file=groups['filename'],
                                     line=int(groups['line']))
Example #41
0
    def run(self):
        """
        Check Python code for unused variables and functions using `vulture`.

        See <https://bitbucket.org/jendrikseipp/vulture> for more information.
        """
        stdout_output, _ = run_shell_command(
            (self.EXECUTABLE,) +
            tuple(filename for filename in self.file_dict.keys()),
            cwd=self.get_config_dir())

        for match in re.finditer(self.OUTPUT_REGEX, stdout_output):
            groups = match.groupdict()
            yield Result.from_values(origin=self,
                                     message=groups['message'],
                                     file=groups['filename'],
                                     line=int(groups['line']))
Example #42
0
    def get_host_from_remotes():
        """
        Retrieve the first host from the list of git remotes.
        """
        remotes, _ = run_shell_command(
            "git config --get-regex '^remote.*.url$'")

        remotes = [url.split()[-1] for url in remotes.splitlines()]
        if len(remotes) == 0:
            return None

        url = remotes[0]
        if 'git@' in url:
            netloc = re.findall(r'@(\S+):', url)[0]
        else:
            netloc = urlparse(url)[1]
        return netloc.split('.')[0]
Example #43
0
    def get_host_from_remotes():
        """
        Retrieve the first host from the list of git remotes.
        """
        remotes, _ = run_shell_command(
            "git config --get-regex '^remote.*.url$'")

        remotes = [url.split()[-1] for url in remotes.splitlines()]
        if len(remotes) == 0:
            return None

        url = remotes[0]
        if 'git@' in url:
            netloc = re.findall(r'@(\S+):', url)[0]
        else:
            netloc = urlparse(url)[1]
        return netloc.split('.')[0]
    def _check_modified_file_similarity(self, file_path,
                                        reverted_commit_sha,
                                        minimum_similarity_ratio):
        """
        Compare the changes in file modified by the
        revert commit with the changes actually
        expected in the revert commit.

        :param file_path:                   Relative path to the modified
                                            file.
        :param reverted_commit_sha:         Commit hash of reverted commit.
        :param minimum_similarity_ratio:    Minimum similarity ratio
                                            required by files in revert
                                            commit.
        """
        def clean_inspect_revert_branch():
            run_shell_command('git checkout master')
            run_shell_command('git branch -D inspectrevertbranch')

        with open(file_path, 'r') as f:
            revert_file_content = f.read()

        create_new_branch_command = (
            'git checkout -b inspectrevertbranch HEAD^')
        run_shell_command(create_new_branch_command)

        create_expected_revert_commit = ('git revert %s --no-'
                                         'edit' %
                                         reverted_commit_sha)
        _, err = run_shell_command(create_expected_revert_commit)
        if err:
            self.warn('Cannot compare the modified files.')
            run_shell_command('git revert --abort')
            clean_inspect_revert_branch()
            return

        expected_revert_commit_sha = run_shell_command(
            'git rev-parse HEAD')[0].strip('\n')

        with open(file_path, 'r') as f:
            expected_revert_file_content = f.read()

        matcher = SequenceMatcher(
            None, revert_file_content, expected_revert_file_content)
        similarity_ratio = matcher.real_quick_ratio()
        if similarity_ratio < minimum_similarity_ratio:
            yield Result(self, 'Changes in modified file %s of '
                         'the revert commit are not exactly '
                         'revert of changes in the reverted '
                         'commit.' %
                         file_path)

        clean_inspect_revert_branch()
Example #45
0
    def _check_modified_file_similarity(self, file_path,
                                        reverted_commit_sha,
                                        minimum_similarity_ratio):
        """
        Compare the changes in file modified by the
        revert commit with the changes actually
        expected in the revert commit.

        :param file_path:                   Relative path to the modified
                                            file.
        :param reverted_commit_sha:         Commit hash of reverted commit.
        :param minimum_similarity_ratio:    Minimum similarity ratio
                                            required by files in revert
                                            commit.
        """
        def clean_inspect_revert_branch():
            run_shell_command('git checkout master')
            run_shell_command('git branch -D inspectrevertbranch')

        with open(file_path, 'r') as f:
            revert_file_content = f.read()

        create_new_branch_command = (
            'git checkout -b inspectrevertbranch HEAD^')
        run_shell_command(create_new_branch_command)

        create_expected_revert_commit = ('git revert %s --no-'
                                         'edit' %
                                         reverted_commit_sha)
        _, err = run_shell_command(create_expected_revert_commit)
        if err:
            self.warn('Cannot compare the modified files.')
            run_shell_command('git revert --abort')
            clean_inspect_revert_branch()
            return

        expected_revert_commit_sha = run_shell_command(
            'git rev-parse HEAD')[0].strip('\n')

        with open(file_path, 'r') as f:
            expected_revert_file_content = f.read()

        matcher = SequenceMatcher(
            None, revert_file_content, expected_revert_file_content)
        similarity_ratio = matcher.real_quick_ratio()
        if similarity_ratio < minimum_similarity_ratio:
            yield Result(self, 'Changes in modified file %s of '
                         'the revert commit are not exactly '
                         'revert of changes in the reverted '
                         'commit.' %
                         file_path)

        clean_inspect_revert_branch()
Example #46
0
        def run(self, filename, file, **settings):
            self._prepare_settings(settings)
            json_string = json.dumps({'filename': filename,
                                      'file': file,
                                      'settings': settings})

            args = self.create_arguments()
            try:
                args = tuple(args)
            except TypeError:
                self.err("The given arguments "
                         "{!r} are not iterable.".format(args))
                return

            shell_command = (self.get_executable(),) + args
            out, err = run_shell_command(shell_command, json_string)

            return self.parse_output(out, filename)
Example #47
0
        def run(self, filename, file, **kwargs):
            # Get the **kwargs params to forward to `generate_config()`
            # (from `_create_config()`).
            generate_config_kwargs = FunctionMetadata.filter_parameters(
                self._get_generate_config_metadata(), kwargs)

            with self._create_config(
                    filename,
                    file,
                    **generate_config_kwargs) as config_file:
                # And now retrieve the **kwargs for `create_arguments()`.
                create_arguments_kwargs = (
                    FunctionMetadata.filter_parameters(
                        self._get_create_arguments_metadata(), kwargs))

                args = self.create_arguments(filename, file, config_file,
                                             **create_arguments_kwargs)

                try:
                    args = tuple(args)
                except TypeError:
                    self.err("The given arguments "
                             "{!r} are not iterable.".format(args))
                    return

                arguments = (self.get_executable(),) + args
                self.debug("Running '{}'".format(' '.join(arguments)))

                output = run_shell_command(
                    arguments,
                    stdin="".join(file) if options["use_stdin"] else None,
                    cwd=self.get_config_dir())

                output = tuple(compress(
                    output,
                    (options["use_stdout"], options["use_stderr"])))
                if len(output) == 1:
                    output = output[0]

                process_output_kwargs = FunctionMetadata.filter_parameters(
                    self._get_process_output_metadata(), kwargs)
                return self.process_output(output, filename, file,
                                           **process_output_kwargs)
Example #48
0
File: Linter.py Project: icoz/coala
        def run(self, filename, file, **kwargs):
            # Get the **kwargs params to forward to `generate_config()`
            # (from `_create_config()`).
            generate_config_kwargs = FunctionMetadata.filter_parameters(
                self._get_generate_config_metadata(), kwargs)

            with self._create_config(
                    filename,
                    file,
                    **generate_config_kwargs) as config_file:
                # And now retrieve the **kwargs for `create_arguments()`.
                create_arguments_kwargs = (
                    FunctionMetadata.filter_parameters(
                        self._get_create_arguments_metadata(), kwargs))

                args = self.create_arguments(filename, file, config_file,
                                             **create_arguments_kwargs)

                try:
                    args = tuple(args)
                except TypeError:
                    self.err('The given arguments '
                             '{!r} are not iterable.'.format(args))
                    return

                arguments = (self.get_executable(),) + args
                self.debug("Running '{}'".format(' '.join(arguments)))

                output = run_shell_command(
                    arguments,
                    stdin=''.join(file) if options['use_stdin'] else None,
                    cwd=self.get_config_dir())

                output = tuple(compress(
                    output,
                    (options['use_stdout'], options['use_stderr'])))
                if len(output) == 1:
                    output = output[0]

                process_output_kwargs = FunctionMetadata.filter_parameters(
                    self._get_process_output_metadata(), kwargs)
                return self.process_output(output, filename, file,
                                           **process_output_kwargs)
Example #49
0
    def test_github_pull_request_temporary_merge_commit(self):
        self.run_git_command('remote', 'add', 'upstream',
                             'git://github.com/kriti21/coala-bears.git')
        run_shell_command('git fetch upstream pull/3/merge:good_test')
        run_shell_command('git checkout good_test')
        self.assertEqual(self.run_uut(), [])

        # If parent of this merge commit is wrong, message is
        # displayed accordingly.
        self.run_git_command('remote', 'add', 'upstream',
                             'git://github.com/kriti21/coala-bears.git')
        run_shell_command('git fetch upstream pull/2/merge:bad_test')
        run_shell_command('git checkout bad_test')
        self.assertEqual(self.run_uut(), [
            'Shortlog of the HEAD commit contains 70 '
            'character(s). This is 20 character(s) longer '
            'than the limit (70 > 50).'
        ])

        self.git_commit('Simple git commit')
        self.assertEqual(self.run_uut(), [])
Example #50
0
    def run(self,
            shortlog_length: int=50,
            body_line_length: int=73,
            force_body: bool=False,
            allow_empty_commit_message: bool=False):
        """
        Checks the current git commit message at HEAD.

        This bear ensures that the shortlog and body do not exceed a given
        line-length and that a newline lies between them.

        :param shortlog_length:            The maximum length of the shortlog.
                                           The shortlog is the first line of
                                           the commit message. The newline
                                           character at end does not count to
                                           the length.
        :param body_line_length:           The maximum line-length of the body.
                                           The newline character at each line
                                           end does not count to the length.
        :param force_body:                 Whether a body shall exist or not.
        :param allow_empty_commit_message: Whether empty commit messages are
                                           allowed or not.
        """
        stdout, stderr = run_shell_command(self._git_command)

        if stderr:
            self.err("git:", repr(stderr))
            return

        # git automatically removes trailing whitespaces. Also we need to
        # remove the last \n printed to align the prompt onto the next line.
        stdout = stdout.splitlines()[:-1]

        if len(stdout) == 0:
            if not allow_empty_commit_message:
                yield Result(self, "HEAD commit has no message.")
            return

        yield from self.check_shortlog(shortlog_length, stdout[0])
        yield from self.check_body(body_line_length, force_body, stdout[1:])
Example #51
0
    def run(self, allow_empty_commit_message: bool = False, **kwargs):
        """
        Check the current git commit message at HEAD.

        This bear ensures automatically that the shortlog and body do not
        exceed a given line-length and that a newline lies between them.

        :param allow_empty_commit_message: Whether empty commit messages are
                                           allowed or not.
        """
        with change_directory(self.get_config_dir() or os.getcwd()):
            stdout, stderr = run_shell_command('git log -1 --pretty=%B')

        if stderr:
            self.err('git:', repr(stderr))
            return

        stdout = stdout.rstrip('\n')
        pos = stdout.find('\n')
        shortlog = stdout[:pos] if pos != -1 else stdout
        body = stdout[pos+1:] if pos != -1 else ''

        if len(stdout) == 0:
            if not allow_empty_commit_message:
                yield Result(self, 'HEAD commit has no message.')
            return

        yield from self.check_shortlog(
            shortlog,
            **self.get_shortlog_checks_metadata().filter_parameters(kwargs))
        yield from self.check_body(
            body,
            **self.get_body_checks_metadata().filter_parameters(kwargs))
        yield from self.check_issue_reference(
            body,
            **self.get_issue_checks_metadata().filter_parameters(kwargs))
    def test_check_file_similarity_with_correct_revert_commit(self):
        Path('testfile6.txt').touch()
        with open('testfile6.txt', 'w') as f:
            f.write('Some other text\n')
        run_shell_command('git add testfile6.txt')
        run_shell_command('git commit -m "Initial commit"')

        with open('testfile6.txt', 'w') as f:
            f.write('Changed text\n')
        run_shell_command('git add testfile6.txt')
        run_shell_command('git commit -m "modify testfile6"')

        run_shell_command('git revert HEAD --no-edit')
        with open('testfile6.txt', 'w') as f:
            f.write('Some more text\n')
        run_shell_command('git add testfile6.txt')
        run_shell_command('git commit --amend --allow-empty --no-edit')
        self.assertEqual(self.run_uut(), [])
 def test_check_simple_git_commit(self):
     Path('testfile1.txt').touch()
     run_shell_command('git add testfile1.txt')
     run_shell_command('git commit -m "Add testfile1"')
     self.assertEqual(self.run_uut(), [])
Example #54
0
 def test_run_shell_command_kwargs_delegation(self):
     with self.assertRaises(TypeError):
         run_shell_command("super-cool-command", weird_parameter2="abc")
    def test_check_file_similarity_with_invalid_revert_commit(self):
        Path('testfile5.txt').touch()
        with open('testfile5.txt', 'w') as f:
            f.write('Some text\n')
        run_shell_command('git add testfile5.txt')
        run_shell_command('git commit -m "Initial commit"')

        with open('testfile5.txt', 'a') as f:
            f.write('Changed text\n')
        run_shell_command('git add testfile5.txt')
        run_shell_command('git commit -m "modify testfile5"')

        run_shell_command('git revert HEAD --no-edit')
        with open('testfile5.txt', 'a') as f:
            f.write('Some text\nSome more text\n')
        run_shell_command('git add testfile5.txt')
        run_shell_command('git commit --amend --allow-empty --no-edit')
        with open('testfile5.txt', 'a') as f:
            f.write('Even more text.\n')
        run_shell_command('git add testfile5.txt')
        run_shell_command('git commit --amend --allow-empty --no-edit')
        with open('testfile5.txt', 'a') as f:
            f.write('Last line\n')
        run_shell_command('git add testfile5.txt')
        run_shell_command('git commit --amend --allow-empty --no-edit')
        self.assertEqual(self.run_uut(),
                         ['Changes in modified file testfile5.txt of the '
                          'revert commit are not exactly revert of changes '
                          'in the reverted commit.'])
    def test_check_git_revert_commit_with_extra_added_file(self):
        Path('testfile1.txt').touch()
        with open('testfile1.txt', 'w') as f:
            f.write('Modify text')
        Path('testfile2.txt').touch()
        with open('testfile2.txt', 'w') as f:
            f.write('Modify text')
        run_shell_command('git add testfile1.txt')
        run_shell_command('git add testfile2.txt')
        run_shell_command('git commit -m "reverted commit"')

        run_shell_command('git revert HEAD --no-edit')
        Path('testfile3.txt').touch()
        run_shell_command('git add testfile3.txt')
        run_shell_command('git commit --amend --allow-empty --no-edit')

        self.assertEqual(self.run_uut(),
                         ['Revert commit has a added file testfile3.txt that '
                          'is not in the reverted commit.'])
    def test_check_git_revert_commit_with_extra_deleted_file(self):
        Path('testfile1.txt').touch()
        with open('testfile1.txt', 'w') as f:
            f.write('Some text')

        Path('testfile2.txt').touch()
        with open('testfile2.txt', 'w') as f:
            f.write('Some more text')

        run_shell_command('git add testfile1.txt')
        run_shell_command('git add testfile2.txt')
        run_shell_command('git commit -m "intial commit"')

        run_shell_command('git rm testfile1.txt')
        run_shell_command('git commit -m "delete file"')

        run_shell_command('git revert HEAD --no-edit')
        run_shell_command('git rm testfile2.txt')
        run_shell_command('git commit --amend --allow-empty --no-edit')

        self.assertEqual(self.run_uut(),
                         ['Revert commit has a deleted file testfile2.txt '
                          'that is not in the reverted commit.'])
    def test_check_modified_file_similarity_error(self, mock_run_shell_command):
        mock_run_shell_command.side_effect = [
            ShellCommandResult(0, 'M\ttestfile7.txt', sys.stderr),
            ShellCommandResult(0, None, sys.stderr),
            ShellCommandResult(0, ('', 'errors'), sys.stderr),
            ShellCommandResult(0, None, sys.stderr),
            ShellCommandResult(0, None, sys.stderr),
            ShellCommandResult(0, None, sys.stderr)
        ]

        Path('testfile7.txt').touch()
        with open('testfile7.txt', 'w') as f:
            f.write('Some other text\n')
        run_shell_command('git add testfile7.txt')
        run_shell_command('git commit -m "Initial commit"')

        with open('testfile7.txt', 'w') as f:
            f.write('Changed text\n')
        run_shell_command('git add testfile7.txt')
        run_shell_command('git commit -m "modify testfile6"')

        run_shell_command('git revert HEAD --no-edit')
        with open('testfile7.txt', 'w') as f:
            f.write('Some more text\n')
        run_shell_command('git add testfile7.txt')
        run_shell_command('git commit --amend --allow-empty --no-edit')

        assert self.run_uut() == []
        mock_run_shell_command.assert_has_calls(
            [unittest.mock.call('git revert --abort')])