Skip to content

Commit 69a0e78

Browse files
committed
buildkite: handle matrix attributes in unexpected locations
soft_fail contains a list of dicts, and the matrix processing was seeing it and getting confused. This change makes lists and dicts get processed all the way down, and also completely ignores data types it doesn't know how to process, rather than blowing up on them. Fixes #2486
1 parent ceba906 commit 69a0e78

File tree

2 files changed

+55
-34
lines changed

2 files changed

+55
-34
lines changed

buildkite/bazelci.py

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -921,6 +921,20 @@ def match_matrix_attr_pattern(s):
921921
return re.match(r"^\${{\s*(\w+)\s*}}$", s)
922922

923923

924+
def get_matrix_attributes_for_value(value):
925+
if isinstance(value, str):
926+
res = match_matrix_attr_pattern(value)
927+
if res:
928+
yield res.groups()[0]
929+
elif isinstance(value, list):
930+
for subvalue in value:
931+
yield from get_matrix_attributes_for_value(subvalue)
932+
elif isinstance(value, dict):
933+
for subkey, subvalue in value.items():
934+
yield from get_matrix_attributes_for_value(subkey)
935+
yield from get_matrix_attributes_for_value(subvalue)
936+
937+
924938
def get_matrix_attributes(task):
925939
"""Get unexpanded matrix attributes from the given task.
926940
@@ -929,16 +943,7 @@ def get_matrix_attributes(task):
929943
"""
930944
attributes = set()
931945
for value in task.values():
932-
if type(value) is str:
933-
res = match_matrix_attr_pattern(value)
934-
if res:
935-
attributes.add(res.groups()[0])
936-
elif type(value) is list:
937-
for subvalue in value:
938-
res = match_matrix_attr_pattern(subvalue)
939-
if res:
940-
attributes.add(res.groups()[0])
941-
946+
attributes.update(get_matrix_attributes_for_value(value))
942947
return sorted(attributes)
943948

944949

@@ -1005,22 +1010,27 @@ def get_combinations(matrix, attributes, excludes=None):
10051010
return all_combinations
10061011

10071012

1013+
def expand_task_for_value(value, parent, parent_item, lookup):
1014+
if isinstance(value, str):
1015+
res = match_matrix_attr_pattern(value)
1016+
if res:
1017+
attr = res.groups()[0]
1018+
parent[parent_item] = lookup[attr].value
1019+
elif isinstance(value, list):
1020+
for i, subvalue in enumerate(value):
1021+
expand_task_for_value(subvalue, parent[parent_item], i, lookup)
1022+
elif isinstance(value, dict):
1023+
for subkey, subvalue in value.items():
1024+
expand_task_for_value(subvalue, parent[parent_item], subkey, lookup)
1025+
expand_task_for_value(subvalue, parent[parent_item], subkey, lookup)
1026+
1027+
10081028
def get_expanded_task(task, combination):
10091029
"""Expand a task with the given combination of values of attributes."""
10101030
combination = dict(combination)
10111031
expanded_task = copy.deepcopy(task)
10121032
for key, value in task.items():
1013-
if type(value) is str:
1014-
res = match_matrix_attr_pattern(value)
1015-
if res:
1016-
attr = res.groups()[0]
1017-
expanded_task[key] = combination[attr].value
1018-
elif type(value) is list:
1019-
for i, subvalue in enumerate(value):
1020-
res = match_matrix_attr_pattern(subvalue)
1021-
if res:
1022-
attr = res.groups()[0]
1023-
expanded_task[key][i] = combination[attr].value
1033+
expand_task_for_value(value, expanded_task, key, combination)
10241034

10251035
if "name" in expanded_task:
10261036
alias_combination = {k: a.alias for k, a in combination.items()}

buildkite/bazelci_test.py

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ class MatrixExpansion(unittest.TestCase):
222222
matrix:
223223
bazel: ["1.2.3", "2.3.4"]
224224
platform: ["pf1", "pf2"]
225+
exit_status: [1, 2]
225226
tasks:
226227
basic:
227228
name: "Basic"
@@ -234,26 +235,36 @@ class MatrixExpansion(unittest.TestCase):
234235
name: "Formatted w/ Bazel v{bazel} on {platform}"
235236
bazel: ${{ bazel }}
236237
platform: ${{ platform }}
238+
exit_status:
239+
name: "Exit Status: {exit_status}"
240+
soft_fail:
241+
- exit_status: ${{exit_status}}
237242
"""
238243
)
239244

240245
def test_basic_functionality(self):
241-
config = self._CONFIGS
246+
import copy
247+
config = copy.deepcopy(self._CONFIGS)
242248

243249
bazelci.expand_task_config(config)
244250
expanded_tasks = config["tasks"]
245-
self.assertEqual(len(expanded_tasks), 9)
246-
expanded_task_names = [task.get("name", None) for id, task in expanded_tasks.items()]
247-
self.assertEqual(expanded_task_names, [
248-
"Basic", # no matrix expansion
249-
"Unformatted", # bazel v1.2.3
250-
"Unformatted", # bazel v2.3.4
251-
None, # no name, bazel v1.2.3
252-
None, # no name, bazel v2.3.4
253-
"Formatted w/ Bazel v1.2.3 on pf1",
254-
"Formatted w/ Bazel v1.2.3 on pf2",
255-
"Formatted w/ Bazel v2.3.4 on pf1",
256-
"Formatted w/ Bazel v2.3.4 on pf2",
251+
252+
self.assertEqual(list(expanded_tasks.values()), [
253+
# no matrix expansion
254+
dict(name = "Basic"),
255+
256+
dict(name = "Unformatted", bazel = "1.2.3"),
257+
dict(name = "Unformatted", bazel = "2.3.4"),
258+
259+
# no name
260+
dict(bazel = "1.2.3"),
261+
dict(bazel = "2.3.4"),
262+
dict(name = "Formatted w/ Bazel v1.2.3 on pf1", bazel = "1.2.3", platform = "pf1"),
263+
dict(name = "Formatted w/ Bazel v1.2.3 on pf2", bazel = "1.2.3", platform = "pf2"),
264+
dict(name = "Formatted w/ Bazel v2.3.4 on pf1", bazel = "2.3.4", platform = "pf1"),
265+
dict(name = "Formatted w/ Bazel v2.3.4 on pf2", bazel = "2.3.4", platform = "pf2"),
266+
dict(name ="Exit Status: 1", soft_fail = [dict(exit_status = 1)]),
267+
dict(name ="Exit Status: 2", soft_fail = [dict(exit_status = 2)]),
257268
])
258269

259270

0 commit comments

Comments
 (0)