Browse files

Backed out changeset b4503e3f8412

--HG--
branch : production-0.8
  • Loading branch information...
1 parent 1a4a706 commit 0a98875c4ed2f7fe9ef88c42602ba8866ca2e069 @lsblakk lsblakk committed Dec 14, 2010
Showing with 168 additions and 1 deletion.
  1. +49 −0 process/release.py
  2. +119 −1 scheduler.py
View
49 process/release.py
@@ -8,6 +8,7 @@
from buildbot.status.mail import MailNotifier
from buildbot.process.factory import BuildFactory
from buildbot.process.properties import WithProperties
+from buildbot.steps.trigger import Trigger
from buildbotcustom.l10n import DependentL10n
from buildbotcustom.status.mail import ChangeNotifier
@@ -22,6 +23,8 @@
TuxedoEntrySubmitterFactory, makeDummyBuilder
from buildbotcustom.changes.ftppoller import FtpPoller, LocalesFtpPoller
from release.platforms import ftp_platform_map, sl_platform_map
+from buildbotcustom.scheduler import TriggerBouncerCheck
+import BuildSlaves
DEFAULT_L10N_CHUNKS = 15
@@ -32,6 +35,8 @@ def generateReleaseBranchObjects(releaseConfig, branchConfig, staging):
l10nChunks = releaseConfig.get('l10nChunks', DEFAULT_L10N_CHUNKS)
tools_repo = '%s%s' % (branchConfig['hgurl'],
branchConfig['build_tools_repo_path'])
+ config_repo = '%s%s' % (branchConfig['hgurl'],
+ branchConfig['config_repo_path'])
if staging:
branchConfigFile = "mozilla/staging_config.py"
else:
@@ -326,6 +331,27 @@ def l10nBuilders(platform):
)
schedulers.append(s)
+ mirror_scheduler1 = TriggerBouncerCheck(
+ name=builderPrefix('ready-for-qa'),
+ configRepo=config_repo,
+ minUptake=10000,
+ builderNames=[builderPrefix('ready_for_qa'),
+ builderPrefix('final_verification')],
+ username=BuildSlaves.tuxedoUsername,
+ password=BuildSlaves.tuxedoPassword)
+
+ schedulers.append(mirror_scheduler1)
+
+ mirror_scheduler2 = TriggerBouncerCheck(
+ name=builderPrefix('ready-for-release'),
+ configRepo=config_repo,
+ minUptake=45000,
+ builderNames=[builderPrefix('ready_for_release')],
+ username=BuildSlaves.tuxedoUsername,
+ password=BuildSlaves.tuxedoPassword)
+
+ schedulers.append(mirror_scheduler2)
+
# Purposely, there is not a Scheduler for ReleaseFinalVerification
# This is a step run very shortly before release, and is triggered manually
# from the waterfall
@@ -799,6 +825,13 @@ def l10nBuilders(platform):
scriptName='scripts/release/push-to-mirrors.sh',
)
+ push_to_mirrors_factory.addStep(Trigger(
+ schedulerNames=[builderPrefix('ready-for-qa'),
+ builderPrefix('ready-for-release')],
+ copy_properties=['revision', 'release_config']
+ ))
+
+
builders.append({
'name': builderPrefix('push_to_mirrors'),
'slavenames': branchConfig['platforms']['linux']['slaves'],
@@ -829,6 +862,22 @@ def l10nBuilders(platform):
'env': builder_env,
})
+ notify_builders.append(builderPrefix('final_verification'))
+
+ builders.append(makeDummyBuilder(
+ name=builderPrefix('ready_for_qa'),
+ slaves=branchConfig['platforms']['linux']['slaves'],
+ category=builderPrefix(''),
+ ))
+ notify_builders.append(builderPrefix('ready_for_qa'))
+
+ builders.append(makeDummyBuilder(
+ name=builderPrefix('ready_for_release'),
+ slaves=branchConfig['platforms']['linux']['slaves'],
+ category=builderPrefix(''),
+ ))
+ notify_builders.append(builderPrefix('ready_for_release'))
+
if releaseConfig['majorUpdateRepoPath']:
# Not attached to any Scheduler
major_update_factory = MajorUpdateFactory(
View
120 scheduler.py
@@ -3,17 +3,22 @@
# Contributor(s):
# Chris AtLee <catlee@mozilla.com>
-from twisted.internet import defer
+from twisted.internet import defer, reactor
from twisted.python import log
+from twisted.internet.task import LoopingCall
+from twisted.web.client import getPage
from buildbot.scheduler import Scheduler
from buildbot.schedulers.base import BaseScheduler
from buildbot.schedulers.timed import Nightly
+from buildbot.schedulers.triggerable import Triggerable
from buildbot.sourcestamp import SourceStamp
from buildbot.process.properties import Properties
from buildbot.util import now
+from util.tuxedo import get_release_uptake
+
import time
class MultiScheduler(Scheduler):
@@ -215,6 +220,119 @@ def do_add_build_and_remove_changes(t, buildersPerChange):
d.addCallback(lambda buildersPerChange: self.parent.db.runInteraction(do_add_build_and_remove_changes, buildersPerChange))
return d
+
+class TriggerBouncerCheck(Triggerable):
+
+ compare_attrs = Triggerable.compare_attrs + \
+ ('minUptake', 'configRepo', 'checkMARs', 'username',
+ 'password', 'pollInterval', 'pollTimeout')
+ working = False
+ loop = None
+ release_config = None
+ revision = None
+ configRepo = None
+
+ def __init__(self, minUptake, configRepo, checkMARs=True,
+ username=None, password=None, pollInterval=5*60,
+ pollTimeout=12*60*60, **kwargs):
+ self.minUptake = minUptake
+ self.configRepo = configRepo
+ self.checkMARs = checkMARs
+ self.username = username
+ self.password = password
+ self.pollInterval = pollInterval
+ self.pollTimeout = pollTimeout
+ self.ss = None
+ self.set_props = None
+ Triggerable.__init__(self, **kwargs)
+
+
+ def trigger(self, ss, set_props=None):
+ self.ss = ss
+ self.set_props = set_props
+
+ props = Properties()
+ props.updateFromProperties(self.properties)
+ if set_props:
+ props.updateFromProperties(set_props)
+
+ self.revision = props.getProperty('revision')
+ assert self.revision, 'revision should be set'
+ self.release_config = props.getProperty('release_config')
+ assert self.release_config, 'release_config should be set'
+
+ def _run_loop(_):
+ self.loop = LoopingCall(self.poll)
+ reactor.callLater(0, self.loop.start, self.pollInterval)
+ reactor.callLater(self.pollTimeout, self.stopLoop,
+ 'Timeout after %s' % self.pollTimeout)
+
+ d = self.getReleaseConfig()
+ d.addCallback(_run_loop)
+
+ def stopLoop(self, reason=None):
+ if reason:
+ log.msg('%s: Stopping uptake monitoring: %s' %
+ (self.__class__.__name__, reason))
+ if self.loop.running:
+ self.loop.stop()
+ else:
+ log.msg('%s: Loop has been alredy stopped' %
+ self.__class__.__name__)
+
+ def getReleaseConfig(self):
+ url = str('%s/raw-file/%s/%s' %
+ (self.configRepo, self.revision, self.release_config))
+ d = getPage(url)
+
+ def setReleaseConfig(res):
+ c = {}
+ exec res in c
+ self.release_config = c.get('releaseConfig')
+ log.msg('%s: release_config loaded' % self.__class__.__name__)
+
+ d.addCallback(setReleaseConfig)
+ return d
+
+ def poll(self):
+ if self.working:
+ log.msg('%s: Not polling because last poll is still working'
+ % self.__class__.__name__)
+ return defer.succeed(None)
+ self.working = True
+ log.msg('%s: polling' % self.__class__.__name__)
+ bouncerProductName = self.release_config.get('bouncerProductName') or \
+ self.release_config.get('productName').capitalize()
+ d = get_release_uptake(
+ tuxedoServerUrl=self.release_config.get('tuxedoServerUrl'),
+ bouncerProductName=bouncerProductName,
+ version=self.release_config.get('version'),
+ oldVersion=self.release_config.get('oldVersion'),
+ checkMARs=self.checkMARs,
+ username=self.username,
+ password=self.password)
+ d.addCallback(self.checkUptake)
+ d.addCallbacks(self.finished_ok, self.finished_failure)
+ return d
+
+ def checkUptake(self, uptake):
+ log.msg('%s: uptake is %s' % (self.__class__.__name__, uptake))
+ if uptake >= self.minUptake:
+ self.stopLoop('Reached required uptake: %s' % uptake)
+ Triggerable.trigger(self, self.ss, self.set_props)
+
+ def finished_ok(self, res):
+ log.msg('%s: polling finished' % (self.__class__.__name__))
+ assert self.working
+ self.working = False
+ return res
+
+ def finished_failure(self, f):
+ log.msg('%s failed:\n%s' % (self.__class__.__name__, f.getTraceback()))
+ assert self.working
+ self.working = False
+ return None # eat the failure
+
def makePropertiesScheduler(base_class, propfuncs, *args, **kw):
"""Return a subclass of `base_class` that will call each of `propfuncs` to
generate a set of properties to attach to new buildsets.

0 comments on commit 0a98875

Please sign in to comment.