diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7420541e6..108426b8a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,5 @@ stages: + - cleanup - docker_build - build - target_test @@ -138,6 +139,17 @@ variables: - cd $ESP_MATTER_PATH/examples/controller - idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults.otbr" set-target esp32s3 build +cancel_redundant_pipelines: + stage: cleanup + image: python:3.12-slim + tags: + - cancel-pipeline + rules: + - if: '$CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "merge_request_event"' + script: + - pip install --no-cache-dir requests + - python tools/ci/cancel_pipelines.py + build_image: stage: docker_build image: espressif/dind:1 diff --git a/tools/ci/cancel_pipelines.py b/tools/ci/cancel_pipelines.py new file mode 100644 index 000000000..6380742bb --- /dev/null +++ b/tools/ci/cancel_pipelines.py @@ -0,0 +1,65 @@ +# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + +# SPDX-License-Identifier: CC0-1.0 + +import re +import os +import requests +from gitlab_api import GitLabAPI + +def cancel_branch_pipelines(gitlab_api): + url = f"{gitlab_api.gitlab_api_url}/projects/{gitlab_api.ci_project_id}/pipelines?ref={gitlab_api.ci_commit_ref_name}&status=running" + headers = {"PRIVATE-TOKEN": gitlab_api.gitlab_token} + response = requests.get(url, headers=headers) + + if response.status_code == 200: + running_pipelines = response.json() + + for pipeline in running_pipelines: + pipeline_id = pipeline.get('id') + source = pipeline.get('source') + ref = pipeline.get('ref') + if pipeline_id != int(gitlab_api.ci_pipeline_id) and source != 'merge_request_event': + print(f"Cancelling branch pipeline with pipeline ID: {pipeline_id}, Source:{source}, Ref: {ref}") + gitlab_api.cancel_pipeline(pipeline_id) + else: + print(f"Skipping current branch pipeline with pipeline ID: {gitlab_api.ci_pipeline_id}") + else: + print(f"Failed to fetch branch pipelines, Status Code: {response.status_code}") + +def cancel_merge_request_pipelines(gitlab_api): + url = f"{gitlab_api.gitlab_api_url}/projects/{gitlab_api.ci_project_id}/pipelines?status=running" + headers = {"PRIVATE-TOKEN": gitlab_api.gitlab_token} + response = requests.get(url, headers=headers) + + if response.status_code == 200: + running_pipelines = response.json() + + for pipeline in running_pipelines: + pipeline_id = pipeline.get('id') + source = pipeline.get('source') + ref = pipeline.get('ref') + merge_request_id_pattern = re.match(r"refs/merge-requests/(\d+)/head", ref) + if merge_request_id_pattern: + print(f"MR pipeline id: {merge_request_id_pattern.group(1)}") + if source == "merge_request_event" and gitlab_api.ci_merge_request_iid == merge_request_id_pattern.group(1): + if pipeline_id == int(gitlab_api.ci_pipeline_id): + print(f"Skipping current MR pipeline with pipeline id: {pipeline_id} ref: {ref} source: {source}") + else: + print(f"Cancelling MR pipeline with pipeline id: {pipeline_id} ref:{ref} source: {source}") + gitlab_api.cancel_pipeline(pipeline_id) + else: + print(f"Skipping pipeline with pipeline ID: {pipeline_id} (ref: {ref}, source: {source})") + + else: + print(f"Failed to fetch pipelines, Status: {response.status_code}") + + +def main(): + gitlab_api = GitLabAPI() + cancel_branch_pipelines(gitlab_api) + cancel_merge_request_pipelines(gitlab_api) + +if __name__ == "__main__": + main() + diff --git a/tools/ci/gitlab_api.py b/tools/ci/gitlab_api.py index 3f72fe1f0..5eeb595af 100644 --- a/tools/ci/gitlab_api.py +++ b/tools/ci/gitlab_api.py @@ -12,8 +12,10 @@ class GitLabAPI: self.gitlab_token = os.getenv("GITLAB_MR_COMMENT_TOKEN") self.ci_project_id = os.getenv("CI_PROJECT_ID") self.ci_merge_request_iid = os.getenv("CI_MERGE_REQUEST_IID") + self.ci_pipeline_id = os.getenv("CI_PIPELINE_ID") + self.ci_commit_ref_name = os.getenv("CI_COMMIT_REF_NAME") - if not all([self.gitlab_api_url, self.gitlab_token, self.ci_project_id, self.ci_merge_request_iid]): + if not all([self.gitlab_api_url, self.gitlab_token, self.ci_project_id, self.ci_pipeline_id]): raise ValueError("Required GitLab environment variables are not set") def fetch_merge_request_description(self): @@ -64,3 +66,13 @@ class GitLabAPI: with open(output_file, 'wb') as f: for chunk in response.iter_content(chunk_size=8192): f.write(chunk) + + def cancel_pipeline(self, pipeline_id): + url = f"{self.gitlab_api_url}/projects/{self.ci_project_id}/pipelines/{pipeline_id}/cancel" + headers = {"PRIVATE-TOKEN": self.gitlab_token} + response = requests.post(url, headers=headers) + + if response.status_code == 200: + print(f"Successfully cancelled Pipeline ID: {pipeline_id}") + else: + print(f"Failed to cancel Pipeline ID: {pipeline_id}, Status Code: {response.status_code}")