blob: eb6fc9cf09ff2c86e12b54f44f391067cc8b8052 [file] [log] [blame]
#!/usr/bin/python
# 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 as cros_lib
class RemoteTryJob(object):
"""Remote Tryjob that is submitted through a Git repo."""
EXT_SSH_URL = os.path.join(constants.GERRIT_SSH_URL,
'chromiumos/tryjobs')
INT_SSH_URL = os.path.join(constants.GERRIT_INT_SSH_URL,
'chromeos/tryjobs')
# In version 2, the tryjob submission code handles adding the
# --remote-trybot flag.
TRYJOB_FORMAT_VERSION = 2
TRYSERVER_URL = 'http://chromegw/p/tryserver.chromiumos'
def __init__(self, options, bots, local_patches):
"""Construct the object.
Args:
options: The parsed options passed into cbuildbot.
bots: A list of configs to run tryjobs for.
local_patches: A list of LocalGitRepoPatch objects.
"""
self.options = options
self.user = getpass.getuser()
cwd = os.path.dirname(os.path.realpath(__file__))
self.user_email = cros_lib.GetProjectUserEmail(cwd)
# Name of the job that appears on the waterfall.
patch_list = options.gerrit_patches + options.local_patches
self.name = ','.join(patch_list)
self.bots = bots[:]
self.description = ('name: %s\n patches: %s\nbots: %s' %
(self.name, patch_list, self.bots))
self.buildroot = options.buildroot
self.extra_args = options.pass_through_args
if '--buildbot' not in self.extra_args:
self.extra_args.append('--remote-trybot')
self.tryjob_repo = None
self.local_patches = local_patches
self.ssh_url = self.EXT_SSH_URL
if (repository.IsARepoRoot(constants.SOURCE_ROOT)
and repository.IsInternalRepoCheckout(constants.SOURCE_ROOT)):
self.ssh_url = self.INT_SSH_URL
@property
def values(self):
return {
'user' : self.user,
'email' : [self.user_email],
'name' : self.name,
'bot' : self.bots,
'extra_args' : self.extra_args,
'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]
local_branch = os.path.basename(patch.ref)
ref_final = os.path.join(ref_base, local_branch, sha1)
patch.Upload(ref_final, dryrun=dryrun)
self.extra_args.append('--remote-patches=%s:%s:%s:%s'
% (patch.project, local_branch, ref_final,
patch.tracking_branch))
# 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_lib.CreatePushBranch(push_branch, self.tryjob_repo, sync=False,
remote_push_branch=remote_branch)
file_name = '%s.%s' % (self.user,
current_time)
user_dir = os.path.join(self.tryjob_repo, self.user)
if not os.path.isdir(user_dir):
os.mkdir(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_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. http://crosbug.com/27939
'GIT_COMMITTER_EMAIL' : self.user_email,
'GIT_AUTHOR_EMAIL' : self.user_email,
}
cros_lib.RunCommand(['git', 'commit', '-m', self.description],
cwd=self.tryjob_repo, extra_env=extra_env)
try:
cros_lib.GitPushWithRetry(push_branch, self.tryjob_repo, retries=3,
dryrun=dryrun)
except cros_lib.RunCommandError:
cros_lib.Error('Failed to submit tryjob. This could be due to too many '
'submission requests by users. Please try again.')
raise
def Submit(self, workdir=None, testjob=False, dryrun=False):
"""Submit the tryjob through Git.
Args:
workdir: The directory to clone tryjob repo into. If you pass this
in, you are responsible for deleting the directory. Used for
testing.
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()
try:
self._Submit(testjob, dryrun)
finally:
if workdir is None:
shutil.rmtree(self.tryjob_repo)
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))