Skip to content

Commit 1b827bc

Browse files
glimaLiliDeng
authored andcommitted
ado_artifact_download: add extra artifact field/property filtering
The method/helper will now get a new filtering mechanism, beyond the if run.result == "succeeded" and run.state == "completed" hardcoded one. Imagine one needs to check for the presence of the following attributes, with the following values: additional_build_checks = { "additional_properties" : { "templateParameters": { "build_tools_image": True, "build_base_os": True } } } With this commit, it is now possible. Without it, it would blindly pick the last succesful build in the pipeline, that could still miss artifacts we are interested in.
1 parent 51ca0e3 commit 1b827bc

File tree

1 file changed

+52
-3
lines changed

1 file changed

+52
-3
lines changed

lisa/advanced_tools/ado_artifact_download.py

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import re
44
from pathlib import Path
55
from time import time
6-
from typing import Any, List
6+
from typing import Any, Dict, List, Union
77

88
import requests
99
from assertpy import assert_that
@@ -28,6 +28,47 @@ def _check_exists(self) -> bool:
2828
def can_install(self) -> bool:
2929
return False
3030

31+
def _check_attrs_recursive(
32+
self, obj: Any, checks: Union[Dict[Any, Any], None]
33+
) -> bool:
34+
if not checks:
35+
return True
36+
37+
for key, expected_value in checks.items():
38+
if isinstance(obj, dict) and key in obj:
39+
current_value = obj[key]
40+
elif hasattr(obj, key):
41+
current_value = getattr(obj, key)
42+
else:
43+
found = False
44+
if isinstance(obj, dict):
45+
for v in obj.values():
46+
if isinstance(
47+
v, (dict, object)
48+
) and self._check_attrs_recursive(v, {key: expected_value}):
49+
found = True
50+
break
51+
elif hasattr(obj, "__dict__"):
52+
for attr_val in vars(obj).values():
53+
if isinstance(
54+
attr_val, (dict, object)
55+
) and self._check_attrs_recursive(
56+
attr_val, {key: expected_value}
57+
):
58+
found = True
59+
break
60+
if not found:
61+
return False
62+
continue # skip rest of loop since match was deep
63+
64+
if isinstance(expected_value, dict):
65+
if not self._check_attrs_recursive(current_value, expected_value):
66+
return False
67+
elif current_value != expected_value:
68+
return False
69+
70+
return True
71+
3172
def download(
3273
self,
3374
personal_access_token: str,
@@ -39,6 +80,7 @@ def download(
3980
build_name: str = "",
4081
timeout: int = 600,
4182
output_path: Path = constants.RUN_LOCAL_WORKING_PATH,
83+
additional_build_checks: Union[Dict[Any, Any], None] = None,
4284
) -> List[Path]:
4385
credentials = BasicAuthentication("", personal_access_token)
4486
connection = Connection(base_url=organization_url, creds=credentials)
@@ -50,7 +92,9 @@ def download(
5092
pipeline_run = [
5193
run
5294
for run in pipeline_runs
53-
if run.result == "succeeded" and run.state == "completed"
95+
if run.result == "succeeded"
96+
and run.state == "completed"
97+
and self._check_attrs_recursive(run, additional_build_checks)
5498
]
5599
assert_that(len(pipeline_run)).described_as(
56100
f"no succeeded and completed run found for pipeline {pipeline_name}"
@@ -61,7 +105,12 @@ def download(
61105
pipeline_runs = self._get_pipeline_runs(
62106
connection, pipeline_name, project_name
63107
)
64-
pipeline_run = [run for run in pipeline_runs if run.name == build_name]
108+
pipeline_run = [
109+
run
110+
for run in pipeline_runs
111+
if run.name == build_name
112+
and self._check_attrs_recursive(run, additional_build_checks)
113+
]
65114
assert_that(len(pipeline_run)).described_as(
66115
f"no succeeded and completed run found for pipeline {pipeline_name}"
67116
).is_not_zero()

0 commit comments

Comments
 (0)