blob: f95ff2fd60fc10944942a5f262594c4eda9603ab [file] [log] [blame]
# Copyright (c) 2012 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.
import constants
import getpass
import json
import os
import shutil
import sys
import tempfile
import time
if __name__ == '__main__':
sys.path.insert(0, constants.SOURCE_ROOT)
from chromite.buildbot import repository
from chromite.buildbot import manifest_version
from chromite.lib import cros_build_lib
class RemoteTryJob(object):
"""Remote Tryjob that is submitted through a Git repo."""
EXT_SSH_URL = os.path.join(constants.GERRIT_SSH_URL,
INT_SSH_URL = os.path.join(constants.GERRIT_INT_SSH_URL,
# In version 3, remote patches have an extra field.
TRYSERVER_URL = 'http://chromegw/p/tryserver.chromiumos'
def __init__(self, options, bots, local_patches):
"""Construct the object.
options: The parsed options passed into cbuildbot.
bots: A list of configs to run tryjobs for.
local_patches: A list of LocalPatch objects.
self.options = options
self.user = getpass.getuser()
cwd = os.path.dirname(os.path.realpath(__file__))
self.user_email = cros_build_lib.GetProjectUserEmail(cwd)
cros_build_lib.Info('Using email:%s', self.user_email)
# Name of the job that appears on the waterfall.
patch_list = options.gerrit_patches + options.local_patches = ''
if options.branch != 'master': = '[%s] ' % options.branch += ','.join(patch_list)
self.bots = bots[:]
self.slaves_request = options.slaves
self.description = ('name: %s\n patches: %s\nbots: %s' %
(, patch_list, self.bots))
self.extra_args = options.pass_through_args
if '--buildbot' not in self.extra_args:
self.tryjob_repo = None
self.local_patches = local_patches
self.ssh_url = self.EXT_SSH_URL
self.manifest = None
if repository.IsARepoRoot(options.sourceroot):
self.manifest = cros_build_lib.ManifestCheckout.Cached(options.sourceroot)
if repository.IsInternalRepoCheckout(options.sourceroot):
self.ssh_url = self.INT_SSH_URL
def values(self):
return {
'bot' : self.bots,
'email' : [self.user_email],
'extra_args' : self.extra_args,
'name' :,
'slaves_request' : self.slaves_request,
'user' : self.user,
'version' : self.TRYJOB_FORMAT_VERSION,}
def _Submit(self, testjob, dryrun):
"""Internal submission function. See Submit() for arg description."""
current_time = str(int(time.time()))
ref_base = os.path.join('refs/tryjobs', self.user, current_time)
for patch in self.local_patches:
sha1 = patch.Sha1Hash()[:8]
# Isolate the name; if it's a tag or a remote, let through.
# Else if it's a branch, get the full branch name minus refs/heads.
local_branch = cros_build_lib.StripLeadingRefsHeads(patch.ref, False)
ref_final = os.path.join(ref_base, local_branch, sha1)
data = self.manifest.projects[patch.project]
patch.Upload(data['push_url'], ref_final, dryrun=dryrun)
tag = (constants.INTERNAL_PATCH_TAG if data['internal']
else constants.EXTERNAL_PATCH_TAG)
% (patch.project, local_branch, ref_final,
patch.tracking_branch, tag))
# TODO(rcui): convert to shallow clone when that's available.
repository.CloneGitRepo(self.tryjob_repo, self.ssh_url)
push_branch = manifest_version.PUSH_BRANCH
remote_branch = ('origin', 'test') if testjob else None
cros_build_lib.CreatePushBranch(push_branch, self.tryjob_repo, sync=False,
file_name = '%s.%s' % (self.user,
user_dir = os.path.join(self.tryjob_repo, self.user)
if not os.path.isdir(user_dir):
fullpath = os.path.join(user_dir, file_name)
with open(fullpath, 'w+') as job_desc_file:
json.dump(self.values, job_desc_file)
cros_build_lib.RunCommand(['git', 'add', fullpath], cwd=self.tryjob_repo)
extra_env = {
# The committer field makes sure the creds match what the remote
# gerrit instance expects while the author field allows lookup
# on the console to work.
'GIT_COMMITTER_EMAIL' : self.user_email,
'GIT_AUTHOR_EMAIL' : self.user_email,
cros_build_lib.RunCommand(['git', 'commit', '-m', self.description],
cwd=self.tryjob_repo, extra_env=extra_env)
push_branch, self.tryjob_repo, retries=3, dryrun=dryrun)
except cros_build_lib.RunCommandError:
'Failed to submit tryjob. This could be due to too many '
'submission requests by users. Please try again.')
def Submit(self, workdir=None, testjob=False, dryrun=False):
"""Submit the tryjob through Git.
workdir: The directory to clone tryjob repo into. If you pass this
in, you are responsible for deleting the directory. Used for
testjob: Submit job to the test branch of the tryjob repo. The tryjob
will be ignored by production master.
dryrun: Setting to true will run everything except the final submit step.
self.tryjob_repo = workdir
if self.tryjob_repo is None:
self.tryjob_repo = tempfile.mkdtemp()
self._Submit(testjob, dryrun)
if workdir is None:
def GetTrybotConsoleLink(self):
"""Get link to the console for the user."""
return ('%s/console?name=%s' % (self.TRYSERVER_URL, self.user_email))
def GetTrybotWaterfallLink(self):
"""Get link to the waterfall for the user."""
# Note that this will only show the jobs submitted by the user in the last
# 24 hours.
return ('%s/waterfall?committer=%s' % (self.TRYSERVER_URL, self.user_email))