Skip to content

Instantly share code, notes, and snippets.

@rshipp
Created June 10, 2014 16:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rshipp/1fb1193e1e7df8f3ca7a to your computer and use it in GitHub Desktop.
Save rshipp/1fb1193e1e7df8f3ca7a to your computer and use it in GitHub Desktop.
#!/usr/bin/python
#
# pylintcodediff --- Locate pylint errors corresponding to changed lines
#
# Copyright (C) 2014 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Author: Anne Mulhern <amulhern@redhat.com>
from __future__ import print_function
import argparse
import os
import subprocess
import sys
def make_parser(parser):
parser.add_argument('commit',
help='most recent ignored commit')
parser.add_argument('--branch',
default='pylint-code-diff-test',
help='name of test branch')
parser.add_argument('--force',
action='store_true',
help='run anyway')
parser.add_argument('--pylint-log',
default='pylint-log',
help='path to pylint log')
def run_command(command):
""" Run a git command.
:return: (stdout, stderr, returncode) tuple
"""
proc = subprocess.Popen(command,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
(stdoutdata, stderrdata) = proc.communicate()
while True:
if proc.returncode is not None:
return (stdoutdata, stderrdata, proc.returncode)
def current_branch_name():
""" Reads current git branch from stdout.
:return: name of current git branch
:rtype: str
"""
command = [ 'git', 'rev-parse', '--abbrev-ref', 'HEAD']
(stdoutdata, _stderrdata, ret) = run_command(command)
if ret == 0:
return stdoutdata.strip()
else:
raise RuntimeError("failed to get current branch name")
def checkout_new_branch(branch):
""" Checkout a git branch.
:param str branch: Name of branch, should not currently exist.
"""
command = [ 'git', 'checkout', '-b', branch ]
(_stdoutdata, _stderrdata, ret) = run_command(command)
if ret != 0:
raise RuntimeError("failed to check out new branch %s" % branch)
def checkout_branch(branch, force=False):
""" Checkout a git branch.
:param str branch: Name of branch, should not currently exist.
"""
command = [ 'git', 'checkout', branch ]
if force:
command.append('-f')
(_stdoutdata, _stderrdata, ret) = run_command(command)
if ret != 0:
raise RuntimeError("failed to check out branch %s" % branch)
def remove_branch(branch):
""" Remove a git branch.
:param str branch: Name of branch, must exist.
"""
command = [ 'git', 'branch', '-D', branch ]
(_stdoutdata, _stderrdata, ret) = run_command(command)
if ret != 0:
raise RuntimeError("failed to delete branch %s" % branch)
def reset(commit):
""" Reset current branch to commit.
:param str commit: commit id
"""
command = [ 'git', 'reset', commit ]
(_stdoutdata, _stderrdata, ret) = run_command(command)
if ret != 0:
raise RuntimeError("failed to reset commit %s" % commit)
def diff_quality(pylint_file):
command = [ 'diff-quality', '--violations=pylint', pylint_file ]
(stdoutdata, _stderrdata, ret) = run_command(command)
if ret != 0:
raise RuntimeError("diff-quality did not complete succesfully")
print(stdoutdata)
def clean():
""" Checks whether git detects some changes in the current branch.
:return: True if git finds no changes, otherwise False
:rtype: bool
"""
command = [ 'git', 'diff-index', '--exit-code', '--cached', 'HEAD' ]
(_stdoutdata, _stderrdata, ret) = run_command(command)
if ret != 0:
return False
command = [ 'git', 'diff-files', '--exit-code' ]
(_stdoutdata, _stderrdata, ret) = run_command(command)
if ret != 0:
return False
return True
def main():
parser = argparse.ArgumentParser(description="Find pylint messages related to changes subsequent to given commit.")
make_parser(parser)
args = parser.parse_args()
branch = args.branch
commit = args.commit
force = args.force
if not force and not clean():
sys.exit(
"Your working branch has some changes that may be lost while "
"running this test. Use the --force flag to proceed anyway."
)
pylint_log = os.path.abspath(args.pylint_log)
if not os.path.isfile(pylint_log):
sys.exit("Pylint log file %s does not exist." % pylint_log)
try:
current_branch = current_branch_name()
checkout_new_branch(branch)
except RuntimeError as e:
sys.exit("Error setting up test branch: %s" % e)
try:
reset(commit)
diff_quality(pylint_log)
except RuntimeError as e:
print("Couldn't complete testing, trying to clean up: %s." % e, file=sys.stderr)
try:
checkout_branch(current_branch, force=True)
remove_branch(branch)
except RuntimeError as e:
sys.exit("Error cleaning up branch %s after testing: %s." % (branch, e))
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment