commit | (?P[a-f0-9]+).*?
+ (?P.*?) """, re.I | re.DOTALL)
+class CGit(IBugtracker):
+ def get_tracker(self, url, bugid):
+ try:
+ match = re.match(r'(?P(?P[^\s/]+\S*)/commit)/[^\s?]*\?([^\s?&]+&)?id=', url)
+ desc = match.group('desc')
+ name = desc.lower()
+ url = 'https://%s' % match.group('url')
+ return CGit(name, url, desc, 'cgit')
+ except:
+ pass
+
+ def get_bug(self, bugtype, bugid):
+ url = "%s/?id=%s" % (self.url, bugid)
+ try:
+ bugdata = utils.web.getUrl(url).decode('utf-8')
+ except Exception as e:
+ if re.match(r'HTTP Error (404|400)', str(e)):
+ raise BugNotFoundError
+ raise BugtrackerError(self.errget % (self.description, e, url))
+ match = cgitre.search(bugdata)
+ if match:
+ bugid = match.group('hash')[:7]
+ title = utils.web.htmlToText(match.group('subj'), tagReplace=' ')
+ title = re.sub(r'\s+', ' ', title)
+ product = match.group('repo')
+ return (bugid, product, title, '', '', '', url, [], [])
+ else:
+ raise BugtrackerError(self.errparseno % (self.description, url))
+
+class Mantis(IBugtracker):
+ def __init__(self, *args, **kwargs):
+ IBugtracker.__init__(self, *args, **kwargs)
+ self.soap_client = SoapClient("%s/api/soap/mantisconnect.php" % self.url, namespace="http://futureware.biz/mantisconnect")
+
+ def get_tracker(self, url):
+ try:
+ match = re.match(r'(?P(?P[^\s/]+)\S*)/view\.php', url)
+ desc = match.group('desc')
+ name = desc.lower()
+ url = 'https://%s' % match.group('url')
+ return Mantis(name, url, desc, 'mantis')
+ except:
+ pass
+
+ def get_bug(self, bugtype, bugid):
+ url = "%s/api/rest/issues/%s" % (self.url, bugid)
+ try:
+ bugjson = utils.web.getUrl(url).decode('utf-8')
+ bug = json.loads(bugjson)['issues'][0]
+ except Exception as e:
+ # REST API may not be enabled yet
+ if 'HTTP Error 404' in str(e):
+ return self.get_bug_old(bugtype, bugid)
+ raise BugtrackerError(self.errget % (self.description, e, url))
+ try:
+ return (bugid, bug['project']['name'], bug['summary'], bug['severity']['name'], bug['resolution']['name'], '',
+ "%s/view.php?id=%s" % (self.url, bugid), [], [])
+ except Exception as e:
+ raise BugtrackerError(self.errparse % (self.description, e, url))
+
+ def get_bug_old(self, bugtype, bugid): # Deprecated
+ url = "%s/view.php?id=%s" % (self.url, bugid)
+ try:
+ raw = self.soap_client.mc_issue_get(username='', password='', issue_id=bugid)
+ except Exception as e:
+ if 'Issue #%s not found' % bugid in str(e):
+ raise BugNotFoundError
+ # Often SOAP is not enabled
+ if '.' in self.name:
+ supylog.exception(self.errget % (self.description, e, url))
+ return
+ raise BugtrackerError(self.errget % (self.description, e, url))
+ if not hasattr(raw, 'id'):
+ raise BugNotFoundError
+ try:
+ title = str(raw.summary)
+ if checkBase64(title):
+ title = decodeBase64(title)
+ return (bugid, str(raw.project.name), title, str(raw.severity.name), str(raw.resolution.name), '', url, [], [])
+ except Exception as e:
+ raise BugtrackerError(self.errparse % (self.description, e, url))
+
+# For Trac-based trackers we get the tab-separated-values format.
+# The other option is a comma-separated-values format, but if the description
+# has commas, things get tricky.
+# This should be more robust than the screen scraping done previously.
+class Trac(IBugtracker):
+ def get_tracker(self, url):
+ try:
+ match = re.match(r'(?P[^\s/]+)\S*/ticket', url)
+ desc = match.group('desc')
+ name = desc.lower()
+ url = 'https://%s' % match.group(0)
+ return Trac(name, url, desc, 'trac')
+ except:
+ pass
+
+ def get_bug(self, bugtype, bugid): # This is still a little rough, but it works :)
+ url = "%s/%s?format=tab" % (self.url, bugid)
+ try:
+ raw = utils.web.getUrl(url).decode('utf-8')
+ except Exception as e:
+ # Due to unreliable matching
+ if '.' in self.name:
+ supylog.exception(self.errget % (self.description, e, url))
+ return
+ if 'HTTP Error 500' in str(e):
+ raise BugNotFoundError
+ raise BugtrackerError(self.errget % (self.description, e, url))
+ try:
+ raw = raw.replace('\r\n', '\n')
+ (headers, rest) = raw.split('\n', 1)
+ headers = headers.strip().split('\t')
+ rest = rest.strip().split('\t')
+
+ title = rest[headers.index("summary")]
+ status = rest[headers.index("status")]
+ package = rest[headers.index("component")]
+ severity = assignee = ""
+ if "severity" in headers:
+ severity = rest[headers.index("severity")]
+ elif "priority" in headers:
+ severity = rest[headers.index("priority")]
+ if "owner" in headers:
+ assignee = rest[headers.index("owner")]
+ return (bugid, package, title, severity, status, assignee, "%s/%s" % (self.url, bugid), [], [])
+ except Exception as e:
+ # Due to unreliable matching
+ if '.' in self.name:
+ supylog.exception(self.errparse % (self.description, e, url))
+ return
+ raise BugtrackerError(self.errparse % (self.description, e, url))
+
+# Introspection is quite cool
+defined_bugtrackers = {}
+v = vars()
+for k in list(v.keys()):
+ if type(v[k]) == type(IBugtracker) and issubclass(v[k], IBugtracker) and not (v[k] == IBugtracker):
+ defined_bugtrackers[k.lower()] = v[k]
diff --git a/ubottu/bugtracker/urls.py b/ubottu/bugtracker/urls.py
new file mode 100644
index 0000000..7ecbfb5
--- /dev/null
+++ b/ubottu/bugtracker/urls.py
@@ -0,0 +1,8 @@
+from django.urls import path
+from . import views
+
+urlpatterns = [
+ #path('', views.list_facts, name='facts-list'),
+ path('api/bugtracker/launchpad//', views.get_launchpad_bug, name='get_launchpad_bug'),
+ path('api/bugtracker/github////', views.get_github_bug, name='get_github_bug'),
+]
diff --git a/ubottu/bugtracker/views.py b/ubottu/bugtracker/views.py
new file mode 100644
index 0000000..aeb4afe
--- /dev/null
+++ b/ubottu/bugtracker/views.py
@@ -0,0 +1,76 @@
+from django.http import HttpResponse, Http404
+from rest_framework.views import APIView
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from django.shortcuts import render
+from django.utils.decorators import method_decorator
+from django.views.decorators.cache import cache_page
+from geopy.geocoders import Nominatim
+from timezonefinder import TimezoneFinder
+from datetime import datetime
+from rest_framework import status
+#from launchpadlib.launchpad import Launchpad
+from .launchpad_singleton import get_launchpad
+import pytz
+import json
+import requests
+
+@api_view(['GET'])
+@cache_page(60 * 15) # Cache for 15 minutes
+def get_launchpad_bug(request, bug_id):
+ #Bug 2059145 in filament (Ubuntu) "please remove filament from noble" [Undecided, In Progress] https://launchpad.net/bugs/2059145
+ package = ''
+ release_name = ''
+ target_link = ''
+ target_name = ''
+ series = ''
+ series_display_name = ''
+ cachedir = "~/.launchpadlib/cache/"
+ try:
+ launchpad = get_launchpad()
+ bug = launchpad.bugs[int(bug_id)]
+ for task in bug.bug_tasks:
+ if task.target.name:
+ package=task.target.name
+ if task.target_link:
+ target_link = task.target_link
+
+ return Response({'id': bug.id, 'title': bug.title, 'target_link': target_link, 'status': task.status, \
+ 'importance': task.importance, 'self_link': bug.self_link, 'link': bug.web_link, 'target_link': target_link, 'package': package})
+
+ except KeyError as e:
+ # Handle the case where the bug is not found
+ print(f"Bug with ID {bug_id} was not found. Error: {e}")
+ return Response({'error': 'Bug not found'}, status=status.HTTP_404_NOT_FOUND)
+ except Exception as e:
+ # Handle other potential exceptions
+ print(f"An error occurred: {e}")
+ print(f"Error processing request for launchpad bug {bug_id}: {str(e)}")
+ return Response({'error': 'An error occurred processing your request'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+@api_view(['GET'])
+@cache_page(60 * 15) # Cache for 15 minutes
+def get_github_bug(request, owner, repo, bug_id):
+ #Issue 81 in NVIDIA/nvidia-container-toolkit "Can't install due to no public key being available for Ubuntu" [Open]
+ try:
+ url = f"https://api.github.com/repos/{owner}/{repo}/issues/{bug_id}"
+ response = requests.get(url)
+ if response.status_code == 404:
+ # If the GitHub API returns a 404 status code, return an appropriate response
+ return Response({'error': 'GitHub bug not found'}, status=status.HTTP_404_NOT_FOUND)
+ bug = response.json()
+ issue_id = bug['number'] # GitHub API uses 'number' as the issue ID in the repository
+ owner_repo = bug['repository_url'].split('/')[-2:] # Extracts owner and repo from the URL
+ description = bug['title']
+ state = bug['state']
+ return Response({'id':issue_id, 'description': description, 'state': state, 'project': '/'.join(owner_repo)})
+ except KeyError as e:
+ # Handle the case where the bug is not found
+ print(f"Bug with ID {bug_id} was not found. Error: {e}")
+ return Response({'error': 'Bug not found'}, status=status.HTTP_404_NOT_FOUND)
+ except Exception as e:
+ # Handle other potential exceptions
+ print(f"An error occurred: {e}")
+ print(f"Error processing request for launchpad bug {bug_id}: {str(e)}")
+ return Response({'error': 'An error occurred processing your request'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
\ No newline at end of file
|
---|