Skip to content

Commit fde5cae

Browse files
authored
ansible_test_splitter - extend feature for roles (#109)
* add splitter for role * changed files * add more log * Display command * add optional argument * Remove base_ref input * fix role matching * add documentation for ansible_test_splitter github action * update after code review
1 parent ee8190a commit fde5cae

File tree

3 files changed

+109
-3
lines changed

3 files changed

+109
-3
lines changed
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# ansible_test_splitter
2+
3+
This action identifies the targets impacted by the changes on a pull request and split them into a number of jobs defined by the user.
4+
5+
## Usage
6+
7+
<!-- start usage -->
8+
9+
```yaml
10+
- uses: ansible-network/github_actions/.github/actions/ansible_test_splitter@main
11+
with:
12+
# Path to a list of collections
13+
collections_to_test: |
14+
path_to_collection_1
15+
path_to_collection_2
16+
(...)
17+
path_to_collection_n
18+
19+
# The total number of jobs to share
20+
total_jobs: 5
21+
```
22+
23+
The action output is a variable `test_targets` containing a list of chunk for each collection with the targets for each chunk.
24+
e.g: `community.aws-1:dynamodb_table;community.aws-2:elb_target;community.aws-3:msk_cluster-auth;community.aws-4:secretsmanager_secret;community.aws-5:redshift,ec2_transit_gateway_vpc_attachment`
25+
26+
<!-- end usage -->
27+
28+
## Relationship between plugins/roles and targets
29+
30+
This action reads elements to test from `plugins` and `roles` directories and corresponding tests from `tests/integration/targets` directory. Here after more details on the relationship between plugins/roles and integration tests targets:
31+
32+
- `modules`, the test target should have the same name as the module or defines the module name into the `aliases` file
33+
34+
_Example_:
35+
36+
```
37+
|___plugins/modules/my_module.py
38+
|___tests
39+
|___integration
40+
|___targets
41+
|___my_module
42+
|___another_test
43+
|___aliases (contains this line my_module)
44+
```
45+
46+
For any change on `plugins/modules/my_module.py`, this action will produce `my_module` and `another_test` as impacted targets.
47+
48+
- `roles`, the test target should defines the role name with the prefix `role` into the `aliases` file.
49+
50+
_Example_:
51+
52+
```
53+
|___roles/some_role
54+
|___tests
55+
|___integration
56+
|___targets
57+
|___test_of_some_role
58+
|___aliases (contains this line role/some_role)
59+
```
60+
61+
For any change on `roles/some_role`, this action will produce `test_of_some_role` as impacted target.
62+
63+
- For any other plugin (inventory, connection, module_utils, plugin_utils, lookup), the test target should have the same name as the plugin or defines the plugin name prefixed by the plugin type and underscore (e.g: **inventory_myinventory**) into the `aliases` file.
64+
65+
_Example_:
66+
67+
```
68+
|___plugins/lookup/random.py
69+
|___tests
70+
|___integration
71+
|___targets
72+
|___lookup_random
73+
|___test_random
74+
|___aliases (contains this line lookup_random)
75+
```
76+
77+
For any change on `plugins/lookup/random.py`, this action will produce `lookup_random` and `test_random` as impacted targets.
78+
79+
## Debugging
80+
81+
- Set the label `test-all-the-targets` on the pull request to run the full test suite instead of the impacted changes.
82+
- Use `TargetsToTest=collection1:target01,target02;collection2:target03,target4` in the pull request description to run a specific list of targets.
83+
_Example_: You need to test the following targets for a pull request
84+
85+
```yaml
86+
- collection1: some_test_1 some_test_2
87+
- collection2: another_test
88+
```
89+
90+
The pull request should contain the following line `TargetsToTest=collection1:some_test_1,some_test_2;collection2:another_test`.

.github/actions/ansible_test_splitter/list_changed_common.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,9 +173,9 @@ def changed_files(self) -> list[PosixPath]:
173173
:returns: a list of pathlib.PosixPath
174174
"""
175175
if not self.files:
176-
stdout = run_command(
177-
command=f"git diff origin/{self.base_ref} --name-only", chdir=self.collection_path
178-
)
176+
changed_files_cmd = f"git diff origin/{self.base_ref} --name-only"
177+
print(f"Command for changed files => {changed_files_cmd}")
178+
stdout = run_command(command=changed_files_cmd, chdir=self.collection_path)
179179
self.files = [PosixPath(p) for p in stdout.split("\n") if p]
180180
return self.files
181181

@@ -229,6 +229,15 @@ def modules(self) -> Generator[PosixPath, None, None]:
229229
"""
230230
yield from self._path_matches("plugins/modules/")
231231

232+
def roles(self) -> Generator[str, None, None]:
233+
"""List the roles impacted by the change.
234+
235+
:yields: path to a role change
236+
"""
237+
for changed_file in self.changed_files():
238+
if str(changed_file).startswith("roles/"):
239+
yield str(changed_file).split("/", maxsplit=2)[1]
240+
232241
def _util_matches(
233242
self, base_path: str, import_path: str
234243
) -> Generator[tuple[PosixPath, str], None, None]:

.github/actions/ansible_test_splitter/list_changed_targets.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ def _add_changed_target(
7777
elif plugin_type == "modules":
7878
file_name = PosixPath(ref_path).stem
7979
plugin_file_name = file_name
80+
elif plugin_type == "roles":
81+
file_name = str(ref_path)
82+
plugin_file_name = f"role/{ref_path}"
8083
else:
8184
file_name = PosixPath(ref_path).stem
8285
plugin_file_name = f"{plugin_type}_{PosixPath(ref_path).stem}"
@@ -85,6 +88,7 @@ def _add_changed_target(
8588
collection.add_target_to_plan(plugin_file_name)
8689

8790
for whc in [WhatHaveChanged(path, self.base_ref) for path in self.collections_to_test]:
91+
print(f"changed file for collection [{whc.collection_name}] => {whc.changed_files()}")
8892
listed_changes[whc.collection_name] = {
8993
"modules": [],
9094
"inventory": [],
@@ -93,6 +97,7 @@ def _add_changed_target(
9397
"plugin_utils": [],
9498
"lookup": [],
9599
"targets": [],
100+
"roles": [],
96101
}
97102
for path in whc.modules():
98103
_add_changed_target(whc.collection_name, path, "modules")
@@ -112,6 +117,8 @@ def _add_changed_target(
112117
_add_changed_target(whc.collection_name, path, "lookup")
113118
for target in whc.targets():
114119
_add_changed_target(whc.collection_name, target, "targets")
120+
for role in whc.roles():
121+
_add_changed_target(whc.collection_name, role, "roles")
115122

116123
print("----------- Listed Changes -----------\n", json.dumps(listed_changes, indent=2))
117124
return {x: make_unique(y["targets"]) for x, y in listed_changes.items()}

0 commit comments

Comments
 (0)