Skip to content

Commit 9106c43

Browse files
committed
Merge branch 'ci/remove_gitlab_api_while_generating_test_pipeline' into 'master'
CI: remove gitlab api call while generating test pipeline See merge request espressif/esp-idf!34397
2 parents 27f11f8 + 502749d commit 9106c43

File tree

3 files changed

+58
-80
lines changed

3 files changed

+58
-80
lines changed

tools/ci/dynamic_pipelines/report.py

+10-6
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import yaml
1313
from artifacts_handler import ArtifactType
14+
from gitlab import GitlabUpdateError
1415
from gitlab_api import Gitlab
1516
from idf_build_apps import App
1617
from idf_build_apps.constants import BuildStatus
@@ -254,6 +255,10 @@ def _update_mr_comment(self, comment: str, print_retry_jobs_message: bool) -> No
254255
)
255256
del_retry_job_pic_pattern = re.escape(RETRY_JOB_TITLE) + r'.*?' + re.escape(f'{RETRY_JOB_PICTURE_PATH})')
256257

258+
new_comment = f'{COMMENT_START_MARKER}\n\n{comment}'
259+
if print_retry_jobs_message:
260+
new_comment += retry_job_picture_comment
261+
257262
for note in self.mr.notes.list(iterator=True):
258263
if note.body.startswith(COMMENT_START_MARKER):
259264
updated_str = self._get_updated_comment(note.body, comment)
@@ -264,14 +269,13 @@ def _update_mr_comment(self, comment: str, print_retry_jobs_message: bool) -> No
264269
updated_str += retry_job_picture_comment
265270

266271
note.body = updated_str
267-
note.save()
272+
try:
273+
note.save()
274+
except GitlabUpdateError:
275+
print('Failed to update MR comment, Creating a new comment')
276+
self.mr.notes.create({'body': new_comment})
268277
break
269278
else:
270-
# Create a new comment if no existing comment is found
271-
new_comment = f'{COMMENT_START_MARKER}\n\n{comment}'
272-
if print_retry_jobs_message:
273-
new_comment += retry_job_picture_comment
274-
275279
self.mr.notes.create({'body': new_comment})
276280

277281
def _get_updated_comment(self, existing_comment: str, new_comment: str) -> str:

tools/ci/dynamic_pipelines/scripts/generate_target_test_child_pipeline.py

