Chromium Code Reviews| Index: third_party/cq_client/validate_config.py |
| diff --git a/third_party/cq_client/validate_config.py b/third_party/cq_client/validate_config.py |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..8deda2407ab58be9e6d69ba3abc3d0edf7accd65 |
| --- /dev/null |
| +++ b/third_party/cq_client/validate_config.py |
| @@ -0,0 +1,116 @@ |
| +#!/usr/bin/env python |
| +# Copyright 2015 The Chromium Authors. All rights reserved. |
| +# Use of this source code is governed by a BSD-style license that can be |
| +# found in the LICENSE file. |
| + |
| +"""CQ config validation library.""" |
| + |
| +import argparse |
| +# The 'from google import protobuf' below was replaced to fix an issue where |
| +# some users may have built-in google package installed on their system, which |
| +# is incompatible with cq_pb2 below. This hack can be removed after |
| +# http://crbug.com/503067 is resolved. |
| +import protobuf26 as protobuf |
| +import logging |
| +import re |
| +import sys |
| + |
| +from cq_client import cq_pb2 |
| + |
| + |
| +REQUIRED_FIELDS = [ |
| + 'version', |
| + 'rietveld', |
| + 'rietveld.url', |
| + 'verifiers', |
| + 'cq_name', |
| +] |
| + |
| +LEGACY_FIELDS = [ |
| + 'svn_repo_url', |
| + 'server_hooks_missing', |
| + 'verifiers_with_patch', |
| +] |
| + |
| +EMAIL_REGEXP = '^[^@]+@[^@]+\.[^@]+$' |
| + |
| + |
| +def _HasField(message, field_path): |
| + """Checks that at least one field with given path exist in the proto message. |
| + |
| + This function correctly handles repeated fields and will make sure that each |
| + repeated field will have required sub-path, e.g. if 'abc' is a repeated field |
| + and field_path is 'abc.def', then the function will only return True when each |
| + entry for 'abc' will contain at least one value for 'def'. |
| + |
| + Args: |
| + message: Protocol Buffer message to check. |
| + field_path: Path to the target field separated with ".". |
|
pgervais
2015/06/24 01:10:43
Nit: add the type of the arguments.
Sergiy Byelozyorov
2015/06/24 05:30:59
Done.
|
| + |
| + Return: |
| + True if at least one such field is explicitly set in the message. |
| + """ |
| + path_parts = field_path.split('.', 1) |
| + field_name = path_parts[0] |
| + sub_path = path_parts[1] if len(path_parts) == 2 else None |
| + |
| + field_labels = {fd.name: fd.label for fd in message.DESCRIPTOR.fields} |
| + repeated_field = (field_labels[field_name] == |
| + protobuf.descriptor.FieldDescriptor.LABEL_REPEATED) |
| + |
| + if sub_path: |
| + field = getattr(message, field_name) |
| + if repeated_field: |
| + if not field: |
| + return False |
| + return all(_HasField(entry, sub_path) for entry in field) |
| + else: |
| + return _HasField(field, sub_path) |
| + else: |
| + if repeated_field: |
| + return len(getattr(message, field_name)) > 0 |
| + else: |
| + return message.HasField(field_name) |
| + |
| + |
| +def IsValid(cq_config): |
| + """Validates a CQ config and prints errors/warnings to the screen. |
| + |
| + Args: |
| + cq_config (string): Unparsed text format of the CQ config proto. |
| + |
| + Returns: |
| + True if the config is valid. |
| + """ |
| + try: |
| + config = cq_pb2.Config() |
| + protobuf.text_format.Merge(cq_config, config) |
| + except protobuf.text_format.ParseError as e: |
| + logging.error('Failed to parse config as protobuf:\n%s', e) |
| + return False |
| + |
| + for fname in REQUIRED_FIELDS: |
| + if not _HasField(config, fname): |
| + logging.error('%s is a required field', fname) |
| + return False |
| + |
| + for fname in LEGACY_FIELDS: |
| + if _HasField(config, fname): |
| + logging.warn('%s is a legacy field', fname) |
| + |
| + |
| + for base in config.rietveld.project_bases: |
| + try: |
| + re.compile(base) |
| + except Exception: |
|
pgervais
2015/06/24 01:10:43
expect re.error:
instead. We don't want to catch
Sergiy Byelozyorov
2015/06/24 05:30:59
Done.
|
| + logging.error('failed to parse "%s" in project_bases as a regexp', base) |
| + return False |
| + |
| + if not config.rietveld.HasField('url'): |
| + logging.error('rietveld.url is a required field') |
| + return False |
|
pgervais
2015/06/24 01:10:43
Why are you checking that again? rietveld.url is i
Sergiy Byelozyorov
2015/06/24 05:30:59
Done.
|
| + |
| + # TODO(sergiyb): For each field, check valid values depending on its |
| + # semantics, e.g. email addresses, regular expressions etc. |
| + |
| + return True |