diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index fc0403e0c42..0e449ec7e9a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -31,4 +31,5 @@ include: - '.gitlab/ci/host-test.yml' - '.gitlab/ci/deploy.yml' - '.gitlab/ci/post_deploy.yml' + - '.gitlab/ci/retry_failed_jobs.yml' - '.gitlab/ci/test-win.yml' diff --git a/.gitlab/ci/common.yml b/.gitlab/ci/common.yml index b43e1d3d570..223a1f9dd9f 100644 --- a/.gitlab/ci/common.yml +++ b/.gitlab/ci/common.yml @@ -12,6 +12,7 @@ stages: - test_deploy - deploy - post_deploy + - retry_failed_jobs variables: # System environment diff --git a/.gitlab/ci/retry_failed_jobs.yml b/.gitlab/ci/retry_failed_jobs.yml new file mode 100644 index 00000000000..28a2c1e06f7 --- /dev/null +++ b/.gitlab/ci/retry_failed_jobs.yml @@ -0,0 +1,14 @@ +retry_failed_jobs: + stage: retry_failed_jobs + tags: [shiny, fast_run] + image: $ESP_ENV_IMAGE + dependencies: null + before_script: [] + cache: [] + extends: [] + script: + - echo "Retrieving and retrying all failed jobs for the pipeline..." + - python tools/ci/python_packages/gitlab_api.py retry_failed_jobs $CI_MERGE_REQUEST_PROJECT_ID --pipeline_id $CI_PIPELINE_ID + when: manual + needs: + - generate_failed_jobs_report diff --git a/tools/ci/dynamic_pipelines/constants.py b/tools/ci/dynamic_pipelines/constants.py index 21f903338df..bbeefcfc4df 100644 --- a/tools/ci/dynamic_pipelines/constants.py +++ b/tools/ci/dynamic_pipelines/constants.py @@ -29,8 +29,18 @@ IDF_PATH, 'tools', 'ci', 'dynamic_pipelines', 'templates', 'report.template.html' ) +RETRY_JOB_PICTURE_PATH = 'tools/ci/dynamic_pipelines/templates/retry-jobs.png' +RETRY_JOB_TITLE = '\n\nRetry failed jobs with with help of "retry_failed_jobs" stage of the pipeline:' +RETRY_JOB_PICTURE_LINK = '![Retry Jobs Image]({pic_url})' + BUILD_ONLY_LABEL = 'For Maintainers: Only Build Tests' KNOWN_GENERATE_TEST_CHILD_PIPELINE_WARNINGS_FILEPATH = os.path.join( IDF_PATH, 'tools', 'ci', 'dynamic_pipelines', 'templates', 'known_generate_test_child_pipeline_warnings.yml' ) + +CI_JOB_TOKEN = os.getenv('CI_JOB_TOKEN', '') +CI_DASHBOARD_API = os.getenv('CI_DASHBOARD_API', '') +CI_PAGES_URL = os.getenv('CI_PAGES_URL', '') +CI_PROJECT_URL = os.getenv('CI_PROJECT_URL', '') +CI_MERGE_REQUEST_SOURCE_BRANCH_SHA = os.getenv('CI_MERGE_REQUEST_SOURCE_BRANCH_SHA', '') diff --git a/tools/ci/dynamic_pipelines/models.py b/tools/ci/dynamic_pipelines/models.py index b40d827448d..55659179401 100644 --- a/tools/ci/dynamic_pipelines/models.py +++ b/tools/ci/dynamic_pipelines/models.py @@ -164,7 +164,7 @@ def from_test_case_node(cls, node: Element) -> t.Optional['TestCase']: 'name': node.attrib['name'], 'file': node.attrib.get('file'), 'time': float(node.attrib.get('time') or 0), - 'ci_job_url': node.attrib.get('ci_job_url') or '', + 'ci_job_url': node.attrib.get('ci_job_url') or 'Not found', 'ci_dashboard_url': f'{grafana_base_url}?{encoded_params}', 'dut_log_url': node.attrib.get('dut_log_url') or 'Not found', } diff --git a/tools/ci/dynamic_pipelines/report.py b/tools/ci/dynamic_pipelines/report.py index be8fce0af35..b36c5409788 100644 --- a/tools/ci/dynamic_pipelines/report.py +++ b/tools/ci/dynamic_pipelines/report.py @@ -19,12 +19,16 @@ from .constants import COMMENT_START_MARKER from .constants import REPORT_TEMPLATE_FILEPATH +from .constants import RETRY_JOB_PICTURE_LINK +from .constants import RETRY_JOB_PICTURE_PATH +from .constants import RETRY_JOB_TITLE from .constants import TEST_RELATED_APPS_DOWNLOAD_URLS_FILENAME from .models import GitlabJob from .models import TestCase from .utils import fetch_failed_testcases_failure_ratio from .utils import format_permalink -from .utils import get_report_url +from .utils import get_artifacts_url +from .utils import get_repository_file_url from .utils import is_url from .utils import load_known_failure_cases @@ -69,13 +73,14 @@ def write_report_to_file(self, report_str: str, job_id: int, output_filepath: st # for example, {URL}/-/esp-idf/-/jobs/{id}/artifacts/list_job_84.txt # CI_PAGES_URL is {URL}/esp-idf, which missed one `-` - report_url: str = get_report_url(job_id, output_filepath) + report_url: str = get_artifacts_url(job_id, output_filepath) return report_url def generate_html_report(self, table_str: str) -> str: # we're using bootstrap table table_str = table_str.replace( - '