[Notes] [Git][BuildStream/buildstream][Qinusty/526-fail-on-warnings] 2 commits: _project.py: Add fatal-warnings configuration item



Title: GitLab

Qinusty pushed to branch Qinusty/526-fail-on-warnings at BuildStream / buildstream

Commits:

6 changed files:

Changes:

  • buildstream/_frontend/app.py
    ... ... @@ -230,6 +230,13 @@ class App():
    230 230
             # Propagate pipeline feedback to the user
    
    231 231
             self.context.set_message_handler(self._message_handler)
    
    232 232
     
    
    233
    +        # Deprecation check now that message handler is initialized
    
    234
    +        if self.project._fail_on_overlap is not None:
    
    235
    +            self._message(MessageType.WARN,
    
    236
    +                          "Use of fail-on-overlap within project.conf" +
    
    237
    +                          "is deprecated. Please use fatal-warnings instead.")
    
    238
    +        self._message(MessageType.DEBUG, str(self.project._fatal_warnings))
    
    239
    +
    
    233 240
             # Now that we have a logger and message handler,
    
    234 241
             # we can override the global exception hook.
    
    235 242
             sys.excepthook = self._global_exception_handler
    

  • buildstream/_project.py
    ... ... @@ -39,6 +39,9 @@ from ._versions import BST_FORMAT_VERSION
    39 39
     # Project Configuration file
    
    40 40
     _PROJECT_CONF_FILE = 'project.conf'
    
    41 41
     
    
    42
    +# This should be updated as warnings are added for `fatal-warnings: True`
    
    43
    +_ALL_WARNINGS = ['overlaps']
    
    44
    +
    
    42 45
     
    
    43 46
     # HostMount()
    
    44 47
     #
    
    ... ... @@ -85,7 +88,7 @@ class Project():
    85 88
     
    
    86 89
             self.options = None                      # OptionPool
    
    87 90
             self.junction = junction                 # The junction Element object, if this is a subproject
    
    88
    -        self.fail_on_overlap = False             # Whether overlaps are treated as errors
    
    91
    +
    
    89 92
             self.ref_storage = None                  # ProjectRefStorage setting
    
    90 93
             self.base_variables = {}                 # The base set of variables
    
    91 94
             self.base_environment = {}               # The base set of environment variables
    
    ... ... @@ -108,6 +111,9 @@ class Project():
    108 111
             self._source_format_versions = {}
    
    109 112
             self._element_format_versions = {}
    
    110 113
     
    
    114
    +        self._fail_on_overlap = False    # Whether to fail on overlaps or not # Deprecated use _warning_is_fatal()
    
    115
    +        self._fatal_warnings = []        # A list of warnings which should trigger an error
    
    116
    +
    
    111 117
             self._shell_command = []      # The default interactive shell command
    
    112 118
             self._shell_environment = {}  # Statically set environment vars
    
    113 119
             self._shell_host_files = []   # A list of HostMount objects
    
    ... ... @@ -232,6 +238,18 @@ class Project():
    232 238
             mirror_list.append(self._aliases[alias])
    
    233 239
             return mirror_list
    
    234 240
     
    
    241
    +    # fail_on_overlap
    
    242
    +    #
    
    243
    +    # Property added to continue support of Project.fail_on_overlap after
    
    244
    +    # introduction of fatal-warnings configuration item.
    
    245
    +    #
    
    246
    +    # Returns:
    
    247
    +    #    (bool): True if the configuration specifies that overlaps should
    
    248
    +    #            cause errors instead of warnings.
    
    249
    +    @property
    
    250
    +    def fail_on_overlap(self):
    
    251
    +        return self._fail_on_overlap or self._warning_is_fatal("overlaps")
    
    252
    +
    
    235 253
         # _load():
    
    236 254
         #
    
    237 255
         # Loads the project configuration file in the project directory.
    
    ... ... @@ -278,7 +296,7 @@ class Project():
    278 296
                 'split-rules', 'elements', 'plugins',
    
    279 297
                 'aliases', 'name',
    
    280 298
                 'artifacts', 'options',
    
    281
    -            'fail-on-overlap', 'shell',
    
    299
    +            'fail-on-overlap', 'shell', 'fatal-warnings',
    
    282 300
                 'ref-storage', 'sandbox', 'mirrors',
    
    283 301
             ])
    
    284 302
     
    
    ... ... @@ -404,7 +422,22 @@ class Project():
    404 422
             self._splits = _yaml.node_get(config, Mapping, 'split-rules')
    
    405 423
     
    
    406 424
             # Fail on overlap
    
    407
    -        self.fail_on_overlap = _yaml.node_get(config, bool, 'fail-on-overlap')
    
    425
    +        self._fail_on_overlap = _yaml.node_get(config, bool, 'fail-on-overlap', default_value=None)
    
    426
    +
    
    427
    +        # Fatal warnings
    
    428
    +        p = _yaml.node_get_provenance(config, 'fatal-warnings')
    
    429
    +        try:  # Check for bool type
    
    430
    +            fatal_warnings = _yaml.node_get(config, bool, 'fatal-warnings', default_value=False)
    
    431
    +        except (ValueError, LoadError) as e:
    
    432
    +            try:  # Check for list type
    
    433
    +                fatal_warnings = _yaml.node_get(config, list, 'fatal-warnings', default_value=[])
    
    434
    +            except (ValueError, LoadError):
    
    435
    +                raise LoadError(LoadErrorReason.INVALID_DATA,
    
    436
    +                                "{}: Invalid value specified for 'fatal-warnings', ".format(p) +
    
    437
    +                                "must be list or bool.")
    
    438
    +
    
    439
    +        # Validate and set fatal warnings
    
    440
    +        self._set_fatal_warnings(fatal_warnings, p)
    
    408 441
     
    
    409 442
             # Use separate file for storing source references
    
    410 443
             self.ref_storage = _yaml.node_get(config, str, 'ref-storage')
    
    ... ... @@ -532,3 +565,43 @@ class Project():
    532 565
                 directory = parent_dir
    
    533 566
     
    
    534 567
             return directory
    
    568
    +
    
    569
    +    # _warning_is_fatal():
    
    570
    +    #
    
    571
    +    # Returns true if the warning in question should be considered fatal based on
    
    572
    +    # the project configuration.
    
    573
    +    #
    
    574
    +    # Args:
    
    575
    +    #   warning_str (str): The warning configuration string to check against
    
    576
    +    #
    
    577
    +    # Returns:
    
    578
    +    #    (bool): True if the warning should be considered fatal and cause an error.
    
    579
    +    #
    
    580
    +    def _warning_is_fatal(self, warning_str):
    
    581
    +        return warning_str in self._fatal_warnings
    
    582
    +
    
    583
    +    # _set_fatal_warnings()
    
    584
    +    #
    
    585
    +    # Validates and sets the self._fatal_warnings
    
    586
    +    #
    
    587
    +    # Args:
    
    588
    +    #   warnings (list|bool): The warnings to set self._fatal_warnings to.
    
    589
    +    #                         If True, _ALL_WARNINGS is used. If False, [] is used.
    
    590
    +    #   provenance (str): The provenance assosciated with the warnings parameter.
    
    591
    +    #
    
    592
    +    def _set_fatal_warnings(self, warnings, provenance="[Unknown Provenance]"):
    
    593
    +        if isinstance(warnings, bool):
    
    594
    +            self._fatal_warnings = _ALL_WARNINGS if warnings else []
    
    595
    +            return
    
    596
    +        elif warnings is None:
    
    597
    +            return
    
    598
    +
    
    599
    +        # Check for unknown warnings.
    
    600
    +        unknown_warnings = filter(lambda x: x not in _ALL_WARNINGS, warnings)
    
    601
    +        if list(unknown_warnings):  # Restrict 'fatal-warnings' to known warnings
    
    602
    +            raise LoadError(LoadErrorReason.INVALID_DATA,
    
    603
    +                            ("{}: Invalid warning provided to fatal-warnings ({})\n" +
    
    604
    +                             "Valid options are: ({})")
    
    605
    +                            .format(provenance, ", ".join(unknown_warnings), ", ".join(_ALL_WARNINGS)))
    
    606
    +        else:
    
    607
    +            self._fatal_warnings = warnings

  • buildstream/_yaml.py
    ... ... @@ -368,9 +368,9 @@ def node_get(node, expected_type, key, indices=None, default_value=_get_sentinel
    368 368
             try:
    
    369 369
                 if (expected_type == bool and isinstance(value, str)):
    
    370 370
                     # Dont coerce booleans to string, this makes "False" strings evaluate to True
    
    371
    -                if value == 'true' or value == 'True':
    
    371
    +                if value in ('true', 'True'):
    
    372 372
                         value = True
    
    373
    -                elif value == 'false' or value == 'False':
    
    373
    +                elif value in ('false', 'False'):
    
    374 374
                         value = False
    
    375 375
                     else:
    
    376 376
                         raise ValueError()
    

  • buildstream/data/projectconfig.yaml
    ... ... @@ -14,7 +14,15 @@ element-path: .
    14 14
     ref-storage: inline
    
    15 15
     
    
    16 16
     # Overlaps are just warnings
    
    17
    -fail-on-overlap: False
    
    17
    +# This has been DEPRECATED in favour of fatal-warnings
    
    18
    +#fail-on-overlap: False
    
    19
    +
    
    20
    +# Allows a collection of warnings to be configured to be raised as errors.
    
    21
    +# Setting this value to true will enable all possible fatal-warnings
    
    22
    +# fatal-warnings: True
    
    23
    +
    
    24
    +# fatal-warnings:
    
    25
    +# - overlaps
    
    18 26
     
    
    19 27
     
    
    20 28
     # Variable Configuration
    

  • doc/source/format_project.rst
    ... ... @@ -125,6 +125,27 @@ following to your ``project.conf``:
    125 125
     
    
    126 126
        The ``ref-storage`` configuration is available since :ref:`format version 8 <project_format_version>`
    
    127 127
     
    
    128
    +Fatal warnings
    
    129
    +~~~~~~~~~~~~~~
    
    130
    +Warnings can be configured as fatal using the ``fatal-warnings`` configuration item.
    
    131
    +When a warning is configured as fatal, where a warning would usually be thrown instead an error will be thrown
    
    132
    +causing the build to fail.
    
    133
    +
    
    134
    +When ``fatal-warnings`` is True, all configurable fatal warnings will be set as fatal. Individual warnings
    
    135
    +can also be set by setting ``fatal-warnings`` to a list of warnings.
    
    136
    +
    
    137
    +.. code:: yaml
    
    138
    +
    
    139
    +  fatal-warnings:
    
    140
    +  - overlaps
    
    141
    +  - <other configurable warnings>
    
    142
    +
    
    143
    +Configurable warnings include:
    
    144
    +
    
    145
    +- :ref:`overlaps <fail_on_overlaps>`
    
    146
    +
    
    147
    +
    
    148
    +.. _fail_on_overlaps:
    
    128 149
     
    
    129 150
     Fail on overlaps
    
    130 151
     ~~~~~~~~~~~~~~~~
    
    ... ... @@ -143,6 +164,10 @@ and the order that the elements were overlapped.
    143 164
     
    
    144 165
       fail-on-overlap: true
    
    145 166
     
    
    167
    +.. deprecated:: 1.4
    
    168
    +
    
    169
    +  However this configuration is still valid, it is deprecated in favour of `fatal-warnings`
    
    170
    +
    
    146 171
     
    
    147 172
     .. _project_source_aliases:
    
    148 173
     
    

  • tests/frontend/overlaps.py
    ... ... @@ -16,26 +16,31 @@ project_template = {
    16 16
     }
    
    17 17
     
    
    18 18
     
    
    19
    -def gen_project(project_dir, fail_on_overlap):
    
    19
    +def gen_project(project_dir, fail_on_overlap, use_fatal_warnings=True):
    
    20 20
         template = dict(project_template)
    
    21
    -    template["fail-on-overlap"] = fail_on_overlap
    
    21
    +    if use_fatal_warnings:
    
    22
    +        template["fatal-warnings"] = ["overlaps"] if fail_on_overlap else []
    
    23
    +    else:
    
    24
    +        template["fail-on-overlap"] = fail_on_overlap
    
    22 25
         projectfile = os.path.join(project_dir, "project.conf")
    
    23 26
         _yaml.dump(template, projectfile)
    
    24 27
     
    
    25 28
     
    
    26 29
     @pytest.mark.datafiles(DATA_DIR)
    
    27
    -def test_overlaps(cli, datafiles):
    
    30
    +@pytest.mark.parametrize("use_fatal_warnings", [True, False])
    
    31
    +def test_overlaps(cli, datafiles, use_fatal_warnings):
    
    28 32
         project_dir = str(datafiles)
    
    29
    -    gen_project(project_dir, False)
    
    33
    +    gen_project(project_dir, False, use_fatal_warnings)
    
    30 34
         result = cli.run(project=project_dir, silent=True, args=[
    
    31 35
             'build', 'collect.bst'])
    
    32 36
         result.assert_success()
    
    33 37
     
    
    34 38
     
    
    35 39
     @pytest.mark.datafiles(DATA_DIR)
    
    36
    -def test_overlaps_error(cli, datafiles):
    
    40
    +@pytest.mark.parametrize("use_fatal_warnings", [True, False])
    
    41
    +def test_overlaps_error(cli, datafiles, use_fatal_warnings):
    
    37 42
         project_dir = str(datafiles)
    
    38
    -    gen_project(project_dir, True)
    
    43
    +    gen_project(project_dir, True, use_fatal_warnings)
    
    39 44
         result = cli.run(project=project_dir, silent=True, args=[
    
    40 45
             'build', 'collect.bst'])
    
    41 46
         result.assert_main_error(ErrorDomain.STREAM, None)
    
    ... ... @@ -74,11 +79,12 @@ def test_overlaps_whitelist_on_overlapper(cli, datafiles):
    74 79
     
    
    75 80
     
    
    76 81
     @pytest.mark.datafiles(DATA_DIR)
    
    77
    -def test_overlaps_script(cli, datafiles):
    
    82
    +@pytest.mark.parametrize("use_fatal_warnings", [True, False])
    
    83
    +def test_overlaps_script(cli, datafiles, use_fatal_warnings):
    
    78 84
         # Test overlaps with script element to test
    
    79 85
         # Element.stage_dependency_artifacts() with Scope.RUN
    
    80 86
         project_dir = str(datafiles)
    
    81
    -    gen_project(project_dir, False)
    
    87
    +    gen_project(project_dir, False, use_fatal_warnings)
    
    82 88
         result = cli.run(project=project_dir, silent=True, args=[
    
    83 89
             'build', 'script.bst'])
    
    84 90
         result.assert_success()



  • [Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]