Skip to content

Commit 8bfab52

Browse files
authored
Merge pull request #4 from dataiku/feature/create-incident-tool
Merging tool for issue creation
2 parents 741ea68 + fdc131a commit 8bfab52

File tree

6 files changed

+151
-5
lines changed

6 files changed

+151
-5
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## [Version 1.1.0](https://github.com/dataiku/dss-plugin-jira/releases/tag/v1.1.0) - Feature release - 2025-04-30
4+
5+
- Add AI agent tool for issue creation
6+
37
## [Version 1.0.2](https://github.com/dataiku/dss-plugin-jira/releases/tag/v1.0.2) - Feature release - 2024-12-12
48

59
- Add option to access Jira on premise

plugin.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
{
22
"id": "jira",
3-
"version": "1.0.2",
3+
"version": "1.1.0",
44
"meta": {
55
"label": "Jira",
66
"description": "Import data from your Jira account",
77
"author": "Dataiku",
88
"icon": "icon-ticket",
9-
"tags": ["Connector", "CRM"],
9+
"tags": ["Connector", "CRM", "Generative AI", "Agents", "Tools"],
1010
"url": "https://www.dataiku.com/product/plugins/jira/",
1111
"licenseInfo": "Apache Software License",
1212
"supportLevel": "NOT_SUPPORTED"
1313
}
14-
}
14+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"id": "create-jira-issue",
3+
"meta": {
4+
"icon": "icon-ticket",
5+
"label": "Create Jira Issue",
6+
"description": "Create a Jira issue based on user input"
7+
},
8+
9+
"params" : [
10+
{
11+
"name": "access_type",
12+
"label": "Access type. Reviewer: hidden menu to keep for future extension",
13+
"visibilityCondition": "false",
14+
"type": "SELECT",
15+
"defaultValue": "token_access",
16+
"selectChoices": [
17+
{
18+
"value": "token_access",
19+
"label": "Token"
20+
}
21+
]
22+
},
23+
{
24+
"name": "token_access",
25+
"label": "Jira connection",
26+
"type": "PRESET",
27+
"parameterSetId": "basic-auth",
28+
"visibilityCondition": "model.access_type == 'token_access'"
29+
},
30+
{
31+
"name": "jira_project_key",
32+
"label":"Jira Project Key",
33+
"type": "STRING",
34+
"mandatory": true,
35+
"description": ""
36+
}
37+
]
38+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
from dataiku.llm.agent_tools import BaseAgentTool
2+
import logging
3+
from jira_client import JiraClient
4+
from utils import get_connection_details
5+
6+
7+
class JiraCreateIssueTool(BaseAgentTool):
8+
def set_config(self, config, plugin_config):
9+
# This logger outputs the key in DEBUG mode ...
10+
logging.getLogger("jiraapiclient.discovery").setLevel("INFO")
11+
logging.info("JiraCreateIssueTool init")
12+
self.config = config
13+
connection_details = get_connection_details(config)
14+
self.client = JiraClient(connection_details)
15+
self.client.start_session("issue")
16+
self.jira_project_key = config.get("jira_project_key")
17+
18+
def get_descriptor(self, tool):
19+
return {
20+
"description": "This tool is a wrapper around atlassian-python-api\'s Jira issue_create API, useful when you need to create a Jira issue. The input to this tool is a dictionary containing the new issue summary and description, e.g. '{'summary':'new issue summary', 'description':'new issue description'}'",
21+
"inputSchema": {
22+
"$id": "https://dataiku.com/agents/tools/search/input",
23+
"title": "Create Jira issue tool",
24+
"type": "object",
25+
"properties": {
26+
"summary": {
27+
"type": "string",
28+
"description": "The issue summary"
29+
},
30+
"description": {
31+
"type": "string",
32+
"description": "The issue description"
33+
}
34+
},
35+
"required": ["summary", "description"]
36+
}
37+
}
38+
39+
def create_jira_issue(self, summary: str, description: str, issue_type: str = "Task"):
40+
try:
41+
new_issue = self.client.create_issue(self.jira_project_key, summary, description, issue_type)
42+
return new_issue
43+
44+
except Exception as exception:
45+
return f"Error creating issue: {str(exception)}"
46+
47+
def invoke(self, input, trace):
48+
args = input.get("input", {})
49+
50+
# Log inputs and config to trace
51+
trace.span["name"] = "JIRA_CREATE_ISSUE_TOOL_CALL"
52+
for key, value in args.items():
53+
trace.inputs[key] = value
54+
trace.attributes["config"] = self.config
55+
56+
summary = args.get("summary")
57+
description = args.get("description")
58+
jira_instance_url = self.client.get_site_url()
59+
created_issue = self.create_jira_issue(summary, description)
60+
61+
if created_issue and "errors" in created_issue:
62+
output_text = "There was a problem while creating the issue ticket: {}".format(
63+
created_issue.get("errors", {}).get("description")
64+
)
65+
else:
66+
output_text = f"Issue created: {created_issue.get('key')} available at {jira_instance_url}browse/{created_issue.get('key')}" if isinstance(created_issue, dict) else created_issue
67+
68+
# Log outputs to trace
69+
trace.outputs["output"] = output_text
70+
71+
return {
72+
"output": output_text
73+
}

python-lib/jira_client.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ def filter_data(self, data, item_value):
148148
if filtering_key is None:
149149
return arrayed(data)
150150
else:
151-
return arrayed(extract_data_with_json_path(data,filtering_key))
151+
return arrayed(extract_data_with_json_path(data, filtering_key))
152152

153153
def format_data(self, data):
154154
for key in self.formating:
@@ -214,6 +214,31 @@ def get(self, url, data=None, params=None):
214214
response = requests.get(url, **args)
215215
return response
216216

217+
def post(self, url, data=None, json=None, params=None):
218+
headers = self.get_headers()
219+
headers['Content-Type'] = 'application/json'
220+
headers['Accept'] = 'application/json'
221+
headers.pop('X-ExperimentalApi', None)
222+
auth = self.get_auth()
223+
response = requests.post(url, params=params, auth=auth, data=data, json=json, headers=headers)
224+
return response
225+
226+
def create_issue(self, jira_project_key, summary, description, issue_type):
227+
issue_data = {
228+
'project': {'key': jira_project_key},
229+
'summary': summary,
230+
'description': description,
231+
'issuetype': {'name': issue_type}
232+
}
233+
json = {
234+
"fields": issue_data,
235+
}
236+
# This data form does not work on v3
237+
url = "/".join([self.get_site_url(), "rest/api/2/issue"])
238+
response = self.post(url=url, json=json)
239+
json_response = response.json()
240+
return json_response
241+
217242
def get_auth(self):
218243
if self.is_opsgenie_api():
219244
return None

python-lib/utils.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,10 @@ def extract_data_with_json_path(data, json_path):
1717
keys = json_path.split(".")
1818
for key in keys:
1919
data = data.get(key, {})
20-
return data
20+
return data
21+
22+
23+
def get_connection_details(config):
24+
access_type = config.get("access_type", "token_access")
25+
connection_details = config.get(access_type)
26+
return connection_details

0 commit comments

Comments
 (0)