-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.py
executable file
·136 lines (114 loc) · 4.27 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#!/usr/bin/env python3
"""
Parse strategy matrix in GitHub Action.
"""
import json
import os
from typing import Any
import yaml
def error(value: str) -> None:
"""
Write out an GitHub Action error.
"""
print(f"::error file={__file__}::{value}")
def output(name: str, value: str) -> None:
"""
Write out an GitHub Action output.
"""
with open(os.environ["GITHUB_OUTPUT"], "a", encoding="UTF-8") as output_file:
output_file.write(f"{name}={value}\r\n")
def setenv(name: str, value: str) -> None:
"""
Write out an GitHub Action environment variable.
"""
with open(os.environ["GITHUB_ENV"], "a", encoding="UTF-8") as output_file:
output_file.write(f"{name}={value}\r\n")
def assert_valid_extra(extra: Any) -> None:
"""
Validate strategy matrix include/exclude.
"""
if not isinstance(extra, list):
raise TypeError(
f"Include/exclude must be a sequence (Python list), but Python "
f"{type(extra)} received."
)
for combination in extra:
if not isinstance(combination, dict):
raise TypeError(
f"Each include/exclude combination must a mapping (Python "
f"dict), but Python {type(combination)} received."
)
if not combination:
raise ValueError("Include/exclude combination contains no values.")
for variable, value in combination.items():
if not isinstance(variable, str):
raise TypeError(
f"Include/exclude variables must be strings, but "
f"Python {type(variable)} received."
)
if not isinstance(value, str):
raise TypeError(
f"Each include/exclude value must be a string, but Python "
f"{type(value)} received for variable '{variable}'."
)
def assert_valid_matrix(matrix: Any) -> None:
"""
Validate strategy matrix.
"""
if matrix is None:
raise RuntimeError("Strategy matrix must define at least one combination.")
if not isinstance(matrix, dict):
raise TypeError(
f"Matrix must be a mapping (Python dict), but Python "
f"{type(matrix)} received."
)
for variable, values in matrix.items():
if not isinstance(variable, str):
raise TypeError(
f"Matrix variables must be strings, but Python "
f"{type(variable)} received."
)
if variable in ("include", "exclude"):
assert_valid_extra(values)
else:
if not isinstance(values, list):
raise TypeError(
f"Matrix values must be sequences (Python lists), but "
f"Python {type(values)} received for variable '{variable}'."
)
if not values:
raise ValueError(f"No values received for variable '{variable}'.")
for value in values:
if not isinstance(value, str):
raise TypeError(
f"Each matrix value must be a string, but Python "
f"{type(value)} received for variable '{variable}'."
)
# The whole matrix, one of or both include and exclude are empty.
if not matrix or all(not values for values in matrix.values()):
raise RuntimeError("Strategy matrix must define at least one combination.")
def parse_matrix(input_matrix: str) -> dict:
"""
Parse strategy matrix from string and validate it.
"""
# Parse every YAML scalar as a string
matrix = yaml.load(input_matrix, Loader=yaml.loader.BaseLoader)
assert_valid_matrix(matrix)
return matrix
def main() -> None:
"""
Parse strategy matrix from GitHub Action input ('matrix'), parse and
validate it, print it out and set it as output ('matrix') and as
environment variable ('MATRIX').
"""
try:
matrix = parse_matrix(os.environ["INPUT_MATRIX"])
print(yaml.dump({"matrix": matrix}, sort_keys=False))
output_matrix = json.dumps(matrix)
except Exception as e:
error(str(e))
raise e
setenv("MATRIX", output_matrix)
output("matrix", output_matrix)
if __name__ == "__main__":
main()