Skip to content

Commit d383d20

Browse files
super-vanilla-bearMinakov
andauthored
[Jira] Update Agile (Greenhopper) REST API URL handling (#1530)
This PR fixes the issue of creating URLs for resources from the Agile (Greenhopper) REST API group. The resource URLs were built incorrectly if we used the OAuth2 authorization method when creating a Jira client object. The problem was that everything worked fine when auth, for example, by username/user_api_token, because, in this case, we could use the “api_root” default value from the Jira client constructor. However, when we use OAuth2, the "api_root" parameter must be overridden, but previously, before the fix, this override did not affect the composition of URLs to the above resources. So, this PR fixes this issue with minimal related reformatting, which makes the code of the corresponding methods more consistent. Co-authored-by: Minakov <mminakov@bcdtriptech.com>
1 parent fed08f0 commit d383d20

File tree

1 file changed

+77
-30
lines changed

1 file changed

+77
-30
lines changed

atlassian/jira.py

Lines changed: 77 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4993,6 +4993,19 @@ def tempo_teams_get_memberships_for_member(self, username: str) -> T_resp_json:
49934993
# Resource: https://docs.atlassian.com/jira-software/REST/7.3.1/
49944994
#######################################################################
49954995
# /rest/agile/1.0/backlog/issue
4996+
def get_agile_resource_url(self, resource: str, legacy_api: bool = False) -> str:
4997+
"""
4998+
Prepare an 'Agile' API-specific URL relying on defaults set for the client.
4999+
5000+
:param resource: Name of an endpoint
5001+
:param legacy_api: If True - use 'greenhopper' as an API type, else - use a newer, 'agile', name.
5002+
:return: String with a full URL path to resource
5003+
"""
5004+
api_version = "1.0"
5005+
api_type = "greenhopper" if legacy_api else "agile"
5006+
api_root = self.api_root.replace("rest/api", f"rest/{api_type}")
5007+
return self.resource_url(resource=resource, api_root=api_root, api_version=api_version)
5008+
49965009
def move_issues_to_backlog(self, issue_keys: list) -> T_resp_json:
49975010
"""
49985011
Move issues to backlog
@@ -5012,7 +5025,8 @@ def add_issues_to_backlog(self, issues: list) -> T_resp_json:
50125025
"""
50135026
if not isinstance(issues, list):
50145027
raise ValueError("`issues` param should be List of Issue Keys")
5015-
url = "/rest/agile/1.0/backlog/issue"
5028+
resource = "backlog/issue"
5029+
url = self.get_agile_resource_url(resource)
50165030
data = dict(issues=issues)
50175031
return self.post(url, data=data)
50185032

@@ -5021,7 +5035,8 @@ def get_agile_board_by_filter_id(self, filter_id: T_id) -> T_resp_json:
50215035
Gets an agile board by the filter id
50225036
:param filter_id: int, str
50235037
"""
5024-
url = f"rest/agile/1.0/board/filter/{filter_id}"
5038+
resource = f"board/filter/{filter_id}"
5039+
url = self.get_agile_resource_url(resource)
50255040
return self.get(url)
50265041

50275042
# /rest/agile/1.0/board
@@ -5033,10 +5048,11 @@ def create_agile_board(self, name: str, type: str, filter_id: T_id, location: Op
50335048
:param filter_id: int
50345049
:param location: dict, Optional. Only specify this for Jira Cloud!
50355050
"""
5051+
resource = "board"
5052+
url = self.get_agile_resource_url(resource)
50365053
data: dict = {"name": name, "type": type, "filterId": filter_id}
50375054
if location:
50385055
data["location"] = location
5039-
url = "rest/agile/1.0/board"
50405056
return self.post(url, data=data)
50415057

50425058
def get_all_agile_boards(
@@ -5056,7 +5072,8 @@ def get_all_agile_boards(
50565072
:param limit:
50575073
:return:
50585074
"""
5059-
url = "rest/agile/1.0/board"
5075+
resource = "board"
5076+
url = self.get_agile_resource_url(resource)
50605077
params: dict = {}
50615078
if board_name:
50625079
params["name"] = board_name
@@ -5077,7 +5094,8 @@ def delete_agile_board(self, board_id: T_id) -> T_resp_json:
50775094
:param board_id:
50785095
:return:
50795096
"""
5080-
url = f"rest/agile/1.0/board/{str(board_id)}"
5097+
resource = f"board/{board_id}"
5098+
url = self.get_agile_resource_url(resource)
50815099
return self.delete(url)
50825100

50835101
def get_agile_board(self, board_id: T_id) -> T_resp_json:
@@ -5086,7 +5104,8 @@ def get_agile_board(self, board_id: T_id) -> T_resp_json:
50865104
:param board_id:
50875105
:return:
50885106
"""
5089-
url = f"rest/agile/1.0/board/{str(board_id)}"
5107+
resource = f"board/{board_id}"
5108+
url = self.get_agile_resource_url(resource)
50905109
return self.get(url)
50915110

50925111
def get_issues_for_backlog(self, board_id: T_id) -> T_resp_json:
@@ -5099,7 +5118,8 @@ def get_issues_for_backlog(self, board_id: T_id) -> T_resp_json:
50995118
By default, the returned issues are ordered by rank.
51005119
:param board_id: int, str
51015120
"""
5102-
url = f"rest/agile/1.0/board/{board_id}/backlog"
5121+
resource = f"board/{board_id}/backlog"
5122+
url = self.get_agile_resource_url(resource)
51035123
return self.get(url)
51045124

51055125
def get_agile_board_configuration(self, board_id: T_id) -> T_resp_json:
@@ -5126,7 +5146,8 @@ def get_agile_board_configuration(self, board_id: T_id) -> T_resp_json:
51265146
:param board_id:
51275147
:return:
51285148
"""
5129-
url = f"rest/agile/1.0/board/{str(board_id)}/configuration"
5149+
resource = f"board/{board_id}/configuration"
5150+
url = self.get_agile_resource_url(resource)
51305151
return self.get(url)
51315152

51325153
def get_issues_for_board(
@@ -5153,6 +5174,8 @@ def get_issues_for_board(
51535174
:param expand: OPTIONAL: expand the search result
51545175
:return:
51555176
"""
5177+
resource = f"board/{board_id}/issue"
5178+
url = self.get_agile_resource_url(resource)
51565179
params: dict = {}
51575180
if start is not None:
51585181
params["startAt"] = int(start)
@@ -5167,7 +5190,6 @@ def get_issues_for_board(
51675190
if expand is not None:
51685191
params["expand"] = expand
51695192

5170-
url = f"rest/agile/1.0/board/{board_id}/issue"
51715193
return self.get(url, params=params)
51725194

51735195
# /rest/agile/1.0/board/{boardId}/epic
@@ -5190,7 +5212,8 @@ def get_epics(
51905212
See the 'Pagination' section at the top of this page for more details.
51915213
:return:
51925214
"""
5193-
url = f"rest/agile/1.0/board/{board_id}/epic"
5215+
resource = f"board/{board_id}/epic"
5216+
url = self.get_agile_resource_url(resource)
51945217
params: dict = {}
51955218
if done:
51965219
params["done"] = done
@@ -5236,7 +5259,8 @@ def get_issues_for_epic(
52365259
If you exceed this limit, your results will be truncated.
52375260
:return:
52385261
"""
5239-
url = f"/rest/agile/1.0/board/{board_id}/epic/{epic_id}/issue"
5262+
resource = f"board/{board_id}/epic/{epic_id}/issue"
5263+
url = self.get_agile_resource_url(resource)
52405264
params: dict = {}
52415265
if jql:
52425266
params["jql"] = jql
@@ -5285,7 +5309,8 @@ def get_issues_without_epic(
52855309
If you exceed this limit, your results will be truncated.
52865310
:return:
52875311
"""
5288-
url = f"/rest/agile/1.0/board/{board_id}/epic/none/issue"
5312+
resource = f"board/{board_id}/epic/none/issue"
5313+
url = self.get_agile_resource_url(resource)
52895314
params: dict = {}
52905315
if jql:
52915316
params["jql"] = jql
@@ -5321,7 +5346,8 @@ def get_all_projects_associated_with_board(self, board_id: T_id, start: int = 0,
53215346
See the 'Pagination' section at the top of this page for more details
53225347
:return:
53235348
"""
5324-
url = f"/rest/agile/1.0/board/{board_id}/project"
5349+
resource = f"board/{board_id}/project"
5350+
url = self.get_agile_resource_url(resource)
53255351
params: dict = {}
53265352
if start:
53275353
params["startAt"] = start
@@ -5336,7 +5362,8 @@ def get_agile_board_properties(self, board_id: T_id) -> T_resp_json:
53365362
The user who retrieves the property keys is required to have permissions to view the board.
53375363
:param board_id: int, str
53385364
"""
5339-
url = f"rest/agile/1.0/board/{board_id}/properties"
5365+
resource = f"board/{board_id}/properties"
5366+
url = self.get_agile_resource_url(resource)
53405367
return self.get(url)
53415368

53425369
def set_agile_board_property(self, board_id: T_id, property_key: str) -> T_resp_json:
@@ -5349,7 +5376,8 @@ def set_agile_board_property(self, board_id: T_id, property_key: str) -> T_resp_
53495376
:param property_key:
53505377
:return:
53515378
"""
5352-
url = f"/rest/agile/1.0/board/{board_id}/properties/{property_key}"
5379+
resource = f"board/{board_id}/properties/{property_key}"
5380+
url = self.get_agile_resource_url(resource)
53535381
return self.put(url)
53545382

53555383
def get_agile_board_property(self, board_id: T_id, property_key: str) -> T_resp_json:
@@ -5360,7 +5388,8 @@ def get_agile_board_property(self, board_id: T_id, property_key: str) -> T_resp_
53605388
:param property_key:
53615389
:return:
53625390
"""
5363-
url = f"/rest/agile/1.0/board/{board_id}/properties/{property_key}"
5391+
resource = f"board/{board_id}/properties/{property_key}"
5392+
url = self.get_agile_resource_url(resource)
53645393
return self.get(url)
53655394

53665395
def delete_agile_board_property(self, board_id: T_id, property_key: str) -> T_resp_json:
@@ -5371,7 +5400,8 @@ def delete_agile_board_property(self, board_id: T_id, property_key: str) -> T_re
53715400
:param property_key:
53725401
:return:
53735402
"""
5374-
url = f"/rest/agile/1.0/board/{board_id}/properties/{property_key}"
5403+
resource = f"board/{board_id}/properties/{property_key}"
5404+
url = self.get_agile_resource_url(resource)
53755405
return self.delete(url)
53765406

53775407
# /rest/agile/1.0/board/{boardId}/settings/refined-velocity
@@ -5381,7 +5411,8 @@ def get_agile_board_refined_velocity(self, board_id: T_id) -> T_resp_json:
53815411
:param board_id:
53825412
:return:
53835413
"""
5384-
url = f"/rest/agile/1.0/board/{board_id}/settings/refined-velocity"
5414+
resource = f"board/{board_id}/settings/refined-velocity"
5415+
url = self.get_agile_resource_url(resource)
53855416
return self.get(url)
53865417

53875418
def set_agile_board_refined_velocity(self, board_id: T_id, data: dict) -> T_resp_json:
@@ -5391,7 +5422,8 @@ def set_agile_board_refined_velocity(self, board_id: T_id, data: dict) -> T_resp
53915422
:param data:
53925423
:return:
53935424
"""
5394-
url = f"/rest/agile/1.0/board/{board_id}/settings/refined-velocity"
5425+
resource = f"board/{board_id}/settings/refined-velocity"
5426+
url = self.get_agile_resource_url(resource)
53955427
return self.put(url, data=data)
53965428

53975429
# /rest/agile/1.0/board/{boardId}/sprint
@@ -5414,14 +5446,15 @@ def get_all_sprints_from_board(
54145446
See the 'Pagination' section at the top of this page for more details.
54155447
:return:
54165448
"""
5449+
resource = f"board/{board_id}/sprint"
5450+
url = self.get_agile_resource_url(resource)
54175451
params: dict = {}
54185452
if start:
54195453
params["startAt"] = start
54205454
if limit:
54215455
params["maxResults"] = limit
54225456
if state:
54235457
params["state"] = state
5424-
url = f"rest/agile/1.0/board/{board_id}/sprint"
54255458
return self.get(url, params=params)
54265459

54275460
@deprecated(version="3.42.0", reason="Use get_all_sprints_from_board instead")
@@ -5472,7 +5505,8 @@ def get_all_issues_for_sprint_in_board(
54725505
'jira.search.views.default.max' in your JIRA instance.
54735506
If you exceed this limit, your results will be truncated.
54745507
"""
5475-
url = f"/rest/agile/1.0/board/{board_id}/sprint/{sprint_id}/issue"
5508+
resource = f"board/{board_id}/sprint/{sprint_id}/issue"
5509+
url = self.get_agile_resource_url(resource)
54765510
params: dict = {}
54775511
if jql:
54785512
params["jql"] = jql
@@ -5510,14 +5544,15 @@ def get_all_versions_from_board(
55105544
See the 'Pagination' section at the top of this page for more details.
55115545
:return:
55125546
"""
5547+
resource = f"board/{board_id}/version"
5548+
url = self.get_agile_resource_url(resource)
55135549
params: dict = {}
55145550
if released:
55155551
params["released"] = released
55165552
if start:
55175553
params["startAt"] = start
55185554
if limit:
55195555
params["maxResults"] = limit
5520-
url = f"rest/agile/1.0/board/{board_id}/version"
55215556
return self.get(url, params=params)
55225557

55235558
def create_sprint(
@@ -5544,7 +5579,8 @@ def create_sprint(
55445579
https://docs.atlassian.com/jira-software/REST/8.9.0/#agile/1.0/sprint
55455580
isoformat can be created with datetime.datetime.isoformat()
55465581
"""
5547-
url = "/rest/agile/1.0/sprint"
5582+
resource = "sprint"
5583+
url = self.get_agile_resource_url(resource)
55485584
data = dict(name=name, originBoardId=board_id)
55495585
if start_date:
55505586
data["startDate"] = start_date
@@ -5580,7 +5616,8 @@ def get_sprint(self, sprint_id: T_id) -> T_resp_json:
55805616
:param sprint_id:
55815617
:return:
55825618
"""
5583-
url = f"rest/agile/1.0/sprint/{sprint_id}"
5619+
resource = f"sprint/{sprint_id}"
5620+
url = self.get_agile_resource_url(resource)
55845621
return self.get(url)
55855622

55865623
def rename_sprint(self, sprint_id: T_id, name: str, start_date: str, end_date: str) -> T_resp_json:
@@ -5592,8 +5629,10 @@ def rename_sprint(self, sprint_id: T_id, name: str, start_date: str, end_date: s
55925629
:param end_date:
55935630
:return:
55945631
"""
5632+
resource = f"sprint/{sprint_id}"
5633+
url = self.get_agile_resource_url(resource, legacy_api=True)
55955634
return self.put(
5596-
f"rest/greenhopper/1.0/sprint/{sprint_id}",
5635+
url,
55975636
data={"name": name, "startDate": start_date, "endDate": end_date},
55985637
)
55995638

@@ -5605,7 +5644,9 @@ def delete_sprint(self, sprint_id: T_id) -> T_resp_json:
56055644
:param sprint_id:
56065645
:return:
56075646
"""
5608-
return self.delete(f"rest/agile/1.0/sprint/{sprint_id}")
5647+
resource = f"sprint/{sprint_id}"
5648+
url = self.get_agile_resource_url(resource)
5649+
return self.delete(url)
56095650

56105651
def update_partially_sprint(self, sprint_id: T_id, data: dict) -> T_resp_json:
56115652
"""
@@ -5625,7 +5666,9 @@ def update_partially_sprint(self, sprint_id: T_id, data: dict) -> T_resp_json:
56255666
:param data: { "name": "new name"}
56265667
:return:
56275668
"""
5628-
return self.post(f"rest/agile/1.0/sprint/{sprint_id}", data=data)
5669+
resource = f"sprint/{sprint_id}"
5670+
url = self.get_agile_resource_url(resource)
5671+
return self.post(url, data=data)
56295672

56305673
def get_sprint_issues(self, sprint_id: T_id, start: T_id, limit: T_id) -> T_resp_json:
56315674
"""
@@ -5644,12 +5687,13 @@ def get_sprint_issues(self, sprint_id: T_id, start: T_id, limit: T_id) -> T_resp
56445687
If you exceed this limit, your results will be truncated.
56455688
:return:
56465689
"""
5690+
resource = f"sprint/{sprint_id}/issue"
5691+
url = self.get_agile_resource_url(resource)
56475692
params: dict = {}
56485693
if start:
56495694
params["startAt"] = start
56505695
if limit:
56515696
params["maxResults"] = limit
5652-
url = f"rest/agile/1.0/sprint/{sprint_id}/issue"
56535697
return self.get(url, params=params)
56545698

56555699
def update_rank(self, issues_to_rank: list, rank_before: str, customfield_number: T_id) -> T_resp_json:
@@ -5660,9 +5704,11 @@ def update_rank(self, issues_to_rank: list, rank_before: str, customfield_number
56605704
:param customfield_number: The number of the custom field Rank
56615705
:return:
56625706
"""
5707+
resource = "issue/rank"
5708+
url = self.get_agile_resource_url(resource)
56635709

56645710
return self.put(
5665-
"rest/agile/1.0/issue/rank",
5711+
url,
56665712
data={
56675713
"issues": issues_to_rank,
56685714
"rankBeforeIssue": rank_before,
@@ -5698,7 +5744,8 @@ def flag_issue(self, issue_keys: List[T_id], flag: bool = True) -> T_resp_json:
56985744
:return: POST request response.
56995745
:rtype: dict
57005746
"""
5701-
url = "rest/greenhopper/1.0/xboard/issue/flag/flag.json"
5747+
resource = f"xboard/issue/flag/flag.json"
5748+
url = self.get_agile_resource_url(resource, legacy_api=True)
57025749
data = {"issueKeys": issue_keys, "flag": flag}
57035750
return self.post(url, data)
57045751

0 commit comments

Comments
 (0)