Browse files

Removed the old github lib and switched to the v3 API for version che…

…cking.
  • Loading branch information...
1 parent 95f85ed commit acaf5cac89df5fe12d400faa6114e6bbcfe84d1e @midgetspy committed Apr 6, 2012
View
25 lib/pygithub/__init__.py
@@ -1,25 +0,0 @@
-# Copyright (c) 2005-2008 Dustin Sallings <dustin@spy.net>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-#
-# <http://www.opensource.org/licenses/mit-license.php>
-"""
-github module.
-"""
-__all__ = ['github','ghsearch','githubsync']
View
50 lib/pygithub/ghsearch.py
@@ -1,50 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (c) 2005-2008 Dustin Sallings <dustin@spy.net>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-#
-# <http://www.opensource.org/licenses/mit-license.php>
-"""
-Search script.
-"""
-
-import sys
-
-import github
-
-def usage():
- """display the usage and exit"""
- print "Usage: %s keyword [keyword...]" % (sys.argv[0])
- sys.exit(1)
-
-def mk_url(repo):
- return "http://github.com/%s/%s" % (repo.username, repo.name)
-
-if __name__ == '__main__':
- g = github.GitHub()
- if len(sys.argv) < 2:
- usage()
- res = g.repos.search(' '.join(sys.argv[1:]))
-
- for repo in res:
- try:
- print "Found %s at %s" % (repo.name, mk_url(repo))
- except AttributeError:
- print "Bug: Couldn't format %s" % repo.__dict__
View
520 lib/pygithub/github.py
@@ -1,520 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (c) 2005-2008 Dustin Sallings <dustin@spy.net>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-#
-# <http://www.opensource.org/licenses/mit-license.php>
-"""
-Interface to github's API (v2).
-
-Basic usage:
-
-g = GitHub()
-
-for r in g.user.search('dustin'):
- print r.name
-
-See the GitHub docs or README.markdown for more usage.
-
-Copyright (c) 2007 Dustin Sallings <dustin@spy.net>
-"""
-
-# GAE friendly URL detection (theoretically)
-try:
- import urllib2
- default_fetcher = urllib2.urlopen
-except LoadError:
- pass
-
-import urllib
-import xml
-import xml.dom.minidom
-
-def _string_parser(x):
- """Extract the data from the first child of the input."""
- return x.firstChild.data
-
-_types = {
- 'string': _string_parser,
- 'integer': lambda x: int(_string_parser(x)),
- 'float': lambda x: float(_string_parser(x)),
- 'datetime': _string_parser,
- 'boolean': lambda x: _string_parser(x) == 'true'
-}
-
-def _parse(el):
- """Generic response parser."""
-
- type = 'string'
- if el.attributes and 'type' in el.attributes.keys():
- type = el.attributes['type'].value
- elif el.localName in _types:
- type = el.localName
- elif len(el.childNodes) > 1:
- # This is a container, find the child type
- type = None
- ch = el.firstChild
- while ch and not type:
- if ch.localName == 'type':
- type = ch.firstChild.data
- ch = ch.nextSibling
-
- if not type:
- raise Exception("Can't parse %s, known: %s"
- % (el.toxml(), repr(_types.keys())))
-
- return _types[type](el)
-
-def parses(t):
- """Parser for a specific type in the github response."""
- def f(orig):
- orig.parses = t
- return orig
- return f
-
-def with_temporary_mappings(m):
- """Allow temporary localized altering of type mappings."""
- def f(orig):
- def every(self, *args):
- global _types
- o = _types.copy()
- for k,v in m.items():
- if v:
- _types[k] = v
- else:
- del _types[k]
- try:
- return orig(self, *args)
- finally:
- _types = o
- return every
- return f
-
-@parses('array')
-def _parseArray(el):
- rv = []
- ch = el.firstChild
- while ch:
- if ch.nodeType != xml.dom.Node.TEXT_NODE and ch.firstChild:
- rv.append(_parse(ch))
- ch=ch.nextSibling
- return rv
-
-class BaseResponse(object):
- """Base class for XML Response Handling."""
-
- def __init__(self, el):
- ch = el.firstChild
- while ch:
- if ch.nodeType != xml.dom.Node.TEXT_NODE and ch.firstChild:
- ln = ch.localName.replace('-', '_')
- self.__dict__[ln] = _parse(ch)
- ch=ch.nextSibling
-
- def __repr__(self):
- return "<<%s>>" % str(self.__class__)
-
-class User(BaseResponse):
- """A github user."""
-
- parses = 'user'
-
- def __repr__(self):
- return "<<User %s>>" % self.name
-
-class Plan(BaseResponse):
- """A github plan."""
-
- parses = 'plan'
-
- def __repr__(self):
- return "<<Plan %s>>" % self.name
-
-class Repository(BaseResponse):
- """A repository."""
-
- parses = 'repository'
-
- @property
- def owner_name(self):
- if hasattr(self, 'owner'):
- return self.owner
- else:
- return self.username
-
- def __repr__(self):
- return "<<Repository %s/%s>>" % (self.owner_name, self.name)
-
-class PublicKey(BaseResponse):
- """A public key."""
-
- parses = 'public-key'
- title = 'untitled'
-
- def __repr__(self):
- return "<<Public key %s>>" % self.title
-
-class Commit(BaseResponse):
- """A commit."""
-
- parses = 'commit'
-
- def __repr__(self):
- return "<<Commit: %s>>" % self.id
-
-class Parent(Commit):
- """A commit parent."""
-
- parses = 'parent'
-
-class Author(User):
- """A commit author."""
-
- parses = 'author'
-
-class Committer(User):
- """A commit committer."""
-
- parses = 'committer'
-
-class Issue(BaseResponse):
- """An issue within the issue tracker."""
-
- parses = 'issue'
-
- def __repr__(self):
- return "<<Issue #%d>>" % self.number
-
-class Label(BaseResponse):
- """A Label within the issue tracker."""
- parses = 'label'
-
- def __repr__(self):
- return "<<Label $%d>>" % self.number
-
-class Tree(BaseResponse):
- """A Tree object."""
-
- # Parsing is scoped to objects...
- def __repr__(self):
- return "<<Tree: %s>>" % self.name
-
-class Blob(BaseResponse):
- """A Blob object."""
-
- # Parsing is scoped to objects...
- def __repr__(self):
- return "<<Blob: %s>>" % self.name
-
-class Modification(BaseResponse):
- """A modification object."""
-
- # Parsing is scoped to usage
- def __repr__(self):
- return "<<Modification of %s>>" % self.filename
-
-class Network(BaseResponse):
- """A network entry."""
-
- parses = 'network'
-
- def __repr__(self):
- return "<<Network of %s/%s>>" % (self.owner, self.name)
-
-# Load the known types.
-for __t in (t for t in globals().values() if hasattr(t, 'parses')):
- _types[__t.parses] = __t
-
-class BaseEndpoint(object):
-
- BASE_URL = 'https://github.com/api/v2/xml/'
-
- def __init__(self, user, token, fetcher):
- self.user = user
- self.token = token
- self.fetcher = fetcher
-
- def _raw_fetch(self, path):
- p = self.BASE_URL + path
- args = ''
- if self.user and self.token:
- params = '&'.join(['login=' + urllib.quote(self.user),
- 'token=' + urllib.quote(self.token)])
- if '?' in path:
- p += params
- else:
- p += '?' + params
- return self.fetcher(p).read()
-
- def _fetch(self, path):
- return xml.dom.minidom.parseString(self._raw_fetch(path))
-
- def _post(self, path, **kwargs):
- p = {'login': self.user, 'token': self.token}
- p.update(kwargs)
- return self.fetcher(self.BASE_URL + path, urllib.urlencode(p)).read()
-
- def _parsed(self, path):
- doc = self._fetch(path)
- return _parse(doc.documentElement)
-
- def _posted(self,path,**kwargs):
- stuff = self._post(path,**kwargs)
- doc = xml.dom.minidom.parseString(stuff)
- return _parse(doc.documentElement)
-
-class UserEndpoint(BaseEndpoint):
-
- def search(self, query):
- """Search for a user."""
- return self._parsed('user/search/' + query)
-
- def show(self, username):
- """Get the info for a user."""
- return self._parsed('user/show/' + username)
-
- def keys(self):
- """Get the public keys for a user."""
- return self._parsed('user/keys')
-
- def removeKey(self, keyId):
- """Remove the key with the given ID (as retrieved from keys)"""
- self._post('user/key/remove', id=keyId)
-
- def addKey(self, name, key):
- """Add an ssh key."""
- self._post('user/key/add', name=name, key=key)
-
-class RepositoryEndpoint(BaseEndpoint):
-
- def forUser(self, username):
- """Get the repositories for the given user."""
- return self._parsed('repos/show/' + username)
-
- def branches(self, user, repo):
- """List the branches for a repo."""
- doc = self._fetch("repos/show/" + user + "/" + repo + "/branches")
- rv = {}
- for c in doc.documentElement.childNodes:
- if c.nodeType != xml.dom.Node.TEXT_NODE:
- rv[c.localName] = str(c.firstChild.data)
- return rv
-
- def search(self, term):
- """Search for repositories."""
- return self._parsed('repos/search/' + urllib.quote_plus(term))
-
- def show(self, user, repo):
- """Lookup an individual repository."""
- return self._parsed('/'.join(['repos', 'show', user, repo]))
-
- def watch(self, user, repo):
- """Watch a repository."""
- self._post('repos/watch/' + user + '/' + repo)
-
- def unwatch(self, user, repo):
- """Stop watching a repository."""
- self._post('repos/unwatch/' + user + '/' + repo)
-
- def watched(self, user):
- """Get watched repositories of a user."""
- return self._parsed('repos/watched/' + user)
-
- def network(self, user, repo):
- """Get the network for a given repo."""
- return self._parsed('repos/show/' + user + '/' + repo + '/network')
-
- def setVisible(self, repo, public=True):
- """Set the visibility of the given repository (owned by the current user)."""
- if public:
- path = 'repos/set/public/' + repo
- else:
- path = 'repos/set/private/' + repo
- self._post(path)
-
- def create(self, name, description='', homepage='', public=1):
- """Create a new repository."""
- self._post('repos/create', name=name, description=description,
- homepage=homepage, public=str(public))
-
- def delete(self, repo):
- """Delete a repository."""
- self._post('repos/delete/' + repo)
-
- def fork(self, user, repo):
- """Fork a user's repo."""
- self._post('repos/fork/' + user + '/' + repo)
-
- def collaborators(self, user, repo):
- """Find all of the collaborators of one of your repositories."""
- return self._parsed('repos/show/%s/%s/collaborators' % (user, repo))
-
- def addCollaborator(self, repo, username):
- """Add a collaborator to one of your repositories."""
- self._post('repos/collaborators/' + repo + '/add/' + username)
-
- def removeCollaborator(self, repo, username):
- """Remove a collaborator from one of your repositories."""
- self._post('repos/collaborators/' + repo + '/remove/' + username)
-
- def collaborators_all(self):
- """Find all of the collaborators of every of your repositories.
-
- Returns a dictionary with reponame as key and a list of collaborators as value."""
- ret = {}
- for reponame in (rp.name for rp in self.forUser(self.user)):
- ret[reponame] = self.collaborators(self.user, reponame)
- return ret
-
- def addCollaborator_all(self, username):
- """Add a collaborator to all of your repositories."""
- for reponame in (rp.name for rp in self.forUser(self.user)):
- self.addCollaborator(reponame, username)
-
- def removeCollaborator_all(self, username):
- """Remove a collaborator from all of your repositories."""
- for reponame in (rp.name for rp in self.forUser(self.user)):
- self.removeCollaborator(reponame, username)
-
- def deployKeys(self, repo):
- """List the deploy keys for the given repository.
-
- The repository must be owned by the current user."""
- return self._parsed('repos/keys/' + repo)
-
- def addDeployKey(self, repo, title, key):
- """Add a deploy key to a repository."""
- self._post('repos/key/' + repo + '/add', title=title, key=key)
-
- def removeDeployKey(self, repo, keyId):
- """Remove a deploy key."""
- self._post('repos/key/' + repo + '/remove', id=keyId)
-
-class CommitEndpoint(BaseEndpoint):
-
- def forBranch(self, user, repo, branch='master'):
- """Get the commits for the given branch."""
- return self._parsed('/'.join(['commits', 'list', user, repo, branch]))
-
- def forFile(self, user, repo, path, branch='master'):
- """Get the commits for the given file within the given branch."""
- return self._parsed('/'.join(['commits', 'list', user, repo, branch, path]))
-
- @with_temporary_mappings({'removed': _parseArray,
- 'added': _parseArray,
- 'modified': Modification,
- 'diff': _string_parser,
- 'filename': _string_parser})
- def show(self, user, repo, sha):
- """Get an individual commit."""
- c = self._parsed('/'.join(['commits', 'show', user, repo, sha]))
- # Some fixup due to weird XML structure
- if hasattr(c, 'removed'):
- c.removed = [i[0] for i in c.removed]
- if hasattr(c, 'added'):
- c.added = [i[0] for i in c.added]
- return c
-
-class IssuesEndpoint(BaseEndpoint):
-
- @with_temporary_mappings({'user': None})
- def list(self, user, repo, state='open'):
- """Get the list of issues for the given repo in the given state."""
- return self._parsed('/'.join(['issues', 'list', user, repo, state]))
-
- @with_temporary_mappings({'user': None})
- def show(self, user, repo, issue_id):
- """Show an individual issue."""
- return self._parsed('/'.join(['issues', 'show', user, repo, str(issue_id)]))
-
- def add_label(self, user, repo, issue_id, label):
- """Add a label to an issue."""
- self._post('issues/label/add/' + user + '/'
- + repo + '/' + label + '/' + str(issue_id))
-
- def remove_label(self, user, repo, issue_id, label):
- """Remove a label from an issue."""
- self._post('issues/label/remove/' + user + '/'
- + repo + '/' + label + '/' + str(issue_id))
-
- def close(self, user, repo, issue_id):
- """Close an issue."""
- self._post('/'.join(['issues', 'close', user, repo, str(issue_id)]))
-
- def reopen(self, user, repo, issue_id):
- """Reopen an issue."""
- self._post('/'.join(['issues', 'reopen', user, repo, str(issue_id)]))
-
- def new(self, user, repo, title, body=''):
- """Create a new issue."""
- return self._posted('/'.join(['issues', 'open', user, repo]),
- title=title, body=body)
-
- def edit(self, user, repo, issue_id, title, body):
- """Create a new issue."""
- self._post('/'.join(['issues', 'edit', user, repo, str(issue_id)]),
- title=title, body=body)
-
-class ObjectsEndpoint(BaseEndpoint):
-
- @with_temporary_mappings({'tree': Tree, 'type': _string_parser})
- def tree(self, user, repo, t):
- """Get the given tree from the given repo."""
- tl = self._parsed('/'.join(['tree', 'show', user, repo, t]))
- return dict([(t.name, t) for t in tl])
-
- @with_temporary_mappings({'blob': Blob})
- def blob(self, user, repo, t, fn):
- return self._parsed('/'.join(['blob', 'show', user, repo, t, fn]))
-
- def raw_blob(self, user, repo, sha):
- """Get a raw blob from a repo."""
- path = 'blob/show/%s/%s/%s' % (user, repo, sha)
- return self._raw_fetch(path)
-
-class GitHub(object):
- """Interface to github."""
-
- def __init__(self, user=None, token=None, fetcher=default_fetcher):
- self.user = user
- self.token = token
- self.fetcher = fetcher
-
- @property
- def users(self):
- """Get access to the user API."""
- return UserEndpoint(self.user, self.token, self.fetcher)
-
- @property
- def repos(self):
- """Get access to the user API."""
- return RepositoryEndpoint(self.user, self.token, self.fetcher)
-
- @property
- def commits(self):
- return CommitEndpoint(self.user, self.token, self.fetcher)
-
- @property
- def issues(self):
- return IssuesEndpoint(self.user, self.token, self.fetcher)
-
- @property
- def objects(self):
- return ObjectsEndpoint(self.user, self.token, self.fetcher)
View
88 lib/pygithub/githubsync.py
@@ -1,88 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (c) 2005-2008 Dustin Sallings <dustin@spy.net>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-#
-# <http://www.opensource.org/licenses/mit-license.php>
-"""
-Grab all of a user's projects from github.
-"""
-
-import os
-import sys
-import subprocess
-
-import github
-
-def check_for_old_format(path, url):
- p = subprocess.Popen(['git', '--git-dir=' + path, 'config',
- 'remote.origin.fetch'], stdout = subprocess.PIPE)
- stdout, stderr = p.communicate()
- if stdout.strip() != '+refs/*:refs/*':
- print "Not properly configured for mirroring, repairing."
- subprocess.call(['git', '--git-dir=' + path, 'remote', 'rm', 'origin'])
- add_mirror(path, url)
-
-def add_mirror(path, url):
- subprocess.call(['git', '--git-dir=' + path, 'remote', 'add', '--mirror',
- 'origin', url])
-
-def sync(path, url, repo_name):
- p = os.path.join(path, repo_name) + ".git"
- print "Syncing %s -> %s" % (repo_name, p)
- if not os.path.exists(p):
- subprocess.call(['git', 'clone', '--bare', url, p])
- add_mirror(p, url)
- check_for_old_format(p, url)
- subprocess.call(['git', '--git-dir=' + p, 'fetch', '-f'])
-
-def sync_user_repo(path, repo):
- sync(path, "git://github.com/%s/%s" % (repo.owner, repo.name), repo.name)
-
-def usage():
- sys.stderr.write("Usage: %s username destination_url\n" % sys.argv[0])
- sys.stderr.write(
- """Ensures you've got the latest stuff for the given user.
-
-Also, if the file $HOME/.github-private exists, it will be read for
-additional projects.
-
-Each line must be a simple project name (e.g. py-github), a tab character,
-and a git URL.
-""")
-
-if __name__ == '__main__':
- try:
- user, path = sys.argv[1:]
- except ValueError:
- usage()
- exit(1)
-
- privfile = os.path.join(os.getenv("HOME"), ".github-private")
- if os.path.exists(privfile):
- f = open(privfile)
- for line in f:
- name, url = line.strip().split("\t")
- sync(path, url, name)
-
- gh = github.GitHub()
-
- for repo in gh.repos.forUser(user):
- sync_user_repo(path, repo)
View
493 lib/pygithub/githubtest.py
@@ -1,493 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (c) 2005-2008 Dustin Sallings <dustin@spy.net>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-#
-# <http://www.opensource.org/licenses/mit-license.php>
-"""
-Defines and runs unittests.
-"""
-
-import urllib
-import hashlib
-import unittest
-
-import github
-
-class BaseCase(unittest.TestCase):
-
- def _gh(self, expUrl, filename):
-
- def opener(url):
- self.assertEquals(expUrl, url)
- return open(filename)
- return github.GitHub(fetcher=opener)
-
- def _agh(self, expUrl, u, t, filename):
-
- def opener(url):
- self.assertEquals(expUrl, url + '?login=' + u + '&token=' + t)
- return open(filename)
- return github.GitHub(fetcher=opener)
-
- def _ghp(self, expUrl, u, t, **kv):
-
- def opener(url, data):
- h = {'login': u, 'token': t}
- h.update(kv)
- self.assertEquals(github.BaseEndpoint.BASE_URL + expUrl, url)
- self.assertEquals(sorted(data.split('&')),
- sorted(urllib.urlencode(h).split('&')))
- return github.GitHub(u, t, fetcher=opener)
-
-class UserTest(BaseCase):
-
- def __loadUserSearch(self):
- return self._gh('http://github.com/api/v2/xml/user/search/dustin',
- 'data/user.search.xml').users.search('dustin')
-
- def __loadUser(self, which, u=None, p=None):
- if u:
- return self._agh('http://github.com/api/v2/xml/user/show/dustin'
- + '?login=' + u + '&token=' + p,
- u, p, 'data/' + which).users.show('dustin')
-
- else:
- return self._gh('http://github.com/api/v2/xml/user/show/dustin',
- 'data/' + which).users.show('dustin')
-
- def testUserSearch(self):
- """Test the base properties of the user object."""
- u = self.__loadUserSearch()[0]
- self.assertEquals("Dustin Sallings", u.fullname)
- self.assertEquals("dustin", u.name)
- self.assertEquals("dustin@spy.net", u.email)
- self.assertEquals("Santa Clara, CA", u.location)
- self.assertEquals("Ruby", u.language)
- self.assertEquals(35, u.actions)
- self.assertEquals(77, u.repos)
- self.assertEquals(78, u.followers)
- self.assertEquals('user-1779', u.id)
- self.assertAlmostEquals(12.231684, u.score)
- self.assertEquals('user', u.type)
- self.assertEquals('2008-02-29T17:59:09Z', u.created)
- self.assertEquals('2009-03-19T09:15:24.663Z', u.pushed)
- self.assertEquals("<<User dustin>>", repr(u))
-
- def testUserPublic(self):
- """Test the user show API with no authentication."""
- u = self.__loadUser('user.public.xml')
- self.assertEquals("Dustin Sallings", u.name)
- # self.assertEquals(None, u.company)
- self.assertEquals(10, u.following_count)
- self.assertEquals(21, u.public_gist_count)
- self.assertEquals(81, u.public_repo_count)
- self.assertEquals('http://bleu.west.spy.net/~dustin/', u.blog)
- self.assertEquals(1779, u.id)
- self.assertEquals(82, u.followers_count)
- self.assertEquals('dustin', u.login)
- self.assertEquals('Santa Clara, CA', u.location)
- self.assertEquals('dustin@spy.net', u.email)
- self.assertEquals('2008-02-29T09:59:09-08:00', u.created_at)
-
- def testUserPrivate(self):
- """Test the user show API with extra info from auth."""
- u = self.__loadUser('user.private.xml', 'dustin', 'blahblah')
- self.assertEquals("Dustin Sallings", u.name)
- # self.assertEquals(None, u.company)
- self.assertEquals(10, u.following_count)
- self.assertEquals(21, u.public_gist_count)
- self.assertEquals(81, u.public_repo_count)
- self.assertEquals('http://bleu.west.spy.net/~dustin/', u.blog)
- self.assertEquals(1779, u.id)
- self.assertEquals(82, u.followers_count)
- self.assertEquals('dustin', u.login)
- self.assertEquals('Santa Clara, CA', u.location)
- self.assertEquals('dustin@spy.net', u.email)
- self.assertEquals('2008-02-29T09:59:09-08:00', u.created_at)
-
- # Begin private data
-
- self.assertEquals("micro", u.plan.name)
- self.assertEquals(1, u.plan.collaborators)
- self.assertEquals(614400, u.plan.space)
- self.assertEquals(5, u.plan.private_repos)
- self.assertEquals(155191, u.disk_usage)
- self.assertEquals(6, u.collaborators)
- self.assertEquals(4, u.owned_private_repo_count)
- self.assertEquals(5, u.total_private_repo_count)
- self.assertEquals(0, u.private_gist_count)
-
- def testKeysList(self):
- """Test key listing."""
- kl = self._agh('http://github.com/api/v2/xml/user/keys?login=dustin&token=blahblah',
- 'dustin', 'blahblah', 'data/keys.xml').users.keys()
- self.assertEquals(7, len(kl))
- k = kl[0]
-
- self.assertEquals('some key', k.title)
- self.assertEquals(2181, k.id)
- self.assertEquals(549, k.key.find('cdEXwCSjAIFp8iRqh3GOkxGyFSc25qv/MuOBg=='))
-
- def testRemoveKey(self):
- """Remove a key."""
- self._ghp('user/key/remove',
- 'dustin', 'p', id=828).users.removeKey(828)
-
- def testAddKey(self):
- """Add a key."""
- self._ghp('user/key/add',
- 'dustin', 'p', name='my key', key='some key').users.addKey(
- 'my key', 'some key')
-
-class RepoTest(BaseCase):
-
- def __loadUserRepos(self):
- return self._gh('http://github.com/api/v2/xml/repos/show/verbal',
- 'data/repos.xml').repos.forUser('verbal')
-
- def testUserRepoList(self):
- """Get a list of repos for a user."""
- rs = self.__loadUserRepos()
- self.assertEquals(10, len(rs))
- r = rs[0]
- self.assertEquals('A beanstalk client for the twisted network framework.',
- r.description)
- self.assertEquals(2, r.watchers)
- self.assertEquals(0, r.forks)
- self.assertEquals('beanstalk-client-twisted', r.name)
- self.assertEquals(False, r.private)
- self.assertEquals('http://github.com/verbal/beanstalk-client-twisted',
- r.url)
- self.assertEquals(True, r.fork)
- self.assertEquals('verbal', r.owner)
- # XXX: Can't parse empty elements. :(
- # self.assertEquals('', r.homepage)
-
- def testRepoSearch(self):
- """Test searching a repository."""
- rl = self._gh('http://github.com/api/v2/xml/repos/search/ruby+testing',
- 'data/repos.search.xml').repos.search('ruby testing')
- self.assertEquals(12, len(rl))
-
- r = rl[0]
- self.assertEquals('synthesis', r.name)
- self.assertAlmostEquals(0.3234576, r.score, 4)
- self.assertEquals(4656, r.actions)
- self.assertEquals(2048, r.size)
- self.assertEquals('Ruby', r.language)
- self.assertEquals(26, r.followers)
- self.assertEquals('gmalamid', r.username)
- self.assertEquals('repo', r.type)
- self.assertEquals('repo-3555', r.id)
- self.assertEquals(1, r.forks)
- self.assertFalse(r.fork)
- self.assertEquals('Ruby test code analysis tool employing a '
- '"Synthesized Testing" strategy, aimed to reduce '
- 'the volume of slower, coupled, complex wired tests.',
- r.description)
- self.assertEquals('2009-01-08T13:45:06Z', r.pushed)
- self.assertEquals('2008-03-11T23:38:04Z', r.created)
-
- def testBranchList(self):
- """Test branch listing for a repo."""
- bl = self._gh('http://github.com/api/v2/xml/repos/show/schacon/ruby-git/branches',
- 'data/repos.branches.xml').repos.branches('schacon', 'ruby-git')
- self.assertEquals(4, len(bl))
- self.assertEquals('ee90922f3da3f67ef19853a0759c1d09860fe3b3', bl['master'])
-
- def testGetOneRepo(self):
- """Fetch an individual repository."""
- r = self._gh('http://github.com/api/v2/xml/repos/show/schacon/grit',
- 'data/repo.xml').repos.show('schacon', 'grit')
-
- self.assertEquals('Grit is a Ruby library for extracting information from a '
- 'git repository in an object oriented manner - this fork '
- 'tries to intergrate as much pure-ruby functionality as possible',
- r.description)
- self.assertEquals(68, r.watchers)
- self.assertEquals(4, r.forks)
- self.assertEquals('grit', r.name)
- self.assertFalse(r.private)
- self.assertEquals('http://github.com/schacon/grit', r.url)
- self.assertTrue(r.fork)
- self.assertEquals('schacon', r.owner)
- self.assertEquals('http://grit.rubyforge.org/', r.homepage)
-
- def testGetRepoNetwork(self):
- """Test network fetching."""
- nl = self._gh('http://github.com/api/v2/xml/repos/show/dustin/py-github/network',
- 'data/network.xml').repos.network('dustin', 'py-github')
- self.assertEquals(5, len(nl))
-
- n = nl[0]
- self.assertEquals('Python interface for talking to the github API',
- n.description)
- self.assertEquals('py-github', n.name)
- self.assertFalse(n.private)
- self.assertEquals('http://github.com/dustin/py-github', n.url)
- self.assertEquals(30, n.watchers)
- self.assertEquals(4, n.forks)
- self.assertFalse(n.fork)
- self.assertEquals('dustin', n.owner)
- self.assertEquals('http://dustin.github.com/2008/12/29/github-sync.html',
- n.homepage)
-
- def testSetPublic(self):
- """Test setting a repo visible."""
- self._ghp('repos/set/public/py-github', 'dustin', 'p').repos.setVisible(
- 'py-github')
-
- def testSetPrivate(self):
- """Test setting a repo to private."""
- self._ghp('repos/set/private/py-github', 'dustin', 'p').repos.setVisible(
- 'py-github', False)
-
- def testCreateRepository(self):
- """Test creating a repository."""
- self._ghp('repos/create', 'dustin', 'p',
- name='testrepo',
- description='woo',
- homepage='',
- public='1').repos.create(
- 'testrepo', description='woo')
-
- def testDeleteRepo(self):
- """Test setting a repo to private."""
- self._ghp('repos/delete/mytest', 'dustin', 'p').repos.delete('mytest')
-
- def testFork(self):
- """Test forking'"""
- self._ghp('repos/fork/someuser/somerepo', 'dustin', 'p').repos.fork(
- 'someuser', 'somerepo')
-
- def testAddCollaborator(self):
- """Adding a collaborator."""
- self._ghp('repos/collaborators/memcached/add/trondn',
- 'dustin', 'p').repos.addCollaborator('memcached', 'trondn')
-
- def testRemoveCollaborator(self):
- """Removing a collaborator."""
- self._ghp('repos/collaborators/memcached/remove/trondn',
- 'dustin', 'p').repos.removeCollaborator('memcached', 'trondn')
-
- def testAddDeployKey(self):
- """Add a deploy key."""
- self._ghp('repos/key/blah/add', 'dustin', 'p',
- title='title', key='key').repos.addDeployKey('blah', 'title', 'key')
-
- def testRemoveDeployKey(self):
- """Remove a deploy key."""
- self._ghp('repos/key/blah/remove', 'dustin', 'p',
- id=5).repos.removeDeployKey('blah', 5)
-
-class CommitTest(BaseCase):
-
- def testCommitList(self):
- """Test commit list."""
- cl = self._gh('http://github.com/api/v2/xml/commits/list/mojombo/grit/master',
- 'data/commits.xml').commits.forBranch('mojombo', 'grit')
- self.assertEquals(30, len(cl))
-
- c = cl[0]
- self.assertEquals("Regenerated gemspec for version 1.1.1", c.message)
- self.assertEquals('4ac4acab7fd9c7fd4c0e0f4ff5794b0347baecde', c.id)
- self.assertEquals('94490563ebaf733cbb3de4ad659eb58178c2e574', c.tree)
- self.assertEquals('2009-03-31T09:54:51-07:00', c.committed_date)
- self.assertEquals('2009-03-31T09:54:51-07:00', c.authored_date)
- self.assertEquals('http://github.com/mojombo/grit/commit/4ac4acab7fd9c7fd4c0e0f4ff5794b0347baecde',
- c.url)
- self.assertEquals(1, len(c.parents))
- self.assertEquals('5071bf9fbfb81778c456d62e111440fdc776f76c', c.parents[0].id)
- self.assertEquals('Tom Preston-Werner', c.author.name)
- self.assertEquals('tom@mojombo.com', c.author.email)
- self.assertEquals('Tom Preston-Werner', c.committer.name)
- self.assertEquals('tom@mojombo.com', c.committer.email)
-
- def testCommitListForFile(self):
- """Test commit list for a file."""
- cl = self._gh('http://github.com/api/v2/xml/commits/list/mojombo/grit/master/grit.gemspec',
- 'data/commits.xml').commits.forFile('mojombo', 'grit', 'grit.gemspec')
- self.assertEquals(30, len(cl))
-
- c = cl[0]
- self.assertEquals("Regenerated gemspec for version 1.1.1", c.message)
- self.assertEquals('4ac4acab7fd9c7fd4c0e0f4ff5794b0347baecde', c.id)
- self.assertEquals('94490563ebaf733cbb3de4ad659eb58178c2e574', c.tree)
- self.assertEquals('2009-03-31T09:54:51-07:00', c.committed_date)
- self.assertEquals('2009-03-31T09:54:51-07:00', c.authored_date)
- self.assertEquals('http://github.com/mojombo/grit/commit/4ac4acab7fd9c7fd4c0e0f4ff5794b0347baecde',
- c.url)
- self.assertEquals(1, len(c.parents))
- self.assertEquals('5071bf9fbfb81778c456d62e111440fdc776f76c', c.parents[0].id)
- self.assertEquals('Tom Preston-Werner', c.author.name)
- self.assertEquals('tom@mojombo.com', c.author.email)
- self.assertEquals('Tom Preston-Werner', c.committer.name)
- self.assertEquals('tom@mojombo.com', c.committer.email)
-
- def testIndividualCommit(self):
- """Grab a single commit."""
- h = '4c86fa592fcc7cb685c6e9d8b6aebe8dcbac6b3e'
- c = self._gh('http://github.com/api/v2/xml/commits/show/dustin/memcached/' + h,
- 'data/commit.xml').commits.show('dustin', 'memcached', h)
- self.assertEquals(['internal_tests.c'], c.removed)
- self.assertEquals(set(['cache.c', 'cache.h', 'testapp.c']), set(c.added))
- self.assertEquals('Create a generic cache for objects of same size\n\n'
- 'The suffix pool could be thread-local and use the generic cache',
- c.message)
-
- self.assertEquals(6, len(c.modified))
- self.assertEquals('.gitignore', c.modified[0].filename)
- self.assertEquals(140, len(c.modified[0].diff))
-
- self.assertEquals(['ee0c3d5ae74d0862b4d9990e2ad13bc79f8c34df'],
- [p.id for p in c.parents])
- self.assertEquals('http://github.com/dustin/memcached/commit/' + h, c.url)
- self.assertEquals('Trond Norbye', c.author.name)
- self.assertEquals('Trond.Norbye@sun.com', c.author.email)
- self.assertEquals(h, c.id)
- self.assertEquals('2009-04-17T16:15:52-07:00', c.committed_date)
- self.assertEquals('2009-03-27T10:30:16-07:00', c.authored_date)
- self.assertEquals('94b644163f6381a9930e2d7c583fae023895b903', c.tree)
- self.assertEquals('Dustin Sallings', c.committer.name)
- self.assertEquals('dustin@spy.net', c.committer.email)
-
- def testWatchRepo(self):
- """Test watching a repo."""
- self._ghp('repos/watch/dustin/py-github', 'dustin', 'p').repos.watch(
- 'dustin', 'py-github')
-
- def testWatchRepo(self):
- """Test watching a repo."""
- self._ghp('repos/unwatch/dustin/py-github', 'dustin', 'p').repos.unwatch(
- 'dustin', 'py-github')
-
-class IssueTest(BaseCase):
-
- def testListIssues(self):
- """Test listing issues."""
- il = self._gh('http://github.com/api/v2/xml/issues/list/schacon/simplegit/open',
- 'data/issues.list.xml').issues.list('schacon', 'simplegit')
- self.assertEquals(1, len(il))
- i = il[0]
-
- self.assertEquals('schacon', i.user)
- self.assertEquals('2009-04-17T16:19:02-07:00', i.updated_at)
- self.assertEquals('something', i.body)
- self.assertEquals('new', i.title)
- self.assertEquals(2, i.number)
- self.assertEquals(0, i.votes)
- self.assertEquals(1.0, i.position)
- self.assertEquals('2009-04-17T16:18:50-07:00', i.created_at)
- self.assertEquals('open', i.state)
-
- def testShowIssue(self):
- """Show an individual issue."""
- i = self._gh('http://github.com/api/v2/xml/issues/show/dustin/py-github/1',
- 'data/issues.show.xml').issues.show('dustin', 'py-github', 1)
-
- self.assertEquals('dustin', i.user)
- self.assertEquals('2009-04-17T18:37:04-07:00', i.updated_at)
- self.assertEquals('http://develop.github.com/p/general.html', i.body)
- self.assertEquals('Add auth tokens', i.title)
- self.assertEquals(1, i.number)
- self.assertEquals(0, i.votes)
- self.assertEquals(1.0, i.position)
- self.assertEquals('2009-04-17T17:00:58-07:00', i.created_at)
- self.assertEquals('closed', i.state)
-
- def testAddLabel(self):
- """Adding a label to an issue."""
- self._ghp('issues/label/add/dustin/py-github/todo/33', 'd', 'pw').issues.add_label(
- 'dustin', 'py-github', 33, 'todo')
-
- def testRemoveLabel(self):
- """Removing a label from an issue."""
- self._ghp('issues/label/remove/dustin/py-github/todo/33',
- 'd', 'pw').issues.remove_label(
- 'dustin', 'py-github', 33, 'todo')
-
- def testCloseIssue(self):
- """Closing an issue."""
- self._ghp('issues/close/dustin/py-github/1', 'd', 'pw').issues.close(
- 'dustin', 'py-github', 1)
-
- def testReopenIssue(self):
- """Reopening an issue."""
- self._ghp('issues/reopen/dustin/py-github/1', 'd', 'pw').issues.reopen(
- 'dustin', 'py-github', 1)
-
- def testCreateIssue(self):
- """Creating an issue."""
- self._ghp('issues/open/dustin/py-github', 'd', 'pw',
- title='test title', body='').issues.new(
- 'dustin', 'py-github', title='test title')
-
- def testEditIssue(self):
- """Editing an existing issue."""
- self._ghp('issues/edit/dustin/py-github/1', 'd', 'pw',
- title='new title', body='new body').issues.edit(
- 'dustin', 'py-github', 1, 'new title', 'new body')
-
-class ObjectTest(BaseCase):
-
- def testTree(self):
- """Test tree fetching."""
- h = '1ddd3f99f0b96019042239375b3ad4d45796ffba'
- tl = self._gh('http://github.com/api/v2/xml/tree/show/dustin/py-github/' + h,
- 'data/tree.xml').objects.tree('dustin', 'py-github', h)
- self.assertEquals(8, len(tl))
- self.assertEquals('setup.py', tl['setup.py'].name)
- self.assertEquals('6e290379ec58fa00ac9d1c2a78f0819a21397445',
- tl['setup.py'].sha)
- self.assertEquals('100755', tl['setup.py'].mode)
- self.assertEquals('blob', tl['setup.py'].type)
-
- self.assertEquals('src', tl['src'].name)
- self.assertEquals('5fb9175803334c82b3fd66f1b69502691b91cf4f',
- tl['src'].sha)
- self.assertEquals('040000', tl['src'].mode)
- self.assertEquals('tree', tl['src'].type)
-
- def testBlob(self):
- """Test blob fetching."""
- h = '1ddd3f99f0b96019042239375b3ad4d45796ffba'
- blob = self._gh('http://github.com/api/v2/xml/blob/show/dustin/py-github/'
- + h + '/setup.py',
- 'data/blob.xml').objects.blob('dustin', 'py-github', h, 'setup.py')
- self.assertEquals('setup.py', blob.name)
- self.assertEquals(1842, blob.size)
- self.assertEquals('6e290379ec58fa00ac9d1c2a78f0819a21397445', blob.sha)
- self.assertEquals('100755', blob.mode)
- self.assertEquals('text/plain', blob.mime_type)
- self.assertEquals(1842, len(blob.data))
- self.assertEquals(1641, blob.data.index('Production/Stable'))
-
- def testRawBlob(self):
- """Test raw blob fetching."""
- h = '6e290379ec58fa00ac9d1c2a78f0819a21397445'
- blob = self._gh('http://github.com/api/v2/xml/blob/show/dustin/py-github/' + h,
- 'data/setup.py').objects.raw_blob('dustin', 'py-github', h)
- self.assertEquals('e2dc8aea9ae8961f4f5923f9febfdd0a',
- hashlib.md5(blob).hexdigest())
-
-
-if __name__ == '__main__':
- unittest.main()
View
59 sickbeard/gh_api.py
@@ -0,0 +1,59 @@
+# Author: Nic Wolfe <nic@wolfeden.ca>
+# URL: http://code.google.com/p/sickbeard/
+#
+# This file is part of Sick Beard.
+#
+# Sick Beard is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Sick Beard is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Sick Beard. If not, see <http://www.gnu.org/licenses/>.
+
+try:
+ import json
+except ImportError:
+ from lib import simplejson as json
+
+import urllib
+
+class GitHub(object):
+ """
+ Simple api wrapper for the Github API v3. Currently only supports the small thing that SB
+ needs it for - list of cimmots.
+ """
+
+ def _access_API(self, path, params=None):
+ """
+ Access the API at the path given and with the optional params given.
+
+ path: A list of the path elements to use (eg. ['repos', 'midgetspy', 'Sick-Beard', 'commits'])
+ params: Optional dict of name/value pairs for extra params to send. (eg. {'per_page': 10})
+
+ Returns a deserialized json object of the result. Doesn't do any error checking (hope it works).
+ """
+
+ url = 'https://api.github.com/' + '/'.join(path)
+
+ if params and type(params) is dict:
+ url += '?' + '&'.join([str(x) + '=' + str(params[x]) for x in params.keys()])
+
+ return json.load(urllib.urlopen(url))
+
+ def commits(self, user, repo, branch='master'):
+ """
+ Uses the API to get a list of the 100 most recent commits from the specified user/repo/branch, starting from HEAD.
+
+ user: The github username of the person whose repo you're querying
+ repo: The repo name to query
+ branch: Optional, the branch name to show commits from
+
+ Returns a deserialized json object containing the commit info. See http://developer.github.com/v3/repos/commits/
+ """
+ return self._access_API(['repos', user, repo, 'commits'], {'per_page': 100, 'branch': branch})
View
8 sickbeard/versionChecker.py
@@ -28,7 +28,7 @@
import zipfile, tarfile
from urllib2 import URLError
-from lib.pygithub import github
+import gh_api as github
class CheckVersion():
"""
@@ -297,13 +297,13 @@ def _check_github_for_update(self):
gh = github.GitHub()
# find newest commit
- for curCommit in gh.commits.forBranch('midgetspy', 'Sick-Beard', version.SICKBEARD_VERSION):
+ for curCommit in gh.commits('midgetspy', 'Sick-Beard', version.SICKBEARD_VERSION):
if not self._newest_commit_hash:
- self._newest_commit_hash = curCommit.id
+ self._newest_commit_hash = curCommit['sha']
if not self._cur_commit_hash:
break
- if curCommit.id == self._cur_commit_hash:
+ if curCommit['sha'] == self._cur_commit_hash:
break
self._num_commits_behind += 1

0 comments on commit acaf5ca

Please sign in to comment.