-
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathjira_issue.py
178 lines (155 loc) · 6.35 KB
/
jira_issue.py
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
"""
title: Jira Issue
description: This tool allows you to get information about a specific issue on Jira.
repository: https://github.com/RomainNeup/open-webui-utilities
author: @romainneup
author_url: https://github.com/RomainNeup
funding_url: https://github.com/sponsors/RomainNeup
version: 0.2.0
changelog:
- 0.0.1 - Initial code base.
- 0.0.2 - Split Jira search and Jira get issue
- 0.1.0 - Add support for Personal Access Token authentication and user settings
- 0.2.0 - Add setting for SSL verification
"""
import base64
import json
from typing import Any, Awaitable, Callable, Dict
import requests
from pydantic import BaseModel, Field
class EventEmitter:
def __init__(self, event_emitter: Callable[[dict], Awaitable[None]]):
self.event_emitter = event_emitter
pass
async def emit_status(self, description: str, done: bool, error: bool = False):
await self.event_emitter(
{
"data": {
"description": f"{done and (error and '❌' or '✅') or '🔎'} {description}",
"status": done and "complete" or "in_progress",
"done": done,
},
"type": "status",
}
)
async def emit_message(self, content: str):
await self.event_emitter({"data": {"content": content}, "type": "message"})
async def emit_source(self, name: str, url: str, content: str, html: bool = False):
await self.event_emitter(
{
"type": "citation",
"data": {
"document": [content],
"metadata": [{"source": url, "html": html}],
"source": {"name": name},
},
}
)
class Jira:
def __init__(self, username: str, api_key: str, base_url: str, api_key_auth: bool = True, ssl_verify: bool = True):
self.base_url = base_url
self.headers = self.authenticate(username, api_key, api_key_auth)
self.ssl_verify = ssl_verify
pass
def get(self, endpoint: str, params: Dict[str, Any]):
url = f"{self.base_url}/rest/api/3/{endpoint}"
response = requests.get(url, params=params, headers=self.headers, verify=self.ssl_verify)
if not response.ok:
raise Exception(f"Failed to get data from Confluence: {response.text}")
return response.json()
def get_issue(self, issue_id: str):
endpoint = f"issue/{issue_id}"
result = self.get(
endpoint,
{"fields": "summary,description,status", "expand": "renderedFields"},
)
return {
"title": result["fields"]["summary"],
"description": result["renderedFields"]["description"],
"status": result["fields"]["status"]["name"],
"link": f"{self.base_url}/browse/{issue_id}",
}
def authenticate_api_key(self, username: str, api_key: str) -> Dict[str, str]:
auth_string = f"{username}:{api_key}"
encoded_auth_string = base64.b64encode(auth_string.encode("utf-8")).decode(
"utf-8"
)
return {"Authorization": "Basic " + encoded_auth_string}
def authenticate_personal_access_token(self, access_token: str) -> Dict[str, str]:
return {"Authorization": f"Bearer {access_token}"}
def authenticate(self, username: str, api_key: str, api_key_auth: bool) -> Dict[str, str]:
if api_key_auth:
return self.authenticate_api_key(username, api_key)
else:
return self.authenticate_personal_access_token(api_key)
class Tools:
def __init__(self):
self.valves = self.Valves()
pass
class Valves(BaseModel):
base_url: str = Field(
"https://example.atlassian.net/wiki",
description="The base URL of your Confluence instance",
)
username: str = Field(
description="Default username (leave empty for personal access token)",
)
api_key: str = Field(
"ABCD1234", description="Default API key or personal access token"
)
ssl_verify: bool = Field(
True,
description="SSL verification"
)
pass
class UserValves(BaseModel):
api_key_auth: bool = Field(
True,
description="Use API key authentication; disable this to use a personal access token instead.",
)
username: str = Field(
"",
description="Username, typically your email address; leave empty if using a personal access token or default settings.",
)
api_key: str = Field(
"",
description="API key or personal access token; leave empty to use the default settings.",
)
pass
async def get_issue(
self,
issue_id: str,
__event_emitter__: Callable[[dict], Awaitable[None]],
__user__: dict = {},
):
"""
Get a Jira issue by its ID. The response includes the title, description as HTML, status, and link to the issue.
:param issue_id: The ID of the issue.
:return: A response in JSON format (title, description, status, link).
"""
event_emitter = EventEmitter(__event_emitter__)
# Get the username and API key
if __user__ and "valves" in __user__:
user_valves = __user__["valves"]
api_key_auth = user_valves.api_key_auth
api_username = user_valves.username or self.valves.username
api_key = user_valves.api_key or self.valves.api_key
else:
api_username = self.valves.username
api_key = self.valves.api_key
api_key_auth = True
jira = Jira(api_username, api_key, self.valves.base_url, api_key_auth, self.valves.ssl_verify)
await event_emitter.emit_status(f"Getting issue {issue_id}", False)
try:
response = jira.get_issue(issue_id)
await event_emitter.emit_status(f"Got issue {issue_id}", True)
await event_emitter.emit_source(
response["title"], response["link"], response["description"], True
)
return json.dumps(response)
except Exception as e:
await event_emitter.emit_status(
f"Failed to get issue {issue_id}: {e}", True, True
)
return f"Error: {e}"