def _GenTSBotSpec(checkouts, change, changed_files, options): bot_spec = [] # Get try slaves from PRESUBMIT.py files if not specified. # Even if the diff comes from options.url, use the local checkout for bot # selection. try: import presubmit_support root_presubmit = checkouts[0].ReadRootFile('PRESUBMIT.py') if not change: if not changed_files: changed_files = checkouts[0].file_tuples change = presubmit_support.Change(options.name, '', checkouts[0].checkout_root, changed_files, options.issue, options.patchset, options.email) trybots = presubmit_support.DoGetTrySlaves( change, checkouts[0].GetFileNames(), checkouts[0].checkout_root, root_presubmit, options.project, options.verbose, sys.stdout) if trybots: old_style = filter(lambda x: isinstance(x, basestring), trybots) new_style = filter(lambda x: isinstance(x, tuple), trybots) # _ParseBotList's testfilter is set to None otherwise it will complain. bot_spec = _ApplyTestFilter(options.testfilter, _ParseBotList(old_style, None)) bot_spec.extend(_ApplyTestFilter(options.testfilter, new_style)) except ImportError: pass return bot_spec
def _GenTSBotSpec(checkouts, change, changed_files, options): bot_spec = [] # Get try slaves from PRESUBMIT.py files if not specified. # Even if the diff comes from options.url, use the local checkout for bot # selection. try: import presubmit_support root_presubmit = checkouts[0].ReadRootFile('PRESUBMIT.py') if not change: if not changed_files: changed_files = checkouts[0].file_tuples change = presubmit_support.Change(options.name, '', checkouts[0].checkout_root, changed_files, options.issue, options.patchset, options.email) masters = presubmit_support.DoGetTryMasters( change, checkouts[0].GetFileNames(), checkouts[0].checkout_root, root_presubmit, options.project, options.verbose, sys.stdout) # Compatibility for old checkouts and bots that were on tryserver.chromium. trybots = masters.get('tryserver.chromium', []) # Compatibility for checkouts that are not using tryserver.chromium # but are stuck with git-try or gcl-try. if not trybots and len(masters) == 1: trybots = masters.values()[0] if trybots: old_style = filter(lambda x: isinstance(x, basestring), trybots) new_style = filter(lambda x: isinstance(x, tuple), trybots) # _ParseBotList's testfilter is set to None otherwise it will complain. bot_spec = _ApplyTestFilter(options.testfilter, _ParseBotList(old_style, None)) bot_spec.extend(_ApplyTestFilter(options.testfilter, new_style)) except ImportError: pass return bot_spec
def TryChange(argv, change, swallow_exception, prog=None, extra_epilog=None): """ Args: argv: Arguments and options. change: Change instance corresponding to the CL. swallow_exception: Whether we raise or swallow exceptions. """ parser = gen_parser(prog) epilog = EPILOG % {'prog': prog} if extra_epilog: epilog += extra_epilog parser.epilog = epilog # Remove epilog formatting parser.format_epilog = lambda x: parser.epilog options, args = parser.parse_args(argv) # If they've asked for help, give it to them if len(args) == 1 and args[0] == 'help': parser.print_help() return 0 # If they've said something confusing, don't spawn a try job until you # understand what they want. if args: parser.error('Extra argument(s) "%s" not understood' % ' '.join(args)) if options.dry_run: options.verbose += 1 LOG_FORMAT = '%(levelname)s %(filename)s(%(lineno)d): %(message)s' if not swallow_exception: if options.verbose == 0: logging.basicConfig(level=logging.WARNING, format=LOG_FORMAT) elif options.verbose == 1: logging.basicConfig(level=logging.INFO, format=LOG_FORMAT) elif options.verbose > 1: logging.basicConfig(level=logging.DEBUG, format=LOG_FORMAT) logging.debug(argv) if (options.patchlevel is not None and (options.patchlevel < 0 or options.patchlevel > 10)): parser.error( 'Have you tried --port instead? You probably confused -p and -P.') # Strip off any @ in the user, otherwise svn gets confused. options.user = options.user.split('@', 1)[0] if options.rietveld_url: # Try to extract the review number if possible and fix the protocol. if not '://' in options.rietveld_url: options.rietveld_url = 'http://' + options.rietveld_url match = re.match(r'^(.*)/(\d+)/?$', options.rietveld_url) if match: if options.issue or options.patchset: parser.error( 'Cannot use both --issue and use a review number url') options.issue = int(match.group(2)) options.rietveld_url = match.group(1) try: changed_files = None # Always include os.getcwd() in the checkout settings. checkouts = [] path = os.getcwd() file_list = [] if options.files: file_list = options.files elif change: file_list = [f.LocalPath() for f in change.AffectedFiles()] if options.upstream_branch: path += '@' + options.upstream_branch # Clear file list so that the correct list will be retrieved from the # upstream branch. file_list = [] checkouts.append(GuessVCS(options, path, file_list)) checkouts[0].AutomagicalSettings() for item in options.sub_rep: # Pass file_list=None because we don't know the sub repo's file list. checkout = GuessVCS(options, os.path.join(checkouts[0].checkout_root, item), None) if checkout.checkout_root in [c.checkout_root for c in checkouts]: parser.error('Specified the root %s two times.' % checkout.checkout_root) checkouts.append(checkout) can_http = options.port and options.host can_svn = options.svn_repo # If there was no transport selected yet, now we must have enough data to # select one. if not options.send_patch and not (can_http or can_svn): parser.error('Please specify an access method.') # Convert options.diff into the content of the diff. if options.url: if options.files: parser.error( 'You cannot specify files and --url at the same time.') options.diff = urllib.urlopen(options.url).read() elif options.diff: if options.files: parser.error( 'You cannot specify files and --diff at the same time.') options.diff = gclient_utils.FileRead(options.diff, 'rb') elif options.issue and options.patchset is None: # Retrieve the patch from rietveld when the diff is not specified. # When patchset is specified, it's because it's done by gcl/git-try. api_url = '%s/api/%d' % (options.rietveld_url, options.issue) logging.debug(api_url) contents = json.loads(urllib.urlopen(api_url).read()) options.patchset = contents['patchsets'][-1] diff_url = ( '%s/download/issue%d_%d.diff' % (options.rietveld_url, options.issue, options.patchset)) diff = GetMungedDiff('', urllib.urlopen(diff_url).readlines()) options.diff = ''.join(diff[0]) changed_files = diff[1] else: # Use this as the base. root = checkouts[0].checkout_root diffs = [] for checkout in checkouts: raw_diff = checkout.GenerateDiff() if not raw_diff: logging.error('Empty or non-existant diff, exiting.') return 1 diff = raw_diff.splitlines(True) path_diff = gclient_utils.PathDifference( root, checkout.checkout_root) # Munge it. diffs.extend(GetMungedDiff(path_diff, diff)[0]) options.diff = ''.join(diffs) if not options.name: if options.issue: options.name = 'Issue %s' % options.issue else: options.name = 'Unnamed' print('Note: use --name NAME to change the try job name.') if not options.email: parser.error( 'Using an anonymous checkout. Please use --email or set ' 'the TRYBOT_RESULTS_EMAIL_ADDRESS environment variable.') print('Results will be emailed to: ' + options.email) if not options.bot: # Get try slaves from PRESUBMIT.py files if not specified. # Even if the diff comes from options.url, use the local checkout for bot # selection. try: import presubmit_support root_presubmit = checkouts[0].ReadRootFile('PRESUBMIT.py') if not change: if not changed_files: changed_files = checkouts[0].file_tuples change = presubmit_support.Change( options.name, '', checkouts[0].checkout_root, changed_files, options.issue, options.patchset, options.email) options.bot = presubmit_support.DoGetTrySlaves( change, checkouts[0].GetFileNames(), checkouts[0].checkout_root, root_presubmit, options.project, options.verbose, sys.stdout) except ImportError: pass if options.testfilter: bots = set() for bot in options.bot: assert ',' not in bot if bot.endswith(':compile'): # Skip over compile-only builders for now. continue bots.add(bot.split(':', 1)[0]) options.bot = list(bots) # If no bot is specified, either the default pool will be selected or the # try server will refuse the job. Either case we don't need to interfere. if any('triggered' in b.split(':', 1)[0] for b in options.bot): print >> sys.stderr, ( 'ERROR You are trying to send a job to a triggered bot. This type of' ' bot requires an\ninitial job from a parent (usually a builder). ' 'Instead send your job to the parent.\nBot list: %s' % options.bot) return 1 if options.print_bots: print 'Bots which would be used:' for bot in options.bot: print ' %s' % bot return 0 # Send the patch. if options.send_patch: # If forced. options.send_patch(options) PrintSuccess(options) return 0 try: if can_http: _SendChangeHTTP(options) PrintSuccess(options) return 0 except NoTryServerAccess: if not can_svn: raise _SendChangeSVN(options) PrintSuccess(options) return 0 except (InvalidScript, NoTryServerAccess), e: if swallow_exception: return 1 print >> sys.stderr, e return 1
def TryChange(argv, change, swallow_exception, prog=None, extra_epilog=None): """ Args: argv: Arguments and options. change: Change instance corresponding to the CL. swallow_exception: Whether we raise or swallow exceptions. """ # Parse argv parser = optparse.OptionParser(usage=USAGE, version=__version__, prog=prog) epilog = EPILOG % {'prog': prog} if extra_epilog: epilog += extra_epilog parser.epilog = epilog # Remove epilog formatting parser.format_epilog = lambda x: parser.epilog parser.add_option("-v", "--verbose", action="count", default=0, help="Prints debugging infos") group = optparse.OptionGroup(parser, "Result and status") group.add_option("-u", "--user", default=getpass.getuser(), help="Owner user name [default: %default]") group.add_option( "-e", "--email", default=os.environ.get('TRYBOT_RESULTS_EMAIL_ADDRESS', os.environ.get('EMAIL_ADDRESS')), help="Email address where to send the results. Use either " "the TRYBOT_RESULTS_EMAIL_ADDRESS environment " "variable or EMAIL_ADDRESS to set the email address " "the try bots report results to [default: %default]") group.add_option("-n", "--name", help="Descriptive name of the try job") group.add_option("--issue", type='int', help="Update rietveld issue try job status") group.add_option("--patchset", type='int', help="Update rietveld issue try job status. This is " "optional if --issue is used, In that case, the " "latest patchset will be used.") group.add_option("--dry_run", action='store_true', help="Don't send the try job. This implies --verbose, so " "it will print the diff.") parser.add_option_group(group) group = optparse.OptionGroup(parser, "Try job options") group.add_option("-b", "--bot", action="append", help="Only use specifics build slaves, ex: " "'--bot win,layout_mac'; see the try " "server waterfall for the slave's name") group.add_option("-r", "--revision", help="Revision to use for the try job; default: the " "revision will be determined by the try server; see " "its waterfall for more info") group.add_option("-c", "--clobber", action="store_true", help="Force a clobber before building; e.g. don't do an " "incremental build") # TODO(maruel): help="Select a specific configuration, usually 'debug' or " # "'release'" group.add_option("--target", help=optparse.SUPPRESS_HELP) group.add_option( "--project", help="Override which project to use. Projects are defined " "server-side to define what default bot set to use") group.add_option( "-t", "--testfilter", action="append", help="Add a gtest_filter to a test. Use multiple times to " "specify filters for different tests. (i.e. " "--testfilter base_unittests:ThreadTest.* " "--testfilter ui_tests) If you specify any testfilters " "the test results will not be reported in rietveld and " "only tests with filters will run.") parser.add_option_group(group) group = optparse.OptionGroup(parser, "Patch to run") group.add_option("-f", "--file", default=[], dest="files", metavar="FILE", action="append", help="Use many times to list the files to include in the " "try, relative to the repository root") group.add_option("--diff", help="File containing the diff to try") group.add_option("--url", help="Url where to grab a patch, e.g. " "http://example.com/x.diff") group.add_option("-R", "--rietveld_url", default="codereview.appspot.com", metavar="URL", help="Has 2 usages, both refer to the rietveld instance: " "Specify which code review patch to use as the try job " "or rietveld instance to update the try job results " "Default:%default") group.add_option("--root", help="Root to use for the patch; base subdirectory for " "patch created in a subdirectory") group.add_option("-p", "--patchlevel", type='int', metavar="LEVEL", help="Used as -pN parameter to patch") group.add_option("-s", "--sub_rep", action="append", default=[], help="Subcheckout to use in addition. This is mainly " "useful for gclient-style checkouts. In git, checkout " "the branch with changes first. Use @rev or " "@branch to specify the " "revision/branch to diff against. If no @branch is " "given the diff will be against the upstream branch. " "If @branch then the diff is branch..HEAD. " "All edits must be checked in.") group.add_option("--no_search", action="store_true", help=("Disable automatic search for gclient or repo " "checkout root.")) group.add_option( "-E", "--exclude", action="append", default=['ChangeLog'], metavar='REGEXP', help="Regexp patterns to exclude files. Default: %default") group.add_option("--upstream_branch", action="store", help="Specify the upstream branch to diff against in the " "main checkout") parser.add_option_group(group) group = optparse.OptionGroup(parser, "Access the try server by HTTP") group.add_option("--use_http", action="store_const", const=_SendChangeHTTP, dest="send_patch", help="Use HTTP to talk to the try server [default]") group.add_option("-H", "--host", help="Host address") group.add_option("-P", "--port", type="int", help="HTTP port") group.add_option("--proxy", help="HTTP proxy") parser.add_option_group(group) group = optparse.OptionGroup(parser, "Access the try server with SVN") group.add_option("--use_svn", action="store_const", const=_SendChangeSVN, dest="send_patch", help="Use SVN to talk to the try server") group.add_option( "-S", "--svn_repo", metavar="SVN_URL", help="SVN url to use to write the changes in; --use_svn is " "implied when using --svn_repo") parser.add_option_group(group) options, args = parser.parse_args(argv) # If they've asked for help, give it to them if len(args) == 1 and args[0] == 'help': parser.print_help() return 0 # If they've said something confusing, don't spawn a try job until you # understand what they want. if args: parser.error('Extra argument(s) "%s" not understood' % ' '.join(args)) if options.dry_run: options.verbose += 1 LOG_FORMAT = '%(levelname)s %(filename)s(%(lineno)d): %(message)s' if not swallow_exception: if options.verbose == 0: logging.basicConfig(level=logging.WARNING, format=LOG_FORMAT) elif options.verbose == 1: logging.basicConfig(level=logging.INFO, format=LOG_FORMAT) elif options.verbose > 1: logging.basicConfig(level=logging.DEBUG, format=LOG_FORMAT) logging.debug(argv) if (options.patchlevel is not None and (options.patchlevel < 0 or options.patchlevel > 10)): parser.error( 'Have you tried --port instead? You probably confused -p and -P.') # Strip off any @ in the user, otherwise svn gets confused. options.user = options.user.split('@', 1)[0] if options.rietveld_url: # Try to extract the review number if possible and fix the protocol. if not '://' in options.rietveld_url: options.rietveld_url = 'http://' + options.rietveld_url match = re.match(r'^(.*)/(\d+)/?$', options.rietveld_url) if match: if options.issue or options.patchset: parser.error( 'Cannot use both --issue and use a review number url') options.issue = int(match.group(2)) options.rietveld_url = match.group(1) try: changed_files = None # Always include os.getcwd() in the checkout settings. checkouts = [] path = os.getcwd() file_list = [] if options.files: file_list = options.files elif change: file_list = [f.LocalPath() for f in change.AffectedFiles()] if options.upstream_branch: path += '@' + options.upstream_branch # Clear file list so that the correct list will be retrieved from the # upstream branch. file_list = [] checkouts.append(GuessVCS(options, path, file_list)) checkouts[0].AutomagicalSettings() for item in options.sub_rep: # Pass file_list=None because we don't know the sub repo's file list. checkout = GuessVCS(options, os.path.join(checkouts[0].checkout_root, item), None) if checkout.checkout_root in [c.checkout_root for c in checkouts]: parser.error('Specified the root %s two times.' % checkout.checkout_root) checkouts.append(checkout) can_http = options.port and options.host can_svn = options.svn_repo # If there was no transport selected yet, now we must have enough data to # select one. if not options.send_patch and not (can_http or can_svn): parser.error('Please specify an access method.') # Convert options.diff into the content of the diff. if options.url: if options.files: parser.error( 'You cannot specify files and --url at the same time.') options.diff = urllib.urlopen(options.url).read() elif options.diff: if options.files: parser.error( 'You cannot specify files and --diff at the same time.') options.diff = gclient_utils.FileRead(options.diff, 'rb') elif options.issue and options.patchset is None: # Retrieve the patch from rietveld when the diff is not specified. # When patchset is specified, it's because it's done by gcl/git-try. if json is None: parser.error( 'json or simplejson library is missing, please install.') api_url = '%s/api/%d' % (options.rietveld_url, options.issue) logging.debug(api_url) contents = json.loads(urllib.urlopen(api_url).read()) options.patchset = contents['patchsets'][-1] diff_url = ( '%s/download/issue%d_%d.diff' % (options.rietveld_url, options.issue, options.patchset)) diff = GetMungedDiff('', urllib.urlopen(diff_url).readlines()) options.diff = ''.join(diff[0]) changed_files = diff[1] else: # Use this as the base. root = checkouts[0].checkout_root diffs = [] for checkout in checkouts: diff = checkout.GenerateDiff().splitlines(True) path_diff = gclient_utils.PathDifference( root, checkout.checkout_root) # Munge it. diffs.extend(GetMungedDiff(path_diff, diff)[0]) options.diff = ''.join(diffs) if not options.name: if options.issue: options.name = 'Issue %s' % options.issue else: options.name = 'Unnamed' print('Note: use --name NAME to change the try job name.') if not options.email: parser.error( 'Using an anonymous checkout. Please use --email or set ' 'the TRYBOT_RESULTS_EMAIL_ADDRESS environment variable.') print('Results will be emailed to: ' + options.email) if not options.bot: # Get try slaves from PRESUBMIT.py files if not specified. # Even if the diff comes from options.url, use the local checkout for bot # selection. try: import presubmit_support root_presubmit = checkouts[0].ReadRootFile('PRESUBMIT.py') if not change: if not changed_files: changed_files = checkouts[0].file_tuples change = presubmit_support.Change( options.name, '', checkouts[0].checkout_root, changed_files, options.issue, options.patchset, options.email) options.bot = presubmit_support.DoGetTrySlaves( change, checkouts[0].GetFileNames(), checkouts[0].checkout_root, root_presubmit, options.project, False, sys.stdout) except ImportError: pass # If no bot is specified, either the default pool will be selected or the # try server will refuse the job. Either case we don't need to interfere. # Send the patch. if options.send_patch: # If forced. options.send_patch(options) PrintSuccess(options) return 0 try: if can_http: _SendChangeHTTP(options) PrintSuccess(options) return 0 except NoTryServerAccess: if not can_svn: raise _SendChangeSVN(options) PrintSuccess(options) return 0 except (InvalidScript, NoTryServerAccess), e: if swallow_exception: return 1 print >> sys.stderr, e return 1