Esempio n. 1
0
    def check(self, branch, old_sha, new_sha):
        logging.debug("Run: branch=%s, old_sha=%s, new_sha=%s",
                      branch, old_sha, new_sha)
        logging.debug("params=%s", self.params)

        permit = True

        # Do not run the hook if the branch is being deleted
        if new_sha == '0' * 40:
            logging.debug("Deleting the branch, skip the hook")
            return True, []

        # Before the hook is run git has already created
        # a new_sha commit object

        log = hookutil.parse_git_log(self.repo_dir, branch, old_sha, new_sha, this_branch_only=False)

        messages = []
        for commit in log:
            modfiles = hookutil.parse_git_show(self.repo_dir, commit['commit'], ['.py'])

            def has_mixed_indent(file_contents):
                '''
                Check if file lines start with tabs and spaces
                file_contents = open(file).read()
                '''
                has_tab = False
                has_space = False
                for line in file_contents.split('\n'):
                    if line.startswith('\t'):
                        has_tab = True
                    elif line.startswith(' '):
                        has_space = True
                    if has_tab and has_space:
                        return True
                return False

            # Get the files from the repo and check indentation.
            for modfile in modfiles:
                # Skip deleted files
                if modfile['status'] == 'D':
                    logging.debug("Deleted '%s', skip", modfile['path'])
                    continue

                cmd = ['git', 'show', modfile['new_blob']]
                _, file_contents, _ = hookutil.run(cmd, self.repo_dir)

                permit_file = not has_mixed_indent(file_contents)
                logging.debug("modfile=%s, permit_file=%s", modfile['path'], permit_file)

                if not permit_file:
                    messages.append({'at': commit['commit'],
                        'text': "Error: file '%s' has mixed indentation" % modfile['path']})

                permit = permit and permit_file

        logging.debug("Permit: %s", permit)

        return permit, messages
Esempio n. 2
0
    def check(self, branch, old_sha, new_sha):
        logging.debug("Run: branch=%s, old_sha=%s, new_sha=%s",
                      branch, old_sha, new_sha)
        logging.debug("params=%s", self.params)

        if not self.settings:
            return True

        permit = True

        # Do not run the hook if the branch is being deleted
        if new_sha == '0' * 40:
            logging.debug("Deleting the branch, skip the hook")
            return True, []

        # Before the hook is run git has already created
        # a new_sha commit object

        log = hookutil.parse_git_log(self.repo_dir, branch, old_sha, new_sha, this_branch_only=False)

        messages = []
        for commit in log:
            modfiles = hookutil.parse_git_show(self.repo_dir, commit['commit'])

            def has_good_copyright(file_contents, copyrights):
                '''
                Check if file contains good copyright string
                '''
                for (start, full) in copyrights:
                    if re.search(start, file_contents):
                        if not re.search(full, file_contents):
                            return False
                return True

            for modfile in modfiles:
                # Skip deleted files
                if modfile['status'] == 'D':
                    logging.debug("Deleted %s, skip", modfile['path'])
                    continue

                cmd = ['git', 'show', modfile['new_blob']]
                _, file_contents, _ = hookutil.run(cmd, self.repo_dir)

                permit_file = has_good_copyright(file_contents, self.settings)
                logging.debug("modfile='%s', permit_file='%s'", modfile['path'], permit_file)

                if not permit_file:
                    messages.append({'at': commit['commit'],
                        'text': "Error: Bad copyright in file '%s'!" % modfile['path']})
                permit = permit and permit_file

        if not permit:
            text = 'Please update the copyright strings to match one of the following:\n\n\t- ' + '\n\t- '.join([full for (start, full) in self.settings])
            messages.append({'at': new_sha, 'text': text + '\n'})

        logging.debug("Permit: %s", permit)

        return permit, messages
