Title: [273742] trunk/Tools
Revision
273742
Author
aakash_j...@apple.com
Date
2021-03-02 11:18:10 -0800 (Tue, 02 Mar 2021)

Log Message

Make build.webkit.org loadconfig similar to EWS
https://bugs.webkit.org/show_bug.cgi?id=222597

Reviewed by Jonathan Bedard.

* CISupport/build-webkit-org/loadConfig.py:
(loadBuilderConfig):
(checkValidWorker): Method to validate worker.
(checkValidBuilder): Method to validate builder.
(checkValidSchedulers): Method to validate schedulers.
(doesTriggerExist):
(isTriggerUsedByAnyBuilder):
(checkWorkersAndBuildersForConsistency):
* CISupport/build-webkit-org/loadConfig_unittest.py: Added unit-tests.
(ConfigDotJSONTest.test_configuration):
(TestcheckValidWorker):
(TestcheckValidWorker.test_invalid_worker):
(TestcheckValidWorker.test_worker_with_missing_name):
(TestcheckValidWorker.test_worker_with_missing_platName):
(TestcheckValidWorker.test_valid_worker):
(TestcheckValidBuilder):
(TestcheckValidBuilder.test_invalid_builder):
(TestcheckValidBuilder.test_builder_with_missing_name):
(TestcheckValidBuilder.test_builder_with_invalid_identifier):
(TestcheckValidBuilder.test_builder_with_extra_long_name):
(TestcheckValidBuilder.test_builder_with_invalid_configuration):
(TestcheckValidBuilder.test_builder_with_missing_factory):
(TestcheckValidBuilder.test_builder_with_missing_scheduler):
(TestcheckValidBuilder.test_builder_with_missing_platform):
(TestcheckValidBuilder.test_valid_builder):
(TestcheckWorkersAndBuildersForConsistency):
(TestcheckWorkersAndBuildersForConsistency.test_checkWorkersAndBuildersForConsistency):
(TestcheckWorkersAndBuildersForConsistency.test_checkWorkersAndBuildersForConsistency1):
(TestcheckWorkersAndBuildersForConsistency.test_duplicate_worker):
(TestcheckWorkersAndBuildersForConsistency.test_success):
* CISupport/ews-build/loadConfig.py:
(checkWorkersAndBuildersForConsistency): Added double-quotes in error message for better readability.
* CISupport/ews-build/loadConfig_unittest.py:
(TestcheckWorkersAndBuildersForConsistency.test_checkWorkersAndBuildersForConsistency1):

Modified Paths

Diff

Modified: trunk/Tools/CISupport/build-webkit-org/loadConfig.py (273741 => 273742)


--- trunk/Tools/CISupport/build-webkit-org/loadConfig.py	2021-03-02 19:16:10 UTC (rev 273741)
+++ trunk/Tools/CISupport/build-webkit-org/loadConfig.py	2021-03-02 19:18:10 UTC (rev 273742)
@@ -20,24 +20,23 @@
 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+
+import json
+import operator
 import os
+import re
 
-from buildbot.worker import Worker
 from buildbot.scheduler import AnyBranchScheduler, Triggerable, Nightly
 from buildbot.schedulers.forcesched import FixedParameter, ForceScheduler, StringParameter, BooleanParameter
 from buildbot.schedulers.filter import ChangeFilter
 from buildbot.process import buildstep, factory, properties
+from buildbot.util import identifiers as buildbot_identifiers
+from buildbot.worker import Worker
 
 from factories import *
-
-import re
-import json
-import operator
-
 import wkbuild
 
 trunk_filter = ChangeFilter(branch=["trunk", None])
-buildbot_identifiers_re = re.compile('^[a-zA-Z_-][a-zA-Z0-9_-]*$')
 
 BUILDER_NAME_LENGTH_LIMIT = 70
 STEP_NAME_LENGTH_LIMIT = 50
@@ -47,17 +46,20 @@
     return max(requests, key=operator.attrgetter("submittedAt"))
 
 
