Last active
October 18, 2017 20:21
-
-
Save hughdbrown/8fdf99a931deea987de065581ae69060 to your computer and use it in GitHub Desktop.
git-bisect function to find error that occurs in web browser
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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