Esempio n. 3
0
    def check(self, branch, old_sha, new_sha):
        logging.debug("Run: branch=%s, old_sha=%s, new_sha=%s",
                      branch, old_sha, new_sha)
        logging.debug("params=%s", self.params)

        permit = True

        # Do not run the hook if the branch is being deleted
        if new_sha == '0' * 40:
            logging.debug("Deleting the branch, skip the hook")
            return True, []

        # Before the hook is run git has already created
        # a new_sha commit object

        log = hookutil.parse_git_log(self.repo_dir, branch, old_sha, new_sha, this_branch_only=False)

        messages = []
        for commit in log:
            modfiles = hookutil.parse_git_show(self.repo_dir, commit['commit'])

            def has_mixed_le(file_contents):
                '''
                Check if file contains both lf and crlf
                file_contents = open(file).read()
                '''
                if ('\r\n' in file_contents and
                        '\n' in file_contents.replace('\r\n', '')):
                    return True
                return False

            for modfile in modfiles:
                # Skip deleted files
                if modfile['status'] == 'D':
                    logging.debug("Deleted %s, skip", modfile['path'])
                    continue

                binary_attr = hookutil.get_attr(
                    self.repo_dir, new_sha, modfile['path'], 'binary')

                if binary_attr != 'set':
                    cmd = ['git', 'show', modfile['new_blob']]
                    _, file_contents, _ = hookutil.run(cmd, self.repo_dir)

                    permit_file = not has_mixed_le(file_contents)
                    logging.debug("modfile='%s', permit_file='%s'", modfile['path'], permit_file)

                    if not permit_file:
                        messages.append({'at': commit['commit'],
                            'text': "Error: file '%s' has mixed line endings (CRLF/LF)" % modfile['path']})

                    permit = permit and permit_file

        logging.debug("Permit: %s", permit)

        return permit, messages
Esempio n. 4
0
    def is_ff_push(self, old_sha, new_sha):
        '''
        Check if new_sha is a fast-forward reference.
        '''
        cmd = ['git', 'rev-list']
        if old_sha == '0' * 40:
            cmd += [new_sha]
        else:
            cmd += ["%s..%s" % (new_sha, old_sha)]

        _, refs, _ = hookutil.run(cmd, self.repo_dir)

        # It is a non-fast-forward push
        if refs:
            return False

        return True
Esempio n. 5
0
    def check(self, branch, old_sha, new_sha):
        logging.debug("Run: branch=%s, old_sha=%s, new_sha=%s",
                      branch, old_sha, new_sha)
        logging.debug("params=%s", self.params)

        permit = True


        log = hookutil.parse_git_log(self.repo_dir, branch, old_sha, new_sha, this_branch_only=False)

        for commit in log:
            print "Checking commit %s ..." % commit['commit']

            # Filter python scripts from the files modified in new_sha
            modfiles = hookutil.parse_git_show(self.repo_dir, commit['commit'], ['.py'])

            # Exit early if there are no modified python scripts in the changeset
            if not modfiles:
                return permit

            # Set up a working directory for pycodestyle and fill it with the blobs to be checked
            pycheck_workdir = tempfile.mkdtemp(suffix='pycheck')

            for modfile in modfiles:
                # Skip deleted files
                if modfile['status'] == 'D':
                    logging.debug("Deleted '%s', skip", modfile['path'])
                    continue

                cmd = ['git', 'show', modfile['new_blob']]
                _, file_contents, _ = hookutil.run(cmd, self.repo_dir)

                file_path = os.path.join(pycheck_workdir, modfile['path'])
                assert(not os.path.exists(file_path))

                file_dir = os.path.join(pycheck_workdir, os.path.dirname(modfile['path']))
                if not os.path.exists(file_dir):
                    os.makedirs(os.path.join(pycheck_workdir, os.path.dirname(modfile['path'])))

                with open(file_path, 'w') as fd:
                    fd.write(file_contents)

            # Copy setup.cfg to the working directory
            shutil.copy(os.path.join(os.path.dirname(__file__), 'setup.cfg'), pycheck_workdir)

            # Get the commit's diff; pycodestyle needs it to report only against modified lines
            cmd = ['git', 'show', commit['commit']]
            _, diff, _ = hookutil.run(cmd, self.repo_dir)

            local_dir = os.curdir
            os.chdir(pycheck_workdir)
            # Run pycodestyle in the working directory we have just prepared.
            selected_lines = pycodestyle.parse_udiff(diff, patterns=['*.py'], parent='')

            pep8style = pycodestyle.StyleGuide(
                {
                    'diff'          : True,
                    'paths'         : sorted(selected_lines),
                    'selected_lines': selected_lines,
                    'reporter'      : pycodestyle.DiffReport
                }
            )

            report = pep8style.check_files()
            os.chdir(local_dir)

            if report.total_errors:
                permit = False

            # Clean up
            shutil.rmtree(pycheck_workdir)

        logging.debug("Permit: %s" % permit)
        return permit, []
