Skip to content

Instantly share code, notes, and snippets.

@hughdbrown
Last active October 18, 2017 20:21
Show Gist options
  • Save hughdbrown/8fdf99a931deea987de065581ae69060 to your computer and use it in GitHub Desktop.
Save hughdbrown/8fdf99a931deea987de065581ae69060 to your computer and use it in GitHub Desktop.
git-bisect function to find error that occurs in web browser
#!/usr/bin/env python
"""
git-bisect code for PRED-1765
"""
import os
import os.path
import sys
import subprocess
import logging
from datetime import datetime
from functools import wraps
BUFSIZE = 32 * 1024 * 1024
BASE_PATH = "/home/ubuntu/workspace/DataRobot/"
FORMAT = '%(asctime)-15s %(message)s'
logging.basicConfig(format=FORMAT, level=logging.DEBUG)
LOGGER = logging.getLogger(__name__)
def timer(func):
""" Timer decorator """
@wraps(func)
def wrapper(*args, **kwargs):
""" Wrapper for timer decorator """
s_time = datetime.now()
result = func(*args, **kwargs)
e_time = datetime.now()
LOGGER.info("{0} elapsed".format(e_time - s_time))
return result
return wrapper
def needs_patch():
""" Check if a patch needs to be applied """
with open(BASE_PATH + "tools/rabbitmq/start_rabbitmq.sh") as handle:
data = handle.read()
return any(
line.startswith('''rabbitmq_image="rabbitmq"''')
for line in data.splitlines()[:5]
)
def logger_fix():
""" Rewrite a file if required. Could be done better with `git apply` """
LOGGER.info("Checking if fix required for logging")
filename = BASE_PATH + "common/utilities/data_prep.py"
result, lineno = False, -1
with open(filename, "r") as handle:
data = [line.rstrip() for line in handle]
for i, line in enumerate(data):
if line == "LOGGER = common.LOGGER.get_LOGGER()":
result = True
lineno = i
break
if result:
LOGGER.debug("Rewriting {0} to replace LOGGER".format(filename))
data[lineno] = "import logging\nLOGGER = logging.getLogger(__name__)"
with open(filename, "w") as handle:
handle.write("\n".join(data) + "\n")
return int(result)
def test_for_failure():
""" Test whether process suceeded by grepping log file """
filenames = [
'logs/run_workers.err',
]
for filename in filenames:
filename = BASE_PATH + filename
if os.path.exists(filename):
with open(filename) as handle:
for line in handle:
line = line.rstrip()
if "Tried to combine with columns not present" in line:
LOGGER.debug("{0}: {1}".format(filename, line))
return 1
return 0
def get_git_revision():
""" Get current revision (for informational purposes) """
cmd = ["git", "rev-parse", "HEAD"]
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=BUFSIZE)
output, errors = proc.communicate()
if errors:
raise Exception(errors)
else:
return output.strip()
@timer
def run_update_env():
"""
Update env unconditionally. Otherwise, start.sh can get stuck waiting for
user interaction.
"""
LOGGER.info("Running update_env.sh")
cmd = [BASE_PATH + "tools/update_env.sh"]
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=BUFSIZE)
output, errors = proc.communicate()
output = output
errors = errors
LOGGER.debug("process return code; {0}".format(proc.returncode))
#LOGGER.info("Elapsed time to run tools/update_env.sh: {0}".format(e - s))
@timer
def run_start():
""" Start the web server """
LOGGER.info("Running start.sh")
cmd = [BASE_PATH + "start.sh", "-G"]
retcode = subprocess.call(cmd)
LOGGER.debug("process return code; {0}".format(retcode))
# LOGGER.info("Elapsed time to run start.sh: {0}".format(e - s))
@timer
def run_stop():
""" Start the web server """
LOGGER.info("Running stop.sh")
cmd = [BASE_PATH + "stop.sh"]
retcode = subprocess.call(cmd)
LOGGER.debug("process return code; {0}".format(retcode))
def apply_patch():
""" Apply a patch to a file if required """
LOGGER.info("Applying patch")
cmd = ["git", "apply", BASE_PATH + "../a.patch"]
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=BUFSIZE)
output, errors = proc.communicate()
if errors:
raise Exception(errors)
else:
LOGGER.info(output)
return 1
def run_stash():
""" Stash files to clean up after changes """
LOGGER.info("Running stash")
cmd = ["git", "stash"]
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=BUFSIZE)
output, errors = proc.communicate()
if errors:
raise Exception(errors)
else:
LOGGER.info(output)
def main():
""" Do everything. Return exit code for process (used by `git bisect`) """
try:
rev = get_git_revision()
print('-' * 30, rev)
# Fixes required to run code
changes = 0
if needs_patch():
changes += apply_patch()
changes += logger_fix()
# Prepare to run
run_update_env()
run_start()
# Wait for user to run tests
raw_input("Run tests, press key to continue >>> ")
result = test_for_failure()
# Undo changes applied to source code
# Could stash conditionally, but git craps out if you miss a required stash
run_stash()
return result
except Exception as exc:
print(exc)
return 1
if __name__ == '__main__':
sys.exit(main())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment