Skip to content

Commit

Permalink
Update for JIRA REST 3, bump version, cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
lmaitresym committed Mar 7, 2024
1 parent 59bcd82 commit 1b46a01
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 47 deletions.
2 changes: 1 addition & 1 deletion jira/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '1.0.1'
__version__ = '1.1.0'
100 changes: 64 additions & 36 deletions jira/api/jira_client.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import requests
import json
from requests.auth import HTTPBasicAuth

import sys

class JiraClient:

Expand Down Expand Up @@ -45,14 +45,11 @@ def login(self, url, username, password):
self.configuration['password'] = password
return 200

def logout(self):
return 500

def dump(self):
return self.configuration

def getFields(self):
r = requests.get(f"{self.url}/rest/api/2/field", auth=self.auth)
r = requests.get(f"{self.url}/rest/api/3/field", auth=self.auth)
return r.status_code, r.content

def getReferenceData(self, field_key):
Expand All @@ -70,18 +67,18 @@ def getSuggestions(self, field_key):
return r.status_code, r.content

def getFieldOption(self, field_key, option_id):
r = requests.get(f"{self.url}/rest/api/2/field/{field_key}/option/{option_id}", auth=self.auth)
r = requests.get(f"{self.url}/rest/api/3/field/{field_key}/option/{option_id}", auth=self.auth)
return r.status_code, r.content

def deleteFieldOption(self, field_key, option_id):
r = requests.delete(f"{self.url}/rest/api/2/field/{field_key}/option/{option_id}", auth=self.auth)
r = requests.delete(f"{self.url}/rest/api/3/field/{field_key}/option/{option_id}", auth=self.auth)
return r.status_code, r.text

def getFieldOptions(self, field_key, context):
if context is None:
base_uri = f"{self.url}/rest/api/3/customFieldOption/{field_key}"
uri = f"{self.url}/rest/api/3/customFieldOption/{field_key}"
else:
base_uri = f"{self.url}/rest/api/3/field/{field_key}/context/{context}/option"
uri = f"{self.url}/rest/api/3/field/{field_key}/context/{context}/option"

isLast = False
startAtIdx = 0
Expand All @@ -90,8 +87,11 @@ def getFieldOptions(self, field_key, context):
all_options = list()
error_message = None
while not isLast:
uri = f"{base_uri}?startAt={startAtIdx}&maxResults={maxResults}"
r = requests.get(uri, auth=self.auth)
params = {
"startAt": startAtIdx,
"maxResults": maxResults
}
r = requests.get(uri, params=params, auth=self.auth)
rc = r.status_code
if rc == 200:
payload = json.loads(r.content)
Expand All @@ -111,7 +111,7 @@ def getFieldContexts(self, field_key):
return r.status_code, r.content

def addOption(self, field_key, option):
r = requests.post(f"{self.url}/rest/api/2/field/{field_key}/option", auth=self.auth, json=option)
r = requests.post(f"{self.url}/rest/api/3/field/{field_key}/option", auth=self.auth, json=option)
return r.status_code, r.content

def addCascadingOption(self, field_key, contextId, parentOptionId, optionValue):
Expand All @@ -132,31 +132,25 @@ def delCascadingOption(self, field_key, contextId, parentOptionId, optionId):
return r.status_code, r.content

def addOptionWithId(self, field_key, option, option_id):
r = requests.put(f"{self.url}/rest/api/2/field/{field_key}/option/{option_id}", auth=self.auth, json=option)
r = requests.put(f"{self.url}/rest/api/3/field/{field_key}/option/{option_id}", auth=self.auth, json=option)
return r.status_code, r.content

def updateFieldOption(self, field_key, option):
r = requests.put(f"{self.url}/rest/api/2/field/{field_key}/option/{option['id']}", auth=self.auth, json=option)
r = requests.put(f"{self.url}/rest/api/3/field/{field_key}/option/{option['id']}", auth=self.auth, json=option)
return r.status_code, r.content

def replaceOption(self, field_key, option_to_replace, option_to_use, jql_filter):
params = {
"replaceWith": option_to_use,
"jql": jql_filter
}
r = requests.delete(f"{self.url}/rest/api/2/field/{field_key}/option/{option_to_replace}/issue",
r = requests.delete(f"{self.url}/rest/api/3/field/{field_key}/option/{option_to_replace}/issue",
auth=self.auth,
params=params)
if r.status_code == 303:
print('Get task status here: %s' % r.content)
return r.status_code, r.content

def manageOptionsForProject(self, field_key, project_id, verb):
return

def addProjectToFieldOptions(self, field_key, project_id):
return

def createCustomField(self, name, description, searcherKey, fieldType):
json = {
"description": description,
Expand All @@ -171,21 +165,55 @@ def createCustomField(self, name, description, searcherKey, fieldType):
r = requests.post(f"{self.url}/rest/api/3/field", headers=headers, json=json, auth=self.auth)
return r.status_code, r.content

def getIssue(self, issue_key):
r = requests.get(f"{self.url}/rest/api/2/issue/{issue_key}", auth=self.auth)
def getIssue(self, issue_key, fields):
params = {
"fields": fields
}
r = requests.get(f"{self.url}/rest/api/3/issue/{issue_key}", params=params, auth=self.auth)
return r.status_code, r.content

def deleteIssue(self, issue_key):
r = requests.delete(f"{self.url}/rest/api/2/issue/{issue_key}", auth=self.auth)
r = requests.delete(f"{self.url}/rest/api/3/issue/{issue_key}", auth=self.auth)
return r.status_code, r.content

def getIssues(self, jql):
def getIssues(self, jql, page_size, fields):
uri = f"{self.url}/rest/api/3/search"
total = 999999
startAtIdx = 0
rc = 0
maxResults = page_size
params = {
"jql": jql,
"fields": "*all"
"fields": fields,
"maxResults": maxResults
}
r = requests.get(f"{self.url}/rest/api/2/search", params=params, auth=self.auth)
return r.status_code, r.content

all_issues = list()
error_message = None
while startAtIdx < total:
print(f"At index {startAtIdx}/{total}...", file=sys.stderr)
params['startAt'] = startAtIdx
r = requests.get(uri, params=params, auth=self.auth)
rc = r.status_code
if rc == 200:
payload = json.loads(r.content)
issues = payload['issues']
nb_issues = len(issues)
all_issues = all_issues + issues
total = payload['total']
print(f"Got {nb_issues} issues...", file=sys.stderr)
if startAtIdx < total:
startAtIdx = startAtIdx + nb_issues
else:
error_message = r.content
break
if rc != 200:
# print(f"{rc}:{error_message}", sys.stderr)
print(f"{rc}:{error_message}", file=sys.stderr)
# pass
return rc, error_message
# pass
return rc, json.dumps(all_issues, indent=True)

def getIssuesPage(self, jql, page, pageSize, expand=None):
params = {
Expand All @@ -196,13 +224,13 @@ def getIssuesPage(self, jql, page, pageSize, expand=None):
}
if expand is not None:
params['expand'] = expand
r = requests.get(f"{self.url}/rest/api/2/search", params=params, auth=self.auth)
r = requests.get(f"{self.url}/rest/api/3/search", params=params, auth=self.auth)
return r.status_code, r.content

def updateIssue(self, issue_key, field_key, value):
payload = { "fields": {} }
payload['fields'][field_key] = value
r = requests.put(f"{self.url}/rest/api/2/issue/{issue_key}", json=payload, auth=self.auth)
r = requests.put(f"{self.url}/rest/api/3/issue/{issue_key}", json=payload, auth=self.auth)
return r.status_code, r.content

def getCreateMeta(self, project_key, issuetype_key):
Expand All @@ -217,7 +245,7 @@ def getCreateMeta(self, project_key, issuetype_key):
params['issuetypeIds'] = issuetype_key
elif isinstance(issuetype_key, str):
params['issuetypeNames'] = issuetype_key
r = requests.get(f"{self.url}/rest/api/2/issue/createmeta", params=params, auth=self.auth)
r = requests.get(f"{self.url}/rest/api/3/issue/createmeta", params=params, auth=self.auth)
return r.status_code, r.content

def getFieldIdFromKeyAndMeta(self, field_key, issue_meta):
Expand Down Expand Up @@ -256,15 +284,15 @@ def getProject(self, project_key_or_id):
"issueTypeHierarchy"
]
}
r = requests.get(f"{self.url}/rest/api/2/project/{project_key_or_id}", params=params, auth=self.auth)
r = requests.get(f"{self.url}/rest/api/3/project/{project_key_or_id}", params=params, auth=self.auth)
return r.status_code, r.content

def listProjects(self):
r = requests.get(f"{self.url}/rest/api/2/project", auth=self.auth)
r = requests.get(f"{self.url}/rest/api/3/project", auth=self.auth)
return r.status_code, r.content

def getRole(self, project_id, role_id):
r = requests.get(f"{self.url}/rest/api/2/project/{project_id}/role/{role_id}", auth=self.auth)
r = requests.get(f"{self.url}/rest/api/3/project/{project_id}/role/{role_id}", auth=self.auth)
return r.status_code, r.content

def getServiceDesk(self, servicedesk_id):
Expand All @@ -276,11 +304,11 @@ def listServiceDesks(self):
return r.status_code, r.content

def createIssue(self, issue):
r = requests.post(f"{self.url}/rest/api/2/issue", auth=self.auth, json=issue)
r = requests.post(f"{self.url}/rest/api/3/issue", auth=self.auth, json=issue)
return r.status_code, r.content

def createIssues(self, issues):
r = requests.post(f"{self.url}/rest/api/2/issue/bulk", auth=self.auth, json=issues)
r = requests.post(f"{self.url}/rest/api/3/issue/bulk", auth=self.auth, json=issues)
return r.status_code, r.content

def deletePage(self, page_id):
Expand Down
6 changes: 3 additions & 3 deletions jira/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
jira
Usage:
jira session (login <url> <username> <password>|logout|dump)
jira session (login <url> <username> <password>|dump)
jira field (get <field_key_or_id_or_name>|getoptions <field_key> <context>|addprojectoptions <field_key> <project_id>|delprojectoptions <field_key> <project_id>|loadoptions <field_key> <options_file> <project_ids>|addoptions <field_key> <options_file> <project_keys>|suggestions <field_key>|referenceDatas <field_key>|getcontexts <field_key>|create <name> <description> <searcher_key> <field_type>)
jira option (get <field_key> <option_id>|add <field_key> <option_value> <project_keys>|del <field_key> <option_id>|exist <field_key> <option_value>|replace <field_key> <option_to_replace> <option_to_use> <jql_filter>|getid <field_key> <option_value>|addcascading <field_key> <context_id> <parent_id> <option_value>|delcascading <field_key> <context_id> <parent_id> <option_id>)
jira options add <field_key> <options_file> <project_keys>
jira issues (get <jql> [--page=<page_index>] [--page-size=<page_size>]|getkeys <jql>|create <json_file>)
jira issue (get <issue_key>|del <issue_key>|set <issue_keys> <field_key> <value_or_field_key>|createmeta <project_key> <issue_type>|create <json_file>)
jira issues (get <jql> [--page=<page_index>] [--page-size=<page_size>] [--fields=<field1,field2...>]|getkeys <jql>|create <json_file>)
jira issue (get <issue_key> [--fields=<field1,field2...>]|del <issue_key>|set <issue_keys> <field_key> <value_or_field_key>|createmeta <project_key> <issue_type>|create <json_file>)
jira project (get <project_key_or_id>|list)
jira role (get <project_id> <role_id>)
jira servicedesk (get <servicedesk_id>|list)
Expand Down
6 changes: 5 additions & 1 deletion jira/commands/issue.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ def run(self):

def getIssue(self):
issue_key = self.options['<issue_key>']
rc, datas = self.jira_client.getIssue(issue_key)
if self.hasOption('--fields'):
fields = self.options['--fields']
else:
fields = [ "*all" ]
rc, datas = self.jira_client.getIssue(issue_key, fields)
self.processResults(rc, datas)

def deleteIssue(self):
Expand Down
19 changes: 13 additions & 6 deletions jira/commands/issues.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class Issues(Base):
"""Manage issues"""

def run(self):
#print('You supplied the following options:', json.dumps(self.options, indent=2, sort_keys=True))
# print('You supplied the following options:', json.dumps(self.options, indent=2, sort_keys=True))
self.jira_client = JiraClient(self.loadConfiguration())
if self.hasOption('get'):
self.getIssues()
Expand All @@ -23,16 +23,23 @@ def run(self):

def getIssues(self):
jql = self.options['<jql>']
by_page = False
if self.hasOption('--page'):
page_index = int(self.options['--page'])
else:
page_index = 0
by_page = True
if self.hasOption('--page-size'):
page_size = int(self.options['--page-size'])
else:
page_size = 50
#print("Get page %s/%s of issues for jql %s" % (page_index, page_size, jql))
rc, datas = self.jira_client.getIssuesPage(jql, page_index, page_size)
page_size = 100
if self.hasOption('--fields'):
fields = self.options['--fields']
else:
fields = [ "*all" ]
if by_page:
#print("Get page %s/%s of issues for jql %s" % (page_index, page_size, jql))
rc, datas = self.jira_client.getIssuesPage(jql, page_index, page_size, fields)
else:
rc, datas = self.jira_client.getIssues(jql, page_size, fields)
self.processResults(rc, datas)

def getIssuesKeys(self):
Expand Down

0 comments on commit 1b46a01

Please sign in to comment.