+39-74
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
"""
99
import argparse
1010
import glob
11-
import logging
1211
import os
1312
import typing as t
1413
from collections import Counter
@@ -21,16 +20,15 @@
2120
from dynamic_pipelines.constants import DEFAULT_TARGET_TEST_CHILD_PIPELINE_FILEPATH
2221
from dynamic_pipelines.constants import DEFAULT_TARGET_TEST_CHILD_PIPELINE_NAME
2322
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+
)
2526
from dynamic_pipelines.models import EmptyJob
2627
from dynamic_pipelines.models import Job
2728
from dynamic_pipelines.models import TargetTestJob
2829
from dynamic_pipelines.utils import dump_jobs_to_yaml
29-
from gitlab.v4.objects import Project
30-
from gitlab_api import Gitlab
3130
from idf_build_apps import App
3231
from idf_ci.app import import_apps_from_txt
33-
from idf_ci_utils import IDF_PATH
3432
from idf_pytest.script import get_pytest_cases
3533

3634

@@ -50,47 +48,38 @@ def get_tags_with_amount(s: str) -> t.List[str]:
5048

5149

5250
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]]:
5553
"""
5654
Return the target test jobs and the extra yaml files to include
5755
"""
58-
issues: t.Dict[str, t.List[str]] = {
59-
'no_env_marker_test_cases': [],
60-
'no_runner_tags': [],
61-
}
62-
6356
if mr_labels := os.getenv('CI_MERGE_REQUEST_LABELS'):
6457
print(f'MR labels: {mr_labels}')
6558

6659
if BUILD_ONLY_LABEL in mr_labels.split(','):
6760
print('MR has build only label, skip generating target test child pipeline')
68-
return [EmptyJob()], [], issues
61+
return [EmptyJob()], [], []
6962

7063
pytest_cases = get_pytest_cases(
7164
paths,
7265
apps=apps,
7366
marker_expr='not host_test', # since it's generating target-test child pipeline
7467
)
7568

69+
no_env_marker_test_cases: t.List[str] = []
7670
res = defaultdict(list)
7771
for case in pytest_cases:
7872
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)
8074
continue
8175

8276
res[(case.target_selector, tuple(sorted(case.env_markers)))].append(case)
8377

8478
target_test_jobs: t.List[Job] = []
8579
for (target_selector, env_markers), cases in res.items():
8680
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)
9483
continue
9584

9685
target_test_job = TargetTestJob(
@@ -115,63 +104,54 @@ def get_target_test_jobs(
115104
if fast_pipeline_flag:
116105
extra_include_yml = ['tools/ci/dynamic_pipelines/templates/fast_pipeline.yml']
117106

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
122109

123110

124111
def generate_target_test_child_pipeline(
125-
project: Project,
126112
paths: str,
127113
apps: t.List[App],
128114
output_filepath: str,
129115
) -> None:
130-
target_test_jobs, extra_include_yml, issues = get_target_test_jobs(project, paths, apps)
131-
132116
with open(KNOWN_GENERATE_TEST_CHILD_PIPELINE_WARNINGS_FILEPATH) as fr:
133117
known_warnings_dict = yaml.safe_load(fr) or dict()
134118

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+
135131
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)
137133

138134
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:
140136
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:
142138
print(f' - {case}')
143139
no_env_marker_test_cases_fail = True
144140

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-
158141
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'
169144
)
170145

171-
if no_env_marker_test_cases_fail or no_runner_tags_fail:
146+
if no_env_marker_test_cases_fail:
172147
raise SystemExit('Failed to generate target test child pipeline.')
173148

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+
)
175155
print(f'Generate child pipeline yaml file {output_filepath} with {sum(j.parallel for j in target_test_jobs)} jobs')
176156

177157

@@ -187,18 +167,6 @@ def generate_target_test_child_pipeline(
187167
default=DEFAULT_TEST_PATHS,
188168
help='Paths to the apps to build.',
189169
)
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-
)
202170
parser.add_argument(
203171
'-o',
204172
'--output',
@@ -215,15 +183,12 @@ def generate_target_test_child_pipeline(
215183

216184
args = parser.parse_args()
217185

218-
gl_project = Gitlab(args.project_id).project
219-
220186
apps = []
221187
for f in glob.glob(args.app_info_filepattern):
222188
apps.extend(import_apps_from_txt(f))
223189

224190
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,
229194
)

tools/ci/dynamic_pipelines/templates/known_generate_test_child_pipeline_warnings.yml

+9
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# This is the file that contains the known warnings for the generate_test_child_pipeline.py script.
2+
# no_env_marker_test_cases: List of test cases that do not have environment markers.
3+
# each item shall be the test node id, you may check the error message to get the node id.
14
no_env_marker_test_cases:
25
- components/nvs_flash/test_apps/pytest_nvs_flash.py::test_nvs_flash[default]
36
- components/vfs/test_apps/pytest_vfs.py::test_vfs_ccomp[ccomp]
@@ -7,6 +10,12 @@ no_env_marker_test_cases:
710
- examples/storage/nvs_rw_value/pytest_nvs_rw_value.py::test_examples_nvs_rw_value
811
- examples/storage/nvs_rw_value_cxx/pytest_nvs_rw_value_cxx.py::test_examples_nvs_rw_value_cxx
912
- examples/storage/wear_levelling/pytest_wear_levelling_example.py::test_wear_levelling_example
13+
14+
# no_runner_tags: List of runner tags that has no test runner set.
15+
# each item shall be a comma separated list of runner tags.
16+
# NOTE:
17+
# 1. for multi dut tests, the runner tag shall be <target>_<count>, e.g. esp32_2 instead of esp32,esp32
18+
# 2. don't have spaces in the comma separated list.
1019
no_runner_tags:
1120
- esp32,ip101
1221
- esp32c2,jtag,xtal_40mhz

0 commit comments

Comments
 (0)