Bug 1296842: check parameters; r?jmaher
MozReview-Commit-ID: 1JCpufowNHD
--- a/taskcluster/mach_commands.py
+++ b/taskcluster/mach_commands.py
@@ -212,16 +212,17 @@ class MachCommands(MachCommandBase):
def show_taskgraph(self, graph_attr, options):
import taskgraph.parameters
import taskgraph.target_tasks
import taskgraph.generator
try:
self.setup_logging(quiet=options['quiet'], verbose=options['verbose'])
parameters = taskgraph.parameters.load_parameters_file(options)
+ parameters.check()
target_tasks_method = parameters.get('target_tasks_method', 'all_tasks')
target_tasks_method = taskgraph.target_tasks.get_method(target_tasks_method)
tgg = taskgraph.generator.TaskGraphGenerator(
root_dir=options['root'],
parameters=parameters,
target_tasks_method=target_tasks_method)
--- a/taskcluster/taskgraph/parameters.py
+++ b/taskcluster/taskgraph/parameters.py
@@ -5,20 +5,56 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from __future__ import absolute_import, print_function, unicode_literals
import json
import yaml
from mozbuild.util import ReadOnlyDict
+# Please keep this list sorted and in sync with taskcluster/docs/parameters.rst
+PARAMETER_NAMES = set([
+ 'base_repository',
+ 'build_date',
+ 'head_ref',
+ 'head_repository',
+ 'head_rev',
+ 'level',
+ 'message',
+ 'moz_build_date',
+ 'optimize_target_tasks',
+ 'owner',
+ 'project',
+ 'pushdate',
+ 'pushlog_id',
+ 'target_tasks_method',
+ 'triggered_by',
+])
+
class Parameters(ReadOnlyDict):
"""An immutable dictionary with nicer KeyError messages on failure"""
+ def check(self):
+ names = set(self)
+ msg = []
+
+ missing = PARAMETER_NAMES - names
+ if missing:
+ msg.append("missing parameters: " + ", ".join(missing))
+
+ extra = names - PARAMETER_NAMES
+ if extra:
+ msg.append("extra parameters: " + ", ".join(extra))
+
+ if msg:
+ raise Exception("; ".join(msg))
+
def __getitem__(self, k):
+ if k not in PARAMETER_NAMES:
+ raise KeyError("no such parameter {!r}".format(k))
try:
return super(Parameters, self).__getitem__(k)
except KeyError:
raise KeyError("taskgraph parameter {!r} not found".format(k))
def load_parameters_file(options):
"""
--- a/taskcluster/taskgraph/test/test_parameters.py
+++ b/taskcluster/taskgraph/test/test_parameters.py
@@ -1,36 +1,55 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from __future__ import absolute_import, print_function, unicode_literals
import unittest
-from ..parameters import Parameters, load_parameters_file
+from ..parameters import Parameters, load_parameters_file, PARAMETER_NAMES
from mozunit import main, MockedOpen
class TestParameters(unittest.TestCase):
+ vals = {n: n for n in PARAMETER_NAMES}
+
def test_Parameters_immutable(self):
- p = Parameters(x=10, y=20)
+ p = Parameters(**self.vals)
def assign():
- p['x'] = 20
+ p['head_ref'] = 20
self.assertRaises(Exception, assign)
- def test_Parameters_KeyError(self):
- p = Parameters(x=10, y=20)
+ def test_Parameters_missing_KeyError(self):
+ p = Parameters(**self.vals)
self.assertRaises(KeyError, lambda: p['z'])
+ def test_Parameters_invalid_KeyError(self):
+ """even if the value is present, if it's not a valid property, raise KeyError"""
+ p = Parameters(xyz=10, **self.vals)
+ self.assertRaises(KeyError, lambda: p['xyz'])
+
def test_Parameters_get(self):
- p = Parameters(x=10, y=20)
- self.assertEqual(p['x'], 10)
+ p = Parameters(head_ref=10, level=20)
+ self.assertEqual(p['head_ref'], 10)
+
+ def test_Parameters_check(self):
+ p = Parameters(**self.vals)
+ p.check() # should not raise
+
+ def test_Parameters_check_missing(self):
+ p = Parameters()
+ self.assertRaises(Exception, lambda: p.check())
+
+ def test_Parameters_check_extra(self):
+ p = Parameters(xyz=10, **self.vals)
+ self.assertRaises(Exception, lambda: p.check())
def test_load_parameters_file_yaml(self):
with MockedOpen({"params.yml": "some: data\n"}):
self.assertEqual(
load_parameters_file({'parameters': 'params.yml'}),
{'some': 'data'})
def test_load_parameters_file_json(self):