8
8
"""
9
9
import argparse
10
10
import glob
11
- import logging
12
11
import os
13
12
import typing as t
14
13
from collections import Counter
21
20
from dynamic_pipelines .constants import DEFAULT_TARGET_TEST_CHILD_PIPELINE_FILEPATH
22
21
from dynamic_pipelines .constants import DEFAULT_TARGET_TEST_CHILD_PIPELINE_NAME
23
22
from dynamic_pipelines .constants import DEFAULT_TEST_PATHS
24
- from dynamic_pipelines .constants import KNOWN_GENERATE_TEST_CHILD_PIPELINE_WARNINGS_FILEPATH
23
+ from dynamic_pipelines .constants import (
24
+ KNOWN_GENERATE_TEST_CHILD_PIPELINE_WARNINGS_FILEPATH ,
25
+ )
25
26
from dynamic_pipelines .models import EmptyJob
26
27
from dynamic_pipelines .models import Job
27
28
from dynamic_pipelines .models import TargetTestJob
28
29
from dynamic_pipelines .utils import dump_jobs_to_yaml
29
- from gitlab .v4 .objects import Project
30
- from gitlab_api import Gitlab
31
30
from idf_build_apps import App
32
31
from idf_ci .app import import_apps_from_txt
33
- from idf_ci_utils import IDF_PATH
34
32
from idf_pytest .script import get_pytest_cases
35
33
36
34
@@ -50,47 +48,38 @@ def get_tags_with_amount(s: str) -> t.List[str]:
50
48
51
49
52
50
def get_target_test_jobs (
53
- project : Project , paths : str , apps : t .List [App ]
54
- ) -> t .Tuple [t .List [Job ], t .List [str ], t .Dict [ str , t . List [str ] ]]:
51
+ paths : str , apps : t .List [App ], exclude_runner_tags : t . Set [ str ]
52
+ ) -> t .Tuple [t .List [Job ], t .List [str ], t .List [str ]]:
55
53
"""
56
54
Return the target test jobs and the extra yaml files to include
57
55
"""
58
- issues : t .Dict [str , t .List [str ]] = {
59
- 'no_env_marker_test_cases' : [],
60
- 'no_runner_tags' : [],
61
- }
62
-
63
56
if mr_labels := os .getenv ('CI_MERGE_REQUEST_LABELS' ):
64
57
print (f'MR labels: { mr_labels } ' )
65
58
66
59
if BUILD_ONLY_LABEL in mr_labels .split (',' ):
67
60
print ('MR has build only label, skip generating target test child pipeline' )
68
- return [EmptyJob ()], [], issues
61
+ return [EmptyJob ()], [], []
69
62
70
63
pytest_cases = get_pytest_cases (
71
64
paths ,
72
65
apps = apps ,
73
66
marker_expr = 'not host_test' , # since it's generating target-test child pipeline
74
67
)
75
68
69
+ no_env_marker_test_cases : t .List [str ] = []
76
70
res = defaultdict (list )
77
71
for case in pytest_cases :
78
72
if not case .env_markers :
79
- issues [ ' no_env_marker_test_cases' ] .append (case .item .nodeid )
73
+ no_env_marker_test_cases .append (case .item .nodeid )
80
74
continue
81
75
82
76
res [(case .target_selector , tuple (sorted (case .env_markers )))].append (case )
83
77
84
78
target_test_jobs : t .List [Job ] = []
85
79
for (target_selector , env_markers ), cases in res .items ():
86
80
runner_tags = get_tags_with_amount (target_selector ) + list (env_markers )
87
- # we don't need to get all runner, as long as we get one runner, it's fine
88
- runner_list = project .runners .list (status = 'online' , tag_list = ',' .join (runner_tags ), get_all = False )
89
- if not runner_list :
90
- issues ['no_runner_tags' ].append (',' .join (runner_tags ))
91
- logging .warning (f'No runner found for { "," .join (runner_tags )} , required by cases:' )
92
- for case in cases :
93
- logging .warning (f' - { case .item .nodeid } ' )
81
+ if ',' .join (runner_tags ) in exclude_runner_tags :
82
+ print ('WARNING: excluding test cases with runner tags:' , runner_tags )
94
83
continue
95
84
96
85
target_test_job = TargetTestJob (
@@ -115,63 +104,54 @@ def get_target_test_jobs(
115
104
if fast_pipeline_flag :
116
105
extra_include_yml = ['tools/ci/dynamic_pipelines/templates/fast_pipeline.yml' ]
117
106
118
- issues ['no_env_marker_test_cases' ] = sorted (issues ['no_env_marker_test_cases' ])
119
- issues ['no_runner_tags' ] = sorted (issues ['no_runner_tags' ])
120
-
121
- return target_test_jobs , extra_include_yml , issues
107
+ no_env_marker_test_cases .sort ()
108
+ return target_test_jobs , extra_include_yml , no_env_marker_test_cases
122
109
123
110
124
111
def generate_target_test_child_pipeline (
125
- project : Project ,
126
112
paths : str ,
127
113
apps : t .List [App ],
128
114
output_filepath : str ,
129
115
) -> None :
130
- target_test_jobs , extra_include_yml , issues = get_target_test_jobs (project , paths , apps )
131
-
132
116
with open (KNOWN_GENERATE_TEST_CHILD_PIPELINE_WARNINGS_FILEPATH ) as fr :
133
117
known_warnings_dict = yaml .safe_load (fr ) or dict ()
134
118
119
+ exclude_runner_tags_set = set (known_warnings_dict .get ('no_runner_tags' , []))
120
+ # EXCLUDE_RUNNER_TAGS is a string separated by ';'
121
+ # like 'esp32,generic;esp32c3,wifi'
122
+ if exclude_runner_tags := os .getenv ('EXCLUDE_RUNNER_TAGS' ):
123
+ exclude_runner_tags_set .update (exclude_runner_tags .split (';' ))
124
+
125
+ target_test_jobs , extra_include_yml , no_env_marker_test_cases = get_target_test_jobs (
126
+ paths = paths ,
127
+ apps = apps ,
128
+ exclude_runner_tags = exclude_runner_tags_set ,
129
+ )
130
+
135
131
known_no_env_marker_test_cases = set (known_warnings_dict .get ('no_env_marker_test_cases' , []))
136
- no_env_marker_test_cases = set (issues [ ' no_env_marker_test_cases' ] )
132
+ no_env_marker_test_cases_set = set (no_env_marker_test_cases )
137
133
138
134
no_env_marker_test_cases_fail = False
139
- if no_env_marker_test_cases - known_no_env_marker_test_cases :
135
+ if no_env_marker_test_cases_set - known_no_env_marker_test_cases :
140
136
print ('ERROR: NEW "no_env_marker_test_cases" detected:' )
141
- for case in no_env_marker_test_cases - known_no_env_marker_test_cases :
137
+ for case in no_env_marker_test_cases_set - known_no_env_marker_test_cases :
142
138
print (f' - { case } ' )
143
139
no_env_marker_test_cases_fail = True
144
140
145
- print ('Please add at least one environment markers to the test cases listed above. '
146
- 'You may check all the env markers here: tools/ci/idf_pytest/constants.py' )
147
-
148
- known_no_runner_tags = set (known_warnings_dict .get ('no_runner_tags' , []))
149
- no_runner_tags = set (issues ['no_runner_tags' ])
150
-
151
- no_runner_tags_fail = False
152
- if no_runner_tags - known_no_runner_tags :
153
- print ('ERROR: NEW "no_runner_tags" detected:' )
154
- for tag in no_runner_tags - known_no_runner_tags :
155
- print (f' - { tag } ' )
156
- no_runner_tags_fail = True
157
-
158
141
print (
159
- '- If you\' re the owner of the missing runners, '
160
- 'please make sure the runners are online and have the required tags.\n '
161
- '- If you\' re the owner of the test cases that require the missing tags, '
162
- 'please add at least one runner with the required tags.\n '
163
- '- For other users, please contact the runner owner first, '
164
- 'or report this issue in our internal CI channel.\n '
165
- 'If the issue cannot be solved in a short time, '
166
- 'please add the missing tags to the "no_runner_tags" section '
167
- 'under the file inside ESP-IDF repo: '
168
- f'{ os .path .relpath (KNOWN_GENERATE_TEST_CHILD_PIPELINE_WARNINGS_FILEPATH , IDF_PATH )} .'
142
+ 'Please add at least one environment markers to the test cases listed above. '
143
+ 'You may check all the env markers here: tools/ci/idf_pytest/constants.py'
169
144
)
170
145
171
- if no_env_marker_test_cases_fail or no_runner_tags_fail :
146
+ if no_env_marker_test_cases_fail :
172
147
raise SystemExit ('Failed to generate target test child pipeline.' )
173
148
174
- dump_jobs_to_yaml (target_test_jobs , output_filepath , DEFAULT_TARGET_TEST_CHILD_PIPELINE_NAME , extra_include_yml )
149
+ dump_jobs_to_yaml (
150
+ target_test_jobs ,
151
+ output_filepath ,
152
+ DEFAULT_TARGET_TEST_CHILD_PIPELINE_NAME ,
153
+ extra_include_yml ,
154
+ )
175
155
print (f'Generate child pipeline yaml file { output_filepath } with { sum (j .parallel for j in target_test_jobs )} jobs' )
176
156
177
157
@@ -187,18 +167,6 @@ def generate_target_test_child_pipeline(
187
167
default = DEFAULT_TEST_PATHS ,
188
168
help = 'Paths to the apps to build.' ,
189
169
)
190
- parser .add_argument (
191
- '--project-id' ,
192
- type = int ,
193
- default = os .getenv ('CI_PROJECT_ID' ),
194
- help = 'Project ID' ,
195
- )
196
- parser .add_argument (
197
- '--pipeline-id' ,
198
- type = int ,
199
- default = os .getenv ('PARENT_PIPELINE_ID' ),
200
- help = 'Pipeline ID' ,
201
- )
202
170
parser .add_argument (
203
171
'-o' ,
204
172
'--output' ,
@@ -215,15 +183,12 @@ def generate_target_test_child_pipeline(
215
183
216
184
args = parser .parse_args ()
217
185
218
- gl_project = Gitlab (args .project_id ).project
219
-
220
186
apps = []
221
187
for f in glob .glob (args .app_info_filepattern ):
222
188
apps .extend (import_apps_from_txt (f ))
223
189
224
190
generate_target_test_child_pipeline (
225
- gl_project ,
226
- args .paths ,
227
- apps ,
228
- args .output ,
191
+ paths = args .paths ,
192
+ apps = apps ,
193
+ output_filepath = args .output ,
229
194
)
0 commit comments