208 lines
6.4 KiB
Python
208 lines
6.4 KiB
Python
import dataclasses
|
|
import logging
|
|
import os
|
|
import webbrowser
|
|
|
|
|
|
def force_import(module: str):
|
|
import importlib
|
|
import subprocess
|
|
import sys
|
|
|
|
try:
|
|
return importlib.import_module(module)
|
|
except ModuleNotFoundError:
|
|
subprocess.run([sys.executable, "-m", "pip", "install", module])
|
|
importlib.invalidate_caches()
|
|
return importlib.import_module(module)
|
|
|
|
|
|
try:
|
|
import httpx
|
|
except ImportError:
|
|
torf = force_import("httpx")
|
|
|
|
try:
|
|
import typer
|
|
except ImportError:
|
|
typer = force_import("typer")
|
|
try:
|
|
import rich
|
|
except ImportError:
|
|
rich = force_import("rich")
|
|
try:
|
|
import inquirer
|
|
except ImportError:
|
|
inquirer = force_import("inquirer")
|
|
|
|
from rich import print
|
|
import rich.table
|
|
|
|
JIRA_EMAIL = os.getenv('JIRA_EMAIL', 'abdussamet.kocak@akinon.com')
|
|
JIRA_TOKEN = os.getenv('JIRA_TOKEN', 'iAZhlJ1AdGwckbVllhlx48C4')
|
|
JIRA_URL = os.getenv('JIRA_URL', 'https://omniplatform.atlassian.net/')
|
|
|
|
if not JIRA_TOKEN:
|
|
logging.info('')
|
|
webbrowser.open('https://id.atlassian.com/manage-profile/security/api-tokens')
|
|
|
|
|
|
@dataclasses.dataclass
|
|
class Issue:
|
|
id: str
|
|
key: str
|
|
summary: str
|
|
|
|
|
|
@dataclasses.dataclass
|
|
class PullRequest:
|
|
id: str
|
|
name: str
|
|
repository: str
|
|
branch: str
|
|
|
|
|
|
class Jira:
|
|
def __init__(self, email: str, token: str):
|
|
self.client = httpx.Client(
|
|
base_url=JIRA_URL,
|
|
auth=httpx.BasicAuth(email, token),
|
|
)
|
|
|
|
def list_issues_for_release(self) -> list[Issue]:
|
|
mergeable_status = 'In Review'
|
|
res = self.client.post(
|
|
'/rest/api/2/search',
|
|
json={
|
|
'jql': f'project = COM AND status = "{mergeable_status}" AND "Team[Dropdown]" = Backend ORDER BY created DESC'
|
|
},
|
|
)
|
|
|
|
res.raise_for_status()
|
|
data = res.json()
|
|
development_type = ['Story', 'Bug', 'Task']
|
|
return [
|
|
Issue(id=it['id'], key=it['key'], summary=it['fields']['summary'])
|
|
for it in data['issues']
|
|
if it['fields']['issuetype']['name'] in development_type
|
|
]
|
|
|
|
def get_approved_prs(self, issue_id: str):
|
|
res = self.client.post(
|
|
f'/jsw/graphql',
|
|
params={'operation': 'DevDetailsDialog'},
|
|
json={
|
|
"operationName": "DevDetailsDialog",
|
|
"query": """
|
|
query DevDetailsDialog ($issueId: ID!) {
|
|
developmentInformation(issueId: $issueId){
|
|
details {
|
|
instanceTypes {
|
|
repository {
|
|
name
|
|
branches {
|
|
name
|
|
pullRequests {
|
|
name
|
|
status
|
|
lastUpdate
|
|
}
|
|
reviews {
|
|
state
|
|
id
|
|
}
|
|
}
|
|
pullRequests {
|
|
id
|
|
name
|
|
branchName
|
|
status
|
|
reviewers{
|
|
name
|
|
isApproved
|
|
}
|
|
}
|
|
}
|
|
danglingPullRequests {
|
|
id
|
|
name
|
|
branchName
|
|
status
|
|
reviewers{
|
|
name
|
|
isApproved
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
""",
|
|
"variables": {"issueId": issue_id},
|
|
},
|
|
)
|
|
res.raise_for_status()
|
|
data = res.json()['data']
|
|
if not data['developmentInformation']['details']['instanceTypes']:
|
|
return []
|
|
repo_name = data['developmentInformation']['details']['instanceTypes'][0]['repository'][0]['name']
|
|
prs = data['developmentInformation']['details']['instanceTypes'][0]['danglingPullRequests']
|
|
if not prs:
|
|
repo_name = data['developmentInformation']['details']['instanceTypes'][0]['repository'][0]['name']
|
|
prs = data['developmentInformation']['details']['instanceTypes'][0]['repository'][0]['pullRequests']
|
|
|
|
return [
|
|
PullRequest(
|
|
id=it['id'],
|
|
name=it['name'],
|
|
repository=repo_name,
|
|
branch=it['branchName'],
|
|
)
|
|
for it in prs
|
|
if it['status'] != 'MERGED'
|
|
]
|
|
|
|
|
|
console = rich.console.Console()
|
|
|
|
|
|
def render_issue(issue: Issue, prs: list[PullRequest]):
|
|
t = rich.table.Table(
|
|
title=f'{issue.key} -- {issue.summary}',
|
|
caption_justify='left',
|
|
)
|
|
t.add_column("Repository", no_wrap=True)
|
|
t.add_column("Branch", no_wrap=True)
|
|
t.add_column("Pull Request")
|
|
|
|
for it in prs:
|
|
t.add_row(it.repository, it.branch, it.name)
|
|
|
|
console.print(t)
|
|
|
|
|
|
def main():
|
|
logging.basicConfig(level=logging.INFO)
|
|
if not JIRA_EMAIL:
|
|
logging.error('JIRA_EMAIL is not set')
|
|
exit(1)
|
|
if not JIRA_TOKEN:
|
|
logging.error('JIRA_TOKEN is not set')
|
|
exit(1)
|
|
|
|
j = Jira(email=JIRA_EMAIL, token=JIRA_TOKEN)
|
|
|
|
logging.info('fetching issues in "ready to release" status')
|
|
issues = j.list_issues_for_release()
|
|
for it in issues:
|
|
logging.info(f'fetching pull requests for issue {it.key}')
|
|
prs = j.get_approved_prs(it.id)
|
|
if not prs:
|
|
logging.info(f'no non-merged pull requests found for issue {it.key}')
|
|
continue
|
|
render_issue(it, prs)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|