initial commit
This commit is contained in:
+207
@@ -0,0 +1,207 @@
|
||||
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()
|
||||
Reference in New Issue
Block a user