Esempio n. 6
0
    def check(self, branch, old_sha, new_sha):
        logging.debug("Run: branch=%s, old_sha=%s, new_sha=%s", branch,
                      old_sha, new_sha)
        logging.debug("params=%s", self.params)

        permit = True

        # Do not run the hook if the branch is being deleted
        if new_sha == '0' * 40:
            logging.debug("Deleting the branch, skip the hook")
            return True, []

        # Before the hook is run git has already created
        # a new_sha commit object

        log = hookutil.parse_git_log(self.repo_dir,
                                     branch,
                                     old_sha,
                                     new_sha,
                                     this_branch_only=False)

        messages = []
        for commit in log:
            modfiles = hookutil.parse_git_show(self.repo_dir, commit['commit'])

            def has_mixed_le(file_contents):
                '''
                Check if file contains both lf and crlf
                file_contents = open(file).read()
                '''
                if ('\r\n' in file_contents
                        and '\n' in file_contents.replace('\r\n', '')):
                    return True
                return False

            for modfile in modfiles:
                # Skip deleted files
                if modfile['status'] == 'D':
                    logging.debug("Deleted %s, skip", modfile['path'])
                    continue

                binary_attr = hookutil.get_attr(self.repo_dir, new_sha,
                                                modfile['path'], 'binary')

                if binary_attr != 'set':
                    cmd = ['git', 'show', modfile['new_blob']]
                    _, file_contents, _ = hookutil.run(cmd, self.repo_dir)

                    permit_file = not has_mixed_le(file_contents)
                    logging.debug("modfile='%s', permit_file='%s'",
                                  modfile['path'], permit_file)

                    if not permit_file:
                        messages.append({
                            'at':
                            commit['commit'],
                            'text':
                            "Error: file '%s' has mixed line endings (CRLF/LF)"
                            % modfile['path']
                        })

                    permit = permit and permit_file

        logging.debug("Permit: %s", permit)

        return permit, messages
Esempio n. 7
0
    def check(self, branch, old_sha, new_sha):
        logging.debug("Run: branch=%s, old_sha=%s, new_sha=%s", branch,
                      old_sha, new_sha)
        logging.debug("params=%s", self.params)

        if not self.settings:
            return True, []

        permit = True

        # Do not run the hook if the branch is being deleted
        if new_sha == '0' * 40:
            logging.debug("Deleting the branch, skip the hook")
            return True, []

        # Before the hook is run git has already created
        # a new_sha commit object

        log = hookutil.parse_git_log(self.repo_dir,
                                     branch,
                                     old_sha,
                                     new_sha,
                                     this_branch_only=False)

        messages = []
        for commit in log:
            modfiles = hookutil.parse_git_show(self.repo_dir, commit['commit'])

            def has_good_copyright(file_contents, copyrights):
                '''
                Check if file contains good copyright string
                '''
                for (start, full) in copyrights:
                    if re.search(start, file_contents):
                        if not re.search(full, file_contents):
                            return False
                return True

            for modfile in modfiles:
                # Skip deleted files
                if modfile['status'] == 'D':
                    logging.debug("Deleted %s, skip", modfile['path'])
                    continue

                cmd = ['git', 'show', modfile['new_blob']]
                _, file_contents, _ = hookutil.run(cmd, self.repo_dir)

                permit_file = has_good_copyright(file_contents, self.settings)
                logging.debug("modfile='%s', permit_file='%s'",
                              modfile['path'], permit_file)

                if not permit_file:
                    messages.append({
                        'at':
                        commit['commit'],
                        'text':
                        "Error: Bad copyright in file '%s'!" % modfile['path']
                    })
                permit = permit and permit_file

        if not permit:
            text = 'Please update the copyright strings to match one of the following:\n\n\t- ' + '\n\t- '.join(
                [full for (start, full) in self.settings])
            messages.append({'at': new_sha, 'text': text + '\n'})

        logging.debug("Permit: %s", permit)

        return permit, messages
