The request on the Atlassian Forums that caught my eye last night was a request to return all Jira Cloud attachments with a certain extension. Ordinarily it would be easy enough to cite ScriptRunner as the solution to this, but the user included data residency concerns in his initial post.
My solution to this was to write him a Python script to provide simple reporting on issues with certain extension types. Most anything that the rest API can accomplish can be accomplished with Python; you don’t HAVE to have ScriptRunner.
The hardest part of working with external scripts is figuring out the authorization scheme. Once you’ve got that figured out, the rest is just the same REST API interaction that you’d get with UniREST and ScriptRunner for cloud.
Authorizing the Script
First, read the instructions: https://developer.atlassian.com/cloud/jira/platform/basic-auth-for-rest-apis/
Then:
1. Generate an API token: https://id.atlassian.com/manage-profile/security/api-tokens
2. Go to https://www.base64encode.net/ (or figure out the Python module to do the encoding)
3. Base-64 encode a string in exactly this format: youratlassianlogin:APIToken.
If your email is john@adaptamist.com and the API token you generated is:
ATATT3xFfGF0nH_KSeZZkb_WbwJgi131SCo9N-ztA3SAySIK5w3qo9hdrxhqHZAZvimLHxbMA7ZmeYRMMNR
Then the string you base-64 encode is:
john@adaptamist.com:ATATT3xFfGF0nH_KSeZZkb_WbwJgi131SCo9N-ztA3SAySIK5w3qo9hdrxhqHZAZvimLHxbMA7ZmeYRMMNR
Do not forget the colon between the two pieces.
The website will spit out a single string of encoded text that looks like this: a21jY2xlYW5AYWQQhcHRhdmlzdC5jb206QVRBVFQzeEZmR0YwbkhfS1NlWlprYl9XYndKZ2kxMzFTQ285Ti16dEEzU0F5U0lLNXczcW85a
4. Stick the encoded string into the header variable like so:
headers = { 'Authorization': 'Basic a21jY2xlYW5AYWQQhcHRhdmlzdC5jb206QVRBVFQzeEZmR0YwbkhfS1NlWlprYl9XYndKZ2kxMzFTQ285Ti16dEEzU0F5U0lLNXczcW85a', 'Content-Type': 'application/json', 'Accept': 'application/json', }
Note that there’s nothing between the encoded string and the word “Basic”, and that both are treated as a single string.
Here’s an example of the script actually using this authorization scheme
import requests
max_results = 100
start_at = 0
attachment_arr = []
still_paginating = True
yourDomain = "<domain>"
headers = {
'Authorization': 'Basic <base-64 encoded string>',
'Content-Type': 'application/json',
'Accept': 'application/json',
}
# Define the global variables
while still_paginating:
# We need to paginate through the results
# We're iterating by 100 results at a time
response = requests.get(f"https://{yourDomain}.atlassian.net/rest/api/3/search?jql=project%20is%20not%20EMPTY&maxResults={max_results}&startAt={start_at}",
headers=headers)
#print(response.content)
issue_keys = response.json().get("issues")
# We start by returning all of the issues in the instance with a JQL search
for issue in issue_keys:
# Next, we're iterating through each result (issue) that was returned
issue_key = issue.get("key")
issue_response = requests.get(f"https://{yourDomain}.atlassian.net/rest/api/3/issue/{issue_key}",
headers=headers)
#print(issue_response.content)
issue_data = issue_response.json()
# We query the system for more information about the issue in question
attachments = issue_data.get("fields", {}).get("attachment", [])
for attachment in attachments:
# Specifically, we're after the ID of any attachment on the issue
attachment_id = attachment.get("id")
attachment_response = requests.get(f"https://{yourDomain}.atlassian.net/rest/api/3/attachment/{attachment_id}",
headers=headers)
#print(attachment_response.content)
attachment_data = attachment_response.json()
# Once we have the ID of the attachment, we can use that ID to get more information about the attachment
filename = attachment_data.get("filename")
if filename and (".csv" in filename or ".xlsx" in filename):
attachment_arr.append(f"Issue {issue_key} has an attachment: {filename}")
if len(issue_keys) < max_results:
still_paginating = False
# Finally, we check to see if we're still paginating
# If the total number of results is less than the total number of maximum possible results,
# we must be at the end of the line and can stop paginating by terminating the loop start_at += 100
start_at += 100
print(attachment_arr)
# Print the results
Leave a Reply