@@ -2,14 +2,21 @@ defmodule Ppl.DefinitionReviser.JobMatrixValidator do
2
2
@ moduledoc """
3
3
This module serves to validate that all job matrix values are provided
4
4
as a list of strings either explicitly or after evaluation by SPC command line tool.
5
+
6
+ It also validates that there are no duplicate environment variable names in the job matrix.
7
+ It also validates that the total product size of the matrix (product of number of values of each environment variable) is not too large.
5
8
"""
6
9
7
10
alias Util.ToTuple
8
11
12
+ @ max_size 100
13
+
9
14
def validate ( definition ) do
10
15
with { :ok , definition } <- do_validate_job_matrix_values ( definition , "blocks" ) ,
11
16
{ :ok , definition } <- do_validate_job_matrix_values ( definition , "after_pipeline" ) do
12
17
ToTuple . ok ( definition )
18
+ else
19
+ { :error , _ } = error -> error
13
20
end
14
21
end
15
22
@@ -43,9 +50,29 @@ defmodule Ppl.DefinitionReviser.JobMatrixValidator do
43
50
jobs = get_in ( block , [ "build" , "jobs" ] ) |> List . wrap ( )
44
51
block_name = get_in ( block , [ "name" ] )
45
52
46
- case Enum . find_value ( jobs , & validate_job_matrices ( block_name , & 1 ) ) do
47
- nil -> { :ok , [ block ] ++ block_acc }
48
- { :error , error } -> { :error , error }
53
+ # Calculate total matrix size across all jobs in the block
54
+ total_result =
55
+ Enum . reduce_while ( jobs , { :ok , 0 } , fn job , { :ok , total_size } ->
56
+ case validate_job_matrices ( block_name , job ) do
57
+ nil -> { :cont , { :ok , total_size } }
58
+ { :ok , matrix_size } -> { :cont , { :ok , total_size + matrix_size } }
59
+ { :error , _ } = error -> { :halt , error }
60
+ end
61
+ end )
62
+
63
+ case total_result do
64
+ { :ok , total_size } ->
65
+ if total_size > @ max_size do
66
+ { :error ,
67
+ { :malformed ,
68
+ "Total matrix size exceeds maximum allowed size (#{ @ max_size } ) in block '#{ block_name } '. " <>
69
+ "The matrix product size is calculated as the product of the number of values for each environment variable." } }
70
+ else
71
+ { :ok , [ block ] ++ block_acc }
72
+ end
73
+
74
+ { :error , _ } = error ->
75
+ error
49
76
end
50
77
end
51
78
@@ -56,10 +83,39 @@ defmodule Ppl.DefinitionReviser.JobMatrixValidator do
56
83
job_name = Map . get ( job , "name" )
57
84
58
85
if Map . has_key? ( job , "matrix" ) and is_list ( matrix_values ) do
59
- Enum . find_value ( matrix_values , & check_matrix_values ( block_name , job_name , & 1 ) )
86
+ case validate_job_matrix ( block_name , job_name , matrix_values , job ) do
87
+ { :ok , matrix_size } -> { :ok , matrix_size }
88
+ { :error , _ } = error -> error
89
+ nil -> nil
90
+ end
60
91
end
61
92
end
62
93
94
+ defp validate_job_matrix ( block_name , job_name , matrix_values , job ) do
95
+ with nil <- check_for_duplicate_env_vars ( block_name , job_name , matrix_values ) ,
96
+ nil <- Enum . find_value ( matrix_values , & check_matrix_values ( block_name , job_name , & 1 ) ) ,
97
+ { :ok , matrix_size } <- check_matrix_product_size ( block_name , job_name , matrix_values , job ) do
98
+ { :ok , matrix_size }
99
+ else
100
+ { :error , _ } = error -> error
101
+ end
102
+ end
103
+
104
+ defp check_for_duplicate_env_vars ( block_name , job_name , matrix_values ) do
105
+ env_var_names_count =
106
+ Enum . reduce ( matrix_values , % { } , fn matrix_entry , acc ->
107
+ env_var = Map . get ( matrix_entry , "env_var" )
108
+ Map . update ( acc , env_var , 1 , & ( & 1 + 1 ) )
109
+ end )
110
+
111
+ Enum . find_value ( env_var_names_count , fn { env_var_name , count } ->
112
+ if count > 1 do
113
+ { :error ,
114
+ { :malformed , duplicate_env_var_error_message ( block_name , job_name , env_var_name ) } }
115
+ end
116
+ end )
117
+ end
118
+
63
119
defp check_matrix_values ( block_name , job_name , matrix_entry ) do
64
120
env_var = get_in ( matrix_entry , [ "env_var" ] )
65
121
values = get_in ( matrix_entry , [ "values" ] )
@@ -72,4 +128,29 @@ defmodule Ppl.DefinitionReviser.JobMatrixValidator do
72
128
defp error_mesasge ( block_name , job_name , env_var ) do
73
129
"Matrix values for env_var '#{ env_var } ' (block '#{ block_name } ', job '#{ job_name } ' must be a non-empty list of strings."
74
130
end
131
+
132
+ defp duplicate_env_var_error_message ( block_name , job_name , env_var_name ) do
133
+ "Duplicate environment variable(s): '#{ env_var_name } ' in job matrix (block '#{ block_name } ', job '#{ job_name } ')."
134
+ end
135
+
136
+ def check_matrix_product_size ( block_name , job_name , matrix_values , _job ) do
137
+ matrix_size =
138
+ Enum . reduce ( matrix_values , 1 , fn matrix_entry , acc ->
139
+ values = get_in ( matrix_entry , [ "values" ] )
140
+ if is_list ( values ) , do: min ( acc * length ( values ) , @ max_size + 1 ) , else: acc
141
+ end )
142
+
143
+ if matrix_size > @ max_size do
144
+ { :error ,
145
+ { :malformed ,
146
+ matrix_product_size_error_message ( block_name , job_name , matrix_size , @ max_size ) } }
147
+ else
148
+ { :ok , matrix_size }
149
+ end
150
+ end
151
+
152
+ defp matrix_product_size_error_message ( block_name , job_name , size , max_size ) do
153
+ "Matrix product size exceeds maximum allowed size (#{ max_size } ) in job matrix (block '#{ block_name } ', job '#{ job_name } '). " <>
154
+ "The matrix product size is calculated as the product of the number of values for each environment variable."
155
+ end
75
156
end
0 commit comments