User can't complete sprint: How to know where the user is missing permissions?

Platform Notice: Cloud Only - This article only applies to Atlassian products on the cloud platform.

Summary

Platform Notice: Cloud Only - This article only applies to Atlassian products on the cloud platform.

Disclaimer

Atlassian does not support this code below, which is provided "AS IS". The goal of this article is to provide a piece of code that illustrates one way to achieve the desired goal.

Feedback provided at the bottom of the page is appreciated, but won't be handled as support.

Sometimes, some users contact their Jira admins to inform them that they can't click on the Complete Sprint Button. Why?

In most part of the cases the user is missing Manage Sprint, Edit Issue, or Schedule issue permission in one of the projects returned by the board's filter.

The Python script on this page will return if the user has permission to Manage Sprint, Edit Issue, or Schedule issue in the projects returned by the board's filter JQL.

Solution

Environment

Jira Cloud.

Usage

It's important to highlight that the script will only projects where you have browser permission.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 import pandas as pd from openpyxl import workbook from openpyxl import load_workbook import requests from requests.auth import HTTPBasicAuth import json #replace with the customer's site, without the domain(atlassian.net) site = <your-site> #The board's Id where the user can't complete Sprint boardId = <boardId> #Your email and API Token auth = HTTPBasicAuth(<email>, <token>) #The user's AAID accountId= <User ID> workbook = load_workbook('results.xlsx') sheet = workbook.active headers = { "Accept": "application/json", "Content-Type": "application/json" } def remove_duplicates(lst): return list(set(lst)) response = requests.request( "GET", "https://"+site+".atlassian.net/rest/agile/1.0/board/"+str(boardId)+"/project", headers=headers, auth=auth ) print("Starting getting the projects from the JQL: ") result = json.loads(response.text) total = result['total'] #array that will save the issue id returned by the request issues_id = [] #array that will save the issue keys returned by the request issues_key = [] #array that will save the project keys returned by the request projects_key = [] #array that will save the project ids returned by the request projects_ids = [] for i in range(total): projects_ids.append(result['values'][i]['id']) projects_key.append(result['values'][i]['key']) i = i+1 # GETTING AN ISSUE TO USE IN THE PERMISSION CHECKER print("Project: ", projects_key) print("total of projects: ", len(projects_key)) for i2 in range(len(projects_key)): response_issue = requests.request( "GET", "https://"+site+".atlassian.net/rest/api/3/search?jql=project="+projects_key[i2]+"&maxResults=1", headers=headers, auth=auth ) result_issue = json.loads(response_issue.text) if 'issues' in result_issue and len(result_issue['issues']) >= 0: # Iterate over available issues instead of using i2 for j, issue in enumerate(result_issue['issues']): print("Issues: ", issue['key']) newLine = [ issue['id'], issue['key'], issue['fields']['project']['id'], issue['fields']['project']['key'] ] issues_id.append(newLine) else: print(f"Next Project") size = len(issues_id) #FROM HERE I WILL TRY TO GET IF THE USER MENTIONED HAS PERMISSION TO MANAGE SPRINT, EDIT ISSUE, AND SCHEDULE ISSUE for i3 in range(size): payload = json.dumps( { "accountId": accountId, "projectPermissions": [ { "issues": [ issues_id[i3][0] ], "permissions": [ "EDIT_ISSUES", "MANAGE_SPRINTS_PERMISSION", "SCHEDULE_ISSUES" ], "projects": [ issues_id[i3][2] ] } ] }) response_permission = requests.request( "POST", "https://"+site+".atlassian.net/rest/api/2/permissions/check", data=payload, headers=headers, auth=auth ) result_permission = json.loads(response_permission.text) size_permission=len(result_permission['projectPermissions']) line = result_permission['projectPermissions'] sheet.append(["Project: "+issues_id[i3][3]]) print(["Project: "+issues_id[i3][3]]) for i4 in range(size_permission): if result_permission['projectPermissions'][i4]['issues'] != []: line = {'B':"HAS PERMISSION TO "+result_permission['projectPermissions'][i4]['permission']} print(line) sheet.append(line) else: line = {'B':"DOESN'T HAVE PERMISSION TO "+result_permission['projectPermissions'][i4]['permission']} print(line) sheet.append(line) i4=i4+1 print("#####################################################################################################") i3 = i3+1 workbook.save('results.xlsx')

The results will be exported to a file named “result.xlsx" in the same folder where the script is:

(Auto-migrated image: description temporarily unavailable)
Updated on April 2, 2025

Still need help?

The Atlassian Community is here for you.