11import os
22import json
33import time
4+ from json import JSONDecodeError
5+ from typing import Dict , Any
6+
47import requests
58
69
710class AzureDevOps :
811
912 def __init__ (self ):
1013 self .base_url = "https://dev.azure.com/NHSD-APIM/API Platform/_apis/pipelines"
11- self .token = os .environ ["AZURE_TOKEN" ]
12- self .auth = requests .auth .HTTPBasicAuth ("" , self .token )
14+ self .client_id = os .environ ["AZ_CLIENT_ID" ]
15+ self .client_secret = os .environ ["AZ_CLIENT_SECRET" ]
16+ self .client_tenant = os .environ ["AZ_CLIENT_TENANT" ]
17+ self .access_token = self ._get_access_token ()
1318 self .notify_commit_sha = os .environ ["NOTIFY_COMMIT_SHA" ]
1419 self .utils_pr_number = os .environ ["UTILS_PR_NUMBER" ]
1520 self .notify_github_repo = "NHSDigital/api-management-utils"
16- self .api_params = {"api-version" : "6.0-preview.1" }
1721 self .api_request_delay = 60
1822
1923 @staticmethod
@@ -34,28 +38,29 @@ def run_pipeline(self,
3438 run_url = self .base_url + f"/{ pipeline_id } /runs"
3539 request_body = self ._build_request_body (pipeline_branch )
3640
37- response = requests .post (run_url , auth = self .auth , params = self .api_params , json = request_body )
41+ response = self .api_request (
42+ run_url ,
43+ json = request_body ,
44+ method = 'post' ,
45+ )
3846 self .print_response (response , f"Initial request to { run_url } " )
3947
4048 result = "failed"
4149 if response .status_code == 200 :
4250 result = self ._check_pipeline_response (response )
4351 print (f"Result of { service } { pipeline_type } pipeline: { result } " )
44- elif response .status_code == 203 or response .status_code == 401 :
45- print (f"{ response .status_code } : Invalid or expired PAT (Personal Access Token),"
46- f" please verify or renew token" )
4752 else :
4853 print (f"Triggering pipeline: { service } { pipeline_type } failed, status code: { response .status_code } " )
4954 return result
5055
5156 def _check_pipeline_response (self , response : requests .Response ):
5257 delay = 0
5358 state_url = response .json ()["_links" ]["self" ]["href" ]
59+ # print("response check from our Start", response.status_code, response.json()["state"])
5460 while response .status_code == 200 and response .json ()["state" ] == "inProgress" :
5561 time .sleep (self .api_request_delay )
5662 delay = delay + self .api_request_delay
57- response = requests .get (state_url , auth = self .auth , params = self .api_params )
58- self .print_response (response , f"Response from { state_url } after { delay } seconds" )
63+ response = self .api_request (state_url )
5964 return response .json ()["result" ]
6065
6166 def _build_request_body (self , pipeline_branch : str ):
@@ -71,19 +76,56 @@ def _build_request_body(self, pipeline_branch: str):
7176 },
7277 "self" : {"refName" : f"{ pipeline_branch } " },
7378 }
74- },
75- "variables" : {
76- "NOTIFY_GITHUB_REPOSITORY" : {
77- "isSecret " : False ,
78- "value" : f"{ self .notify_github_repo } " ,
79- },
80- "NOTIFY_COMMIT_SHA" : {
81- "isSecret " : False ,
82- "value" : f"{ self .notify_commit_sha } "
83- },
84- "UTILS_PR_NUMBER" : {
85- "isSecret " : False ,
86- "value" : f"{ self .utils_pr_number } " ,
87- }
8879 }
8980 }
81+
82+ def _get_access_token (self ):
83+ url = f"https://login.microsoftonline.com/{ self .client_tenant } /oauth2/v2.0/token"
84+ data = {
85+ "client_id" : self .client_id ,
86+ "client_secret" : self .client_secret ,
87+ "grant_type" : "client_credentials" ,
88+ "scope" : "https://app.vssps.visualstudio.com/.default" ,
89+ }
90+ headers = {"Content-Type" : "application/x-www-form-urlencoded" }
91+ res = requests .post (url = url , data = data , headers = headers )
92+ res .raise_for_status ()
93+
94+ return res .json ()["access_token" ]
95+
96+ def api_request (
97+ self ,
98+ uri ,
99+ params : Dict [str , Any ] = None ,
100+ headers : Dict [str , Any ] = None ,
101+ api_version : str = "6.0-preview.1" ,
102+ method : str = "get" ,
103+ max_tries : int = 5 ,
104+ ** kwargs ,
105+ ):
106+ def get_headers ():
107+
108+ _headers = {"Accept" : "application/json" , "Authorization" : f"Bearer { self .access_token } " }
109+ _headers .update (headers or {})
110+ return _headers
111+
112+ _params = {"api-version" : api_version , "NOTIFY_GITHUB_REPOSITORY" : self .notify_github_repo , "NOTIFY_COMMIT_SHA" : self .notify_commit_sha , "UTILS_PR_NUMBER" : self .utils_pr_number }
113+ _params .update (params or {})
114+ action = getattr (requests , method )
115+
116+ result = action (uri , params = _params , headers = get_headers (), ** kwargs )
117+ tries = 0
118+ while result .status_code not in (200 , 201 , 202 , 204 ):
119+ tries += 1
120+
121+ if tries > max_tries :
122+ break
123+
124+ if result .status_code in (203 , 401 ):
125+ print ("REFRESHING ACCESS TOKEN..." )
126+ self .access_token = self ._get_access_token ()
127+
128+ time .sleep (0.5 * tries )
129+ result = action (uri , params = _params , headers = get_headers (), ** kwargs )
130+
131+ return result
0 commit comments