forked from pantsbuild/pants
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add filtering subsystem to permit skipping targets by tags (pantsbuil…
…d#7275) This subsystem is responsible for handling options meant to exclude targets from specific tasks The application of the logic itself is contained in the TargetFiltering class - which currently only handles excluding targets with provided tags and can be expanded upon for additional filtering options.
- Loading branch information
1 parent
b34d66f
commit a86639e
Showing
4 changed files
with
132 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
# coding=utf-8 | ||
# Copyright 2019 Pants project contributors (see CONTRIBUTORS.md). | ||
# Licensed under the Apache License, Version 2.0 (see LICENSE). | ||
|
||
from __future__ import absolute_import, division, print_function, unicode_literals | ||
|
||
import logging | ||
from builtins import object, set | ||
|
||
from pants.subsystem.subsystem import Subsystem | ||
|
||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class TargetFilter(Subsystem): | ||
"""Filter targets matching configured criteria. | ||
:API: public | ||
""" | ||
|
||
options_scope = 'target-filter' | ||
|
||
@classmethod | ||
def register_options(cls, register): | ||
super(TargetFilter, cls).register_options(register) | ||
|
||
register('--exclude-tags', type=list, | ||
default=[], fingerprint=True, | ||
help='Skip targets with given tag(s).') | ||
|
||
def apply(self, targets): | ||
exclude_tags = set(self.get_options().exclude_tags) | ||
return TargetFiltering(targets, exclude_tags).apply_tag_blacklist() | ||
|
||
|
||
class TargetFiltering(object): | ||
"""Apply filtering logic against targets.""" | ||
|
||
def __init__(self, targets, exclude_tags): | ||
self.targets = targets | ||
self.exclude_tags = exclude_tags | ||
|
||
def apply_tag_blacklist(self): | ||
return [t for t in self.targets if not self.exclude_tags.intersection(t.tags)] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
61 changes: 61 additions & 0 deletions
61
tests/python/pants_test/build_graph/test_target_filter_subsystem.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
# coding=utf-8 | ||
# Copyright 2019 Pants project contributors (see CONTRIBUTORS.md). | ||
# Licensed under the Apache License, Version 2.0 (see LICENSE). | ||
|
||
from __future__ import absolute_import, division, print_function, unicode_literals | ||
|
||
from builtins import set | ||
|
||
from pants.build_graph.target_filter_subsystem import TargetFilter, TargetFiltering | ||
from pants.task.task import Task | ||
from pants_test.task_test_base import TaskTestBase | ||
|
||
|
||
class TestTargetFilter(TaskTestBase): | ||
|
||
class DummyTask(Task): | ||
options_scope = 'dummy' | ||
|
||
def execute(self): | ||
self.context.products.safe_create_data('task_targets', self.get_targets) | ||
|
||
@classmethod | ||
def task_type(cls): | ||
return cls.DummyTask | ||
|
||
def test_task_execution_with_filter(self): | ||
a = self.make_target('a', tags=['skip-me']) | ||
b = self.make_target('b', dependencies=[a], tags=[]) | ||
|
||
context = self.context(for_task_types=[self.DummyTask], for_subsystems=[TargetFilter], target_roots=[b], options={ | ||
TargetFilter.options_scope: { | ||
'exclude_tags': ['skip-me'] | ||
} | ||
}) | ||
|
||
self.create_task(context).execute() | ||
self.assertEqual([b], context.products.get_data('task_targets')) | ||
|
||
def test_filtering_single_tag(self): | ||
a = self.make_target('a', tags=[]) | ||
b = self.make_target('b', tags=['skip-me']) | ||
c = self.make_target('c', tags=['tag1', 'skip-me']) | ||
|
||
filtered_targets = TargetFiltering([a, b, c], {'skip-me'}).apply_tag_blacklist() | ||
self.assertEqual([a], filtered_targets) | ||
|
||
def test_filtering_multiple_tags(self): | ||
a = self.make_target('a', tags=['tag1', 'skip-me']) | ||
b = self.make_target('b', tags=['tag1', 'tag2', 'skip-me']) | ||
c = self.make_target('c', tags=['tag2']) | ||
|
||
filtered_targets = TargetFiltering([a, b, c], {'skip-me', 'tag2'}).apply_tag_blacklist() | ||
self.assertEqual([], filtered_targets) | ||
|
||
def test_filtering_no_tags(self): | ||
a = self.make_target('a', tags=['tag1']) | ||
b = self.make_target('b', tags=['tag1', 'tag2']) | ||
c = self.make_target('c', tags=['tag2']) | ||
|
||
filtered_targets = TargetFiltering([a, b, c], set()).apply_tag_blacklist() | ||
self.assertEqual([a, b, c], filtered_targets) |