| #!/usr/bin/python |
| # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Bugdroid Git implementation for the Skia repositories. |
| |
| Execute the script with the following command: |
| python bugdroid_git.py --repo /storage/skia-repos/skia \ |
| --log-file-name skia-bugdroid-log.txt |
| """ |
| |
| import logging |
| import optparse |
| import os |
| import sys |
| import time |
| import traceback |
| |
| from bugdroid import Bugdroid |
| |
| # Set the PYTHONPATH for this script to include skia_slave_scripts.utils. |
| sys.path.append( |
| os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir, |
| os.pardir, 'slave', 'skia_slave_scripts', 'utils')) |
| import shell_utils |
| |
| |
| # Time to sleep between repository polls. |
| SLEEP_BETWEEN_POLLS = 60 |
| # The user BugDroid is run as |
| BUGDROID_USER = 'skia-commit-bot@chromium.org' |
| # The number of times to retry the git fetch command if it fails. |
| RETRY_FETCH_COUNT = 5 |
| |
| |
| def main(): |
| parser = optparse.OptionParser() |
| parser.add_option('-a', '--allowed-projects', action='append', |
| default=['skia'], |
| dest='trackers', |
| help='issue trackers that can be updated') |
| parser.add_option('-e', '--default-project', dest='default_tracker', |
| help='the issue tracker to update if no project name is ' |
| 'given in the BUG= line', default='skia') |
| parser.add_option('-c', '--rev-link', dest='rev_link', |
| help='the link to the committed revision in the repository ' |
| 'Eg: https://skia.googlesource.com/skia/+/') |
| parser.add_option('-v', '--version', dest='version_string', |
| help='the version string to be printed in the log.', |
| default='1.0') |
| parser.add_option('-r', '--repo', dest='repo_location', |
| help='the complete path to the git repository bugdroid ' |
| 'should track.') |
| parser.add_option('-l', '--log-file-name', dest='log_file_name', |
| help='the name of the bugdroid log file, it will be ' |
| 'created in the same directory as this file.') |
| (options, _args) = parser.parse_args() |
| |
| # Validate arguments. |
| repo_location = options.repo_location |
| if not repo_location or not os.path.exists(repo_location): |
| raise Exception('Must specify a valid path to a repository using --repo') |
| |
| # Configure the logger |
| folder_path = os.path.dirname(os.path.abspath(__file__)) |
| log_file_path = os.path.join(folder_path, options.log_file_name) |
| logging.basicConfig(filename=log_file_path, level=logging.DEBUG, maxBytes=10) |
| |
| logging.debug('===========================================') |
| logging.debug(time.strftime('Bugdroid starting: %Y-%m-%d %H:%M:%S')) |
| logging.debug('Current bugdroid version %s' % options.version_string) |
| |
| # Find and use the .bugdroid_password file from the toplevel buildbot dir. |
| parent = os.path.dirname(os.path.abspath(__file__)) |
| password_path = os.path.join(parent, os.pardir, os.pardir, |
| '.bugdroid_password') |
| if os.path.exists(password_path): |
| logging.debug('Using the local password file: %s' % password_path) |
| password = open(password_path, 'r').readline().strip() |
| else: |
| logging.debug('No password file present, aborting!') |
| return 1 |
| bugger = Bugdroid(BUGDROID_USER, password) |
| if not bugger.login(): |
| logging.debug('Login failed, aborting.') |
| return 1 |
| |
| # Keep going till the process is killed by a Keyboard Interrupt. |
| try: |
| while True: |
| # Change cwd to the repo_location. |
| os.chdir(repo_location) |
| |
| # Do a git fetch on the specified repository. |
| git_fetch_cmd = ['git', 'fetch'] |
| for _ in range(RETRY_FETCH_COUNT): |
| try: |
| shell_utils.run(git_fetch_cmd) |
| break |
| except shell_utils.CommandFailedException: |
| # git fetch in bugdroid sometimes seems to fail with a 406. Retry when |
| # this happens. |
| traceback.print_exc() |
| else: |
| # If we get here then the git fetch command did not succeed and thus did |
| # not break out of the loop. |
| raise Exception('git fetch failed!') |
| |
| # Find all new commits. |
| git_rev_list_cmd = [ |
| 'git', |
| 'rev-list', |
| '--topo-order', |
| 'HEAD..origin/master', |
| ] |
| remaining_hashes = shell_utils.run(git_rev_list_cmd) |
| if remaining_hashes: |
| remaining_hashes = remaining_hashes.split() |
| while remaining_hashes: |
| next_hash = remaining_hashes.pop() |
| |
| # Checkout the next commit hash. |
| git_checkout_cmd = [ |
| 'git', |
| 'checkout', |
| next_hash |
| ] |
| shell_utils.run(git_checkout_cmd) |
| |
| # Run Bugdroid using the content_info of the hash. |
| get_content_info = [ |
| 'git', |
| 'show', |
| '--pretty=format:Commit: ' + |
| options.rev_link + '%h%n Email: %ae%n%n%s%n%n%b%n%ad', |
| '--name-status' |
| ] |
| content = shell_utils.run(get_content_info) |
| if not bugger.process_all_bugs(content, options.trackers, |
| options.default_tracker): |
| logging.debug('No bug ID was found in %s.', next_hash) |
| |
| # Wait for a minute before trying everything again |
| logging.debug('Sleeping %s seconds before trying again.', |
| SLEEP_BETWEEN_POLLS) |
| time.sleep(SLEEP_BETWEEN_POLLS) |
| |
| except KeyboardInterrupt as e: |
| logging.exception(e) |
| |
| logging.debug(time.strftime('Bugdroid exiting: %Y-%m-%d %H:%M:%S')) |
| |
| |
| if __name__ == '__main__': |
| main() |
| |