No bug: [taskgraph] Make verify_test_packaging handle --target-kind gracefully; r=Callek

If we are generating only a part of the graph, to given kind, don't fail if a
build is packaging tests and there is no corresponding test task, as the tests
may not have been generated.

Differential Revision: https://phabricator.services.mozilla.com/D82097
This commit is contained in:
Tom Prince 2020-07-14 07:17:26 +00:00
parent 51f106a3a3
commit e92bbf5dd8
7 changed files with 57 additions and 30 deletions

View file

@ -235,3 +235,10 @@ Code Review
``phabricator_diff`` ``phabricator_diff``
The code review process needs to know the Phabricator Differential diff that The code review process needs to know the Phabricator Differential diff that
started the analysis. This parameter must start with `PHID-DIFF-` started the analysis. This parameter must start with `PHID-DIFF-`
Local configuration
-------------------
``target-kind``
Generate only the given kind and its kind-dependencies. This is used for local inspection of the graph
and is not supported at run-time.

View file

@ -337,12 +337,15 @@ class MachCommands(MachCommandBase):
try: try:
self.setup_logging(quiet=options['quiet'], verbose=options['verbose']) self.setup_logging(quiet=options['quiet'], verbose=options['verbose'])
parameters = taskgraph.parameters.parameters_loader(options['parameters']) parameters = taskgraph.parameters.parameters_loader(
options['parameters'],
overrides={'target-kind': options.get('target_kind')},
strict=False,
)
tgg = taskgraph.generator.TaskGraphGenerator( tgg = taskgraph.generator.TaskGraphGenerator(
root_dir=options.get('root'), root_dir=options.get('root'),
parameters=parameters, parameters=parameters,
target_kind=options.get('target_kind'),
) )
tg = getattr(tgg, graph_attr) tg = getattr(tgg, graph_attr)

View file