-def loadBuilderConfig(c, is_test_mode_enabled=False):
+def loadBuilderConfig(c, is_test_mode_enabled=False, master_prefix_path='./'):
     # FIXME: These file handles are leaked.
+    config = json.load(open(os.path.join(master_prefix_path, 'config.json')))
     if is_test_mode_enabled:
         passwords = {}
     else:
-        passwords = json.load(open('passwords.json'))
+        passwords = json.load(open(os.path.join(master_prefix_path, 'passwords.json')))
     results_server_api_key = passwords.get('results-server-api-key')
     if results_server_api_key:
         os.environ['RESULTS_SERVER_API_KEY'] = results_server_api_key
 
-    config = json.load(open('config.json'))
+    checkWorkersAndBuildersForConsistency(config, config['workers'], config['builders'])
+    checkValidSchedulers(config, config['schedulers'])
+
     c['workers'] = [Worker(worker['name'], passwords.get(worker['name'], 'password'), max_builds=1) for worker in config['workers']]
 
     c['schedulers'] = []
@@ -77,37 +79,24 @@
 
     c['builders'] = []
     for builder in config['builders']:
-        for workerName in builder['workernames']:
-            for worker in config['workers']:
-                if worker['name'] != workerName or worker['platform'] == '*':
-                    continue
-
-                if worker['platform'] != builder['platform']:
-                    raise Exception('Builder {} is for platform {} but has worker {} for platform {}!'.format(builder['name'], builder['platform'], worker['name'], worker['platform']))
-                break
-
+        builder['tags'] = getTagsForBuilder(builder)
         platform = builder['platform']
-
         factoryName = builder.pop('factory')
         factory = globals()[factoryName]
         factorykwargs = {}
-        for key in "platform", "configuration", "architectures", "triggers", "additionalArguments", "device_model":
+        for key in ['platform', 'configuration', 'architectures', 'triggers', 'additionalArguments', 'device_model']:
             value = builder.pop(key, None)
             if value:
                 factorykwargs[key] = value
 
-        builder["factory"] = factory(**factorykwargs)
+        builder['factory'] = factory(**factorykwargs)
 
         builder_name = builder['name']
-        if len(builder_name) > BUILDER_NAME_LENGTH_LIMIT:
-            raise Exception('Builder name "{}" is longer than maximum allowed by Buildbot ({} characters).'.format(builder_name, BUILDER_NAME_LENGTH_LIMIT))
-        if not buildbot_identifiers_re.match(builder_name):
-            raise Exception('Builder name "{}" is not a valid buildbot identifier.'.format(builder_name))
         for step in builder["factory"].steps:
             step_name = step.buildStep().name
             if len(step_name) > STEP_NAME_LENGTH_LIMIT:
                 raise Exception('step name "{}" is longer than maximum allowed by Buildbot ({} characters).'.format(step_name, STEP_NAME_LENGTH_LIMIT))
-            if not buildbot_identifiers_re.match(step_name):
+            if not buildbot_identifiers.ident_re.match(step_name):
                 raise Exception('step name "{}" is not a valid buildbot identifier.'.format(step_name))
 
         if platform.startswith('mac'):
@@ -130,7 +119,6 @@
         if (category in ('AppleMac', 'AppleWin', 'iOS')) and factoryName != 'BuildFactory':
             builder['nextBuild'] = pickLatestBuild
 
-        builder['tags'] = getTagsForBuilder(builder)
         c['builders'].append(builder)
 
 
@@ -144,6 +132,91 @@
         return wkbuild.should_build(self.platform, change.files)
 
 
