mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 03:00:34 +03:00
ci(buildv2): skip patching the fake_pass build child pipeline
idf-ci emits a skip pipeline containing only a fake_pass job, with no include of test_child_pipeline.yml, when the modified files match no buildable apps. patch_buildv2_child_pipeline.py redefined generate_pytest_child_pipeline unconditionally, assuming the included template supplied its tags, image and assign_test stage via keyword merge. With the template absent, the injected job was bare: no tags, default test stage. It was scheduled on the wrong runner and failed, turning the allow_failure build_child_pipeline_buildv2 bridge red on every buildv2 MR whose changes produce an empty app matrix. Return early when a fake_pass job is present so the child pipeline is left untouched and skips, matching the default build path. Add a unit test for the patch script and a host_test job to run it.
This commit is contained in:
@@ -295,6 +295,12 @@ test_idf_build_apps_load_soc_caps:
|
|||||||
- cd tools/ci
|
- cd tools/ci
|
||||||
- pytest_for_ut ./test_soc_headers_load_in_idf_build_apps.py
|
- pytest_for_ut ./test_soc_headers_load_in_idf_build_apps.py
|
||||||
|
|
||||||
|
test_dynamic_pipelines_scripts:
|
||||||
|
extends: .host_test_template
|
||||||
|
script:
|
||||||
|
- cd ${IDF_PATH}/tools/ci/dynamic_pipelines/tests
|
||||||
|
- pytest_for_ut ./test_patch_buildv2_child_pipeline.py
|
||||||
|
|
||||||
test_nvs_gen_check:
|
test_nvs_gen_check:
|
||||||
extends: .host_test_template
|
extends: .host_test_template
|
||||||
artifacts:
|
artifacts:
|
||||||
|
|||||||
@@ -134,6 +134,9 @@
|
|||||||
|
|
||||||
- "tools/ci/test_soc_headers_load_in_idf_build_apps.py"
|
- "tools/ci/test_soc_headers_load_in_idf_build_apps.py"
|
||||||
|
|
||||||
|
- "tools/ci/dynamic_pipelines/scripts/patch_buildv2_child_pipeline.py"
|
||||||
|
- "tools/ci/dynamic_pipelines/tests/**/*"
|
||||||
|
|
||||||
.patterns-docker: &patterns-docker
|
.patterns-docker: &patterns-docker
|
||||||
- "tools/docker/**/*"
|
- "tools/docker/**/*"
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,13 @@ def patch(path: str) -> None:
|
|||||||
with open(path) as f:
|
with open(path) as f:
|
||||||
d = yaml.safe_load(f)
|
d = yaml.safe_load(f)
|
||||||
|
|
||||||
|
if 'fake_pass' in d:
|
||||||
|
# idf-ci emitted a skip pipeline (no apps matched the modified files): there
|
||||||
|
# are no build jobs to activate and no included generate_pytest_child_pipeline
|
||||||
|
# to redefine. Leave it untouched so Build system v2 skips like the default path.
|
||||||
|
print('Skip pipeline (fake_pass) detected, leaving it untouched')
|
||||||
|
return
|
||||||
|
|
||||||
injected = []
|
injected = []
|
||||||
for k, v in d.items():
|
for k, v in d.items():
|
||||||
if isinstance(v, dict) and 'extends' in v:
|
if isinstance(v, dict) and 'extends' in v:
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
"""Unit tests for patch_buildv2_child_pipeline.patch()."""
|
||||||
|
|
||||||
|
import importlib.util
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
_SCRIPT = Path(__file__).parent.parent / 'scripts' / 'patch_buildv2_child_pipeline.py'
|
||||||
|
_spec = importlib.util.spec_from_file_location('patch_buildv2_child_pipeline', _SCRIPT)
|
||||||
|
assert _spec is not None and _spec.loader is not None
|
||||||
|
patch_mod: Any = importlib.util.module_from_spec(_spec)
|
||||||
|
_spec.loader.exec_module(patch_mod)
|
||||||
|
|
||||||
|
|
||||||
|
def _write_and_patch(tmp_path: Path, content: dict[str, Any]) -> dict[str, Any]:
|
||||||
|
p = tmp_path / 'buildv2_child_pipeline.yml'
|
||||||
|
p.write_text(yaml.safe_dump(content, sort_keys=False))
|
||||||
|
patch_mod.patch(str(p))
|
||||||
|
result: dict[str, Any] = yaml.safe_load(p.read_text())
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def test_fake_pass_skip_pipeline_is_left_untouched(tmp_path: Path) -> None:
|
||||||
|
# idf-ci emits a skip pipeline with only a `fake_pass` job when no apps match
|
||||||
|
# the modified files. There is no included generate_pytest_child_pipeline to
|
||||||
|
# redefine, so the patch must leave the pipeline untouched and let it skip.
|
||||||
|
# Mirrors idf_ci.idf_gitlab.pipeline._get_fake_pass_job(): the sole job is
|
||||||
|
# `fake_pass` and no test_child_pipeline.yml is included.
|
||||||
|
skip_pipeline = {
|
||||||
|
'fake_pass': {
|
||||||
|
'stage': 'build',
|
||||||
|
'tags': ['build', 'shiny'],
|
||||||
|
'before_script': [],
|
||||||
|
'after_script': [],
|
||||||
|
'cache': [],
|
||||||
|
'needs': [],
|
||||||
|
'script': ['echo "skip the entire child pipeline"'],
|
||||||
|
},
|
||||||
|
'workflow': {'name': 'build_child_pipeline', 'rules': [{'when': 'always'}]},
|
||||||
|
}
|
||||||
|
|
||||||
|
result = _write_and_patch(tmp_path, dict(skip_pipeline))
|
||||||
|
|
||||||
|
assert 'generate_pytest_child_pipeline' not in result
|
||||||
|
assert result == skip_pipeline
|
||||||
|
|
||||||
|
|
||||||
|
def test_build_jobs_get_buildv2_injection(tmp_path: Path) -> None:
|
||||||
|
# A real pipeline (apps matched) carries build jobs that `extends` the dynamic
|
||||||
|
# template. Those must get IDF_BUILD_V2 / PIPELINE_COMMIT_SHA injected and
|
||||||
|
# generate_pytest_child_pipeline redefined with the post-processing step.
|
||||||
|
pipeline = {
|
||||||
|
'build_test_related_apps': {
|
||||||
|
'extends': '.dynamic_build_template',
|
||||||
|
'needs': [{'pipeline': '$PARENT_PIPELINE_ID', 'job': 'generate_build_child_pipeline'}],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
result = _write_and_patch(tmp_path, pipeline)
|
||||||
|
|
||||||
|
job = result['build_test_related_apps']
|
||||||
|
assert job['variables']['IDF_BUILD_V2'] == '1'
|
||||||
|
assert job['variables']['PIPELINE_COMMIT_SHA'] == patch_mod.PIPELINE_COMMIT_SHA_V2
|
||||||
|
assert job['needs'][0]['job'] == patch_mod.BUILDV2_GENERATOR_JOB
|
||||||
|
assert 'generate_pytest_child_pipeline' in result
|
||||||
|
assert result['generate_pytest_child_pipeline']['variables']['IDF_BUILD_V2'] == '1'
|
||||||
Reference in New Issue
Block a user