Esempio n. 8
0
    def check(self, branch, old_sha, new_sha):
        logging.debug("Run: branch=%s, old_sha=%s, new_sha=%s", branch,
                      old_sha, new_sha)
        logging.debug("params=%s", self.params)

        # Do not run the hook if the branch is being deleted
        if new_sha == '0' * 40:
            logging.debug("Deleting the branch, skip the hook")
            return True, []

        def print_commit(commit, formatter='\t%s'):
            '''
            Print a commit using a formatter for each new line.
            The default formatter is a signle tabulation.
            '''
            return '\n'.join([
                formatter % i for i in [
                    "commit %s" % commit['commit'],
                    "Merge: %s %s" %
                    (parentCommits[0][:7], parentCommits[1][:7]),
                    "Author: %s <%s>" %
                    (commit['author_name'], commit['author_email']),
                    "Date:   %s" % commit['date']
                ] + [""] +  # Add a newline
                wrap(commit['message'], width=120) + [""]
            ])

        permit = True

        log = hookutil.parse_git_log(self.repo_dir,
                                     branch,
                                     old_sha,
                                     new_sha,
                                     this_branch_only=False)

        messages = []
        for commit in log:
            # Parse commit parents
            cmd = ['git', 'rev-list', '--parents', '-n', '1', commit['commit']]
            _, out, _ = hookutil.run(cmd, self.repo_dir)
            parentCommits = out.strip().split(' ')[1:]

            # Skip commit if it is not a merge commit
            if len(parentCommits) < 2:
                continue

            logging.debug("Found merge %s, parents: %s %s",
                          commit['commit'][:7], parentCommits[0][:7],
                          parentCommits[1][:7])

            # Find branches that contain parent commits
            parentBranches = []
            for parentCommit in parentCommits:
                cmd = ['git', 'branch', '--contains', parentCommit]
                ret, out, err = hookutil.run(cmd, self.repo_dir)
                # FIXME Skip if parent commit was not found on any branch
                if not out and not err and not ret:
                    # These are stdout, stderr and return code that Popen.wait produces for 'git branch --continue'
                    # with shell=False. When a commit does not exist in the remote, the command should return 129
                    # and an error meesage in stderr. With shell=True, it does not work as extected either (returns 1
                    # and git usage in stdout, similar to running just 'git' instead of 'git branch --continue ...').
                    continue
                if not out:
                    parentBranches.append(branch.replace('refs/heads/', ''))
                else:
                    parentBranches += [
                        br.replace("* ", "") for br in out.strip().split('\n')
                    ]

            if len(set(parentBranches)) != 1:
                continue

            mergedBranch = parentBranches[0]
            logging.debug("All parents are on branch '%s'", mergedBranch)

            # First parent must be on the destination branch
            firstParent = parentCommits[0]
            cmd = ['git', 'branch', '--contains', firstParent]
            _, out, _ = hookutil.run(cmd, self.repo_dir)

            if not out.startswith('* '):
                permit = False
                text = '\n'.join([
                    "Merging a remote branch onto a local branch is prohibited when updating the remote with that local branch.",
                    "",
                    print_commit(commit)
                ] + wrap(
                    "You must remove this merge by updating your local branch properly. Please rebase on top of the remote branch:",
                    width=120
                ) + ["",
                     "\tgit pull --rebase origin %s" % mergedBranch, ""])
                messages += [{'at': commit['commit'], 'text': text}]

                logging.info("%s is same-branch merge, permit = %s",
                             commit['commit'][:7], permit)

        logging.debug("Permit: %s", permit)

        return permit, messages