Skip to content

Commit b7f9a97

Browse files
committed
Fix for issue #289 - check for location at deployment level if it does not exist at the organization level.
1 parent 7f26ce3 commit b7f9a97

File tree

1 file changed

+47
-26
lines changed

1 file changed

+47
-26
lines changed

azure-devops/azure/devops/client.py

Lines changed: 47 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ def __init__(self, base_url=None, creds=None):
3636
_base_client_models = {k: v for k, v in _models.__dict__.items() if isinstance(v, type)}
3737
self._base_deserialize = Deserializer(_base_client_models)
3838
self._base_serialize = Serializer(_base_client_models)
39-
self._all_host_types_locations = None
40-
self._locations = None
39+
self._all_host_types_locations = {}
40+
self._locations = {}
4141
self._suppress_fedauth_redirect = True
4242
self._force_msa_pass_through = True
4343
self.normalized_url = Client._normalize_url(base_url)
@@ -76,7 +76,7 @@ def _send(self, http_method, location_id, version, route_values=None,
7676
route_values=route_values,
7777
query_parameters=query_parameters)
7878
negotiated_version = self._negotiate_request_version(
79-
self._get_resource_location(location_id),
79+
self._get_resource_location(self.normalized_url, location_id),
8080
version)
8181

8282
if version != negotiated_version:
@@ -116,19 +116,31 @@ def _unwrap_collection(self, response):
116116

117117
def _create_request_message(self, http_method, location_id, route_values=None,
118118
query_parameters=None):
119-
location = self._get_resource_location(location_id)
119+
location = self._get_organization_resource_location(location_id)
120+
deployment_level = False
121+
deployment_url = None
120122
if location is None:
121-
raise ValueError('API resource location ' + location_id + ' is not registered on '
122-
+ self.config.base_url + '.')
123+
logger.debug('API resource location ' + location_id + ' is not registered on ' + self.config.base_url + '.')
124+
deployment_url = self._get_deployment_url()
125+
if deployment_url is not None:
126+
logger.debug('Checking for location at deployment level: ' + deployment_url)
127+
location = self._get_resource_location(deployment_url, location_id)
128+
deployment_level = True
129+
if location is None:
130+
raise ValueError('API resource location ' + location_id + ' is not registered on '
131+
+ self.config.base_url + '.')
123132
if route_values is None:
124133
route_values = {}
125134
route_values['area'] = location.area
126135
route_values['resource'] = location.resource_name
127136
route_template = self._remove_optional_route_parameters(location.route_template,
128137
route_values)
129138
logger.debug('Route template: %s', location.route_template)
130-
url = self._client.format_url(route_template, **route_values)
131-
request = ClientRequest(method=http_method, url=self._client.format_url(url))
139+
if not deployment_level:
140+
url = self._client.format_url(route_template, **route_values)
141+
else:
142+
url = self._client.format_url(deployment_url + route_template, **route_values)
143+
request = ClientRequest(method=http_method, url=url)
132144
if query_parameters:
133145
request.format_parameters(query_parameters)
134146
return request
@@ -144,35 +156,44 @@ def _remove_optional_route_parameters(route_template, route_values):
144156
new_template = new_template + '/' + path_segment
145157
return new_template
146158

147-
def _get_resource_location(self, location_id):
148-
if self.config.base_url not in Client._locations_cache:
149-
Client._locations_cache[self.config.base_url] = self._get_resource_locations(all_host_types=False)
150-
for location in Client._locations_cache[self.config.base_url]:
159+
def _get_organization_resource_location(self, location_id):
160+
return self._get_resource_location(self.normalized_url, location_id)
161+
162+
def _get_deployment_url(self):
163+
pos = self.normalized_url.rfind('/')
164+
if pos > 0:
165+
return self.normalized_url[:pos]
166+
return None
167+
168+
def _get_resource_location(self, url, location_id):
169+
if url not in Client._locations_cache:
170+
Client._locations_cache[url] = self._get_resource_locations(url, all_host_types=False)
171+
for location in Client._locations_cache[url]:
151172
if location.id == location_id:
152173
return location
153174

154-
def _get_resource_locations(self, all_host_types):
175+
def _get_resource_locations(self, url, all_host_types):
155176
# Check local client's cached Options first
156177
if all_host_types:
157-
if self._all_host_types_locations is not None:
158-
return self._all_host_types_locations
159-
elif self._locations is not None:
160-
return self._locations
178+
if url in self._all_host_types_locations:
179+
return self._all_host_types_locations[url]
180+
elif url in self._locations:
181+
return self._locations[url]
161182

162183
# Next check for options cached on disk
163-
if not all_host_types and OPTIONS_FILE_CACHE[self.normalized_url]:
184+
if not all_host_types and OPTIONS_FILE_CACHE[url]:
164185
try:
165-
logger.debug('File cache hit for options on: %s', self.normalized_url)
166-
self._locations = self._base_deserialize.deserialize_data(OPTIONS_FILE_CACHE[self.normalized_url],
186+
logger.debug('File cache hit for options on: %s', url)
187+
self._locations[url] = self._base_deserialize.deserialize_data(OPTIONS_FILE_CACHE[url],
167188
'[ApiResourceLocation]')
168-
return self._locations
189+
return self._locations[url]
169190
except DeserializationError as ex:
170191
logger.debug(ex, exc_info=True)
171192
else:
172-
logger.debug('File cache miss for options on: %s', self.normalized_url)
193+
logger.debug('File cache miss for options on: %s', url)
173194

174195
# Last resort, make the call to the server
175-
options_uri = self._combine_url(self.config.base_url, '_apis')
196+
options_uri = self._combine_url(url, '_apis')
176197
request = ClientRequest(method='OPTIONS', url=self._client.format_url(options_uri))
177198
if all_host_types:
178199
query_parameters = {'allHostTypes': True}
@@ -190,11 +211,11 @@ def _get_resource_locations(self, all_host_types):
190211
returned_locations = self._base_deserialize('[ApiResourceLocation]',
191212
collection)
192213
if all_host_types:
193-
self._all_host_types_locations = returned_locations
214+
self._all_host_types_locations[url] = returned_locations
194215
else:
195-
self._locations = returned_locations
216+
self._locations[url] = returned_locations
196217
try:
197-
OPTIONS_FILE_CACHE[self.normalized_url] = wrapper.value
218+
OPTIONS_FILE_CACHE[url] = wrapper.value
198219
except SerializationError as ex:
199220
logger.debug(ex, exc_info=True)
200221
return returned_locations

0 commit comments

Comments
 (0)