Commits

David Lawrence committed 240988b

Fix for bitbucket API changes:
-last_updated and created_on date format changes
-responsible cannot be None

New feature:
-update() method to alter existing issue using PUT

Comments (0)

Files changed (1)

 import json
 from urllib import urlencode
 import datetime
+import re
 
 class Repository(object):
     name = None
                 if i not in ['last_updated', 'created_on']:
                     setattr(self, i, data[i])
                 else:
-                    setattr(self, i, datetime.datetime.strptime(data[i], "%Y-%m-%d %H:%M:%S"))
+                    date = Repository.get_date(data, i)
+                    setattr(self, i, date)
 
     def __repr__(self):
         return "<Repository: %s>" % self.name
 
+    @staticmethod
+    def get_date(data, i):
+        def convert_date(d):
+            return datetime.datetime.strptime(d, "%Y-%m-%d %H:%M:%S")
+
+        def fix_date(d):
+            ''' Remove 'T' in the middle and milliseconds from end, as Bitbucket changed dates on us:
+                https://bitbucket.org/site/master/issue/8244/api-repositories-user-repo-date-fields '''
+            d = re.sub(r'(\d)T(\d)', r'\1 \2', d)
+            return re.sub(r'\.(\d{3})$', r'', d)
+        
+        try:
+            date = convert_date(data[i])
+        except Exception:
+            try:
+                # Failed - try to fix
+                d = fix_date(data[i])
+                date = convert_date(d)
+            except Exception:
+                # Just insert raw string
+                date = i
+        return date
+
     def get_issues(self):
         if self.has_issues:
             return self.api.get_issues(self.owner, self.slug)
     milestone = None
     version = None
     responsible = None
+    issue_id = None
     priority = "major"
     status = "new"
     kind = "bug"
     def __init__(self, api, username, repository, data=None):
         self.api = api
         self.responsible = username
-        self.url = 'repositories/%s/%s/issues/' % (username, repository)
+        self.url = 'repositories/%s/%s/issues' % (username, repository)
         if data:
-            self.url = 'repositories/%s/%s/issues/%s/' % (username, repository, data['local_id'])
+            self.url = 'repositories/%s/%s/issues/%s' % (username, repository, data['local_id'])
             self.title = data['title']
             self.content = data['content']
             self.component = data['metadata']['component']
             self.priority = data['priority']
             self.status = data['status']
             self.kind = data['metadata']['kind']
+            self.issue_id = data['local_id']
 
     def __repr__(self):
         return "<Issue: %s>" % self.title
 
     def as_dict(self):
         data = {'title':self.title, 'content':self.content, 'priority':self.priority, 'status':self.status, 'kind':self.kind}
-        data.update({'responsible':self.responsible})
+        # At the moment bitbucket doesn't like sending None as responsible
+        # The downside is we can't now set responsible to None
+        if self.responsible:
+            data.update({'responsible':self.responsible})
         if self.component:
             data.update({'component':self.component})
         if self.milestone:
     def save(self):
         self.json = self.api.post(self.url, self.as_dict())
         return self.json
+    
+    def update(self):
+        data = self.as_dict()
+        data.update({'issue_id' : self.issue_id})
+        self.json = self.api.put(self.url, data)
+        return self.json
+
+    def add_comment(self, content):
+        if not self.issue_id:
+            raise ValueError("Needs to be an existing issue!")
+        
+        data = {"content" : content}
+        self.api.post(self.url + "comments", data)
+
 
 class API(object):
     api_url = 'https://api.bitbucket.org/1.0/'
             opener = urllib2.build_opener(cookie_handler)
         return opener
 
-    def _raw_request(self, url, data=None):
+    def _raw_request(self, url, **kwargs):
+        data = kwargs.get('data')
+        request_class = kwargs.get('request', urllib2.Request)
+
         query_url = self.api_url + url
         if data:
-          data = urlencode(data)
+            data = urlencode(data)
         try:
-            req = urllib2.Request(query_url, data, {"Authorization": self._auth })
+            req = request_class(query_url, data, {"Authorization": self._auth })
             handler = self._opener.open(req)
         except urllib2.HTTPError, e:
             print e.headers
             raise e
         return handler
 
-    def _request(self, url, data=None):
-        return json.load(self._raw_request(url, data))
+    def _request(self, url, **kwargs):
+        return json.load(self._raw_request(url, **kwargs))
 
     def post(self, url, data):
-        return self._request(url, data)
+        return self._request(url, data=data)
+
+    def put(self, url, data):
+
+        class PutRequest(urllib2.Request):
+            def get_method(self):
+                return "PUT"
+
+        return self._request(url, data=data, request=PutRequest)
+
 
     def get(self, url):
-        return self._request(url, None)
+        return self._request(url)
 
     def get_raw(self, url):
         return self._raw_request(url, None)