Skip to content

Instantly share code, notes, and snippets.

@leplatrem
Created February 3, 2023 10:11
Show Gist options
  • Save leplatrem/73f7f713c8f28688e5234fc8eb5f3503 to your computer and use it in GitHub Desktop.
Save leplatrem/73f7f713c8f28688e5234fc8eb5f3503 to your computer and use it in GitHub Desktop.

Github Actions Matrix Debug

Goal: Implement the matrix expansion behaviour in matrix_combinations() function, following the official Github Actions documentation.

Run tests:

pytest main.py

Use on real workflow file:

python main.py .github/workflows/CI.yml
import sys
def matrix_combinations(matrix) -> list[dict]:
"""
https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#expanding-or-adding-matrix-configurations
For each object in the include list, the key:value pairs in the object will
be added to each of the matrix combinations if none of the key:value pairs
overwrite any of the original matrix values. If the object cannot be added
to any of the matrix combinations, a new matrix combination will be created
instead. Note that the original matrix values will not be overwritten, but
added matrix values can be overwritten.
"""
return []
def test_include_only():
matrix = {
"include": [
{"a": 42},
{"a": "foo"},
]
}
expected = [
{"a": 42},
{"a": "foo"},
]
assert matrix_combinations(matrix) == expected
def test_exclude():
matrix = {
"a": [1, 2],
"b": [3, 4],
"exclude": [
{"a": 1},
{"a": 2, "b": 4},
],
}
expected = [
{"a": 2, "b": 3},
]
assert matrix_combinations(matrix) == expected
def test_official_documentation_example():
matrix = {
"fruit": ["apple", "pear"],
"animal": ["cat", "dog"],
"include": [
{"color": "green"},
{"color": "pink", "animal": "cat"},
{"fruit": "apple", "shape": "circle"},
{"fruit": "banana"},
{"fruit": "banana", "animal": "cat"},
],
}
expected = [
{"fruit": "apple", "animal": "cat", "color": "pink", "shape": "circle"},
{"fruit": "apple", "animal": "dog", "color": "green", "shape": "circle"},
{"fruit": "pear", "animal": "cat", "color": "pink"},
{"fruit": "pear", "animal": "dog", "color": "green"},
{"fruit": "banana"},
{"fruit": "banana", "animal": "cat"},
]
# * {color: green} is added to all of the original matrix combinations because
# it can be added without overwriting any part of the original
# combinations.
# * {color: pink, animal: cat} adds color:pink only to the
# original matrix combinations that include animal: cat. This overwrites
# the color: green that was added by the previous include entry.
# * {fruit: apple, shape: circle} adds shape: circle only to the original
# matrix combinations that include fruit: apple.
# * {fruit: banana} cannot be
# added to any original matrix combination without overwriting a value, so
# it is added as an additional matrix combination.
# * {fruit: banana, animal: cat} cannot be added to any original matrix combination
# without overwriting a value, so it is added as an additional matrix combination.
# It does not add to the {fruit: banana} matrix combination because that
# combination was not one of the original matrix combinations.
combinations = matrix_combinations(matrix)
for combination in expected:
assert combination in combinations
combinations.remove(combination)
assert len(combinations) == 0
if __name__ == "__main__":
try:
import yaml
except ImportError:
print("Run `pip install pyyaml`")
sys.exit(1)
with open(sys.argv[1]) as f:
content = yaml.safe_load(f)
for name, job in content["jobs"].items():
job_name = job.get("name", name)
interpolated = re.findall("\\$\\{\\{([^\\}]+)\\}\\}", job_name)
matrix = job.get("strategy", {}).get("matrix")
if not matrix:
continue
combinations = matrix_combinations(matrix)
for combination in combinations:
for var in interpolated:
_, field = var.split(".") # ${{ matrix.{var} }}
value = combination.get(field.strip(), "")
job_name = job_name.replace(f"${{{{{var}}}}}", str(value))
print(f"\n- {job_name}")
for var, value in combination.items():
print(f" {var}: {value}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment