Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(345)

Unified Diff: scripts/tools/blink_roller/auto_roll.py

Issue 2205383002: Remove Blink auto-roll script (scripts/tools/blink_roller/). (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/build.git@master
Patch Set: Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « scripts/tools/blink_roller/OWNERS ('k') | scripts/tools/blink_roller/auto_roll_test.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: scripts/tools/blink_roller/auto_roll.py
diff --git a/scripts/tools/blink_roller/auto_roll.py b/scripts/tools/blink_roller/auto_roll.py
deleted file mode 100755
index 1cbf24db9414ee8f8ed9a2381d84095332f95ab4..0000000000000000000000000000000000000000
--- a/scripts/tools/blink_roller/auto_roll.py
+++ /dev/null
@@ -1,443 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-
-"""Automates creation and management of DEPS roll CLs.
-
-This script is designed to be run in a loop (eg. with auto_roll_wrapper.sh) or
-on a timer. It may take one of several actions, depending on the state of
-in-progress DEPS roll CLs and the state of the repository:
-
-- If there is already a DEPS roll CL in the Commit Queue, just exit.
-- If there is an open DEPS roll CL which is not in the Commit Queue:
- - If there's a comment containing the "STOP" keyword, just exit.
- - Otherwise, close the issue and continue.
-- If there is no open DEPS roll CL, create one using the
- src/tools/safely-roll-deps.py script.
-"""
-
-
-import datetime
-import json
-import optparse
-import os.path
-import re
-import sys
-import textwrap
-import urllib2
-
-
-SCRIPTS_DIR = os.path.realpath(os.path.join(os.path.dirname(__file__),
- os.pardir, os.pardir))
-sys.path.insert(0, SCRIPTS_DIR)
-
-# pylint: disable=W0611
-from common import find_depot_tools
-
-import auth
-import rietveld
-import scm
-import subprocess2
-
-
-ROLL_DESCRIPTION_STR = (
-'''Roll %(dep_path)s %(before_rev)s:%(after_rev)s%(svn_range)s
-
-Summary of changes available at:
-%(revlog_url)s
-''')
-
-NO_TRY_STR = (
-'''
-Sheriffs: In case of breakage, do NOT revert this roll, revert the
-offending commit in the %(project)s repository instead.
-
-NOTRY=true''')
-
-BLINK_SHERIFF_URL = (
- 'http://build.chromium.org/p/chromium.webkit/sheriff_webkit.js')
-CHROMIUM_SHERIFF_URL = (
- 'http://build.chromium.org/p/chromium.webkit/sheriff.js')
-
-CQ_INCLUDE_TRYBOTS = 'CQ_INCLUDE_TRYBOTS='
-
-# Does not support unicode or special characters.
-VALID_EMAIL_REGEXP = re.compile(r'^[A-Za-z0-9\.&\'\+-/=_]+@'
- r'[A-Za-z0-9\.\-]+$')
-
-
-def _get_skia_sheriff():
- """Finds and returns the current Skia sheriff."""
- skia_sheriff_url = 'https://skia-tree-status.appspot.com/current-sheriff'
- return json.load(urllib2.urlopen(skia_sheriff_url))['username']
-
-
-def _complete_email(name):
- """If the name does not include '@', append '@chromium.org'."""
- if '@' not in name:
- return name + '@chromium.org'
- return name
-
-
-def _names_from_sheriff_js(sheriff_js):
- match = re.match(r'document.write\(\'(.*)\'\)', sheriff_js)
- emails_string = match.group(1)
- # Detect 'none (channel is sheriff)' text and ignore it.
- if 'channel is sheriff' in emails_string.lower():
- return []
- return map(str.strip, emails_string.split(','))
-
-
-def _email_is_valid(email):
- """Determines whether the given email address is valid."""
- return VALID_EMAIL_REGEXP.match(email) is not None
-
-
-def _filter_emails(emails):
- """Returns the given list with any invalid email addresses removed."""
- rv = []
- for email in emails:
- if _email_is_valid(email):
- rv.append(email)
- else:
- print 'WARNING: Not including %s (invalid email address)' % email
- return rv
-
-
-def _emails_from_url(sheriff_url):
- sheriff_js = urllib2.urlopen(sheriff_url).read()
- return map(_complete_email, _names_from_sheriff_js(sheriff_js))
-
-
-def _current_gardener_emails():
- return _emails_from_url(BLINK_SHERIFF_URL)
-
-
-def _current_sheriff_emails():
- return _emails_from_url(CHROMIUM_SHERIFF_URL)
-
-
-def _do_git_fetch(git_dir):
- subprocess2.check_call(['git', '--git-dir', git_dir, 'fetch'])
-
-
-PROJECT_CONFIGS = {
- 'blink': {
- 'extra_emails_fn': _current_gardener_emails,
- 'path_to_project': os.path.join('third_party', 'WebKit'),
- 'project_alias': 'webkit',
- },
- 'skia': {
- 'cq_extra_trybots': ['tryserver.blink:linux_blink_rel'],
- 'extra_emails_fn': lambda: [_get_skia_sheriff()],
- 'path_to_project': os.path.join('third_party', 'skia'),
- 'include_commit_log': True,
- # 'dry_run': True,
- },
-}
-
-
-class AutoRollException(Exception):
- pass
-
-
-class AutoRoller(object):
- RIETVELD_URL = 'https://codereview.chromium.org'
- RIETVELD_TIME_FORMAT = '%Y-%m-%d %H:%M:%S.%f'
- ROLL_TIME_LIMIT = datetime.timedelta(hours=24)
- STOP_NAG_TIME_LIMIT = datetime.timedelta(hours=12)
- ADMIN_EMAIL = 'dpranke@chromium.org'
-
- ROLL_DESCRIPTION_REGEXP = ROLL_DESCRIPTION_STR % {
- 'dep_path': '%(project)s',
- 'before_rev': '(?P<from_revision>[0-9a-fA-F]{2,40})',
- 'after_rev': '(?P<to_revision>[0-9a-fA-F]{2,40})',
- 'svn_range': '.*',
- 'revlog_url': '.+',
- }
-
- # FIXME: These are taken from gardeningserver.py and should be shared.
- CHROMIUM_SVN_DEPS_URL = 'http://src.chromium.org/chrome/trunk/src/DEPS'
-
- ROLL_BOT_INSTRUCTIONS = textwrap.dedent(
- '''This roll was created by the Blink AutoRollBot.
- http://www.chromium.org/blink/blinkrollbot''')
-
- PLEASE_RESUME_NAG = textwrap.dedent('''
- Rollbot was stopped by the presence of 'STOP' in an earlier comment.
- The last update to this issue was over %(stop_nag_timeout)s hours ago.
- Please close this issue as soon as possible to allow the bot to continue.
-
- Please email (%(admin)s) if the Rollbot is causing trouble.
- ''' % {'admin': ADMIN_EMAIL, 'stop_nag_timeout': STOP_NAG_TIME_LIMIT})
-
- def __init__(self, project, author, path_to_chrome, auth_config=None,
- options=None):
- self._author = author
- self._project = project
- self._path_to_chrome = path_to_chrome
- self._rietveld = rietveld.Rietveld(
- self.RIETVELD_URL, auth_config, self._author)
- self._notry = options and options.notry
- self._cached_last_roll_revision = None
-
- project_config = PROJECT_CONFIGS.get(self._project, {
- 'path_to_project': os.path.join('third_party', self._project),
- })
- self._project_alias = project_config.get('project_alias', self._project)
- self._path_to_project = project_config['path_to_project']
- self._get_extra_emails = project_config.get('extra_emails_fn', lambda: [])
- self._cq_extra_trybots = project_config.get('cq_extra_trybots', [])
- self._include_commit_log = project_config.get('include_commit_log', False)
- self._cq_dry_run = project_config.get('dry_run', False)
-
- self._chromium_git_dir = self._path_from_chromium_root('.git')
- self._project_git_dir = self._path_from_chromium_root(
- self._path_to_project, '.git')
- self._roll_description_regexp = (self.ROLL_DESCRIPTION_REGEXP % {
- 'project': 'src/' + self._path_to_project
- }).splitlines()[0]
-
- def _parse_time(self, time_string):
- return datetime.datetime.strptime(time_string, self.RIETVELD_TIME_FORMAT)
-
- def _url_for_issue(self, issue_number):
- return '%s/%d/' % (self.RIETVELD_URL, issue_number)
-
- def _search_for_active_roll(self):
- # FIXME: Rietveld.search is broken, we should use closed=False
- # but that sends closed=1, we want closed=3. Using closed=2
- # to that search translates it correctly to closed=3 internally.
- # https://code.google.com/p/chromium/issues/detail?id=242628
- for result in self._rietveld.search(owner=self._author, closed=2):
- if re.search(self._roll_description_regexp, result['subject']):
- return result
- return None
-
- def _rollbot_should_stop(self, issue):
- issue_number = issue['issue']
- for message in issue['messages']:
- if 'STOP' in message['text']:
- last_modified = self._parse_time(issue['modified'])
- time_since_last_comment = datetime.datetime.utcnow() - last_modified
- if time_since_last_comment > self.STOP_NAG_TIME_LIMIT:
- self._rietveld.add_comment(issue_number, self.PLEASE_RESUME_NAG)
-
- print '%s: Rollbot was stopped by %s on at %s, waiting.' % (
- self._url_for_issue(issue_number), message['sender'], message['date'])
- return True
- return False
-
- def _close_issue(self, issue_number, message=None):
- print 'Closing %s with message: \'%s\'' % (
- self._url_for_issue(issue_number), message)
- if message:
- self._rietveld.add_comment(issue_number, message)
- self._rietveld.close_issue(issue_number)
-
- def _path_from_chromium_root(self, *components):
- assert os.pardir not in components
- return os.path.join(self._path_to_chrome, *components)
-
- def _last_roll_revision(self):
- """Returns the revision of the last roll.
-
- Returns:
- revision of the last roll; either a 40-character Git commit hash or an
- SVN revision number.
- """
- if not self._cached_last_roll_revision:
- revinfo = subprocess2.check_output(['gclient', 'revinfo'],
- cwd=self._path_to_chrome)
- project_path = 'src/' + self._path_to_project
- for line in revinfo.splitlines():
- dep_path, source = line.split(': ', 1)
- if dep_path == project_path:
- self._cached_last_roll_revision = source.split('@')[-1]
- break
- assert len(self._cached_last_roll_revision) == 40
- return self._cached_last_roll_revision
-
- def _current_revision(self):
- git_revparse_cmd = ['git', '--git-dir', self._project_git_dir,
- 'rev-parse', 'origin/master']
- return subprocess2.check_output(git_revparse_cmd).rstrip()
-
- def _emails_to_cc_on_rolls(self):
- return _filter_emails(self._get_extra_emails())
-
- def _start_roll(self, last_roll_revision, new_roll_revision):
- roll_branch = '%s_roll' % self._project
- cwd_kwargs = {'cwd': self._path_to_chrome}
- subprocess2.check_call(['git', 'clean', '-d', '-f'], **cwd_kwargs)
- subprocess2.call(['git', 'rebase', '--abort'], **cwd_kwargs)
- subprocess2.call(['git', 'branch', '-D', roll_branch], **cwd_kwargs)
- subprocess2.check_call(['git', 'checkout', 'origin/master', '-f'],
- **cwd_kwargs)
- subprocess2.check_call(['git', 'checkout', '-b', roll_branch,
- '-t', 'origin/master', '-f'], **cwd_kwargs)
- try:
- subprocess2.check_call(['roll-dep-svn', self._path_to_project,
- new_roll_revision], **cwd_kwargs)
- subprocess2.check_call(['git', 'add', 'DEPS'], **cwd_kwargs)
- subprocess2.check_call(['git', 'commit', '--no-edit'], **cwd_kwargs)
- commit_msg = subprocess2.check_output(
- ['git', 'log', '-n1', '--format=%B', 'HEAD'],
- **cwd_kwargs).decode('utf-8')
-
- if self._notry:
- commit_msg += NO_TRY_STR % { 'project': self._project }
-
- upload_cmd = ['git', 'cl', 'upload', '--bypass-hooks', '-f']
- if self._cq_dry_run:
- upload_cmd.append('--cq-dry-run')
- else:
- upload_cmd.append('--use-commit-queue')
- if self._cq_extra_trybots:
- commit_msg += ('\n' + CQ_INCLUDE_TRYBOTS +
- ','.join(self._cq_extra_trybots))
- tbr = '\nTBR='
- emails = self._emails_to_cc_on_rolls()
- if emails:
- emails_str = ','.join(emails)
- tbr += emails_str
- upload_cmd.extend(['--cc', emails_str, '--send-mail'])
- commit_msg += tbr
- if self._include_commit_log:
- log_cmd = ['git', 'log', '--format=%h %ae %s',
- '%s..%s' % (last_roll_revision, new_roll_revision)]
- git_log = subprocess2.check_output(log_cmd, cwd=self._project_git_dir)
- commit_msg += '\n\nCommits in this roll:\n' + git_log.decode('utf-8')
- upload_cmd.extend(['-m', commit_msg])
- subprocess2.check_call(upload_cmd, **cwd_kwargs)
- finally:
- subprocess2.check_call(['git', 'checkout', 'origin/master', '-f'],
- **cwd_kwargs)
- subprocess2.check_call(
- ['git', 'branch', '-D', roll_branch], **cwd_kwargs)
-
- # FIXME: It's easier to pull the issue id from rietveld rather than
- # parse it from the safely-roll-deps output. Once we inline
- # safely-roll-deps into this script this can go away.
- search_result = self._search_for_active_roll()
- if search_result:
- self._rietveld.add_comment(search_result['issue'],
- self.ROLL_BOT_INSTRUCTIONS)
-
- def _maybe_close_active_roll(self, issue):
- issue_number = issue['issue']
-
- # If the CQ failed, this roll is DOA.
- if not issue['commit']:
- self._close_issue(
- issue_number,
- 'No longer marked for the CQ. Closing, will open a new roll.')
- return True
-
- create_time = self._parse_time(issue['created'])
- time_since_roll = datetime.datetime.utcnow() - create_time
- print '%s started %s ago' % (
- self._url_for_issue(issue_number), time_since_roll)
- if time_since_roll > self.ROLL_TIME_LIMIT:
- self._close_issue(
- issue_number,
- 'Giving up on this roll after %s. Closing, will open a new roll.' %
- self.ROLL_TIME_LIMIT)
- return True
-
- last_roll_revision = self._short_rev(self._last_roll_revision())
- match = re.match(self._roll_description_regexp, issue['subject'])
- if match.group('from_revision') != last_roll_revision:
- self._close_issue(
- issue_number,
- 'DEPS has already rolled to %s. Closing, will open a new roll.' %
- last_roll_revision)
- return True
-
- return False
-
- def _compare_revisions(self, last_roll_revision, new_roll_revision):
- """Ensure that new_roll_revision is newer than last_roll_revision."""
- # Ensure that new_roll_revision is not an ancestor of old_roll_revision.
- try:
- subprocess2.check_call(['git', '--git-dir', self._project_git_dir,
- 'merge-base', '--is-ancestor',
- new_roll_revision, last_roll_revision])
- print ('Already at %s refusing to roll backwards to %s.' % (
- last_roll_revision, new_roll_revision))
- return False
- except subprocess2.CalledProcessError:
- pass
- return True
-
- def _short_rev(self, revision):
- """Shorten a Git commit hash."""
- return subprocess2.check_output(['git', '--git-dir', self._project_git_dir,
- 'rev-parse', '--short', revision]
- ).rstrip()
-
- def main(self):
- _do_git_fetch(self._chromium_git_dir)
- _do_git_fetch(self._project_git_dir)
-
- search_result = self._search_for_active_roll()
- issue_number = search_result['issue'] if search_result else None
- if issue_number:
- issue = self._rietveld.get_issue_properties(issue_number, messages=True)
- else:
- issue = None
-
- if issue:
- if self._rollbot_should_stop(issue):
- return 1
- if not self._maybe_close_active_roll(issue):
- print '%s is still active, nothing to do.' % \
- self._url_for_issue(issue_number)
- return 0
-
- last_roll_revision = self._last_roll_revision()
- new_roll_revision = self._current_revision()
-
- if not new_roll_revision:
- raise AutoRollException(
- 'Could not determine the current revision.')
-
- if not self._compare_revisions(last_roll_revision, new_roll_revision):
- return 0
-
- self._start_roll(last_roll_revision, new_roll_revision)
- return 0
-
-
-def main():
- usage = 'Usage: %prog project_name author path_to_chromium'
-
- # The default HelpFormatter causes the docstring to display improperly.
- class VanillaHelpFormatter(optparse.IndentedHelpFormatter):
- def format_description(self, description):
- if description:
- return description
- else:
- return ''
-
- parser = optparse.OptionParser(usage=usage,
- description=sys.modules[__name__].__doc__,
- formatter=VanillaHelpFormatter())
-
- parser.add_option('--no-try', action='store_true', dest='notry',
- help='Create the CL with NOTRY=true')
-
- auth.add_auth_options(parser)
- options, args = parser.parse_args()
- auth_config = auth.extract_auth_config_from_options(options)
- if len(args) != 3:
- parser.print_usage()
- return 1
-
- AutoRoller(*args, auth_config=auth_config, options=options).main()
-
-
-if __name__ == '__main__':
- sys.exit(main())
« no previous file with comments | « scripts/tools/blink_roller/OWNERS ('k') | scripts/tools/blink_roller/auto_roll_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698