xref: /aosp_15_r20/external/pytorch/.circleci/scripts/trigger_azure_pipeline.py (revision da0073e96a02ea20f0ac840b70461e3646d07c45)
1# Documentation: https://docs.microsoft.com/en-us/rest/api/azure/devops/build/?view=azure-devops-rest-6.0
2
3import json
4import os
5import re
6import sys
7import time
8
9import requests
10
11
12AZURE_PIPELINE_BASE_URL = "https://aiinfra.visualstudio.com/PyTorch/"
13AZURE_DEVOPS_PAT_BASE64 = os.environ.get("AZURE_DEVOPS_PAT_BASE64_SECRET", "")
14PIPELINE_ID = "911"
15PROJECT_ID = "0628bce4-2d33-499e-bac5-530e12db160f"
16TARGET_BRANCH = os.environ.get("CIRCLE_BRANCH", "main")
17TARGET_COMMIT = os.environ.get("CIRCLE_SHA1", "")
18
19build_base_url = AZURE_PIPELINE_BASE_URL + "_apis/build/builds?api-version=6.0"
20
21s = requests.Session()
22s.headers.update({"Authorization": "Basic " + AZURE_DEVOPS_PAT_BASE64})
23
24
25def submit_build(pipeline_id, project_id, source_branch, source_version):
26    print("Submitting build for branch: " + source_branch)
27    print("Commit SHA1: ", source_version)
28
29    run_build_raw = s.post(
30        build_base_url,
31        json={
32            "definition": {"id": pipeline_id},
33            "project": {"id": project_id},
34            "sourceBranch": source_branch,
35            "sourceVersion": source_version,
36        },
37    )
38
39    try:
40        run_build_json = run_build_raw.json()
41    except json.decoder.JSONDecodeError as e:
42        print(e)
43        print(
44            "Failed to parse the response. Check if the Azure DevOps PAT is incorrect or expired."
45        )
46        sys.exit(-1)
47
48    build_id = run_build_json["id"]
49
50    print("Submitted bulid: " + str(build_id))
51    print("Bulid URL: " + run_build_json["url"])
52    return build_id
53
54
55def get_build(_id):
56    get_build_url = (
57        AZURE_PIPELINE_BASE_URL + f"/_apis/build/builds/{_id}?api-version=6.0"
58    )
59    get_build_raw = s.get(get_build_url)
60    return get_build_raw.json()
61
62
63def get_build_logs(_id):
64    get_build_logs_url = (
65        AZURE_PIPELINE_BASE_URL + f"/_apis/build/builds/{_id}/logs?api-version=6.0"
66    )
67    get_build_logs_raw = s.get(get_build_logs_url)
68    return get_build_logs_raw.json()
69
70
71def get_log_content(url):
72    resp = s.get(url)
73    return resp.text
74
75
76def wait_for_build(_id):
77    build_detail = get_build(_id)
78    build_status = build_detail["status"]
79
80    while build_status == "notStarted":
81        print("Waiting for run to start: " + str(_id))
82        sys.stdout.flush()
83        try:
84            build_detail = get_build(_id)
85            build_status = build_detail["status"]
86        except Exception as e:
87            print("Error getting build")
88            print(e)
89
90        time.sleep(30)
91
92    print("Bulid started: ", str(_id))
93
94    handled_logs = set()
95    while build_status == "inProgress":
96        try:
97            print("Waiting for log: " + str(_id))
98            logs = get_build_logs(_id)
99        except Exception as e:
100            print("Error fetching logs")
101            print(e)
102            time.sleep(30)
103            continue
104
105        for log in logs["value"]:
106            log_id = log["id"]
107            if log_id in handled_logs:
108                continue
109            handled_logs.add(log_id)
110            print("Fetching log: \n" + log["url"])
111            try:
112                log_content = get_log_content(log["url"])
113                print(log_content)
114            except Exception as e:
115                print("Error getting log content")
116                print(e)
117            sys.stdout.flush()
118        build_detail = get_build(_id)
119        build_status = build_detail["status"]
120        time.sleep(30)
121
122    build_result = build_detail["result"]
123
124    print("Bulid status: " + build_status)
125    print("Bulid result: " + build_result)
126
127    return build_status, build_result
128
129
130if __name__ == "__main__":
131    # Convert the branch name for Azure DevOps
132    match = re.search(r"pull/(\d+)", TARGET_BRANCH)
133    if match is not None:
134        pr_num = match.group(1)
135        SOURCE_BRANCH = f"refs/pull/{pr_num}/head"
136    else:
137        SOURCE_BRANCH = f"refs/heads/{TARGET_BRANCH}"
138
139    MAX_RETRY = 2
140    retry = MAX_RETRY
141
142    while retry > 0:
143        build_id = submit_build(PIPELINE_ID, PROJECT_ID, SOURCE_BRANCH, TARGET_COMMIT)
144        build_status, build_result = wait_for_build(build_id)
145
146        if build_result != "succeeded":
147            retry = retry - 1
148            if retry > 0:
149                print("Retrying... remaining attempt: " + str(retry))
150                # Wait a bit before retrying
151                time.sleep((MAX_RETRY - retry) * 120)
152                continue
153            else:
154                print("No more chance to retry. Giving up.")
155                sys.exit(-1)
156        else:
157            break
158