@ -114,7 +114,6 @@ class TaskGraphGenerator(object):
parameters, parameters,
decision_task_id="DECISION-TASK", decision_task_id="DECISION-TASK",
write_artifacts=False, write_artifacts=False,
target_kind=None,
): ):
""" """
@param root_dir: root directory, with subdirectories for each kind @param root_dir: root directory, with subdirectories for each kind
@ -126,7 +125,6 @@ class TaskGraphGenerator(object):
root_dir = 'taskcluster/ci' root_dir = 'taskcluster/ci'
self.root_dir = ensure_text(root_dir) self.root_dir = ensure_text(root_dir)
self._parameters = parameters self._parameters = parameters
self._target_kind = target_kind
self._decision_task_id = decision_task_id self._decision_task_id = decision_task_id
self._write_artifacts = write_artifacts self._write_artifacts = write_artifacts
@ -262,11 +260,12 @@ class TaskGraphGenerator(object):
edges.add((kind.name, dep, 'kind-dependency')) edges.add((kind.name, dep, 'kind-dependency'))
kind_graph = Graph(set(kinds), edges) kind_graph = Graph(set(kinds), edges)
if self._target_kind: if parameters.get('target-kind'):
target_kind = parameters['target-kind']
logger.info( logger.info(
"Limiting kinds to {target_kind} and dependencies".format( "Limiting kinds to {target_kind} and dependencies".format(
target_kind=self._target_kind)) target_kind=target_kind))
kind_graph = kind_graph.transitive_closure({self._target_kind, 'docker-image'}) kind_graph = kind_graph.transitive_closure({target_kind, 'docker-image'})
logger.info("Generating full task set") logger.info("Generating full task set")
all_tasks = {} all_tasks = {}
@ -419,7 +418,10 @@ def load_tasks_for_kind(parameters, kind, root_dir=None):
This function is designed to be called from outside of taskgraph. This function is designed to be called from outside of taskgraph.
""" """
tgg = TaskGraphGenerator(root_dir=root_dir, parameters=parameters, target_kind=kind) # make parameters read-write
parameters = dict(parameters)
parameters['target-kind'] = kind
tgg = TaskGraphGenerator(root_dir=root_dir, parameters=parameters)
return { return {
task.task['metadata']['name']: task task.task['metadata']['name']: task
for task in tgg.full_task_set for task in tgg.full_task_set

View file

@ -96,6 +96,8 @@ base_schema = Schema({
Required('release_product'): Any(None, text_type), Required('release_product'): Any(None, text_type),
Required('required_signoffs'): [text_type], Required('required_signoffs'): [text_type],
Required('signoff_urls'): dict, Required('signoff_urls'): dict,
# target-kind is not included, since it should never be
# used at run-time
Required('target_tasks_method'): text_type, Required('target_tasks_method'): text_type,
Required('tasks_for'): text_type, Required('tasks_for'): text_type,
Required('test_manifest_loader'): text_type, Required('test_manifest_loader'): text_type,

View file

@ -45,9 +45,18 @@ class VerificationSequence(object):
continue continue
scratch_pad = {} scratch_pad = {}
graph.for_each_task( graph.for_each_task(
verification.verify, scratch_pad=scratch_pad, graph_config=graph_config verification.verify,
scratch_pad=scratch_pad,
graph_config=graph_config,
parameters=parameters,
)
verification.verify(
None,
graph,
scratch_pad=scratch_pad,
graph_config=graph_config,
parameters=parameters,
) )
verification.verify(None, graph, scratch_pad=scratch_pad, graph_config=graph_config)
return graph_name, graph return graph_name, graph
def add(self, graph_name, run_on_projects={"all"}): def add(self, graph_name, run_on_projects={"all"}):
@ -128,7 +137,7 @@ def verify_docs(filename, identifiers, appearing_as):
@verifications.add('full_task_graph') @verifications.add('full_task_graph')
def verify_task_graph_symbol(task, taskgraph, scratch_pad, graph_config): def verify_task_graph_symbol(task, taskgraph, scratch_pad, graph_config, parameters):
""" """
This function verifies that tuple This function verifies that tuple
(collection.keys(), machine.platform, groupSymbol, symbol) is unique (collection.keys(), machine.platform, groupSymbol, symbol) is unique
@ -169,7 +178,7 @@ def verify_task_graph_symbol(task, taskgraph, scratch_pad, graph_config):
@verifications.add('full_task_graph') @verifications.add('full_task_graph')
def verify_trust_domain_v2_routes(task, taskgraph, scratch_pad, graph_config): def verify_trust_domain_v2_routes(task, taskgraph, scratch_pad, graph_config, parameters):
""" """
This function ensures that any two tasks have distinct ``index.{trust-domain}.v2`` routes. This function ensures that any two tasks have distinct ``index.{trust-domain}.v2`` routes.
""" """
@ -191,7 +200,7 @@ def verify_trust_domain_v2_routes(task, taskgraph, scratch_pad, graph_config):
@verifications.add('full_task_graph') @verifications.add('full_task_graph')
def verify_routes_notification_filters(task, taskgraph, scratch_pad, graph_config): def verify_routes_notification_filters(task, taskgraph, scratch_pad, graph_config, parameters):
""" """
This function ensures that only understood filters for notifications are This function ensures that only understood filters for notifications are
specified. specified.
@ -217,7 +226,7 @@ def verify_routes_notification_filters(task, taskgraph, scratch_pad, graph_confi
@verifications.add('full_task_graph') @verifications.add('full_task_graph')
def verify_dependency_tiers(task, taskgraph, scratch_pad, graph_config): def verify_dependency_tiers(task, taskgraph, scratch_pad, graph_config, parameters):
tiers = scratch_pad tiers = scratch_pad
if task is not None: if task is not None:
tiers[task.label] = task.task.get('extra', {}) \ tiers[task.label] = task.task.get('extra', {}) \
@ -244,7 +253,7 @@ def verify_dependency_tiers(task, taskgraph, scratch_pad, graph_config):
@verifications.add('full_task_graph') @verifications.add('full_task_graph')
def verify_required_signoffs(task, taskgraph, scratch_pad, graph_config): def verify_required_signoffs(task, taskgraph, scratch_pad, graph_config, parameters):
""" """
Task with required signoffs can't be dependencies of tasks with less Task with required signoffs can't be dependencies of tasks with less
required signoffs. required signoffs.
@ -271,7 +280,7 @@ def verify_required_signoffs(task, taskgraph, scratch_pad, graph_config):
@verifications.add('full_task_graph') @verifications.add('full_task_graph')
def verify_toolchain_alias(task, taskgraph, scratch_pad, graph_config): def verify_toolchain_alias(task, taskgraph, scratch_pad, graph_config, parameters):
""" """
This function verifies that toolchain aliases are not reused. This function verifies that toolchain aliases are not reused.
""" """
@ -294,7 +303,7 @@ def verify_toolchain_alias(task, taskgraph, scratch_pad, graph_config):
@verifications.add('optimized_task_graph') @verifications.add('optimized_task_graph')
def verify_always_optimized(task, taskgraph, scratch_pad, graph_config): def verify_always_optimized(task, taskgraph, scratch_pad, graph_config, parameters):
""" """
This function ensures that always-optimized tasks have been optimized. This function ensures that always-optimized tasks have been optimized.
""" """
@ -305,7 +314,7 @@ def verify_always_optimized(task, taskgraph, scratch_pad, graph_config):
@verifications.add('full_task_graph', run_on_projects=RELEASE_PROJECTS) @verifications.add('full_task_graph', run_on_projects=RELEASE_PROJECTS)
def verify_shippable_no_sccache(task, taskgraph, scratch_pad, graph_config): def verify_shippable_no_sccache(task, taskgraph, scratch_pad, graph_config, parameters):
if task and task.attributes.get('shippable'): if task and task.attributes.get('shippable'):
if task.task.get('payload', {}).get('env', {}).get('USE_SCCACHE'): if task.task.get('payload', {}).get('env', {}).get('USE_SCCACHE'):
raise Exception( raise Exception(
@ -313,8 +322,9 @@ def verify_shippable_no_sccache(task, taskgraph, scratch_pad, graph_config):
@verifications.add('full_task_graph') @verifications.add('full_task_graph')
def verify_test_packaging(task, taskgraph, scratch_pad, graph_config): def verify_test_packaging(task, taskgraph, scratch_pad, graph_config, parameters):
if task is None: if task is None:
has_target_kind = parameters.get('target-kind') is None
exceptions = [] exceptions = []
for task in six.itervalues(taskgraph.tasks): for task in six.itervalues(taskgraph.tasks):
if task.kind == 'build' and not task.attributes.get('skip-verify-test-packaging'): if task.kind == 'build' and not task.attributes.get('skip-verify-test-packaging'):
@ -342,6 +352,9 @@ def verify_test_packaging(task, taskgraph, scratch_pad, graph_config):
# With the caveat that we expect shippable jobs to always # With the caveat that we expect shippable jobs to always
# produce tests. # produce tests.
if not build_has_tests and not shippable: if not build_has_tests and not shippable:
# If we have not generated all task kinds, we can't verify that
# there are no dependent tests.
if has_target_kind:
exceptions.append( exceptions.append(
'Build job {} has no tests, but specifies ' 'Build job {} has no tests, but specifies '
'MOZ_AUTOMATION_PACKAGE_TESTS={} in the environment. ' 'MOZ_AUTOMATION_PACKAGE_TESTS={} in the environment. '
@ -356,7 +369,7 @@ def verify_test_packaging(task, taskgraph, scratch_pad, graph_config):
@verifications.add('full_task_graph') @verifications.add('full_task_graph')
def verify_run_known_projects(task, taskgraph, scratch_pad, graph_config): def verify_run_known_projects(task, taskgraph, scratch_pad, graph_config, parameters):
""" Validates the inputs in run-on-projects. """ Validates the inputs in run-on-projects.
We should never let 'try' (or 'try-comm-central') be in run-on-projects even though it We should never let 'try' (or 'try-comm-central') be in run-on-projects even though it
@ -381,7 +394,7 @@ def verify_run_known_projects(task, taskgraph, scratch_pad, graph_config):
@verifications.add('full_task_graph') @verifications.add('full_task_graph')
def verify_local_toolchains(task, taskgraph, scratch_pad, graph_config): def verify_local_toolchains(task, taskgraph, scratch_pad, graph_config, parameters):
""" """
Toolchains that are used for local development need to be built on a Toolchains that are used for local development need to be built on a
level-3 branch to installable via `mach bootstrap`. We ensure here that all level-3 branch to installable via `mach bootstrap`. We ensure here that all

View file

@ -35,9 +35,9 @@ def create_tgg(responses, datadir):
lm = LoggingManager() lm = LoggingManager()
lm.add_terminal_logging() lm.add_terminal_logging()
def inner(parameters=None, overrides=None, target_kind=None): def inner(parameters=None, overrides=None):
params = parameters_loader(parameters, strict=False, overrides=overrides) params = parameters_loader(parameters, strict=False, overrides=overrides)
tgg = TaskGraphGenerator(None, params, target_kind=target_kind) tgg = TaskGraphGenerator(None, params)
# Mock out certain requests as they may depend on a revision that does # Mock out certain requests as they may depend on a revision that does
# not exist on hg.mozilla.org. # not exist on hg.mozilla.org.

View file

@ -19,9 +19,9 @@ pytestmark = pytest.mark.slow
def tgg(create_tgg): def tgg(create_tgg):
params = TRY_AUTO_PARAMETERS.copy() params = TRY_AUTO_PARAMETERS.copy()
params.update( params.update(
{"head_repository": "https://hg.mozilla.org/try", "project": "try"} {"head_repository": "https://hg.mozilla.org/try", "project": "try", "target_kind": "test"}
) )
tgg = create_tgg(overrides=params, target_kind="test") tgg = create_tgg(overrides=params)
return tgg return tgg