+def checkValidWorker(worker):
+    if not worker:
+        raise Exception('Worker is None or Empty.')
+
+    if not worker.get('name'):
+        raise Exception('Worker "{}" does not have name defined.'.format(worker))
+
+    if not worker.get('platform'):
+        raise Exception('Worker {} does not have platform defined.'.format(worker['name']))
+
+
+def checkValidBuilder(config, builder):
+    if not builder:
+        raise Exception('Builder is None or Empty.')
+
+    if not builder.get('name'):
+        raise Exception('Builder "{}" does not have name defined.'.format(builder))
+
+    if not buildbot_identifiers.ident_re.match(builder['name']):
+        raise Exception('Builder name {} is not a valid buildbot identifier.'.format(builder['name']))
+
+    if len(builder['name']) > BUILDER_NAME_LENGTH_LIMIT:
+        raise Exception('Builder name {} is longer than maximum allowed by Buildbot ({} characters).'.format(builder['name'], BUILDER_NAME_LENGTH_LIMIT))
+
+    if 'configuration' in builder and builder['configuration'] not in ['debug', 'production', 'release']:
+        raise Exception('Invalid configuration: {} for builder: {}'.format(builder.get('configuration'), builder.get('name')))
+
+    if not builder.get('factory'):
+        raise Exception('Builder {} does not have factory defined.'.format(builder['name']))
+
+    if not builder.get('platform'):
+        raise Exception('Builder {} does not have platform defined.'.format(builder['name']))
+
+    for trigger in builder.get('triggers') or []:
+        if not doesTriggerExist(config, trigger):
+            raise Exception('Trigger: {} in builder {} does not exist in list of Trigerrable schedulers.'.format(trigger, builder['name']))
+
+
+def checkValidSchedulers(config, schedulers):
+    for scheduler in config.get('schedulers') or []:
+        if scheduler.get('type') == 'Triggerable':
+            if not isTriggerUsedByAnyBuilder(config, scheduler['name']) and 'build' not in scheduler['name'].lower():
+                raise Exception('Trigger: {} is not used by any builder in config.json'.format(scheduler['name']))
+
+
+def doesTriggerExist(config, trigger):
+    for scheduler in config.get('schedulers') or []:
+        if scheduler.get('name') == trigger:
+            return True
+    return False
+
+
+def isTriggerUsedByAnyBuilder(config, trigger):
+    for builder in config.get('builders'):
+        if trigger in (builder.get('triggers') or []):
+            return True
+    return False
+
+
+def checkWorkersAndBuildersForConsistency(config, workers, builders):
+    def _find_worker_with_name(workers, worker_name):
+        result = None
+        for worker in workers:
+            if worker['name'] == worker_name:
+                if not result:
+                    result = worker
+                else:
+                    raise Exception('Duplicate worker entry found for {}.'.format(worker['name']))
+        return result
+
+    for worker in workers:
+        checkValidWorker(worker)
+
+    for builder in builders:
+        checkValidBuilder(config, builder)
+        for worker_name in builder['workernames']:
+            worker = _find_worker_with_name(workers, worker_name)
+            if worker is None:
+                raise Exception('Builder {} has worker {}, which is not defined in workers list!'.format(builder['name'], worker_name))
+
+            if worker['platform'] != builder['platform'] and worker['platform'] != '*' and builder['platform'] != '*':
+                raise Exception('Builder "{0}" is for platform "{1}", but has worker "{2}" for platform "{3}"!'.format(
+                    builder['name'], builder['platform'], worker['name'], worker['platform']))
+
+
 def getInvalidTags():
     """
     We maintain a list of words which we do not want to display as tag in buildbot.

Modified: trunk/Tools/CISupport/build-webkit-org/loadConfig_unittest.py (273741 => 273742)


--- trunk/Tools/CISupport/build-webkit-org/loadConfig_unittest.py	2021-03-02 19:16:10 UTC (rev 273741)
+++ trunk/Tools/CISupport/build-webkit-org/loadConfig_unittest.py	2021-03-02 19:18:10 UTC (rev 273742)
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #
-# Copyright (C) 2020 Apple Inc. All rights reserved.
+# Copyright (C) 2020-2021 Apple Inc. All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions
@@ -29,11 +29,16 @@
 
 import loadConfig
 
+
 class ConfigDotJSONTest(unittest.TestCase):
     def get_config(self):
         cwd = os.path.dirname(os.path.abspath(__file__))
         return json.load(open(os.path.join(cwd, 'config.json')))
 
+    def test_configuration(self):
+        cwd = os.path.dirname(os.path.abspath(__file__))
+        loadConfig.loadBuilderConfig({}, is_test_mode_enabled=True, master_prefix_path=cwd)
+
     def test_builder_keys(self):
         config = self.get_config()
         valid_builder_keys = ['additionalArguments', 'architectures', 'builddir', 'configuration', 'description',
@@ -97,6 +102,98 @@
         self.assertEqual(invalidTags, expectedTags)
 
 
+class TestcheckValidWorker(unittest.TestCase):
+    def test_invalid_worker(self):
+        with self.assertRaises(Exception) as context:
+            loadConfig.checkValidWorker({})
+        self.assertEqual(context.exception.args, ('Worker is None or Empty.',))
+
+    def test_worker_with_missing_name(self):
+        with self.assertRaises(Exception) as context:
+            loadConfig.checkValidWorker({'platform': 'mac-sierra'})
+        self.assertEqual(context.exception.args, ('Worker "{\'platform\': \'mac-sierra\'}" does not have name defined.',))
+
+    def test_worker_with_missing_platName(self):
+        with self.assertRaises(Exception) as context:
+            loadConfig.checkValidWorker({'name': 'ews101'})
+        self.assertEqual(context.exception.args, ('Worker ews101 does not have platform defined.',))
+
+    def test_valid_worker(self):
+        loadConfig.checkValidWorker({'name': 'ews101', 'platform': 'mac-sierra'})
+
+
+class TestcheckValidBuilder(unittest.TestCase):
+    def test_invalid_builder(self):
+        with self.assertRaises(Exception) as context:
+            loadConfig.checkValidBuilder({}, {})
+        self.assertEqual(context.exception.args, ('Builder is None or Empty.',))
+
+    def test_builder_with_missing_name(self):
+        with self.assertRaises(Exception) as context:
+            loadConfig.checkValidBuilder({}, {'platform': 'mac-sierra'})
+        self.assertEqual(context.exception.args, ('Builder "{\'platform\': \'mac-sierra\'}" does not have name defined.',))
+
+    def test_builder_with_invalid_identifier(self):
+        with self.assertRaises(Exception) as context:
+            loadConfig.checkValidBuilder({}, {'name': 'mac-wk2(test)', 'shortname': 'mac-wk2'})
+        self.assertEqual(context.exception.args, ('Builder name mac-wk2(test) is not a valid buildbot identifier.',))
+
+    def test_builder_with_extra_long_name(self):
+        longName = 'a' * 71
+        with self.assertRaises(Exception) as context:
+            loadConfig.checkValidBuilder({}, {'name': longName, 'shortname': 'a'})
+        self.assertEqual(context.exception.args, ('Builder name {} is longer than maximum allowed by Buildbot (70 characters).'.format(longName),))
+
+    def test_builder_with_invalid_configuration(self):
+        with self.assertRaises(Exception) as context:
+            loadConfig.checkValidBuilder({}, {'name': 'mac-wk2', 'shortname': 'mac-wk2', 'configuration': 'asan'})
+        self.assertEqual(context.exception.args, ('Invalid configuration: asan for builder: mac-wk2',))
+
+    def test_builder_with_missing_factory(self):
+        with self.assertRaises(Exception) as context:
+            loadConfig.checkValidBuilder({}, {'name': 'mac-wk2', 'shortname': 'mac-wk2', 'configuration': 'release'})
+        self.assertEqual(context.exception.args, ('Builder mac-wk2 does not have factory defined.',))
+
+    def test_builder_with_missing_scheduler(self):
+        with self.assertRaises(Exception) as context:
+            loadConfig.checkValidBuilder({}, {'name': 'mac-wk2', 'shortname': 'mac-wk2', 'configuration': 'release', 'factory': 'WK2Factory', 'platform': 'mac-sierra', 'triggers': ['api-tests-mac-ews']})
+        self.assertEqual(context.exception.args, ('Trigger: api-tests-mac-ews in builder mac-wk2 does not exist in list of Trigerrable schedulers.',))
+
+    def test_builder_with_missing_platform(self):
+        with self.assertRaises(Exception) as context:
+            loadConfig.checkValidBuilder({}, {'name': 'mac-wk2', 'shortname': 'mac-wk2', 'configuration': 'release', 'factory': 'WK2Factory'})
+        self.assertEqual(context.exception.args, ('Builder mac-wk2 does not have platform defined.',))
+
+    def test_valid_builder(self):
+        loadConfig.checkValidBuilder({}, {'name': 'macOS-High-Sierra-WK2-EWS', 'shortname': 'mac-wk2', 'configuration': 'release', 'factory': 'WK2Factory', 'platform': 'mac-sierra'})
+
+
+class TestcheckWorkersAndBuildersForConsistency(unittest.TestCase):
+    def __init__(self, *args, **kwargs):
+        self.WK2Builder = {'name': 'macOS-High-Sierra-WK2-EWS', 'shortname': 'mac-wk2', 'factory': 'WK2Factory', 'platform': 'mac-sierra', 'workernames': ['ews101', 'ews102']}
+        self.ews101 = {'name': 'ews101', 'platform': 'mac-sierra'}
+        self.ews102 = {'name': 'ews102', 'platform': 'ios-11'}
+        super(TestcheckWorkersAndBuildersForConsistency, self).__init__(*args, **kwargs)
+
+    def test_checkWorkersAndBuildersForConsistency(self):
+        with self.assertRaises(Exception) as context:
+            loadConfig.checkWorkersAndBuildersForConsistency({}, [], [self.WK2Builder])
+        self.assertEqual(context.exception.args, ('Builder macOS-High-Sierra-WK2-EWS has worker ews101, which is not defined in workers list!',))
+
+    def test_checkWorkersAndBuildersForConsistency1(self):
+        with self.assertRaises(Exception) as context:
+            loadConfig.checkWorkersAndBuildersForConsistency({}, [self.ews101, self.ews102], [self.WK2Builder])
+        self.assertEqual(context.exception.args, ('Builder "macOS-High-Sierra-WK2-EWS" is for platform "mac-sierra", but has worker "ews102" for platform "ios-11"!',))
+
+    def test_duplicate_worker(self):
+        with self.assertRaises(Exception) as context:
+            loadConfig.checkWorkersAndBuildersForConsistency({}, [self.ews101, self.ews101], [self.WK2Builder])
+        self.assertEqual(context.exception.args, ('Duplicate worker entry found for ews101.',))
+
+    def test_success(self):
+        loadConfig.checkWorkersAndBuildersForConsistency({}, [self.ews101, {'name': 'ews102', 'platform': 'mac-sierra'}], [self.WK2Builder])
+
+
 if __name__ == '__main__':
     from steps_unittest_old import BuildBotConfigLoader
     BuildBotConfigLoader()._add_dependent_modules_to_sys_modules()

Modified: trunk/Tools/CISupport/ews-build/loadConfig.py (273741 => 273742)


--- trunk/Tools/CISupport/ews-build/loadConfig.py	2021-03-02 19:16:10 UTC (rev 273741)
+++ trunk/Tools/CISupport/ews-build/loadConfig.py	2021-03-02 19:18:10 UTC (rev 273742)
@@ -175,7 +175,7 @@
                 raise Exception('Builder {} has worker {}, which is not defined in workers list!'.format(builder['name'], worker_name))
 
             if worker['platform'] != builder['platform'] and worker['platform'] != '*' and builder['platform'] != '*':
-                raise Exception('Builder {0} is for platform {1}, but has worker {2} for platform {3}!'.format(
+                raise Exception('Builder "{0}" is for platform "{1}", but has worker "{2}" for platform "{3}"!'.format(
                     builder['name'], builder['platform'], worker['name'], worker['platform']))
 
 

Modified: trunk/Tools/CISupport/ews-build/loadConfig_unittest.py (273741 => 273742)


--- trunk/Tools/CISupport/ews-build/loadConfig_unittest.py	2021-03-02 19:16:10 UTC (rev 273741)
+++ trunk/Tools/CISupport/ews-build/loadConfig_unittest.py	2021-03-02 19:18:10 UTC (rev 273742)
@@ -224,7 +224,7 @@
     def test_checkWorkersAndBuildersForConsistency1(self):
         with self.assertRaises(Exception) as context:
             loadConfig.checkWorkersAndBuildersForConsistency({}, [self.ews101, self.ews102], [self.WK2Builder])
-        self.assertEqual(context.exception.args, ('Builder macOS-High-Sierra-WK2-EWS is for platform mac-sierra, but has worker ews102 for platform ios-11!',))
+        self.assertEqual(context.exception.args, ('Builder "macOS-High-Sierra-WK2-EWS" is for platform "mac-sierra", but has worker "ews102" for platform "ios-11"!',))
 
     def test_duplicate_worker(self):
         with self.assertRaises(Exception) as context:

Modified: trunk/Tools/ChangeLog (273741 => 273742)


--- trunk/Tools/ChangeLog	2021-03-02 19:16:10 UTC (rev 273741)
+++ trunk/Tools/ChangeLog	2021-03-02 19:18:10 UTC (rev 273742)
@@ -1,3 +1,45 @@
+2021-03-02  Aakash Jain  <aakash_j...@apple.com>
+
+        Make build.webkit.org loadconfig similar to EWS
+        https://bugs.webkit.org/show_bug.cgi?id=222597
+
+        Reviewed by Jonathan Bedard.
+
+        * CISupport/build-webkit-org/loadConfig.py:
+        (loadBuilderConfig):
+        (checkValidWorker): Method to validate worker.
+        (checkValidBuilder): Method to validate builder.
+        (checkValidSchedulers): Method to validate schedulers.
+        (doesTriggerExist):
+        (isTriggerUsedByAnyBuilder):
+        (checkWorkersAndBuildersForConsistency):
+        * CISupport/build-webkit-org/loadConfig_unittest.py: Added unit-tests.
+        (ConfigDotJSONTest.test_configuration):
+        (TestcheckValidWorker):
+        (TestcheckValidWorker.test_invalid_worker):
+        (TestcheckValidWorker.test_worker_with_missing_name):
+        (TestcheckValidWorker.test_worker_with_missing_platName):
+        (TestcheckValidWorker.test_valid_worker):
+        (TestcheckValidBuilder):
+        (TestcheckValidBuilder.test_invalid_builder):
+        (TestcheckValidBuilder.test_builder_with_missing_name):
+        (TestcheckValidBuilder.test_builder_with_invalid_identifier):
+        (TestcheckValidBuilder.test_builder_with_extra_long_name):
+        (TestcheckValidBuilder.test_builder_with_invalid_configuration):
+        (TestcheckValidBuilder.test_builder_with_missing_factory):
+        (TestcheckValidBuilder.test_builder_with_missing_scheduler):
+        (TestcheckValidBuilder.test_builder_with_missing_platform):
+        (TestcheckValidBuilder.test_valid_builder):
+        (TestcheckWorkersAndBuildersForConsistency):
+        (TestcheckWorkersAndBuildersForConsistency.test_checkWorkersAndBuildersForConsistency):
+        (TestcheckWorkersAndBuildersForConsistency.test_checkWorkersAndBuildersForConsistency1):
+        (TestcheckWorkersAndBuildersForConsistency.test_duplicate_worker):
+        (TestcheckWorkersAndBuildersForConsistency.test_success):
+        * CISupport/ews-build/loadConfig.py:
+        (checkWorkersAndBuildersForConsistency): Added double-quotes in error message for better readability.
+        * CISupport/ews-build/loadConfig_unittest.py:
+        (TestcheckWorkersAndBuildersForConsistency.test_checkWorkersAndBuildersForConsistency1):
+
 2021-03-02  Carlos Garcia Campos  <cgar...@igalia.com>
 
         REGRESSION(r263094): [GTK][WPE] API test /webkit/WebKitWebContext/languages is failing
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to