+++ /dev/null
-;;; gh-api.el --- api definition for gh.el -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2011 Yann Hodique
-
-;; Author: Yann Hodique <yann.hodiqueNOSPAMgmail.com>
-;; Keywords:
-
-;; This file 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 2, or (at your option)
-;; any later version.
-
-;; This file 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 GNU Emacs; see the file COPYING. If not, write to
-;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
-
-;;; Commentary:
-
-;;
-
-;;; Code:
-
-(require 'eieio)
-
-(require 'json)
-
-(require 'gh-profile)
-(require 'gh-url)
-(require 'gh-auth)
-(require 'gh-cache)
-
-(require 'logito)
-
-(defgroup gh-api nil
- "Github API."
- :group 'gh)
-
-(defcustom gh-api-username-filter 'gh-api-enterprise-username-filter
- "Filter to apply to usernames to build URL components"
- :type 'function
- :group 'gh-api)
-
-(defclass gh-api ()
- ((sync :initarg :sync :initform t)
- (cache :initarg :cache :initform nil)
- (base :initarg :base :type string)
- (profile :initarg :profile :type string)
- (auth :initarg :auth :initform nil)
- (data-format :initarg :data-format)
- (num-retries :initarg :num-retries :initform 0)
- (log :initarg :log :initform nil)
- (cache-cls :initform gh-cache :allocation :class))
- "Github API")
-
-(cl-defmethod logito-log ((api gh-api) level tag string &rest objects)
- (apply 'logito-log (oref api :log) level tag string objects))
-
-(cl-defmethod initialize-instance ((api gh-api) &rest args)
- (cl-call-next-method))
-
-(cl-defmethod gh-api-set-default-auth ((api gh-api) auth)
- (let ((auth (or (oref api :auth) auth))
- (cache (oref api :cache))
- (classname (symbol-name (funcall (if (fboundp 'eieio-object-class)
- 'eieio-object-class
- 'object-class)
- api))))
- (oset api :auth auth)
- (unless (or (null cache)
- (and (eieio-object-p cache)
- (object-of-class-p cache 'gh-cache)))
- (oset api :cache (make-instance
- (oref api cache-cls)
- :object-name
- (format "gh/%s/%s"
- classname
- (gh-api-get-username api)))))))
-
-(cl-defmethod gh-api-expand-resource ((api gh-api)
- resource)
- resource)
-
-(defun gh-api-enterprise-username-filter (username)
- (replace-regexp-in-string (regexp-quote ".") "-" username))
-
-(cl-defmethod gh-api-get-username ((api gh-api))
- (let ((username (oref (oref api :auth) :username)))
- (funcall gh-api-username-filter username)))
-
-(defclass gh-api-v3 (gh-api)
- ((data-format :initarg :data-format :initform :json))
- "Github API v3")
-
-(defcustom gh-api-v3-authenticator 'gh-oauth-authenticator
- "Authenticator for Github API v3"
- :type '(choice (const :tag "Password" gh-password-authenticator)
- (const :tag "OAuth" gh-oauth-authenticator))
- :group 'gh-api)
-
-(cl-defmethod initialize-instance ((api gh-api-v3) &rest args)
- (cl-call-next-method)
- (let ((gh-profile-current-profile (gh-profile-current-profile)))
- (oset api :profile (gh-profile-current-profile))
- (oset api :base (gh-profile-url))
- (gh-api-set-default-auth api
- (or (oref api :auth)
- (funcall gh-api-v3-authenticator "auth")))))
-
-(defclass gh-api-request (gh-url-request)
- ((default-response-cls :allocation :class :initform gh-api-response)))
-
-(defclass gh-api-response (gh-url-response)
- ())
-
-(defun gh-api-json-decode (repr)
- (if (or (null repr) (string= repr ""))
- 'empty
- (let ((json-array-type 'list))
- (json-read-from-string repr))))
-
-(defun gh-api-json-encode (json)
- (encode-coding-string (json-encode-list json) 'utf-8))
-
-(cl-defmethod gh-url-response-set-data ((resp gh-api-response) data)
- (cl-call-next-method resp (gh-api-json-decode data)))
-
-(defclass gh-api-paged-request (gh-api-request)
- ((default-response-cls :allocation :class :initform gh-api-paged-response)
- (page-limit :initarg :page-limit :initform -1)))
-
-(defclass gh-api-paged-response (gh-api-response)
- ())
-
-(cl-defmethod gh-api-paging-links ((resp gh-api-paged-response))
- (let ((links-header (cdr (assoc "Link" (oref resp :headers)))))
- (when links-header
- (cl-loop for item in (split-string links-header ", ")
- when (string-match "^<\\(.*\\)>; rel=\"\\(.*\\)\"" item)
- collect (cons (match-string 2 item)
- (match-string 1 item))))))
-
-(cl-defmethod gh-url-response-set-data ((resp gh-api-paged-response) data)
- (let ((previous-data (oref resp :data))
- (next (cdr (assoc "next" (gh-api-paging-links resp)))))
- (cl-call-next-method)
- (oset resp :data (append previous-data (oref resp :data)))
- (when (and next (not (equal 304 (oref resp :http-status))))
- (let* ((req (oref resp :-req))
- (last-page-limit (oref req :page-limit))
- (this-page-limit (if (numberp last-page-limit) (- last-page-limit 1) -1)))
- (oset req :page-limit this-page-limit)
- (unless (eq (oref req :page-limit) 0)
- ;; We use an explicit check for 0 since -1 indicates that
- ;; paging should continue forever.
- (oset resp :data-received nil)
- (oset req :url next)
- ;; Params need to be set to nil because the next uri will
- ;; already have query params. If params are non-nil this will
- ;; cause another set of params to be added to the end of the
- ;; string which will override the params that are set in the
- ;; next link.
- (oset req :query nil)
- (gh-url-run-request req resp))))))
-
-(cl-defmethod gh-api-authenticated-request
- ((api gh-api) transformer method resource &optional data params page-limit)
- (let* ((fmt (oref api :data-format))
- (headers (cond ((eq fmt :form)
- '(("Content-Type" .
- "application/x-www-form-urlencoded")))
- ((eq fmt :json)
- '(("Content-Type" .
- "application/json")))))
- (cache (oref api :cache))
- (key (list resource
- method
- (sha1 (format "%s" transformer))))
- (cache-key (and cache
- (member method (oref cache safe-methods))
- key))
- (has-value (and cache-key (pcache-has cache cache-key)))
- (value (and has-value (pcache-get cache cache-key)))
- (is-outdated (and has-value (gh-cache-outdated-p cache cache-key)))
- (etag (and is-outdated (gh-cache-etag cache cache-key)))
- (req
- (and (or (not has-value)
- is-outdated)
- (gh-auth-modify-request
- (oref api :auth)
- ;; TODO: use gh-api-paged-request only when needed
- (make-instance 'gh-api-paged-request
- :method method
- :url (concat (oref api :base)
- (gh-api-expand-resource
- api resource))
- :query params
- :headers (if etag
- (cons (cons "If-None-Match" etag)
- headers)
- headers)
- :data (or (and (eq fmt :json)
- (gh-api-json-encode data))
- (and (eq fmt :form)
- (gh-url-form-encode data))
- "")
- :page-limit page-limit)))))
- (cond ((and has-value ;; got value from cache
- (not is-outdated))
- (make-instance 'gh-api-response :data-received t :data value))
- (cache-key ;; no value, but cache exists and method is safe
- (let ((resp (make-instance (oref req default-response-cls)
- :transform transformer)))
- (gh-url-run-request req resp)
- (gh-url-add-response-callback
- resp (make-instance 'gh-api-callback :cache cache :key cache-key
- :revive etag))
- resp))
- (cache ;; unsafe method, cache exists
- (pcache-invalidate cache key)
- (gh-url-run-request req (make-instance
- (oref req default-response-cls)
- :transform transformer)))
- (t ;; no cache involved
- (gh-url-run-request req (make-instance
- (oref req default-response-cls)
- :transform transformer))))))
-
-(defclass gh-api-callback (gh-url-callback)
- ((cache :initarg :cache)
- (key :initarg :key)
- (revive :initarg :revive)))
-
-(cl-defmethod gh-url-callback-run ((cb gh-api-callback) resp)
- (let ((cache (oref cb :cache))
- (key (oref cb :key)))
- (if (and (oref cb :revive) (equal (oref resp :http-status) 304))
- (progn
- (gh-cache-revive cache key)
- (oset resp :data (pcache-get cache key)))
- (pcache-put cache key (oref resp :data))
- (gh-cache-set-etag cache key
- (cdr (assoc "ETag" (oref resp :headers)))))))
-
-(define-obsolete-function-alias 'gh-api-add-response-callback
- 'gh-url-add-response-callback "0.6.0")
-
-(provide 'gh-api)
-;;; gh-api.el ends here
-
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
+++ /dev/null
-;;; gh-auth.el --- authentication for gh.el -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2011 Yann Hodique
-
-;; Author: Yann Hodique <yann.hodiqueNOSPAMgmail.com>
-;; Keywords:
-
-;; This file 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 2, or (at your option)
-;; any later version.
-
-;; This file 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 GNU Emacs; see the file COPYING. If not, write to
-;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
-
-;;; Commentary:
-
-;;
-
-;;; Code:
-
-(require 'eieio)
-
-(require 'gh-profile)
-(require 'gh-common)
-(require 'gh-url)
-
-(defgroup gh-auth nil
- "Github authentication."
- :group 'gh)
-
-(defvar gh-auth-alist nil)
-
-(defun gh-auth-remember (profile key value)
- (let ((cell (assoc profile gh-auth-alist)))
- (when (not cell)
- (setq cell (cons profile nil))
- (setq gh-auth-alist (append gh-auth-alist (list cell))))
- (setcdr cell (plist-put (cdr cell) key value))))
-
-(defun gh-auth-get-username ()
- (let* ((profile (gh-profile-current-profile))
- (user (or (plist-get (cdr (assoc profile gh-auth-alist)) :username)
- (plist-get (cdr (assoc profile gh-profile-alist)) :username)
- (gh-config "user"))))
- (when (not user)
- (setq user (read-string "GitHub username: "))
- (gh-set-config "user" user))
- (gh-auth-remember profile :username user)
- user))
-
-(defun gh-auth-get-password (&optional remember)
- (let* ((profile (gh-profile-current-profile))
- (pass (or (plist-get (cdr (assoc profile gh-auth-alist)) :password)
- (plist-get (cdr (assoc profile gh-profile-alist)) :password)
- (gh-config "password"))))
- (when (not pass)
- (setq pass (read-passwd "GitHub password: "))
- (when remember
- (gh-set-config "password" pass)))
- (when remember
- (gh-auth-remember profile :password pass))
- pass))
-
-(declare-function 'gh-oauth-auth-new "gh-oauth")
-
-(defun gh-auth-get-oauth-token ()
- (let* ((profile (gh-profile-current-profile))
- (token (or (plist-get (cdr (assoc profile gh-auth-alist)) :token)
- (plist-get (cdr (assoc profile gh-profile-alist)) :token)
- (gh-config "oauth-token"))))
- (when (not token)
- (let* ((api (make-instance 'gh-oauth-api))
- (tok (and (fboundp 'gh-oauth-auth-new)
- (oref (oref (funcall 'gh-oauth-auth-new api
- '(user repo gist)) :data)
- :token))))
- (setq token (or tok (read-string "GitHub OAuth token: ")))
- (gh-set-config "oauth-token" token)))
- (when (functionp token) (setq token (funcall token)))
- (gh-auth-remember profile :token token)
- token))
-
-(defclass gh-authenticator ()
- ((username :initarg :username :initform nil))
- "Abstract authenticator")
-
-(cl-defmethod initialize-instance ((auth gh-authenticator) &rest args)
- (cl-call-next-method)
- (or (oref auth :username)
- (oset auth :username (gh-auth-get-username))))
-
-(cl-defmethod gh-auth-modify-request ((auth gh-authenticator) req)
- req)
-
-(defclass gh-auth-2fa-callback (gh-url-callback)
- ((req :initarg :req :initform nil))
- "2-factor callback")
-
-(cl-defmethod gh-url-callback-run ((cb gh-auth-2fa-callback) resp)
- (when (equal (oref resp :http-status) 401)
- (let* ((otp-header "X-GitHub-OTP")
- (h (assoc otp-header (oref resp :headers))))
- (when (and h (string-prefix-p "required;" (cdr h)))
- (let ((otp (read-from-minibuffer "Enter dual-factor auth code: "))
- (req (oref cb :req)))
- ;; reset resp
- (oset resp :data nil)
- (oset resp :data-received nil)
-
- (object-add-to-list req :headers
- (cons otp-header otp))
- (gh-url-run-request req resp))))))
-
-(defclass gh-password-authenticator (gh-authenticator)
- ((password :initarg :password :protection :private :initform nil)
- (remember :allocation :class :initform t)
-
- (2fa-cls :initform gh-auth-2fa-callback :allocation :class))
- "Password-based authenticator")
-
-(cl-defmethod initialize-instance ((auth gh-password-authenticator) &rest args)
- (cl-call-next-method)
- (or (oref auth :password)
- (oset auth :password (gh-auth-get-password (oref auth remember)))))
-
-(cl-defmethod gh-auth-modify-request ((auth gh-password-authenticator) req)
- (object-add-to-list req :headers
- (cons "Authorization"
- (concat "Basic "
- (base64-encode-string
- (format "%s:%s" (oref auth :username)
- (encode-coding-string
- (oref auth :password) 'utf-8))))))
- (object-add-to-list req :install-callbacks
- (make-instance (oref auth 2fa-cls) :req req))
- req)
-
-(defclass gh-oauth-authenticator (gh-authenticator)
- ((token :initarg :token :protection :private :initform nil))
- "Oauth-based authenticator")
-
-(cl-defmethod initialize-instance ((auth gh-oauth-authenticator) &rest args)
- (cl-call-next-method)
- (or (oref auth :token)
- (oset auth :token (gh-auth-get-oauth-token))))
-
-(cl-defmethod gh-auth-modify-request ((auth gh-oauth-authenticator) req)
- (object-add-to-list req :headers
- (cons "Authorization"
- (encode-coding-string
- (format "token %s" (oref auth :token)) 'utf-8)))
- req)
-
-(provide 'gh-auth)
-;; to avoid circular dependencies...
-(require 'gh-oauth)
-;;; gh-auth.el ends here
-
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
+++ /dev/null
-;;; gh-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*-
-;; Generated by the `loaddefs-generate' function.
-
-;; This file is part of GNU Emacs.
-
-;;; Code:
-
-(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path)))
-
-
-\f
-;;; Generated autoloads from gh-api.el
-
-(register-definition-prefixes "gh-api" '("gh-api"))
-
-\f
-;;; Generated autoloads from gh-auth.el
-
-(register-definition-prefixes "gh-auth" '("gh-"))
-
-\f
-;;; Generated autoloads from gh-cache.el
-
-(register-definition-prefixes "gh-cache" '("gh-cache"))
-
-\f
-;;; Generated autoloads from gh-comments.el
-
-(register-definition-prefixes "gh-comments" '("gh-comments-api-mixin"))
-
-\f
-;;; Generated autoloads from gh-common.el
-
-(register-definition-prefixes "gh-common" '("gh-"))
-
-\f
-;;; Generated autoloads from gh-gist.el
-
-(register-definition-prefixes "gh-gist" '("gh-gist-api"))
-
-\f
-;;; Generated autoloads from gh-issues.el
-
-(register-definition-prefixes "gh-issues" '("gh-issues-"))
-
-\f
-;;; Generated autoloads from gh-oauth.el
-
-(register-definition-prefixes "gh-oauth" '("gh-oauth-"))
-
-\f
-;;; Generated autoloads from gh-orgs.el
-
-(register-definition-prefixes "gh-orgs" '("gh-orgs-api"))
-
-\f
-;;; Generated autoloads from gh-profile.el
-
-(register-definition-prefixes "gh-profile" '("gh-profile-"))
-
-\f
-;;; Generated autoloads from gh-pulls.el
-
-(register-definition-prefixes "gh-pulls" '("gh-pulls-"))
-
-\f
-;;; Generated autoloads from gh-repos.el
-
-(register-definition-prefixes "gh-repos" '("gh-repos-api"))
-
-\f
-;;; Generated autoloads from gh-search.el
-
-(register-definition-prefixes "gh-search" '("gh-search-"))
-
-\f
-;;; Generated autoloads from gh-url.el
-
-(register-definition-prefixes "gh-url" '("gh-url-"))
-
-\f
-;;; Generated autoloads from gh-users.el
-
-(register-definition-prefixes "gh-users" '("gh-users-api"))
-\f
-;;; End of scraped data
-
-(provide 'gh-autoloads)
-
-;; Local Variables:
-;; version-control: never
-;; no-byte-compile: t
-;; no-update-autoloads: t
-;; no-native-compile: t
-;; coding: utf-8-emacs-unix
-;; End:
-
-;;; gh-autoloads.el ends here
+++ /dev/null
-;;; gh-cache.el --- caching for gh.el -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2011 Yann Hodique
-
-;; Author: Yann Hodique <yann.hodiqueNOSPAMgmail.com>
-;; Keywords:
-
-;; This file 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 2, or (at your option)
-;; any later version.
-
-;; This file 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 GNU Emacs; see the file COPYING. If not, write to
-;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
-
-;;; Commentary:
-
-;;
-
-;;; Code:
-
-(require 'eieio)
-
-(require 'pcache)
-
-(defconst gh-cache-outdated-expiration-delay (* 60 60 24))
-
-(defconst gh-cache-internal-version-constant 4)
-
-(defconst gh-cache-version-constant
- (format "%s/gh-%s" pcache-version-constant gh-cache-internal-version-constant))
-
-(defclass gh-cache (pcache-repository)
- ((version-constant :allocation :class)
- (entries :initarg :entries :initform (make-hash-table :test 'equal))
- (safe-methods :allocation :class :initform ("HEAD" "GET" "OPTIONS" "TRACE"))
- (invalidation-chain :allocation :class :initform nil)
-
- (entry-cls :initarg :entry-cls :initform gh-cache-entry)))
-
-(oset-default 'gh-cache version-constant gh-cache-version-constant)
-
-(defclass gh-cache-entry (pcache-entry)
- ((etag :initarg :etag :initform nil)
- (outdated :initarg :outdated :initform nil)
- ;; (ttl :initarg :ttl :initform 0)
- ))
-
-(cl-defmethod pcache-invalidate :after ((cache gh-cache) key)
- (let ((resource (car key)))
- (pcache-map cache #'(lambda (k v)
- (when (equal (car k) resource)
- (pcache-invalidate cache k))))
- (dolist (next (oref cache invalidation-chain))
- (let ((nextresource
- (replace-regexp-in-string (car next) (cdr next) resource)))
- (when (not (equal nextresource resource))
- (pcache-map cache #'(lambda (k v)
- (when (equal (car k) nextresource)
- (pcache-invalidate cache k)))))))))
-
-(cl-defmethod pcache-get ((cache gh-cache) key &optional default)
- (let* ((table (oref cache :entries))
- (entry (gethash key table)))
- (if (not entry)
- default
- (unless (pcache-entry-valid-p entry)
- (oset entry :outdated t))
- (oref entry :value))))
-
-(cl-defmethod pcache-has ((cache pcache-repository) key)
- (let* ((default (make-symbol ":nil"))
- (table (oref cache :entries))
- (entry (gethash key table default)))
- (not (eq entry default))))
-
-(cl-defmethod pcache-purge-invalid ((cache gh-cache))
- (let ((table (oref cache :entries)))
- (maphash #'(lambda (k e)
- (unless (gh-cache-expired-p e)
- (remhash k table)))
- table)
- (pcache-save cache)))
-
-(cl-defmethod gh-cache-outdated-p ((cache gh-cache) key)
- (let* ((table (oref cache :entries))
- (entry (gethash key table)))
- (and entry
- (oref entry :outdated))))
-
-(cl-defmethod gh-cache-expired-p ((cache gh-cache) key)
- (let* ((table (oref cache :entries))
- (entry (gethash key table)))
- (and (gh-cache-outdated-p cache key)
- (not
- (let ((time (float-time (current-time))))
- (< time (+ gh-cache-outdated-expiration-delay
- (oref entry :timestamp))))))))
-
-(cl-defmethod gh-cache-revive ((cache gh-cache) key)
- (let* ((table (oref cache :entries))
- (entry (gethash key table)))
- (and entry
- (oset entry :outdated nil)
- (oset entry :timestamp (float-time (current-time)))
- t)))
-
-(cl-defmethod gh-cache-etag ((cache gh-cache) key)
- (let* ((table (oref cache :entries))
- (entry (gethash key table)))
- (and entry
- (oref entry :etag))))
-
-(cl-defmethod gh-cache-set-etag ((cache gh-cache) key etag)
- (let* ((table (oref cache :entries))
- (entry (gethash key table)))
- (and entry
- (oset entry :etag etag))))
-
-(provide 'gh-cache)
-;;; gh-cache.el ends here
-
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
+++ /dev/null
-;;; gh-comments.el --- support for comment-enabled APIs -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2014-2015 Yann Hodique
-
-;; Author: Yann Hodique <hodiqueyNOSPAMvmware.com>
-;; Keywords:
-
-;; This file 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 2, or (at your option)
-;; any later version.
-
-;; This file 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 GNU Emacs; see the file COPYING. If not, write to
-;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
-
-;;; Commentary:
-
-;;
-
-;;; Code:
-
-(require 'eieio)
-
-(require 'gh-common)
-(require 'gh-api)
-
-(defclass gh-comments-api-mixin ()
- ((comment-cls :allocation :class :initform gh-comment))
- :abstract t)
-
-(cl-defmethod gh-comments-list ((api gh-comments-api-mixin) base)
- (gh-api-authenticated-request
- api (gh-object-list-reader (oref api comment-cls)) "GET"
- (format "%s/comments" (gh-ref-object-base base))))
-
-(cl-defmethod gh-comments-get ((api gh-comments-api-mixin) base comment-id)
- (gh-api-authenticated-request
- api (gh-object-reader (oref api comment-cls)) "GET"
- (format "%s/comments/%s" (gh-ref-object-base base) comment-id)))
-
-(cl-defmethod gh-comments-update ((api gh-comments-api-mixin) base comment-id comment)
- (gh-api-authenticated-request
- api (gh-object-reader (oref api comment-cls)) "PATCH"
- (format "%s/comments/%s" (gh-ref-object-base base) comment-id)
- (gh-comment-req-to-update comment)))
-
-(cl-defmethod gh-comments-new ((api gh-comments-api-mixin) base comment)
- (gh-api-authenticated-request
- api (gh-object-reader (oref api comment-cls)) "POST"
- (format "%s/comments" (gh-ref-object-base base))
- (gh-comment-req-to-update comment)))
-
-(cl-defmethod gh-comments-delete ((api gh-comments-api-mixin) base comment-id)
- (gh-api-authenticated-request
- api nil "DELETE"
- (format "%s/comments/%s" (gh-ref-object-base base) comment-id)))
-
-(provide 'gh-comments)
-;;; gh-comments.el ends here
+++ /dev/null
-;;; gh-common.el --- common objects for gh.el -*- lexical-binding: t; no-byte-compile: t-*-
-
-;; Copyright (C) 2011 Yann Hodique
-
-;; Author: Yann Hodique <yann.hodiqueNOSPAMgmail.com>
-;; Keywords:
-
-;; This file 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 2, or (at your option)
-;; any later version.
-
-;; This file 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 GNU Emacs; see the file COPYING. If not, write to
-;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
-
-;;; Commentary:
-
-;;
-
-;;; Code:
-
-(require 'eieio)
-(require 'marshal)
-
-(autoload 'gh-profile-current-profile "gh-profile")
-(autoload 'gh-profile-default-profile "gh-profile")
-
-(defgroup gh nil
- "Github API client libraries."
- :group 'applications)
-
-(defcustom gh-use-local-git-config nil
- "If `t' use git configuration from the machine running
-Emacs. This makes a difference when running with TRAMP."
- :type 'boolean
- :group 'gh)
-
-;;; Helper functions
-
-(defun gh-read (obj field)
- (cdr (assoc field obj)))
-
-(defun gh-namespaced-key (key)
- (let ((profile (gh-profile-current-profile)))
- (concat "github."
- (if (string= profile (gh-profile-default-profile))
- ""
- (concat profile "."))
- key)))
-
-(defun gh-config (key)
- "Returns a GitHub specific value from the global Git config."
- (let ((strip (lambda (string)
- (if (> (length string) 0)
- (substring string 0 (- (length string) 1))))))
- (funcall strip (gh-command-to-string "config" (gh-namespaced-key key)))))
-
-(defun gh-set-config (key value)
- "Sets a GitHub specific value to the global Git config."
- (gh-command-to-string "config" "--global" (gh-namespaced-key key) value))
-
-(defun gh-command-to-string (&rest args)
- (let ((git (executable-find "git"))
- (runner (if gh-use-local-git-config
- 'call-process
- 'process-file)))
- (with-output-to-string
- (apply runner git nil standard-output nil args))))
-
-(defun gh-sanitize-content (content)
- "Remove all non-unicode characters. This can be used to
-sanitize API calls that need to handle potentially dirty data."
- (let (res skipped)
- (mapc (lambda (c)
- (if (eq 'Cn (get-char-code-property c 'general-category))
- (setq skipped t)
- (push c res)))
- content)
- (when skipped
- (warn "Content contained non-unicode characters"))
- (apply #'string (nreverse res))))
-
-;;; Base classes for common objects
-
-(defun gh-marshal-default-spec (slot)
- (let ((slot-name (symbol-name slot)))
- (list (cons 'alist
- (intern (replace-regexp-in-string "-" "_" slot-name))))))
-
-(defmacro gh-defclass (name superclass slots &rest options-and-doc)
- `(marshal-defclass ,name ,superclass ,slots ,@options-and-doc
- :marshal-default-spec gh-marshal-default-spec))
-
-(gh-defclass gh-object ()
- ())
-
-(cl-defmethod gh-object-read ((cls (subclass gh-object)) data)
- (let ((target (make-instance cls)))
- (when data
- (gh-object-read-into target data))
- target))
-
-(cl-defmethod gh-object-read ((obj gh-object) data)
- (when data
- (gh-object-read-into obj data)))
-
-(cl-defmethod gh-object-reader ((obj gh-object))
- (apply-partially 'gh-object-read obj))
-
-(cl-defmethod gh-object-reader ((cls (subclass gh-object)))
- (apply-partially 'gh-object-read cls))
-
-(cl-defmethod gh-object-list-read ((obj gh-object) data)
- (mapcar (gh-object-reader obj) data))
-
-(cl-defmethod gh-object-list-read ((cls (subclass gh-object)) data)
- (mapcar (gh-object-reader cls) data))
-
-(cl-defmethod gh-object-list-reader ((obj gh-object))
- (apply-partially 'gh-object-list-read obj))
-
-(cl-defmethod gh-object-list-reader ((cls (subclass gh-object)))
- (apply-partially 'gh-object-list-read cls))
-
-(cl-defmethod gh-object-read-into ((obj gh-object) data)
- (unmarshal obj data 'alist))
-
-(cl-defmethod slot-unbound ((obj gh-object) cls slot-name fn)
- (if (eq fn 'oref) nil
- (cl-call-next-method)))
-
-(gh-defclass gh-ref-object (gh-object)
- ((id :initarg :id)
- (url :initarg :url)
- (html-url :initarg :html-url)))
-
-(cl-defmethod gh-ref-object-base ((obj gh-ref-object))
- (let ((url (oref obj :url)))
- (concat "/"
- (mapconcat #'identity
- (cddr (split-string url "/" t))
- "/"))))
-
-(cl-defmethod gh-ref-object-base (obj)
- (if (stringp obj) obj
- (error "illegal input for `gh-ref-object-base'")))
-
-(gh-defclass gh-user (gh-ref-object)
- ((login :initarg :login)
- (gravatar-url :initarg :gravatar-url))
- "Github user object")
-
-(gh-defclass gh-comment (gh-ref-object)
- ((body :initarg :body)
- (user :initarg :user :initform nil :marshal-type gh-user)
- (created-at :initarg :created_at)
- (updated-at :initarg :updated_at))
- "Github comment object")
-
-(cl-defmethod gh-comment-req-to-update ((req gh-comment))
- `(("body" . ,(oref req :body))))
-
-(provide 'gh-common)
-;;; gh-common.el ends here
-
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
+++ /dev/null
-;;; gh-gist.el --- gist module for gh.el -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2011 Yann Hodique
-
-;; Author: Yann Hodique <yann.hodiqueNOSPAMgmail.com>
-;; Keywords:
-
-;; This file 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 2, or (at your option)
-;; any later version.
-
-;; This file 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 GNU Emacs; see the file COPYING. If not, write to
-;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
-
-;;; Commentary:
-
-;;
-
-;;; Code:
-
-(require 'eieio)
-
-(require 'gh-api)
-(require 'gh-auth)
-(require 'gh-common)
-
-(defclass gh-gist-api (gh-api-v3)
- ((gist-cls :allocation :class :initform gh-gist-gist))
- "Gist API")
-
-(gh-defclass gh-gist-gist-stub (gh-object)
- ((files :initarg :files :type list :initform nil :marshal-type (list gh-gist-gist-file))
- (public :initarg :public :marshal-type bool)
- (description :initarg :description))
- "Class for user-created gist objects")
-
-(gh-defclass gh-gist-history-change (gh-object)
- ((total :initarg :total)
- (additions :initarg :additions)
- (deletions :initarg :deletions)))
-
-(gh-defclass gh-gist-history-entry (gh-object)
- ((user :initarg :user :initform nil :marshal-type gh-user)
- (version :initarg :version)
- (committed :initarg :committed :marshal ((alist . committed_at)))
- (change :initarg :change :marshal ((alist . change_status))
- :marshal-type gh-gist-history-change)
- (url :initarg :url)))
-
-(gh-defclass gh-gist-fork-entry (gh-ref-object)
- ((user :initarg :user :initform nil :marshal-type gh-user)
- (created :initarg :created :marshal ((alist . created_at)))
- (updated :initarg :updated :marshal ((alist . updated_at)))))
-
-(gh-defclass gh-gist-gist (gh-ref-object gh-gist-gist-stub)
- ((date :initarg :date :marshal ((alist . created_at)))
- (update :initarg :update :marshal ((alist . updated_at)))
- (push-url :initarg :push-url :marshal ((alist . git_push_url)))
- (pull-url :initarg :pull-url :marshal ((alist . git_pull_url)))
- (comments :initarg :comments)
- (user :initarg :user :initform nil :marshal-type gh-user :marshal ((alist . owner)))
- (history :initarg :history :initform nil :type list :marshal-type (list gh-gist-history-entry))
- (forks :initarg :forks :initform nil :type list :marshal-type (list gh-gist-fork-entry)))
- "Gist object")
-
-(gh-defclass gh-gist-gist-file (gh-object)
- ((filename :initarg :filename)
- (size :initarg :size)
- (url :initarg :url :marshal ((alist . raw_url)))
- (content :initarg :content)))
-
-(cl-defmethod make-instance ((cls (subclass gh-gist-gist-file)) &rest args)
- (let ((obj (cl-call-next-method)))
- (when (oref obj :content)
- (oset obj :content (gh-sanitize-content (oref obj :content))))
- obj))
-
-(cl-defmethod gh-gist-gist-to-obj ((gist gh-gist-gist-stub))
- (let ((files (mapcar #'gh-gist-gist-file-to-obj (oref gist :files))))
- `(("description" . ,(oref gist :description))
- ("public" . ,(oref gist :public))
- ,@(and files (list (cons "files" files))))))
-
-(cl-defmethod gh-gist-gist-has-files ((gist gh-gist-gist-stub))
- (not (memq nil (mapcar (lambda (f)
- (oref f :content)) (oref gist :files)))))
-
-(cl-defmethod gh-gist-gist-file-to-obj ((file gh-gist-gist-file))
- (let* ((filename (oref file :filename))
- (content (oref file :content))
- (file (if content
- `(("filename" . ,filename)
- ("content" . ,content))
- nil)))
- (cons filename file)))
-
-(cl-defmethod gh-gist-list ((api gh-gist-api) &optional username)
- (gh-api-authenticated-request
- api (gh-object-list-reader (oref api gist-cls)) "GET"
- (format "/users/%s/gists" (or username (gh-api-get-username api)))))
-
-(cl-defmethod gh-gist-list-public ((api gh-gist-api))
- (gh-api-authenticated-request
- api (gh-object-list-reader (oref api gist-cls)) "GET" "/gists/public"))
-
-(cl-defmethod gh-gist-list-starred ((api gh-gist-api))
- (gh-api-authenticated-request
- api (gh-object-list-reader (oref api gist-cls)) "GET" "/gists/starred"))
-
-(cl-defmethod gh-gist-get ((api gh-gist-api) gist-or-id)
- (let (id transformer)
- (if (stringp gist-or-id)
- (setq id gist-or-id
- transformer (gh-object-reader (oref api gist-cls)))
- (setq id (oref gist-or-id :id)
- transformer (gh-object-reader gist-or-id)))
- (gh-api-authenticated-request
- api transformer "GET" (format "/gists/%s" id))))
-
-(cl-defmethod gh-gist-new ((api gh-gist-api) gist-stub)
- (gh-api-authenticated-request
- api (gh-object-reader (oref api gist-cls)) "POST" "/gists"
- (gh-gist-gist-to-obj gist-stub)))
-
-(cl-defmethod gh-gist-edit ((api gh-gist-api) gist)
- (gh-api-authenticated-request
- api (gh-object-reader (oref api gist-cls)) "PATCH"
- (format "/gists/%s"
- (oref gist :id))
- (gh-gist-gist-to-obj gist)))
-
-(cl-defmethod gh-gist-set-star ((api gh-gist-api) gist-or-id star)
- (let ((id (if (stringp gist-or-id) gist-or-id
- (oref gist-or-id :id))))
- (gh-api-authenticated-request
- api 'ignore (if star "PUT" "DELETE")
- (format "/gists/%s/star" id))))
-
-(cl-defmethod gh-gist-get-star ((api gh-gist-api) gist-or-id)
- (let ((id (if (stringp gist-or-id) gist-or-id
- (oref gist-or-id :id))))
- (gh-api-authenticated-request
- api 'ignore "GET" (format "/gists/%s/star" id))))
-
-(cl-defmethod gh-gist-fork ((api gh-gist-api) gist-or-id)
- (let ((id (if (stringp gist-or-id) gist-or-id
- (oref gist-or-id :id))))
- (gh-api-authenticated-request
- api (gh-object-reader (oref api gist-cls)) "POST"
- (format "/gists/%s/forks" id))))
-
-(cl-defmethod gh-gist-delete ((api gh-gist-api) gist-or-id)
- (let ((id (if (stringp gist-or-id) gist-or-id
- (oref gist-or-id :id))))
- (gh-api-authenticated-request
- api 'ignore "DELETE" (format "/gists/%s" id))))
-
-(provide 'gh-gist)
-;;; gh-gist.el ends here
-
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
+++ /dev/null
-;;; gh-issue-comments.el --- issue comments api for github -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2014 Travis Thieman
-
-;; Author: Travis Thieman <travis.thiemanNOSPAMgmail.com>
-;; Keywords:
-
-;; This program 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.
-
-;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; TODOS:
-;; * Support listing all comments in a repository
-
-;; Basic usage:
-
-;; (setf api (gh-issue-comments-api "api" :sync nil :cache nil :num-retries 1))
-;; (setf comments (gh-issue-comments-list api "user" "repo" "issue id"))
-;; (setq my-comment (make-instance 'gh-issue-comments-comment :body "This is great!"))
-;; (gh-issue-comments-new api "user" "repo" "issue id" my-comment)
-
-;;; Code:
-
-(require 'eieio)
-
-(require 'gh-api)
-(require 'gh-auth)
-(require 'gh-common)
-
-(require 'gh-issues)
-
-(let ((ver "1.0.0"))
- (define-obsolete-function-alias
- 'gh-issue-comments-api 'gh-issues-api ver)
- (define-obsolete-function-alias
- 'gh-issue-comments-comment 'gh-issues-comment ver)
-
- (define-obsolete-function-alias
- 'gh-issue-comments-req-to-update 'gh-comment-req-to-update ver)
-
- (define-obsolete-function-alias
- 'gh-issue-comments-list 'gh-issues-comments-list ver)
- (define-obsolete-function-alias
- 'gh-issue-comments-get 'gh-issues-comments-get ver)
- (define-obsolete-function-alias
- 'gh-issue-comments-update 'gh-issues-comments-update ver)
- (define-obsolete-function-alias
- 'gh-issue-comments-new 'gh-issues-comments-new ver)
- (define-obsolete-function-alias
- 'gh-issue-comments-delete 'gh-issues-comments-delete ver))
-
-(provide 'gh-issue-comments)
-;;; gh-issue-comments.el ends here
-
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
+++ /dev/null
-;;; gh-issues.el --- issues api for github -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2014-2015 Yann Hodique
-;; Copyright (C) 2014 Travis Thieman
-;; Copyright (C) 2012 Raimon Grau
-
-;; Author: Raimon Grau <raimonsterNOSPAMgmail.com>
-;; Keywords:
-
-;; This program 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.
-
-;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Basic usage:
-
-;; (setf api (gh-issues-api "api" :sync nil :cache nil :num-retries 1))
-;; (setf issues (gh-issues-issue-list api "user" "repo"))
-;; (last (oref issues data)) ; get one issue
-;; (setq mi (make-instance 'gh-issues-issue :body "issue body" :title "issue title"))
-;; (gh-issues-issue-new api "user" "repo" mi)
-;; (setf comments (gh-issues-comments-list api "user" "repo" "issue id"))
-;; (setq my-comment (make-instance 'gh-issues-comment :body "This is great!"))
-;; (gh-issues-comments-new api "user" "repo" "issue id" my-comment)
-
-;;; Code:
-
-(require 'eieio)
-
-(require 'gh-api)
-(require 'gh-auth)
-(require 'gh-comments)
-(require 'gh-common)
-
-(require 'gh-repos)
-
-(defclass gh-issues-api (gh-api-v3 gh-comments-api-mixin)
- ((issue-cls :allocation :class :initform gh-issues-issue)
- (milestone-cls :allocation :class :initform gh-issues-milestone)
- (label-cls :allocation :class :initform gh-issues-label)
- (comment-cls :allocation :class :initform gh-issues-comment))
- "Github Issues api")
-
-(gh-defclass gh-issues-issue (gh-ref-object)
- ((number :initarg :number)
- (state :initarg :state)
- (title :initarg :title)
- (body :initarg :body)
- (user :initarg :user :initform nil :marshal-type gh-user)
- (labels :initarg :labels :initform nil :marshal-type (list gh-issues-label))
- (assignees :initarg :assignees :initform nil :marshal-type (list gh-user))
- (assignee :initarg :assignee :initform nil :marshal-type gh-user)
- (milestone :initarg :milestone :initform nil :marshal-type gh-issues-milestone)
- (comments :initarg :comments :initform 0)
- (pull-request :initarg :pull-request :marshal-type gh-issues-pull-request)
- (closed-at :initarg :closed-at)
- (created-at :initarg :created-at)
- (updated-at :initarg :updated-at))
- "issues request")
-
-(gh-defclass gh-issues-pull-request (gh-object)
- ((html-url :initarg :html-url)
- (diff-url :initarg :diff-url)
- (patch-url :initarg :patch-url)))
-
-(gh-defclass gh-issues-label (gh-ref-object)
- ((name :initarg :name)
- (color :initarg :color)))
-
-(cl-defmethod gh-issues-label-req-to-update ((label gh-issues-label))
- `(("name" . ,(oref label :name))
- ("color" . ,(oref label :color))))
-
-(gh-defclass gh-issues-milestone (gh-ref-object)
- ((number :initarg :number)
- (state :initarg :state)
- (title :initarg :title)
- (description :initarg :description)
- (creator :initarg :creator :initform nil :marshal-type gh-user)
- (open-issues :initarg :open-issues )
- (closed-issues :initarg :closed-issues)
- (created-at :initarg :created-at)
- (due-on :initarg :due-on))
- "github milestone")
-
-(gh-defclass gh-issues-comment (gh-comment)
- ())
-
-(cl-defmethod gh-issues-issue-list ((api gh-issues-api) user repo)
- (gh-api-authenticated-request
- api (gh-object-list-reader (oref api issue-cls)) "GET"
- (format "/repos/%s/%s/issues" user repo)))
-
-(cl-defmethod gh-issues-milestone-list ((api gh-issues-api) user repo)
- (gh-api-authenticated-request
- api (gh-object-list-reader (oref api milestone-cls)) "GET"
- (format "/repos/%s/%s/milestones" user repo)))
-
-(cl-defmethod gh-issues-milestone-get ((api gh-issues-api) user repo id)
- (gh-api-authenticated-request
- api (gh-object-reader (oref api milestone-cls)) "GET"
- (format "/repos/%s/%s/milestones/%s" user repo id)))
-
-(cl-defmethod gh-issues-milestone-new ((api gh-issues-api) user repo milestone)
- (gh-api-authenticated-request
- api (gh-object-reader (oref api milestone-cls)) "POST"
- (format "/repos/%s/%s/milestones" user repo)
- (gh-issues-milestone-req-to-update milestone)))
-
-(cl-defmethod gh-issues-milestone-update ((api gh-issues-api) user repo
- id milestone)
- (gh-api-authenticated-request
- api (gh-object-reader (oref api milestone-cls)) "PATCH"
- (format "/repos/%s/%s/milestones/%s" user repo id)
- (gh-issues-milestone-req-to-update milestone)))
-
-(cl-defmethod gh-issues-milestone-req-to-update ((milestone gh-issues-milestone))
- (let ((state (oref milestone :state))
- (description (oref milestone :description))
- (due-on (oref milestone :due-on))
- (to-update `(("title" . ,(oref milestone :title)))))
- (when state (nconc to-update `(("state" . ,state))))
- (when description (nconc to-update `(("description" . ,description))))
- (when due-on (nconc to-update `(("due_on" . ,due-on))))
- to-update))
-
-(cl-defmethod gh-issues-issue-get ((api gh-issues-api) user repo id)
- (gh-api-authenticated-request
- api (gh-object-reader (oref api issue-cls)) "GET"
- (format "/repos/%s/%s/issues/%s" user repo id)))
-
-(cl-defmethod gh-issues-issue-req-to-update ((req gh-issues-issue))
- (let ((assignee (oref req :assignee))
- ;; (labels (oref req labels))
- (milestone (oref req :milestone))
- (to-update `(("title" . ,(oref req :title))
- ("state" . ,(oref req :state))
- ("body" . ,(oref req :body)))))
-
- ;; (when labels (nconc to-update `(("labels" . ,(oref req labels) ))))
- (when milestone
- (nconc to-update `(("milestone" . ,(oref milestone :number)))))
- (when assignee
- (nconc to-update `(("assignee" . ,(oref assignee :login)))))
- to-update))
-
-(cl-defmethod gh-issues-issue-update ((api gh-issues-api) user repo id req)
- (gh-api-authenticated-request
- api (gh-object-reader (oref api issue-cls)) "PATCH"
- (format "/repos/%s/%s/issues/%s" user repo id)
- (gh-issues-issue-req-to-update req)))
-
-(cl-defmethod gh-issues-issue-new ((api gh-issues-api) user repo issue)
- (gh-api-authenticated-request
- api (gh-object-reader (oref api issue-cls)) "POST"
- (format "/repos/%s/%s/issues" user repo)
- (gh-issues-issue-req-to-update issue)))
-
-;;; Labels
-
-(cl-defmethod gh-issues-label-get ((api gh-issues-api) user repo name)
- (gh-api-authenticated-request
- api (gh-object-reader (oref api label-cls)) "GET"
- (format "/repos/%s/%s/labels/%s" user repo name)))
-
-(cl-defmethod gh-issues-label-list ((api gh-issues-api) user repo)
- (gh-api-authenticated-request
- api (gh-object-list-reader (oref api label-cls)) "GET"
- (format "/repos/%s/%s/labels" user repo )))
-
-(cl-defmethod gh-issues-label-new ((api gh-issues-api) user repo req)
- (gh-api-authenticated-request
- api (gh-object-reader (oref api label-cls)) "POST"
- (format "/repos/%s/%s/labels" user repo)
- (gh-issues-label-req-to-update req)))
-
-(cl-defmethod gh-issues-label-update ((api gh-issues-api) user repo req)
- (gh-api-authenticated-request
- api (gh-object-reader (oref api label-cls)) "POST"
- (format "/repos/%s/%s/labels/%s" user repo (oref req :name))
- (gh-issues-label-req-to-update req)))
-
-(cl-defmethod gh-issues-label-delete ((api gh-issues-api) user repo name)
- (gh-api-authenticated-request
- api (gh-object-reader (oref api label-cls)) "DELETE"
- (format "/repos/%s/%s/labels/%s" user repo name)))
-
-
-(cl-defmethod gh-issues-labels-in-issue ((api gh-issues-api) user repo
- issue-or-issue-id)
- (let ((issue-id (gh-issues--issue-id issue-or-issue-id)))
- (gh-api-authenticated-request
- api (gh-object-list-reader (oref api label-cls)) "GET"
- (format "/repos/%s/%s/issues/%s/labels" user repo issue-id))))
-
-(cl-defmethod gh-issues-labels-add-to-issue ((api gh-issues-api) user repo
- issue-or-issue-id labels)
- (let ((issue-id (gh-issues--issue-id issue-or-issue-id)))
- (gh-api-authenticated-request
- api (gh-object-list-reader (oref api label-cls)) "PUT"
- (format "/repos/%s/%s/issues/%s/labels" user repo issue-id)
- (mapcar #'gh-issues--label-name labels))))
-
-(cl-defmethod gh-issues-labels-remove-all-from-issue ((api gh-issues-api) user repo
- issue-or-issue-id )
- (let ((issue-id (gh-issues--issue-id issue-or-issue-id)))
- (gh-api-authenticated-request
- api (lambda (x) x) "DELETE"
- (format "/repos/%s/%s/issues/%s/labels" user repo issue-id))))
-
-(cl-defmethod gh-issues-labels-in-milestone ((api gh-issues-api) user repo
- milestone-or-milestone-id)
- (let ((milestone-id (gh-issues--milestone-id milestone-or-milestone-id)))
- (gh-api-authenticated-request
- api (gh-object-list-reader (oref api label-cls)) "GET"
- (format "/repos/%s/%s/milestones/%s/labels" user repo milestone-id))))
-
-;;; Comments
-
-(cl-defmethod gh-issues-comments-list ((api gh-issues-api) user repo issue-id)
- (gh-comments-list api (format "/repos/%s/%s/issues/%s" user repo issue-id)))
-
-(cl-defmethod gh-issues-comments-get ((api gh-issues-api) user repo comment-id)
- (gh-comments-get api (format "/repos/%s/%s/issues" user repo) comment-id))
-
-(cl-defmethod gh-issues-comments-update ((api gh-issues-api)
- user repo comment-id comment)
- (gh-comments-update api (format "/repos/%s/%s/issues" user repo)
- comment-id comment))
-
-(cl-defmethod gh-issues-comments-new ((api gh-issues-api)
- user repo issue-id comment)
- (gh-comments-new api (format "/repos/%s/%s/issues/%s" user repo issue-id)
- comment))
-
-(cl-defmethod gh-issues-comments-delete ((api gh-issues-api) user repo comment-id)
- (gh-comments-delete api (format "/repos/%s/%s/issues" user repo) comment-id))
-
-;;; helpers
-
-(defun gh-issues--issue-id (issue-or-issue-id)
- (if (eieio-object-p issue-or-issue-id)
- (oref issue-or-issue-id :id)
- issue-or-issue-id))
-
-(defun gh-issues--milestone-id (milestone-or-milestone-id)
- (if (eieio-object-p milestone-or-milestone-id)
- (oref milestone-or-milestone-id :id)
- milestone-or-milestone-id))
-
-(defun gh-issues--label-name (label-or-label-name)
- (if (eieio-object-p label-or-label-name)
- (oref label-or-label-name :name)
- label-or-label-name))
-
-
-(provide 'gh-issues)
-;;; gh-issues.el ends here
-
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
+++ /dev/null
-;;; gh-oauth.el --- oauth module for gh.el -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2012 Yann Hodique
-
-;; Author: Yann Hodique <yann.hodiqueNOSPAMgmail.com>
-;; Keywords:
-
-;; This file 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 2, or (at your option)
-;; any later version.
-
-;; This file 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 GNU Emacs; see the file COPYING. If not, write to
-;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
-
-;;; Commentary:
-
-;;
-
-;;; Code:
-
-(require 'eieio)
-
-(require 'gh-api)
-(require 'gh-auth)
-(require 'gh-common)
-
-(defclass gh-oauth-api (gh-api-v3)
- ((auth-cls :allocation :class :initform gh-oauth-authorization))
- "OAuth API")
-
-(defclass gh-oauth-password-authenticator (gh-password-authenticator)
- ((remember :allocation :class :initform nil)))
-
-(cl-defmethod initialize-instance ((api gh-oauth-api) &rest args)
- ;; force password authentication for this API
- (let ((gh-api-v3-authenticator 'gh-oauth-password-authenticator))
- (cl-call-next-method)))
-
-(gh-defclass gh-oauth-authorization (gh-ref-object)
- ((scopes :initarg :scopes)
- (token :initarg :token)
- (app :initarg :app :initform nil :marshal-type gh-oauth-app)
- (updated-at :initarg :updated-at)
- (created-at :initarg :created-at)))
-
-(gh-defclass gh-oauth-app (gh-object)
- ((url :initarg :url)
- (name :initarg :name)))
-
-(cl-defmethod gh-oauth-auth-list ((api gh-oauth-api))
- (gh-api-authenticated-request
- api (gh-object-list-reader (oref api auth-cls)) "GET"
- (format "/authorizations")))
-
-(cl-defmethod gh-oauth-auth-get ((api gh-oauth-api) id)
- (gh-api-authenticated-request
- api (gh-object-reader (oref api auth-cls)) "GET"
- (format "/authorizations/%s" id)))
-
-(cl-defmethod gh-oauth-auth-new ((api gh-oauth-api) &optional scopes)
- (gh-api-authenticated-request
- api (gh-object-reader (oref api auth-cls)) "POST"
- (format "/authorizations") (list (cons 'scopes scopes)
- (cons 'note (format "gh.el - %s"
- (system-name))))))
-
-(cl-defmethod gh-oauth-auth-update ((api gh-oauth-api) id &optional scopes)
- (gh-api-authenticated-request
- api (gh-object-reader (oref api auth-cls)) "PATCH"
- (format "/authorizations/%s" id) (list (cons 'scopes scopes))))
-
-(cl-defmethod gh-oauth-auth-delete ((api gh-oauth-api) id)
- (gh-api-authenticated-request
- api nil "DELETE" (format "/authorizations/%s" id)))
-
-(provide 'gh-oauth)
-;;; gh-oauth.el ends here
-
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
+++ /dev/null
-;;; gh-org.el --- orgs module for gh.el -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2012 Yann Hodique
-
-;; Author: Yann Hodique <yann.hodiqueNOSPAMgmail.com>
-;; Keywords:
-
-;; This file 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 2, or (at your option)
-;; any later version.
-
-;; This file 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 GNU Emacs; see the file COPYING. If not, write to
-;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
-
-;;; Commentary:
-
-;;
-
-;;; Code:
-
-(require 'eieio)
-
-(require 'gh-api)
-(require 'gh-auth)
-(require 'gh-common)
-
-(defclass gh-orgs-api (gh-api-v3)
- ((org-cls :allocation :class :initform gh-orgs-org))
- "Orgs API")
-
-(gh-defclass gh-orgs-org-stub (gh-ref-object)
- ((login :initarg :login)
- (avatar-url :initarg :avatar-url)
- (description :initarg :description)))
-
-(gh-defclass gh-orgs-plan (gh-object)
- ((name :initarg :name)
- (space :initarg :space)
- (private-repos :initarg :private-repos)))
-
-(gh-defclass gh-orgs-org (gh-orgs-org-stub)
- ((name :initarg :name)
- (company :initarg :company)
- (blog :initarg :blog)
- (location :initarg :location)
- (email :initarg :email)
- (public-repos :initarg :public-repos)
- (public-gists :initarg :public-gists)
- (followers :initarg :followers)
- (following :initarg :following)
- (created-at :initarg :created-at)
- (type :initarg :type)
- (total-private-repos :initarg :total-private-repos)
- (owned-private-repos :initarg :owned-private-repos)
- (private-gists :initarg :private-gists)
- (disk-usage :initarg :disk-usage)
- (collaborators :initarg :collaborators)
- (billing-email :initarg :billing-email)
- (plan :initarg :plan :initform nil :marshal-type gh-orgs-plan))
- "Class for GitHub organizations")
-
-(cl-defmethod gh-orgs-org-to-obj ((org gh-orgs-org))
- `(,@(when (slot-boundp org :billing-email)
- (list (cons "billing_email" (oref org :billing-email))))
- ,@(when (slot-boundp org :blog)
- (list (cons "blog" (oref org :blog))))
- ,@(when (slot-boundp org :company)
- (list (cons "company" (oref org :company))))
- ,@(when (slot-boundp org :email)
- (list (cons "email" (oref org :email))))
- ,@(when (slot-boundp org :location)
- (list (cons "location" (oref org :location))))
- ,@(when (slot-boundp org :name)
- (list (cons "name" (oref org :name))))))
-
-(cl-defmethod gh-orgs-list ((api gh-orgs-api) &optional username)
- (gh-api-authenticated-request
- api (gh-object-list-reader (oref api org-cls)) "GET"
- (format "/users/%s/orgs" (or username (gh-api-get-username api)))))
-
-(cl-defmethod gh-orgs-get ((api gh-orgs-api) org)
- (gh-api-authenticated-request
- api (gh-object-reader (oref api org-cls)) "GET"
- (format "/orgs/%s" org)))
-
-(cl-defmethod gh-orgs-update ((api gh-orgs-api) org-obj)
- (gh-api-authenticated-request
- api (gh-object-reader (oref api org-cls)) "PATCH"
- (format "/orgs/%s" (oref org-obj :login))
- (apply 'gh-orgs-org-to-obj org-obj nil)))
-
-(provide 'gh-orgs)
-;;; gh-org.el ends here
-
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
+++ /dev/null
-(define-package "gh" "20230825.1217" "A GitHub library for Emacs"
- '((emacs "25.1")
- (pcache "0.4.2")
- (logito "0.1")
- (marshal "0.9.0")
- (cl-lib "0.3"))
- :commit "b5a8d8209340d49ad82dab22d23dae0434499fdf" :authors
- '(("Yann Hodique" . "yhodiqueNOSPAMgmail.com"))
- :maintainer
- '("Yann Hodique" . "yhodiqueNOSPAMgmail.com")
- :url "https://github.com/sigma/gh.el")
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
+++ /dev/null
-;;; gh-profile.el --- profile support for gh.el -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2013 Yann Hodique
-
-;; Author: Yann Hodique <yann.hodiqueNOSPAMgmail.com>
-;; Keywords:
-
-;; This file 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 2, or (at your option)
-;; any later version.
-
-;; This file 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 GNU Emacs; see the file COPYING. If not, write to
-;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
-
-;;; Commentary:
-
-;;
-
-;;; Code:
-
-(require 'rx)
-(require 'url-parse)
-
-(defgroup gh-profile nil
- "Github profile."
- :group 'gh)
-
-(defun gh-profile-remote-regexp (domain)
- (eval
- `(rx bol (or ,(concat "git@" domain ":")
- (and (or "git" "ssh" "http" "https") "://"
- (* nonl) (? "@") ,domain "/"))
- (and (group (* nonl)) "/" (group (* nonl))) (? ".git"))))
-
-(defcustom gh-profile-alist `(("github"
- :url "https://api.github.com"
- :remote-regexp
- ,(gh-profile-remote-regexp "github.com")))
- "List of profiles for Github access. List every Github
-Enterprise server and/or Github accounts you have access
-to here."
- :type '(alist :key-type string
- :value-type (plist :key-type (choice (const :url)
- (const :username)
- (const :password)
- (const :token)
- (const :remote-regexp))
- :value-type string))
- :group 'gh-profile)
-
-(defun gh-profile-get-remote-regexp (profile)
- (let* ((profile-plist (cdr (assoc profile gh-profile-alist)))
- (regexp (plist-get profile-plist :remote-regexp)))
- (if regexp
- regexp
- ;; try to guess remote format (just use the hostname)
- (let* ((url (url-generic-parse-url (plist-get profile-plist :url)))
- (host (url-host url)))
- (gh-profile-remote-regexp host)))))
-
-(defcustom gh-profile-default-profile "github"
- "Default profile. This needs to be a key present in
- `gh-profile-alist'"
- :type 'string
- :group 'gh-profile)
-
-(defun gh-profile-default-profile ()
- gh-profile-default-profile)
-
-(defvar gh-profile-current-profile nil)
-(make-variable-buffer-local 'gh-profile-current-profile)
-
-(defun gh-profile-current-profile ()
- (or gh-profile-current-profile
- (gh-profile-default-profile)))
-
-(defun gh-profile-url ()
- (plist-get (cdr (assoc (gh-profile-current-profile)
- gh-profile-alist)) :url))
-
-(defun gh-profile-completing-read ()
- (let ((profiles (mapcar #'car gh-profile-alist)))
- (if (> (length profiles) 1)
- (completing-read "Github profile: " profiles nil t nil nil (cl-first profiles))
- (car profiles))))
-
-(defun gh-profile-get-remote-profile (remote-url)
- (cl-loop for (id . props) in gh-profile-alist
- if (string-match (gh-profile-get-remote-regexp id)
- remote-url)
- return id))
-
-(provide 'gh-profile)
-;;; gh-profile.el ends here
+++ /dev/null
-;;; gh-pull-comments.el --- pull request comments api for github -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2014 Toni Reina
-
-;; Author: Toni Reina <areina0NOSPAMgmail.com>
-;; Keywords:
-
-;; This program 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.
-
-;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; TODOS:
-;; * Support listing all comments in a repository
-
-;; Basic usage:
-
-;; (setf api (gh-pull-comments-api "api" :sync nil :cache nil :num-retries 1))
-;; (setf comments (gh-pull-comments-list api "user" "repo" "pull request id"))
-;; (setq my-comment (make-instance 'gh-pull-comments-comment
-;; :body "This is great!"
-;; :path "README.md"
-;; :position 2
-;; :commit-id "commit sha"))
-;; (gh-pull-comments-new api "user" "repo" "pull request id" my-comment)
-
-;;; Code:
-
-(require 'eieio)
-
-(require 'gh-api)
-(require 'gh-auth)
-(require 'gh-common)
-
-(require 'gh-pulls)
-
-(let ((ver "1.0.0"))
- (define-obsolete-function-alias
- 'gh-pull-comments-api 'gh-pulls-api ver)
- (define-obsolete-function-alias
- 'gh-pull-comments-comment 'gh-pulls-comment ver)
-
- (define-obsolete-function-alias
- 'gh-pull-comments-req-to-update 'gh-comment-req-to-update ver)
- (define-obsolete-function-alias
- 'gh-pull-comments-req-to-create 'gh-pulls-comment-req-to-create ver)
-
- (define-obsolete-function-alias
- 'gh-pull-comments-list 'gh-pulls-comments-list ver)
- (define-obsolete-function-alias
- 'gh-pull-comments-get 'gh-pulls-comments-get ver)
- (define-obsolete-function-alias
- 'gh-pull-comments-update 'gh-pulls-comments-update ver)
- (define-obsolete-function-alias
- 'gh-pull-comments-new 'gh-pulls-comments-new ver)
- (define-obsolete-function-alias
- 'gh-pull-comments-delete 'gh-pulls-comments-delete ver))
-
-(provide 'gh-pull-comments)
-;;; gh-pull-comments.el ends here
-
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
+++ /dev/null
-;;; gh-pulls.el --- pull requests module for gh.el -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2011 Yann Hodique
-
-;; Author: Yann Hodique <yann.hodiqueNOSPAMgmail.com>
-;; Keywords:
-
-;; This file 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 2, or (at your option)
-;; any later version.
-
-;; This file 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 GNU Emacs; see the file COPYING. If not, write to
-;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
-
-;;; Commentary:
-
-;;
-
-;;; Code:
-
-(require 'eieio)
-
-(require 'gh-api)
-(require 'gh-auth)
-(require 'gh-comments)
-(require 'gh-common)
-
-(require 'gh-repos)
-
-(defclass gh-pulls-cache (gh-cache)
- ((invalidation-chain :allocation :class
- :initform '(("^/repos/.*/.*/pulls$" . "\0")
- ("^/repos/.*/.*/pulls/.*$" . "\0")))))
-
-(defclass gh-pulls-api (gh-api-v3 gh-comments-api-mixin)
- ((cache-cls :allocation :class :initform gh-pulls-cache)
-
- (req-cls :allocation :class :initform gh-pulls-request)
- (comment-cls :allocation :class :initform gh-pulls-comment))
- "Git pull requests API")
-
-(gh-defclass gh-pulls-comment (gh-comment)
- ((path :initarg :path)
- (diff-hunk :initarg :diff-hunk)
- (position :initarg :position)
- (original-position :initarg :original-position)
- (commit-id :initarg :commit-id)
- (original-commit-id :initarg :original-commit-id)
- (in-reply-to :initarg :in-reply-to :initform nil)))
-
-(cl-defmethod gh-pulls-comment-req-to-create ((req gh-pulls-comment))
- (let ((in-reply-to (oref req in-reply-to))
- (to-update `(("body" . ,(oref req body)))))
- (if in-reply-to
- (nconc to-update `(("in_reply_to" . ,in-reply-to)))
- (nconc to-update `(("commit_id" . ,(oref req commit-id))
- ("path" . ,(oref req path))
- ("position" . ,(oref req position)))))
- to-update))
-
-(gh-defclass gh-pulls-request-stub (gh-ref-object)
- ((diff-url :initarg :diff-url)
- (patch-url :initarg :patch-url)
- (issue-url :initarg :issue-url)
- (number :initarg :number)
- (state :initarg :state)
- (title :initarg :title)
- (body :initarg :body)
- (created-at :initarg :created-at)
- (updated-at :initarg :updated-at)
- (closed-at :initarg :closed-at)
- (merged-at :initarg :merged-at)
- (head :initarg :head :initform nil :marshal-type gh-repos-ref)
- (base :initarg :base :initform nil :marshal-type gh-repos-ref)))
-
-(gh-defclass gh-pulls-request (gh-pulls-request-stub)
- ((merged :initarg :merged)
- (mergeable :initarg :mergeable)
- (merged-by :initarg :merged-by)
- (comments :initarg :comments)
- (user :initarg :user :initform nil :marshal-type gh-user)
- (commits :initarg :commits)
- (additions :initarg :additions)
- (deletions :initarg :deletions)
- (changed-files :initarg :changed-files))
- "Git pull requests API")
-
-(cl-defmethod gh-pulls-req-to-new ((req gh-pulls-request))
- (let ((head (oref req :head))
- (base (oref req :base)))
- `(("title" . ,(oref req :title))
- ("body" . ,(oref req :body))
- ("head" . ,(or (oref head :ref) (oref head :sha)))
- ("base" . ,(or (oref base :ref) (oref base :sha))))))
-
-(cl-defmethod gh-pulls-req-to-update ((req gh-pulls-request-stub))
- `(("title" . ,(oref req :title))
- ("body" . ,(oref req :body))
- ("state" . ,(oref req :state))))
-
-(cl-defmethod gh-pulls-list ((api gh-pulls-api) user repo)
- (gh-api-authenticated-request
- api (gh-object-list-reader (oref api req-cls)) "GET"
- (format "/repos/%s/%s/pulls" user repo)))
-
-(cl-defmethod gh-pulls-get ((api gh-pulls-api) user repo id)
- (gh-api-authenticated-request
- api (gh-object-reader (oref api req-cls)) "GET"
- (format "/repos/%s/%s/pulls/%s" user repo id)))
-
-(cl-defmethod gh-pulls-new ((api gh-pulls-api) user repo req)
- (gh-api-authenticated-request
- api (gh-object-reader (oref api req-cls)) "POST"
- (format "/repos/%s/%s/pulls" user repo)
- (gh-pulls-req-to-new req)))
-
-(cl-defmethod gh-pulls-update ((api gh-pulls-api) user repo id req)
- (gh-api-authenticated-request
- api (gh-object-reader (oref api req-cls)) "PATCH"
- (format "/repos/%s/%s/pulls/%s" user repo id)
- (gh-pulls-req-to-update req)))
-
-;;; Comments
-
-(cl-defmethod gh-pulls-comments-list ((api gh-pulls-api) user repo pull-id)
- (gh-comments-list api (format "/repos/%s/%s/pulls/%s" user repo pull-id)))
-
-(cl-defmethod gh-pulls-comments-get ((api gh-pulls-api) user repo comment-id)
- (gh-comments-get api (format "/repos/%s/%s/pulls" user repo) comment-id))
-
-(cl-defmethod gh-pulls-comments-update ((api gh-pulls-api)
- user repo comment-id comment)
- (gh-comments-update api (format "/repos/%s/%s/pulls" user repo)
- comment-id (gh-comment-req-to-update comment)))
-
-(cl-defmethod gh-pulls-comments-new ((api gh-pulls-api)
- user repo pull-id comment)
- (gh-comments-new api (format "/repos/%s/%s/pulls/%s" user repo pull-id)
- (gh-pulls-comment-req-to-create comment)))
-
-(cl-defmethod gh-pulls-comments-delete ((api gh-pulls-api) user repo comment-id)
- (gh-comments-delete api (format "/repos/%s/%s/pulls" user repo) comment-id))
-
-(provide 'gh-pulls)
-;;; gh-pulls.el ends here
-
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
+++ /dev/null
-;;; gh-repos.el --- repos module for gh.el -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2011 Yann Hodique
-
-;; Author: Yann Hodique <yann.hodiqueNOSPAMgmail.com>
-;; Keywords:
-
-;; This file 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 2, or (at your option)
-;; any later version.
-
-;; This file 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 GNU Emacs; see the file COPYING. If not, write to
-;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
-
-;;; Commentary:
-
-;;
-
-;;; Code:
-
-(require 'eieio)
-
-(require 'gh-api)
-(require 'gh-auth)
-(require 'gh-common)
-
-(defclass gh-repos-api (gh-api-v3)
- ((repo-cls :allocation :class :initform gh-repos-repo)
- (user-cls :allocation :class :initform gh-user))
- "Repos API")
-
-(gh-defclass gh-repos-repo-stub (gh-object)
- ((name :initarg :name)
- (description :initarg :description)
- (homepage :initarg :homepage)
- (private :initarg :private))
- "Class for user-created repository objects")
-
-(gh-defclass gh-repos-repo (gh-ref-object gh-repos-repo-stub)
- ((clone-url :initarg :clone-url)
- (git-url :initarg :git-url)
- (ssh-url :initarg :ssh-url)
- (svn-url :initarg :svn-url)
- (mirror-url :initarg :mirror-url)
- (owner :initarg :owner :initform nil :marshal-type gh-user)
- (full-name :initarg :full-name)
- (language :initarg :language)
- (fork :initarg :fork)
- (forks :initarg :forks)
- (forks-count :initarg :forks-count)
- (watchers :initarg :watchers)
- (watchers-count :initarg :watchers-count)
- (stargazers-count :initarg :stargazers-count)
- (size :initarg :size)
- (master-branch :initarg :master-branch)
- (open-issues :initarg :open-issues)
- (pushed-at :initarg :pushed-at)
- (created-at :initarg :created-at)
- (updated-at :initarg :updated-at)
- (organisation :initarg :organisation :initform nil :marshal-type gh-user)
- (parent :initarg :parent :marshal-type gh-repos-repo)
- (source :initarg :source :marshal-type gh-repos-repo)
- (has-issues :initarg :has-issues)
- (has-wiki :initarg :has-wiki)
- (has-downloads :initarg :has-downloads))
- "Class for GitHub repositories")
-
-(gh-defclass gh-repos-ref (gh-object)
- ((label :initarg :label)
- (ref :initarg :ref :initform nil)
- (sha :initarg :sha :initform nil)
- (user :initarg :user :initform nil :marshal-type gh-user)
- (repo :initarg :repo :initform nil :marshal-type gh-repos-repo)))
-
-(cl-defmethod gh-repos-user-list ((api gh-repos-api) &optional username)
- (gh-api-authenticated-request
- api (gh-object-list-reader (oref api repo-cls)) "GET"
- (format "/users/%s/repos" (or username (gh-api-get-username api)))))
-
-(cl-defmethod gh-repos-org-list ((api gh-repos-api) org)
- (gh-api-authenticated-request
- api (gh-object-list-reader (oref api repo-cls)) "GET"
- (format "/orgs/%s/repos" org)))
-
-(cl-defmethod gh-repos-repo-to-obj ((repo gh-repos-repo-stub)
- &rest caps)
- (let ((has_issues (plist-member caps :issues))
- (has_wiki (plist-member caps :wiki))
- (has_downloads (plist-member caps :downloads)))
- `(("name" . ,(oref repo :name))
- ,@(when (slot-boundp repo :homepage)
- (list (cons "homepage" (oref repo :homepage))))
- ,@(when (slot-boundp repo :description)
- (list (cons "description" (oref repo :description))))
- ,@(when (slot-boundp repo :private)
- (list (cons "public" (not (oref repo :private)))))
- ,@(when has_issues
- (list (cons "has_issues" (plist-get caps :issues))))
- ,@(when has_wiki
- (list (cons "has_wiki" (plist-get caps :wiki))))
- ,@(when has_downloads
- (list (cons "has_downloads" (plist-get caps :downloads)))))))
-
-(cl-defmethod gh-repos-repo-new ((api gh-repos-api) repo-stub
- &optional org &rest caps)
- (gh-api-authenticated-request
- api (gh-object-reader (oref api repo-cls)) "POST"
- (if org (format "/orgs/%s/repos" org)
- "/user/repos")
- (apply 'gh-repos-repo-to-obj repo-stub caps)))
-
-(cl-defmethod gh-repos-repo-get ((api gh-repos-api) repo-id &optional user)
- (gh-api-authenticated-request
- api (gh-object-reader (oref api repo-cls)) "GET"
- (format "/repos/%s/%s"
- (or user (gh-api-get-username api))
- repo-id)))
-
-(cl-defmethod gh-repos-repo-update ((api gh-repos-api) repo-stub
- &optional user &rest caps)
- (gh-api-authenticated-request
- api (gh-object-reader (oref api repo-cls)) "PATCH"
- (format "/repos/%s/%s"
- (or user (gh-api-get-username api))
- (oref repo-stub :name))
- (apply 'gh-repos-repo-to-obj repo-stub caps)))
-
-(cl-defmethod gh-repos-repo-rename ((api gh-repos-api) repo-stub new-name
- &optional user)
- (let ((new-stub (make-instance 'gh-repos-repo-stub :name new-name)))
- (gh-api-authenticated-request
- api (gh-object-reader (oref api repo-cls)) "PATCH"
- (format "/repos/%s/%s"
- (or user (gh-api-get-username api))
- (oref repo-stub :name))
- (gh-repos-repo-to-obj new-stub))))
-
-(cl-defmethod gh-repos-repo-delete ((api gh-repos-api) repo-id
- &optional user)
- (gh-api-authenticated-request
- api (gh-object-reader (oref api repo-cls)) "DELETE"
- (format "/repos/%s/%s"
- (or user (gh-api-get-username api))
- repo-id)))
-
-;; TODO gh-repos-repo-move
-
-(cl-defmethod gh-repos-repo-contributors ((api gh-repos-api) repo)
- (gh-api-authenticated-request
- api (gh-object-reader (oref api repo-cls)) "GET"
- (format "/repos/%s/%s/contributors"
- (oref (oref repo :owner) :login)
- (oref repo :name))))
-
-;;; TODO: generate some useful objects with the return values
-
-(cl-defmethod gh-repos-repo-languages ((api gh-repos-api) repo)
- (gh-api-authenticated-request
- api nil "GET" (format "/repos/%s/%s/languages"
- (oref (oref repo :owner) :login)
- (oref repo :name))))
-
-(cl-defmethod gh-repos-repo-teams ((api gh-repos-api) repo)
- (gh-api-authenticated-request
- api nil "GET" (format "/repos/%s/%s/teams"
- (oref (oref repo :owner) :login)
- (oref repo :name))))
-
-(cl-defmethod gh-repos-repo-tags ((api gh-repos-api) repo)
- (gh-api-authenticated-request
- api nil "GET" (format "/repos/%s/%s/tags"
- (oref (oref repo :owner) :login)
- (oref repo :name))))
-
-(cl-defmethod gh-repos-repo-branches ((api gh-repos-api) repo)
- (gh-api-authenticated-request
- api nil "GET" (format "/repos/%s/%s/branches"
- (oref (oref repo :owner) :login)
- (oref repo :name))))
-
-;;; TODO gh-repos-repo-branch-commits
-
-;;; Collaborators sub-API
-
-(cl-defmethod gh-repos-collaborators-list ((api gh-repos-api) repo)
- (gh-api-authenticated-request
- api (gh-object-list-reader (oref api user-cls)) "GET" (format "/repos/%s/%s/collaborators"
- (oref (oref repo :owner) :login)
- (oref repo :name))))
-
-(cl-defmethod gh-repos-collaborators-p ((api gh-repos-api) repo user)
- (eq (oref (gh-api-authenticated-request
- api nil "GET"
- (format "/repos/%s/%s/collaborators/%s"
- (oref (oref repo :owner) :login)
- (oref repo :name)
- user))
- :http-status)
- 204))
-
-(cl-defmethod gh-repos-collaborators-add ((api gh-repos-api) repo user)
- (gh-api-authenticated-request
- api nil "PUT"
- (format "/repos/%s/%s/collaborators/%s"
- (oref (oref repo :owner) :login)
- (oref repo :name)
- user)))
-
-(cl-defmethod gh-repos-collaborators-delete ((api gh-repos-api) repo user)
- (gh-api-authenticated-request
- api nil "DELETE"
- (format "/repos/%s/%s/collaborators/%s"
- (oref (oref repo :owner) :login)
- (oref repo :name)
- user)))
-
-;;; TODO Comments sub-API
-;;; TODO Commits sub-API
-;;; TODO Contents sub-API
-;;; TODO Downloads sub-API
-
-;;; Forks sub-API
-
-(cl-defmethod gh-repos-forks-list ((api gh-repos-api) repo &optional recursive)
- (let ((resp (gh-api-authenticated-request
- api (gh-object-list-reader (oref api repo-cls)) "GET"
- (format "/repos/%s/%s/forks"
- (oref (oref repo :owner) :login)
- (oref repo :name)))))
- (when recursive
- (let ((forks (oref resp :data)))
- (oset resp :data
- (apply 'nconc forks
- (mapcar
- (lambda (f)
- (oref (gh-repos-forks-list api f t) data))
- forks)))))
- resp))
-
-(cl-defmethod gh-repos-fork ((api gh-repos-api) repo &optional org)
- (gh-api-authenticated-request
- api (gh-object-reader (oref api repo-cls)) "POST"
- (format "/repos/%s/%s/forks"
- (oref (oref repo :owner) :login)
- (oref repo :name))
- nil (when org `(("org" . ,org)))))
-
-;;; TODO Keys sub-API
-;;; TODO Hooks sub-API
-;;; TODO Merging sub-API
-
-;;; Starring sub-API
-
-(cl-defmethod gh-repos-stargazers ((api gh-repos-api) repo)
- (gh-api-authenticated-request
- api (gh-object-list-reader (oref api user-cls)) "GET"
- (format "/repos/%s/%s/stargazers"
- (oref (oref repo :owner) :login)
- (oref repo :name))))
-
-(cl-defmethod gh-repos-starred-list ((api gh-repos-api) &optional username)
- (gh-api-authenticated-request
- api (gh-object-list-reader (oref api repo-cls)) "GET"
- (format "/users/%s/starred" (or username (gh-api-get-username api)))))
-
-(cl-defmethod gh-repos-starred-p ((api gh-repos-api) repo)
- (eq (oref (gh-api-authenticated-request
- api nil "GET"
- (format "/user/starred/%s/%s"
- (oref (oref repo :owner) :login)
- (oref repo :name)))
- :http-status)
- 204))
-
-(cl-defmethod gh-repos-star ((api gh-repos-api) repo)
- (gh-api-authenticated-request
- api nil "PUT"
- (format "/user/starred/%s/%s"
- (oref (oref repo :owner) :login)
- (oref repo :name))))
-
-(cl-defmethod gh-repos-unstar ((api gh-repos-api) repo)
- (gh-api-authenticated-request
- api nil "DELETE"
- (format "/user/starred/%s/%s"
- (oref (oref repo :owner) :login)
- (oref repo :name))))
-
-;;; TODO Statuses sub-API
-
-;;; Watching sub-API
-
-(cl-defmethod gh-repos-watchers ((api gh-repos-api) repo)
- (gh-api-authenticated-request
- api (gh-object-list-reader (oref api user-cls)) "GET"
- (format "/repos/%s/%s/subscribers"
- (oref (oref repo :owner) :login)
- (oref repo :name))))
-
-(cl-defmethod gh-repos-watched-list ((api gh-repos-api) &optional username)
- (gh-api-authenticated-request
- api (gh-object-list-reader (oref api repo-cls)) "GET"
- (format "/users/%s/subscriptions"
- (or username (gh-api-get-username api)))))
-
-(cl-defmethod gh-repos-watched-p ((api gh-repos-api) repo)
- (eq (oref (gh-api-authenticated-request
- api nil "GET"
- (format "/user/subscriptions/%s/%s"
- (oref (oref repo :owner) :login)
- (oref repo :name)))
- :http-status)
- 204))
-
-(cl-defmethod gh-repos-watch ((api gh-repos-api) repo)
- (gh-api-authenticated-request
- api nil "PUT"
- (format "/user/subscriptions/%s/%s"
- (oref (oref repo :owner) :login)
- (oref repo :name))))
-
-(cl-defmethod gh-repos-unwatch ((api gh-repos-api) repo)
- (gh-api-authenticated-request
- api nil "DELETE"
- (format "/user/subscriptions/%s/%s"
- (oref (oref repo :owner) :login)
- (oref repo :name))))
-
-(provide 'gh-repos)
-;;; gh-repos.el ends here
-
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
+++ /dev/null
-;;; gh-search.el --- repository search for gh.el -*- lexical-binding: t; -*-
-;; Copyright (C) 2016 Ivan Malison
-
-;; Author: Ivan Malison <IvanMalisonNOSPAMgmail.com>
-
-;; This program 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.
-
-;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;;
-
-;;; Code:
-
-(require 'gh-users)
-(require 'gh-repos)
-
-(defclass gh-search-api (gh-api-v3)
- ((repo-cls :allocation :class :initform gh-repos-repo)
- (user-cls :allocation :class :initform gh-users-user)))
-
-(defmacro gh-search-method-builder (method-name uri process-result-function)
- `(cl-defmethod ,method-name ((search-api gh-search-api)
- query-string &optional page-limit
- &rest additional-arguments)
- (unless (and (stringp query-string) (> (length query-string) 1))
- (error "a non-empty query string must be provided to github search"))
- (gh-api-authenticated-request
- search-api
- (apply-partially (quote ,process-result-function) search-api)
- "GET" ,uri nil
- `((q . ,query-string) ,@additional-arguments) page-limit)))
-
-(defmacro gh-search-process-method-builder (method-name class-symbol)
- `(cl-defmethod ,method-name ((search-api gh-search-api) data)
- (unless (listp data)
- (error "Did not recieve a list from the search query"))
- (let ((items (assoc 'items data)))
- (unless items
- (error "Search query did not return items"))
- (gh-object-list-read (oref search-api ,class-symbol) (cdr items)))))
-
-(gh-search-process-method-builder gh-process-repo-search-result repo-cls)
-(gh-search-process-method-builder gh-process-user-search-result user-cls)
-(gh-search-method-builder gh-search-repos "/search/repositories"
- gh-process-repo-search-result)
-(gh-search-method-builder gh-search-users "/search/users"
- gh-process-user-search-result)
-
-(provide 'gh-search)
-;;; gh-search.el ends here
+++ /dev/null
-;;; gh-url.el --- url wrapper for gh.el -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2012 Yann Hodique
-
-;; Author: Yann Hodique <yann.hodiqueNOSPAMgmail.com>
-;; Keywords:
-
-;; This file 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 2, or (at your option)
-;; any later version.
-
-;; This file 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 GNU Emacs; see the file COPYING. If not, write to
-;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
-
-;;; Commentary:
-
-;;
-
-;;; Code:
-
-(require 'eieio)
-
-(require 'url-http)
-
-(defclass gh-url-request ()
- ((method :initarg :method :type string)
- (url :initarg :url :type string)
- (query :initarg :query :initform nil)
- (headers :initarg :headers :initform nil)
- (data :initarg :data :initform "" :type string)
- (async :initarg :async :initform nil)
- (num-retries :initarg :num-retries :initform 0)
- (install-callbacks :initarg :install-callbacks :initform nil)
-
- (default-response-cls :allocation :class :initform gh-url-response)))
-
-(defclass gh-url-response ()
- ((data-received :initarg :data-received :initform nil)
- (data :initarg :data :initform nil)
- (headers :initarg :headers :initform nil)
- (http-status :initarg :http-status :initform nil)
- (callbacks :initarg :callbacks :initform nil)
- (transform :initarg :transform :initform nil)
- (-req :initarg :-req :initform nil)))
-
-(cl-defmethod gh-url-response-set-data ((resp gh-url-response) data)
- (let ((transform (oref resp :transform)))
- (oset resp :data
- (if transform
- (funcall transform data)
- data))
- (oset resp :data-received t)))
-
-(defclass gh-url-callback ()
- nil)
-
-(cl-defmethod gh-url-callback-run ((cb gh-url-callback) resp)
- nil)
-
-(cl-defmethod gh-url-response-run-callbacks ((resp gh-url-response))
- (let ((copy-list (lambda (list)
- (if (consp list)
- (let ((res nil))
- (while (consp list) (push (pop list) res))
- (prog1 (nreverse res) (setcdr res list)))
- (car list)))))
- (let ((data (oref resp :data)))
- (dolist (cb (funcall copy-list (oref resp :callbacks)))
- (cond ((and (object-p cb)
- (object-of-class-p cb 'gh-url-callback))
- (gh-url-callback-run cb resp))
- ((or (functionp cb) (symbolp cb))
- (funcall cb data))
- (t (apply (car cb) data (cdr cb))))
- (object-remove-from-list resp :callbacks cb))))
- resp)
-
-(cl-defmethod gh-url-add-response-callback ((resp gh-url-response) callback)
- (object-add-to-list resp :callbacks callback t)
- (if (oref resp :data-received)
- (gh-url-response-run-callbacks resp)
- resp))
-
-;;; code borrowed from nicferrier's web.el
-(defun gh-url-parse-headers (data)
- (let* ((headers nil)
- (header-lines (split-string data "\n"))
- (status-line (car header-lines)))
- (when (string-match
- "HTTP/\\([0-9.]+\\) \\([0-9]\\{3\\}\\)\\( \\(.*\\)\\)*"
- status-line)
- (push (cons 'status-version (match-string 1 status-line)) headers)
- (push (cons 'status-code (match-string 2 status-line)) headers)
- (push (cons 'status-string
- (or (match-string 4 status-line) ""))
- headers))
- (cl-loop for line in (cdr header-lines)
- if (string-match
- "^\\([A-Za-z0-9.-]+\\):[ ]*\\(.*\\)"
- line)
- do
- (let ((name (match-string 1 line))
- (value (match-string 2 line)))
- (push (cons name value) headers)))
- headers))
-
-(cl-defmethod gh-url-response-finalize ((resp gh-url-response))
- (when (oref resp :data-received)
- (gh-url-response-run-callbacks resp)))
-
-(cl-defmethod gh-url-response-init ((resp gh-url-response)
- buffer)
- (declare (special url-http-end-of-headers))
- (unwind-protect
- (with-current-buffer buffer
- (let ((headers (gh-url-parse-headers
- (buffer-substring
- (point-min) (1+ url-http-end-of-headers)))))
- (oset resp :headers headers)
- (oset resp :http-status (read (cdr (assoc 'status-code headers)))))
- (goto-char (1+ url-http-end-of-headers))
- (let ((raw (buffer-substring (point) (point-max))))
- (gh-url-response-set-data resp raw)))
- (kill-buffer buffer))
- (gh-url-response-finalize resp)
- resp)
-
-(defun gh-url-set-response (status req-resp)
- (set-buffer-multibyte t)
- (cl-destructuring-bind (req resp) req-resp
- (let ((responses-req (clone req))
- (num (oref req :num-retries)))
- (oset resp :-req responses-req)
- (if (or (null num) (zerop num))
- (gh-url-response-init resp (current-buffer))
- (condition-case err
- (gh-url-response-init resp (current-buffer))
- (error
- (oset req :num-retries (1- num))
- (gh-url-run-request req resp)))))))
-
-(defun gh-url-form-encode (form)
- (mapconcat (lambda (x) (format "%s=%s" (car x) (cdr x)))
- form "&"))
-
-(defun gh-url-params-encode (form)
- (concat "?" (gh-url-form-encode form)))
-
-(cl-defmethod gh-url-run-request ((req gh-url-request) &optional resp)
- (let ((url-registered-auth-schemes
- '(("basic" ignore . 4))) ;; don't let default handlers kick in
- (url-privacy-level 'high)
- (url-user-agent (format "User-Agent: URL/%s\r\n"
- url-version))
- (url-request-method (oref req :method))
- (url-request-data (oref req :data))
- (url-request-extra-headers (oref req :headers))
- (url (concat (oref req :url)
- (let ((params (oref req :query)))
- (if params
- (gh-url-params-encode params)
- "")))))
- (if (oref req :async)
- (let* ((resp (or resp (make-instance (oref req default-response-cls))))
- (req-resp (list req resp)))
- (with-current-buffer
- (url-retrieve url 'gh-url-set-response (list req-resp))
- (set (make-local-variable 'url-registered-auth-schemes)
- url-registered-auth-schemes)))
- (let* ((resp (or resp (make-instance (oref req default-response-cls))))
- (req-resp (list req resp)))
- (with-current-buffer (url-retrieve-synchronously url)
- (gh-url-set-response nil req-resp)))))
- (mapc (lambda (cb)
- (gh-url-add-response-callback resp cb))
- (oref req :install-callbacks))
- resp)
-
-(provide 'gh-url)
-;;; gh-url.el ends here
+++ /dev/null
-;;; gh-users.el --- users module for gh.el -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2013 Yann Hodique
-
-;; Author: Yann Hodique <yann.hodiqueNOSPAMgmail.com>
-;; Keywords:
-
-;; This file 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 2, or (at your option)
-;; any later version.
-
-;; This file 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 GNU Emacs; see the file COPYING. If not, write to
-;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
-
-;;; Commentary:
-
-;;
-
-;;; Code:
-
-(require 'eieio)
-
-(require 'gh-api)
-(require 'gh-auth)
-(require 'gh-common)
-
-(defclass gh-users-api (gh-api-v3)
- ((users-cls :allocation :class :initform gh-users-user))
- "Users API")
-
-(gh-defclass gh-users-user (gh-user)
- ((gravatar-id :initarg :gravatar-id)
- (html-url :initarg :html-url)
- (followers-url :initarg :followers-url)
- (following-url :initarg :following-url)
- (gists-url :initarg :gists-url)
- (starred-url :initarg :starred-url)
- (subscriptions-url :initarg :subscriptions-url)
- (organizations-url :initarg :organizations-url)
- (repos-url :initarg :repos-url)
- (events-url :initarg :events-url)
- (received-events-url :initarg :received-events-url)
- (type :initarg :type)
- (site-admin :initarg :site-admin)
- (name :initarg :name)
- (company :initarg :company)
- (blog :initarg :blog)
- (location :initarg :location)
- (email :initarg :email)
- (hireable :initarg :hireable)
- (bio :initarg :bio)
- (public-repos :initarg :public-repos)
- (public-gists :initarg :public-gists)
- (followers :initarg :followers)
- (following :initarg :following)
- (created-at :initarg :created-at)
- (update-at :initarg :update-at)))
-
-(cl-defmethod gh-users-get ((api gh-users-api) &optional username)
- (gh-api-authenticated-request
- api (gh-object-reader (oref api users-cls)) "GET"
- (if username
- (format "/users/%s" username)
- "/user")))
-
-(cl-defmethod gh-users-list ((api gh-users-api))
- (gh-api-authenticated-request
- api (gh-object-list-reader (oref api users-cls)) "GET"
- "/users"))
-
-(provide 'gh-users)
-;;; gh-users.el ends here
+++ /dev/null
-;;; gh.el --- Github API client libraries -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2011 Yann Hodique
-
-;; Author: Yann Hodique <yhodiqueNOSPAMgmail.com>
-;; Keywords:
-;; Homepage: https://github.com/sigma/gh.el
-
-;; This file 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 2, or (at your option)
-;; any later version.
-
-;; This file 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 GNU Emacs; see the file COPYING. If not, write to
-;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
-
-;;; Commentary:
-
-;;
-
-;;; Code:
-
-(require 'gh-gist)
-(require 'gh-pulls)
-(require 'gh-issues)
-(require 'gh-users)
-
-(provide 'gh)
-;;; gh.el ends here
-
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
--- /dev/null
+;;; gh-api.el --- api definition for gh.el -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2011 Yann Hodique
+
+;; Author: Yann Hodique <yann.hodiqueNOSPAMgmail.com>
+;; Keywords:
+
+;; This file 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 2, or (at your option)
+;; any later version.
+
+;; This file 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 GNU Emacs; see the file COPYING. If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'eieio)
+
+(require 'json)
+
+(require 'gh-profile)
+(require 'gh-url)
+(require 'gh-auth)
+(require 'gh-cache)
+
+(require 'logito)
+
+(defgroup gh-api nil
+ "Github API."
+ :group 'gh)
+
+(defcustom gh-api-username-filter 'gh-api-enterprise-username-filter
+ "Filter to apply to usernames to build URL components"
+ :type 'function
+ :group 'gh-api)
+
+(defclass gh-api ()
+ ((sync :initarg :sync :initform t)
+ (cache :initarg :cache :initform nil)
+ (base :initarg :base :type string)
+ (profile :initarg :profile :type string)
+ (auth :initarg :auth :initform nil)
+ (data-format :initarg :data-format)
+ (num-retries :initarg :num-retries :initform 0)
+ (log :initarg :log :initform nil)
+ (cache-cls :initform gh-cache :allocation :class))
+ "Github API")
+
+(cl-defmethod logito-log ((api gh-api) level tag string &rest objects)
+ (apply 'logito-log (oref api :log) level tag string objects))
+
+(cl-defmethod initialize-instance ((api gh-api) &rest args)
+ (cl-call-next-method))
+
+(cl-defmethod gh-api-set-default-auth ((api gh-api) auth)
+ (let ((auth (or (oref api :auth) auth))
+ (cache (oref api :cache))
+ (classname (symbol-name (funcall (if (fboundp 'eieio-object-class)
+ 'eieio-object-class
+ 'object-class)
+ api))))
+ (oset api :auth auth)
+ (unless (or (null cache)
+ (and (eieio-object-p cache)
+ (object-of-class-p cache 'gh-cache)))
+ (oset api :cache (make-instance
+ (oref api cache-cls)
+ :object-name
+ (format "gh/%s/%s"
+ classname
+ (gh-api-get-username api)))))))
+
+(cl-defmethod gh-api-expand-resource ((api gh-api)
+ resource)
+ resource)
+
+(defun gh-api-enterprise-username-filter (username)
+ (replace-regexp-in-string (regexp-quote ".") "-" username))
+
+(cl-defmethod gh-api-get-username ((api gh-api))
+ (let ((username (oref (oref api :auth) :username)))
+ (funcall gh-api-username-filter username)))
+
+(defclass gh-api-v3 (gh-api)
+ ((data-format :initarg :data-format :initform :json))
+ "Github API v3")
+
+(defcustom gh-api-v3-authenticator 'gh-oauth-authenticator
+ "Authenticator for Github API v3"
+ :type '(choice (const :tag "Password" gh-password-authenticator)
+ (const :tag "OAuth" gh-oauth-authenticator))
+ :group 'gh-api)
+
+(cl-defmethod initialize-instance ((api gh-api-v3) &rest args)
+ (cl-call-next-method)
+ (let ((gh-profile-current-profile (gh-profile-current-profile)))
+ (oset api :profile (gh-profile-current-profile))
+ (oset api :base (gh-profile-url))
+ (gh-api-set-default-auth api
+ (or (oref api :auth)
+ (funcall gh-api-v3-authenticator "auth")))))
+
+(defclass gh-api-request (gh-url-request)
+ ((default-response-cls :allocation :class :initform gh-api-response)))
+
+(defclass gh-api-response (gh-url-response)
+ ())
+
+(defun gh-api-json-decode (repr)
+ (if (or (null repr) (string= repr ""))
+ 'empty
+ (let ((json-array-type 'list))
+ (json-read-from-string repr))))
+
+(defun gh-api-json-encode (json)
+ (encode-coding-string (json-encode-list json) 'utf-8))
+
+(cl-defmethod gh-url-response-set-data ((resp gh-api-response) data)
+ (cl-call-next-method resp (gh-api-json-decode data)))
+
+(defclass gh-api-paged-request (gh-api-request)
+ ((default-response-cls :allocation :class :initform gh-api-paged-response)
+ (page-limit :initarg :page-limit :initform -1)))
+
+(defclass gh-api-paged-response (gh-api-response)
+ ())
+
+(cl-defmethod gh-api-paging-links ((resp gh-api-paged-response))
+ (let ((links-header (cdr (assoc "Link" (oref resp :headers)))))
+ (when links-header
+ (cl-loop for item in (split-string links-header ", ")
+ when (string-match "^<\\(.*\\)>; rel=\"\\(.*\\)\"" item)
+ collect (cons (match-string 2 item)
+ (match-string 1 item))))))
+
+(cl-defmethod gh-url-response-set-data ((resp gh-api-paged-response) data)
+ (let ((previous-data (oref resp :data))
+ (next (cdr (assoc "next" (gh-api-paging-links resp)))))
+ (cl-call-next-method)
+ (oset resp :data (append previous-data (oref resp :data)))
+ (when (and next (not (equal 304 (oref resp :http-status))))
+ (let* ((req (oref resp :-req))
+ (last-page-limit (oref req :page-limit))
+ (this-page-limit (if (numberp last-page-limit) (- last-page-limit 1) -1)))
+ (oset req :page-limit this-page-limit)
+ (unless (eq (oref req :page-limit) 0)
+ ;; We use an explicit check for 0 since -1 indicates that
+ ;; paging should continue forever.
+ (oset resp :data-received nil)
+ (oset req :url next)
+ ;; Params need to be set to nil because the next uri will
+ ;; already have query params. If params are non-nil this will
+ ;; cause another set of params to be added to the end of the
+ ;; string which will override the params that are set in the
+ ;; next link.
+ (oset req :query nil)
+ (gh-url-run-request req resp))))))
+
+(cl-defmethod gh-api-authenticated-request
+ ((api gh-api) transformer method resource &optional data params page-limit)
+ (let* ((fmt (oref api :data-format))
+ (headers (cond ((eq fmt :form)
+ '(("Content-Type" .
+ "application/x-www-form-urlencoded")))
+ ((eq fmt :json)
+ '(("Content-Type" .
+ "application/json")))))
+ (cache (oref api :cache))
+ (key (list resource
+ method
+ (sha1 (format "%s" transformer))))
+ (cache-key (and cache
+ (member method (oref cache safe-methods))
+ key))
+ (has-value (and cache-key (pcache-has cache cache-key)))
+ (value (and has-value (pcache-get cache cache-key)))
+ (is-outdated (and has-value (gh-cache-outdated-p cache cache-key)))
+ (etag (and is-outdated (gh-cache-etag cache cache-key)))
+ (req
+ (and (or (not has-value)
+ is-outdated)
+ (gh-auth-modify-request
+ (oref api :auth)
+ ;; TODO: use gh-api-paged-request only when needed
+ (make-instance 'gh-api-paged-request
+ :method method
+ :url (concat (oref api :base)
+ (gh-api-expand-resource
+ api resource))
+ :query params
+ :headers (if etag
+ (cons (cons "If-None-Match" etag)
+ headers)
+ headers)
+ :data (or (and (eq fmt :json)
+ (gh-api-json-encode data))
+ (and (eq fmt :form)
+ (gh-url-form-encode data))
+ "")
+ :page-limit page-limit)))))
+ (cond ((and has-value ;; got value from cache
+ (not is-outdated))
+ (make-instance 'gh-api-response :data-received t :data value))
+ (cache-key ;; no value, but cache exists and method is safe
+ (let ((resp (make-instance (oref req default-response-cls)
+ :transform transformer)))
+ (gh-url-run-request req resp)
+ (gh-url-add-response-callback
+ resp (make-instance 'gh-api-callback :cache cache :key cache-key
+ :revive etag))
+ resp))
+ (cache ;; unsafe method, cache exists
+ (pcache-invalidate cache key)
+ (gh-url-run-request req (make-instance
+ (oref req default-response-cls)
+ :transform transformer)))
+ (t ;; no cache involved
+ (gh-url-run-request req (make-instance
+ (oref req default-response-cls)
+ :transform transformer))))))
+
+(defclass gh-api-callback (gh-url-callback)
+ ((cache :initarg :cache)
+ (key :initarg :key)
+ (revive :initarg :revive)))
+
+(cl-defmethod gh-url-callback-run ((cb gh-api-callback) resp)
+ (let ((cache (oref cb :cache))
+ (key (oref cb :key)))
+ (if (and (oref cb :revive) (equal (oref resp :http-status) 304))
+ (progn
+ (gh-cache-revive cache key)
+ (oset resp :data (pcache-get cache key)))
+ (pcache-put cache key (oref resp :data))
+ (gh-cache-set-etag cache key
+ (cdr (assoc "ETag" (oref resp :headers)))))))
+
+(define-obsolete-function-alias 'gh-api-add-response-callback
+ 'gh-url-add-response-callback "0.6.0")
+
+(provide 'gh-api)
+;;; gh-api.el ends here
+
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
--- /dev/null
+;;; gh-auth.el --- authentication for gh.el -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2011 Yann Hodique
+
+;; Author: Yann Hodique <yann.hodiqueNOSPAMgmail.com>
+;; Keywords:
+
+;; This file 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 2, or (at your option)
+;; any later version.
+
+;; This file 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 GNU Emacs; see the file COPYING. If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'eieio)
+
+(require 'gh-profile)
+(require 'gh-common)
+(require 'gh-url)
+
+(defgroup gh-auth nil
+ "Github authentication."
+ :group 'gh)
+
+(defvar gh-auth-alist nil)
+
+(defun gh-auth-remember (profile key value)
+ (let ((cell (assoc profile gh-auth-alist)))
+ (when (not cell)
+ (setq cell (cons profile nil))
+ (setq gh-auth-alist (append gh-auth-alist (list cell))))
+ (setcdr cell (plist-put (cdr cell) key value))))
+
+(defun gh-auth-get-username ()
+ (let* ((profile (gh-profile-current-profile))
+ (user (or (plist-get (cdr (assoc profile gh-auth-alist)) :username)
+ (plist-get (cdr (assoc profile gh-profile-alist)) :username)
+ (gh-config "user"))))
+ (when (not user)
+ (setq user (read-string "GitHub username: "))
+ (gh-set-config "user" user))
+ (gh-auth-remember profile :username user)
+ user))
+
+(defun gh-auth-get-password (&optional remember)
+ (let* ((profile (gh-profile-current-profile))
+ (pass (or (plist-get (cdr (assoc profile gh-auth-alist)) :password)
+ (plist-get (cdr (assoc profile gh-profile-alist)) :password)
+ (gh-config "password"))))
+ (when (not pass)
+ (setq pass (read-passwd "GitHub password: "))
+ (when remember
+ (gh-set-config "password" pass)))
+ (when remember
+ (gh-auth-remember profile :password pass))
+ pass))
+
+(declare-function 'gh-oauth-auth-new "gh-oauth")
+
+(defun gh-auth-get-oauth-token ()
+ (let* ((profile (gh-profile-current-profile))
+ (token (or (plist-get (cdr (assoc profile gh-auth-alist)) :token)
+ (plist-get (cdr (assoc profile gh-profile-alist)) :token)
+ (gh-config "oauth-token"))))
+ (when (not token)
+ (let* ((api (make-instance 'gh-oauth-api))
+ (tok (and (fboundp 'gh-oauth-auth-new)
+ (oref (oref (funcall 'gh-oauth-auth-new api
+ '(user repo gist)) :data)
+ :token))))
+ (setq token (or tok (read-string "GitHub OAuth token: ")))
+ (gh-set-config "oauth-token" token)))
+ (when (functionp token) (setq token (funcall token)))
+ (gh-auth-remember profile :token token)
+ token))
+
+(defclass gh-authenticator ()
+ ((username :initarg :username :initform nil))
+ "Abstract authenticator")
+
+(cl-defmethod initialize-instance ((auth gh-authenticator) &rest args)
+ (cl-call-next-method)
+ (or (oref auth :username)
+ (oset auth :username (gh-auth-get-username))))
+
+(cl-defmethod gh-auth-modify-request ((auth gh-authenticator) req)
+ req)
+
+(defclass gh-auth-2fa-callback (gh-url-callback)
+ ((req :initarg :req :initform nil))
+ "2-factor callback")
+
+(cl-defmethod gh-url-callback-run ((cb gh-auth-2fa-callback) resp)
+ (when (equal (oref resp :http-status) 401)
+ (let* ((otp-header "X-GitHub-OTP")
+ (h (assoc otp-header (oref resp :headers))))
+ (when (and h (string-prefix-p "required;" (cdr h)))
+ (let ((otp (read-from-minibuffer "Enter dual-factor auth code: "))
+ (req (oref cb :req)))
+ ;; reset resp
+ (oset resp :data nil)
+ (oset resp :data-received nil)
+
+ (object-add-to-list req :headers
+ (cons otp-header otp))
+ (gh-url-run-request req resp))))))
+
+(defclass gh-password-authenticator (gh-authenticator)
+ ((password :initarg :password :protection :private :initform nil)
+ (remember :allocation :class :initform t)
+
+ (2fa-cls :initform gh-auth-2fa-callback :allocation :class))
+ "Password-based authenticator")
+
+(cl-defmethod initialize-instance ((auth gh-password-authenticator) &rest args)
+ (cl-call-next-method)
+ (or (oref auth :password)
+ (oset auth :password (gh-auth-get-password (oref auth remember)))))
+
+(cl-defmethod gh-auth-modify-request ((auth gh-password-authenticator) req)
+ (object-add-to-list req :headers
+ (cons "Authorization"
+ (concat "Basic "
+ (base64-encode-string
+ (format "%s:%s" (oref auth :username)
+ (encode-coding-string
+ (oref auth :password) 'utf-8))))))
+ (object-add-to-list req :install-callbacks
+ (make-instance (oref auth 2fa-cls) :req req))
+ req)
+
+(defclass gh-oauth-authenticator (gh-authenticator)
+ ((token :initarg :token :protection :private :initform nil))
+ "Oauth-based authenticator")
+
+(cl-defmethod initialize-instance ((auth gh-oauth-authenticator) &rest args)
+ (cl-call-next-method)
+ (or (oref auth :token)
+ (oset auth :token (gh-auth-get-oauth-token))))
+
+(cl-defmethod gh-auth-modify-request ((auth gh-oauth-authenticator) req)
+ (object-add-to-list req :headers
+ (cons "Authorization"
+ (encode-coding-string
+ (format "token %s" (oref auth :token)) 'utf-8)))
+ req)
+
+(provide 'gh-auth)
+;; to avoid circular dependencies...
+(require 'gh-oauth)
+;;; gh-auth.el ends here
+
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
--- /dev/null
+;;; gh-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*-
+;; Generated by the `loaddefs-generate' function.
+
+;; This file is part of GNU Emacs.
+
+;;; Code:
+
+(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path)))
+
+
+\f
+;;; Generated autoloads from gh-api.el
+
+(register-definition-prefixes "gh-api" '("gh-api"))
+
+\f
+;;; Generated autoloads from gh-auth.el
+
+(register-definition-prefixes "gh-auth" '("gh-"))
+
+\f
+;;; Generated autoloads from gh-cache.el
+
+(register-definition-prefixes "gh-cache" '("gh-cache"))
+
+\f
+;;; Generated autoloads from gh-comments.el
+
+(register-definition-prefixes "gh-comments" '("gh-comments-api-mixin"))
+
+\f
+;;; Generated autoloads from gh-common.el
+
+(register-definition-prefixes "gh-common" '("gh-"))
+
+\f
+;;; Generated autoloads from gh-gist.el
+
+(register-definition-prefixes "gh-gist" '("gh-gist-api"))
+
+\f
+;;; Generated autoloads from gh-issues.el
+
+(register-definition-prefixes "gh-issues" '("gh-issues-"))
+
+\f
+;;; Generated autoloads from gh-oauth.el
+
+(register-definition-prefixes "gh-oauth" '("gh-oauth-"))
+
+\f
+;;; Generated autoloads from gh-orgs.el
+
+(register-definition-prefixes "gh-orgs" '("gh-orgs-api"))
+
+\f
+;;; Generated autoloads from gh-profile.el
+
+(register-definition-prefixes "gh-profile" '("gh-profile-"))
+
+\f
+;;; Generated autoloads from gh-pulls.el
+
+(register-definition-prefixes "gh-pulls" '("gh-pulls-"))
+
+\f
+;;; Generated autoloads from gh-repos.el
+
+(register-definition-prefixes "gh-repos" '("gh-repos-api"))
+
+\f
+;;; Generated autoloads from gh-search.el
+
+(register-definition-prefixes "gh-search" '("gh-search-"))
+
+\f
+;;; Generated autoloads from gh-url.el
+
+(register-definition-prefixes "gh-url" '("gh-url-"))
+
+\f
+;;; Generated autoloads from gh-users.el
+
+(register-definition-prefixes "gh-users" '("gh-users-api"))
+\f
+;;; End of scraped data
+
+(provide 'gh-autoloads)
+
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; no-native-compile: t
+;; coding: utf-8-emacs-unix
+;; End:
+
+;;; gh-autoloads.el ends here
--- /dev/null
+;;; gh-cache.el --- caching for gh.el -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2011 Yann Hodique
+
+;; Author: Yann Hodique <yann.hodiqueNOSPAMgmail.com>
+;; Keywords:
+
+;; This file 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 2, or (at your option)
+;; any later version.
+
+;; This file 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 GNU Emacs; see the file COPYING. If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'eieio)
+
+(require 'pcache)
+
+(defconst gh-cache-outdated-expiration-delay (* 60 60 24))
+
+(defconst gh-cache-internal-version-constant 4)
+
+(defconst gh-cache-version-constant
+ (format "%s/gh-%s" pcache-version-constant gh-cache-internal-version-constant))
+
+(defclass gh-cache (pcache-repository)
+ ((version-constant :allocation :class)
+ (entries :initarg :entries :initform (make-hash-table :test 'equal))
+ (safe-methods :allocation :class :initform ("HEAD" "GET" "OPTIONS" "TRACE"))
+ (invalidation-chain :allocation :class :initform nil)
+
+ (entry-cls :initarg :entry-cls :initform gh-cache-entry)))
+
+(oset-default 'gh-cache version-constant gh-cache-version-constant)
+
+(defclass gh-cache-entry (pcache-entry)
+ ((etag :initarg :etag :initform nil)
+ (outdated :initarg :outdated :initform nil)
+ ;; (ttl :initarg :ttl :initform 0)
+ ))
+
+(cl-defmethod pcache-invalidate :after ((cache gh-cache) key)
+ (let ((resource (car key)))
+ (pcache-map cache #'(lambda (k v)
+ (when (equal (car k) resource)
+ (pcache-invalidate cache k))))
+ (dolist (next (oref cache invalidation-chain))
+ (let ((nextresource
+ (replace-regexp-in-string (car next) (cdr next) resource)))
+ (when (not (equal nextresource resource))
+ (pcache-map cache #'(lambda (k v)
+ (when (equal (car k) nextresource)
+ (pcache-invalidate cache k)))))))))
+
+(cl-defmethod pcache-get ((cache gh-cache) key &optional default)
+ (let* ((table (oref cache :entries))
+ (entry (gethash key table)))
+ (if (not entry)
+ default
+ (unless (pcache-entry-valid-p entry)
+ (oset entry :outdated t))
+ (oref entry :value))))
+
+(cl-defmethod pcache-has ((cache pcache-repository) key)
+ (let* ((default (make-symbol ":nil"))
+ (table (oref cache :entries))
+ (entry (gethash key table default)))
+ (not (eq entry default))))
+
+(cl-defmethod pcache-purge-invalid ((cache gh-cache))
+ (let ((table (oref cache :entries)))
+ (maphash #'(lambda (k e)
+ (unless (gh-cache-expired-p e)
+ (remhash k table)))
+ table)
+ (pcache-save cache)))
+
+(cl-defmethod gh-cache-outdated-p ((cache gh-cache) key)
+ (let* ((table (oref cache :entries))
+ (entry (gethash key table)))
+ (and entry
+ (oref entry :outdated))))
+
+(cl-defmethod gh-cache-expired-p ((cache gh-cache) key)
+ (let* ((table (oref cache :entries))
+ (entry (gethash key table)))
+ (and (gh-cache-outdated-p cache key)
+ (not
+ (let ((time (float-time (current-time))))
+ (< time (+ gh-cache-outdated-expiration-delay
+ (oref entry :timestamp))))))))
+
+(cl-defmethod gh-cache-revive ((cache gh-cache) key)
+ (let* ((table (oref cache :entries))
+ (entry (gethash key table)))
+ (and entry
+ (oset entry :outdated nil)
+ (oset entry :timestamp (float-time (current-time)))
+ t)))
+
+(cl-defmethod gh-cache-etag ((cache gh-cache) key)
+ (let* ((table (oref cache :entries))
+ (entry (gethash key table)))
+ (and entry
+ (oref entry :etag))))
+
+(cl-defmethod gh-cache-set-etag ((cache gh-cache) key etag)
+ (let* ((table (oref cache :entries))
+ (entry (gethash key table)))
+ (and entry
+ (oset entry :etag etag))))
+
+(provide 'gh-cache)
+;;; gh-cache.el ends here
+
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
--- /dev/null
+;;; gh-comments.el --- support for comment-enabled APIs -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2014-2015 Yann Hodique
+
+;; Author: Yann Hodique <hodiqueyNOSPAMvmware.com>
+;; Keywords:
+
+;; This file 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 2, or (at your option)
+;; any later version.
+
+;; This file 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 GNU Emacs; see the file COPYING. If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'eieio)
+
+(require 'gh-common)
+(require 'gh-api)
+
+(defclass gh-comments-api-mixin ()
+ ((comment-cls :allocation :class :initform gh-comment))
+ :abstract t)
+
+(cl-defmethod gh-comments-list ((api gh-comments-api-mixin) base)
+ (gh-api-authenticated-request
+ api (gh-object-list-reader (oref api comment-cls)) "GET"
+ (format "%s/comments" (gh-ref-object-base base))))
+
+(cl-defmethod gh-comments-get ((api gh-comments-api-mixin) base comment-id)
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api comment-cls)) "GET"
+ (format "%s/comments/%s" (gh-ref-object-base base) comment-id)))
+
+(cl-defmethod gh-comments-update ((api gh-comments-api-mixin) base comment-id comment)
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api comment-cls)) "PATCH"
+ (format "%s/comments/%s" (gh-ref-object-base base) comment-id)
+ (gh-comment-req-to-update comment)))
+
+(cl-defmethod gh-comments-new ((api gh-comments-api-mixin) base comment)
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api comment-cls)) "POST"
+ (format "%s/comments" (gh-ref-object-base base))
+ (gh-comment-req-to-update comment)))
+
+(cl-defmethod gh-comments-delete ((api gh-comments-api-mixin) base comment-id)
+ (gh-api-authenticated-request
+ api nil "DELETE"
+ (format "%s/comments/%s" (gh-ref-object-base base) comment-id)))
+
+(provide 'gh-comments)
+;;; gh-comments.el ends here
--- /dev/null
+;;; gh-common.el --- common objects for gh.el -*- lexical-binding: t; no-byte-compile: t-*-
+
+;; Copyright (C) 2011 Yann Hodique
+
+;; Author: Yann Hodique <yann.hodiqueNOSPAMgmail.com>
+;; Keywords:
+
+;; This file 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 2, or (at your option)
+;; any later version.
+
+;; This file 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 GNU Emacs; see the file COPYING. If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'eieio)
+(require 'marshal)
+
+(autoload 'gh-profile-current-profile "gh-profile")
+(autoload 'gh-profile-default-profile "gh-profile")
+
+(defgroup gh nil
+ "Github API client libraries."
+ :group 'applications)
+
+(defcustom gh-use-local-git-config nil
+ "If `t' use git configuration from the machine running
+Emacs. This makes a difference when running with TRAMP."
+ :type 'boolean
+ :group 'gh)
+
+;;; Helper functions
+
+(defun gh-read (obj field)
+ (cdr (assoc field obj)))
+
+(defun gh-namespaced-key (key)
+ (let ((profile (gh-profile-current-profile)))
+ (concat "github."
+ (if (string= profile (gh-profile-default-profile))
+ ""
+ (concat profile "."))
+ key)))
+
+(defun gh-config (key)
+ "Returns a GitHub specific value from the global Git config."
+ (let ((strip (lambda (string)
+ (if (> (length string) 0)
+ (substring string 0 (- (length string) 1))))))
+ (funcall strip (gh-command-to-string "config" (gh-namespaced-key key)))))
+
+(defun gh-set-config (key value)
+ "Sets a GitHub specific value to the global Git config."
+ (gh-command-to-string "config" "--global" (gh-namespaced-key key) value))
+
+(defun gh-command-to-string (&rest args)
+ (let ((git (executable-find "git"))
+ (runner (if gh-use-local-git-config
+ 'call-process
+ 'process-file)))
+ (with-output-to-string
+ (apply runner git nil standard-output nil args))))
+
+(defun gh-sanitize-content (content)
+ "Remove all non-unicode characters. This can be used to
+sanitize API calls that need to handle potentially dirty data."
+ (let (res skipped)
+ (mapc (lambda (c)
+ (if (eq 'Cn (get-char-code-property c 'general-category))
+ (setq skipped t)
+ (push c res)))
+ content)
+ (when skipped
+ (warn "Content contained non-unicode characters"))
+ (apply #'string (nreverse res))))
+
+;;; Base classes for common objects
+
+(defun gh-marshal-default-spec (slot)
+ (let ((slot-name (symbol-name slot)))
+ (list (cons 'alist
+ (intern (replace-regexp-in-string "-" "_" slot-name))))))
+
+(defmacro gh-defclass (name superclass slots &rest options-and-doc)
+ `(marshal-defclass ,name ,superclass ,slots ,@options-and-doc
+ :marshal-default-spec gh-marshal-default-spec))
+
+(gh-defclass gh-object ()
+ ())
+
+(cl-defmethod gh-object-read ((cls (subclass gh-object)) data)
+ (let ((target (make-instance cls)))
+ (when data
+ (gh-object-read-into target data))
+ target))
+
+(cl-defmethod gh-object-read ((obj gh-object) data)
+ (when data
+ (gh-object-read-into obj data)))
+
+(cl-defmethod gh-object-reader ((obj gh-object))
+ (apply-partially 'gh-object-read obj))
+
+(cl-defmethod gh-object-reader ((cls (subclass gh-object)))
+ (apply-partially 'gh-object-read cls))
+
+(cl-defmethod gh-object-list-read ((obj gh-object) data)
+ (mapcar (gh-object-reader obj) data))
+
+(cl-defmethod gh-object-list-read ((cls (subclass gh-object)) data)
+ (mapcar (gh-object-reader cls) data))
+
+(cl-defmethod gh-object-list-reader ((obj gh-object))
+ (apply-partially 'gh-object-list-read obj))
+
+(cl-defmethod gh-object-list-reader ((cls (subclass gh-object)))
+ (apply-partially 'gh-object-list-read cls))
+
+(cl-defmethod gh-object-read-into ((obj gh-object) data)
+ (unmarshal obj data 'alist))
+
+(cl-defmethod slot-unbound ((obj gh-object) cls slot-name fn)
+ (if (eq fn 'oref) nil
+ (cl-call-next-method)))
+
+(gh-defclass gh-ref-object (gh-object)
+ ((id :initarg :id)
+ (url :initarg :url)
+ (html-url :initarg :html-url)))
+
+(cl-defmethod gh-ref-object-base ((obj gh-ref-object))
+ (let ((url (oref obj :url)))
+ (concat "/"
+ (mapconcat #'identity
+ (cddr (split-string url "/" t))
+ "/"))))
+
+(cl-defmethod gh-ref-object-base (obj)
+ (if (stringp obj) obj
+ (error "illegal input for `gh-ref-object-base'")))
+
+(gh-defclass gh-user (gh-ref-object)
+ ((login :initarg :login)
+ (gravatar-url :initarg :gravatar-url))
+ "Github user object")
+
+(gh-defclass gh-comment (gh-ref-object)
+ ((body :initarg :body)
+ (user :initarg :user :initform nil :marshal-type gh-user)
+ (created-at :initarg :created_at)
+ (updated-at :initarg :updated_at))
+ "Github comment object")
+
+(cl-defmethod gh-comment-req-to-update ((req gh-comment))
+ `(("body" . ,(oref req :body))))
+
+(provide 'gh-common)
+;;; gh-common.el ends here
+
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
--- /dev/null
+;;; gh-gist.el --- gist module for gh.el -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2011 Yann Hodique
+
+;; Author: Yann Hodique <yann.hodiqueNOSPAMgmail.com>
+;; Keywords:
+
+;; This file 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 2, or (at your option)
+;; any later version.
+
+;; This file 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 GNU Emacs; see the file COPYING. If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'eieio)
+
+(require 'gh-api)
+(require 'gh-auth)
+(require 'gh-common)
+
+(defclass gh-gist-api (gh-api-v3)
+ ((gist-cls :allocation :class :initform gh-gist-gist))
+ "Gist API")
+
+(gh-defclass gh-gist-gist-stub (gh-object)
+ ((files :initarg :files :type list :initform nil :marshal-type (list gh-gist-gist-file))
+ (public :initarg :public :marshal-type bool)
+ (description :initarg :description))
+ "Class for user-created gist objects")
+
+(gh-defclass gh-gist-history-change (gh-object)
+ ((total :initarg :total)
+ (additions :initarg :additions)
+ (deletions :initarg :deletions)))
+
+(gh-defclass gh-gist-history-entry (gh-object)
+ ((user :initarg :user :initform nil :marshal-type gh-user)
+ (version :initarg :version)
+ (committed :initarg :committed :marshal ((alist . committed_at)))
+ (change :initarg :change :marshal ((alist . change_status))
+ :marshal-type gh-gist-history-change)
+ (url :initarg :url)))
+
+(gh-defclass gh-gist-fork-entry (gh-ref-object)
+ ((user :initarg :user :initform nil :marshal-type gh-user)
+ (created :initarg :created :marshal ((alist . created_at)))
+ (updated :initarg :updated :marshal ((alist . updated_at)))))
+
+(gh-defclass gh-gist-gist (gh-ref-object gh-gist-gist-stub)
+ ((date :initarg :date :marshal ((alist . created_at)))
+ (update :initarg :update :marshal ((alist . updated_at)))
+ (push-url :initarg :push-url :marshal ((alist . git_push_url)))
+ (pull-url :initarg :pull-url :marshal ((alist . git_pull_url)))
+ (comments :initarg :comments)
+ (user :initarg :user :initform nil :marshal-type gh-user :marshal ((alist . owner)))
+ (history :initarg :history :initform nil :type list :marshal-type (list gh-gist-history-entry))
+ (forks :initarg :forks :initform nil :type list :marshal-type (list gh-gist-fork-entry)))
+ "Gist object")
+
+(gh-defclass gh-gist-gist-file (gh-object)
+ ((filename :initarg :filename)
+ (size :initarg :size)
+ (url :initarg :url :marshal ((alist . raw_url)))
+ (content :initarg :content)))
+
+(cl-defmethod make-instance ((cls (subclass gh-gist-gist-file)) &rest args)
+ (let ((obj (cl-call-next-method)))
+ (when (oref obj :content)
+ (oset obj :content (gh-sanitize-content (oref obj :content))))
+ obj))
+
+(cl-defmethod gh-gist-gist-to-obj ((gist gh-gist-gist-stub))
+ (let ((files (mapcar #'gh-gist-gist-file-to-obj (oref gist :files))))
+ `(("description" . ,(oref gist :description))
+ ("public" . ,(oref gist :public))
+ ,@(and files (list (cons "files" files))))))
+
+(cl-defmethod gh-gist-gist-has-files ((gist gh-gist-gist-stub))
+ (not (memq nil (mapcar (lambda (f)
+ (oref f :content)) (oref gist :files)))))
+
+(cl-defmethod gh-gist-gist-file-to-obj ((file gh-gist-gist-file))
+ (let* ((filename (oref file :filename))
+ (content (oref file :content))
+ (file (if content
+ `(("filename" . ,filename)
+ ("content" . ,content))
+ nil)))
+ (cons filename file)))
+
+(cl-defmethod gh-gist-list ((api gh-gist-api) &optional username)
+ (gh-api-authenticated-request
+ api (gh-object-list-reader (oref api gist-cls)) "GET"
+ (format "/users/%s/gists" (or username (gh-api-get-username api)))))
+
+(cl-defmethod gh-gist-list-public ((api gh-gist-api))
+ (gh-api-authenticated-request
+ api (gh-object-list-reader (oref api gist-cls)) "GET" "/gists/public"))
+
+(cl-defmethod gh-gist-list-starred ((api gh-gist-api))
+ (gh-api-authenticated-request
+ api (gh-object-list-reader (oref api gist-cls)) "GET" "/gists/starred"))
+
+(cl-defmethod gh-gist-get ((api gh-gist-api) gist-or-id)
+ (let (id transformer)
+ (if (stringp gist-or-id)
+ (setq id gist-or-id
+ transformer (gh-object-reader (oref api gist-cls)))
+ (setq id (oref gist-or-id :id)
+ transformer (gh-object-reader gist-or-id)))
+ (gh-api-authenticated-request
+ api transformer "GET" (format "/gists/%s" id))))
+
+(cl-defmethod gh-gist-new ((api gh-gist-api) gist-stub)
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api gist-cls)) "POST" "/gists"
+ (gh-gist-gist-to-obj gist-stub)))
+
+(cl-defmethod gh-gist-edit ((api gh-gist-api) gist)
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api gist-cls)) "PATCH"
+ (format "/gists/%s"
+ (oref gist :id))
+ (gh-gist-gist-to-obj gist)))
+
+(cl-defmethod gh-gist-set-star ((api gh-gist-api) gist-or-id star)
+ (let ((id (if (stringp gist-or-id) gist-or-id
+ (oref gist-or-id :id))))
+ (gh-api-authenticated-request
+ api 'ignore (if star "PUT" "DELETE")
+ (format "/gists/%s/star" id))))
+
+(cl-defmethod gh-gist-get-star ((api gh-gist-api) gist-or-id)
+ (let ((id (if (stringp gist-or-id) gist-or-id
+ (oref gist-or-id :id))))
+ (gh-api-authenticated-request
+ api 'ignore "GET" (format "/gists/%s/star" id))))
+
+(cl-defmethod gh-gist-fork ((api gh-gist-api) gist-or-id)
+ (let ((id (if (stringp gist-or-id) gist-or-id
+ (oref gist-or-id :id))))
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api gist-cls)) "POST"
+ (format "/gists/%s/forks" id))))
+
+(cl-defmethod gh-gist-delete ((api gh-gist-api) gist-or-id)
+ (let ((id (if (stringp gist-or-id) gist-or-id
+ (oref gist-or-id :id))))
+ (gh-api-authenticated-request
+ api 'ignore "DELETE" (format "/gists/%s" id))))
+
+(provide 'gh-gist)
+;;; gh-gist.el ends here
+
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
--- /dev/null
+;;; gh-issue-comments.el --- issue comments api for github -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2014 Travis Thieman
+
+;; Author: Travis Thieman <travis.thiemanNOSPAMgmail.com>
+;; Keywords:
+
+;; This program 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.
+
+;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; TODOS:
+;; * Support listing all comments in a repository
+
+;; Basic usage:
+
+;; (setf api (gh-issue-comments-api "api" :sync nil :cache nil :num-retries 1))
+;; (setf comments (gh-issue-comments-list api "user" "repo" "issue id"))
+;; (setq my-comment (make-instance 'gh-issue-comments-comment :body "This is great!"))
+;; (gh-issue-comments-new api "user" "repo" "issue id" my-comment)
+
+;;; Code:
+
+(require 'eieio)
+
+(require 'gh-api)
+(require 'gh-auth)
+(require 'gh-common)
+
+(require 'gh-issues)
+
+(let ((ver "1.0.0"))
+ (define-obsolete-function-alias
+ 'gh-issue-comments-api 'gh-issues-api ver)
+ (define-obsolete-function-alias
+ 'gh-issue-comments-comment 'gh-issues-comment ver)
+
+ (define-obsolete-function-alias
+ 'gh-issue-comments-req-to-update 'gh-comment-req-to-update ver)
+
+ (define-obsolete-function-alias
+ 'gh-issue-comments-list 'gh-issues-comments-list ver)
+ (define-obsolete-function-alias
+ 'gh-issue-comments-get 'gh-issues-comments-get ver)
+ (define-obsolete-function-alias
+ 'gh-issue-comments-update 'gh-issues-comments-update ver)
+ (define-obsolete-function-alias
+ 'gh-issue-comments-new 'gh-issues-comments-new ver)
+ (define-obsolete-function-alias
+ 'gh-issue-comments-delete 'gh-issues-comments-delete ver))
+
+(provide 'gh-issue-comments)
+;;; gh-issue-comments.el ends here
+
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
--- /dev/null
+;;; gh-issues.el --- issues api for github -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2014-2015 Yann Hodique
+;; Copyright (C) 2014 Travis Thieman
+;; Copyright (C) 2012 Raimon Grau
+
+;; Author: Raimon Grau <raimonsterNOSPAMgmail.com>
+;; Keywords:
+
+;; This program 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.
+
+;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Basic usage:
+
+;; (setf api (gh-issues-api "api" :sync nil :cache nil :num-retries 1))
+;; (setf issues (gh-issues-issue-list api "user" "repo"))
+;; (last (oref issues data)) ; get one issue
+;; (setq mi (make-instance 'gh-issues-issue :body "issue body" :title "issue title"))
+;; (gh-issues-issue-new api "user" "repo" mi)
+;; (setf comments (gh-issues-comments-list api "user" "repo" "issue id"))
+;; (setq my-comment (make-instance 'gh-issues-comment :body "This is great!"))
+;; (gh-issues-comments-new api "user" "repo" "issue id" my-comment)
+
+;;; Code:
+
+(require 'eieio)
+
+(require 'gh-api)
+(require 'gh-auth)
+(require 'gh-comments)
+(require 'gh-common)
+
+(require 'gh-repos)
+
+(defclass gh-issues-api (gh-api-v3 gh-comments-api-mixin)
+ ((issue-cls :allocation :class :initform gh-issues-issue)
+ (milestone-cls :allocation :class :initform gh-issues-milestone)
+ (label-cls :allocation :class :initform gh-issues-label)
+ (comment-cls :allocation :class :initform gh-issues-comment))
+ "Github Issues api")
+
+(gh-defclass gh-issues-issue (gh-ref-object)
+ ((number :initarg :number)
+ (state :initarg :state)
+ (title :initarg :title)
+ (body :initarg :body)
+ (user :initarg :user :initform nil :marshal-type gh-user)
+ (labels :initarg :labels :initform nil :marshal-type (list gh-issues-label))
+ (assignees :initarg :assignees :initform nil :marshal-type (list gh-user))
+ (assignee :initarg :assignee :initform nil :marshal-type gh-user)
+ (milestone :initarg :milestone :initform nil :marshal-type gh-issues-milestone)
+ (comments :initarg :comments :initform 0)
+ (pull-request :initarg :pull-request :marshal-type gh-issues-pull-request)
+ (closed-at :initarg :closed-at)
+ (created-at :initarg :created-at)
+ (updated-at :initarg :updated-at))
+ "issues request")
+
+(gh-defclass gh-issues-pull-request (gh-object)
+ ((html-url :initarg :html-url)
+ (diff-url :initarg :diff-url)
+ (patch-url :initarg :patch-url)))
+
+(gh-defclass gh-issues-label (gh-ref-object)
+ ((name :initarg :name)
+ (color :initarg :color)))
+
+(cl-defmethod gh-issues-label-req-to-update ((label gh-issues-label))
+ `(("name" . ,(oref label :name))
+ ("color" . ,(oref label :color))))
+
+(gh-defclass gh-issues-milestone (gh-ref-object)
+ ((number :initarg :number)
+ (state :initarg :state)
+ (title :initarg :title)
+ (description :initarg :description)
+ (creator :initarg :creator :initform nil :marshal-type gh-user)
+ (open-issues :initarg :open-issues )
+ (closed-issues :initarg :closed-issues)
+ (created-at :initarg :created-at)
+ (due-on :initarg :due-on))
+ "github milestone")
+
+(gh-defclass gh-issues-comment (gh-comment)
+ ())
+
+(cl-defmethod gh-issues-issue-list ((api gh-issues-api) user repo)
+ (gh-api-authenticated-request
+ api (gh-object-list-reader (oref api issue-cls)) "GET"
+ (format "/repos/%s/%s/issues" user repo)))
+
+(cl-defmethod gh-issues-milestone-list ((api gh-issues-api) user repo)
+ (gh-api-authenticated-request
+ api (gh-object-list-reader (oref api milestone-cls)) "GET"
+ (format "/repos/%s/%s/milestones" user repo)))
+
+(cl-defmethod gh-issues-milestone-get ((api gh-issues-api) user repo id)
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api milestone-cls)) "GET"
+ (format "/repos/%s/%s/milestones/%s" user repo id)))
+
+(cl-defmethod gh-issues-milestone-new ((api gh-issues-api) user repo milestone)
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api milestone-cls)) "POST"
+ (format "/repos/%s/%s/milestones" user repo)
+ (gh-issues-milestone-req-to-update milestone)))
+
+(cl-defmethod gh-issues-milestone-update ((api gh-issues-api) user repo
+ id milestone)
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api milestone-cls)) "PATCH"
+ (format "/repos/%s/%s/milestones/%s" user repo id)
+ (gh-issues-milestone-req-to-update milestone)))
+
+(cl-defmethod gh-issues-milestone-req-to-update ((milestone gh-issues-milestone))
+ (let ((state (oref milestone :state))
+ (description (oref milestone :description))
+ (due-on (oref milestone :due-on))
+ (to-update `(("title" . ,(oref milestone :title)))))
+ (when state (nconc to-update `(("state" . ,state))))
+ (when description (nconc to-update `(("description" . ,description))))
+ (when due-on (nconc to-update `(("due_on" . ,due-on))))
+ to-update))
+
+(cl-defmethod gh-issues-issue-get ((api gh-issues-api) user repo id)
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api issue-cls)) "GET"
+ (format "/repos/%s/%s/issues/%s" user repo id)))
+
+(cl-defmethod gh-issues-issue-req-to-update ((req gh-issues-issue))
+ (let ((assignee (oref req :assignee))
+ ;; (labels (oref req labels))
+ (milestone (oref req :milestone))
+ (to-update `(("title" . ,(oref req :title))
+ ("state" . ,(oref req :state))
+ ("body" . ,(oref req :body)))))
+
+ ;; (when labels (nconc to-update `(("labels" . ,(oref req labels) ))))
+ (when milestone
+ (nconc to-update `(("milestone" . ,(oref milestone :number)))))
+ (when assignee
+ (nconc to-update `(("assignee" . ,(oref assignee :login)))))
+ to-update))
+
+(cl-defmethod gh-issues-issue-update ((api gh-issues-api) user repo id req)
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api issue-cls)) "PATCH"
+ (format "/repos/%s/%s/issues/%s" user repo id)
+ (gh-issues-issue-req-to-update req)))
+
+(cl-defmethod gh-issues-issue-new ((api gh-issues-api) user repo issue)
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api issue-cls)) "POST"
+ (format "/repos/%s/%s/issues" user repo)
+ (gh-issues-issue-req-to-update issue)))
+
+;;; Labels
+
+(cl-defmethod gh-issues-label-get ((api gh-issues-api) user repo name)
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api label-cls)) "GET"
+ (format "/repos/%s/%s/labels/%s" user repo name)))
+
+(cl-defmethod gh-issues-label-list ((api gh-issues-api) user repo)
+ (gh-api-authenticated-request
+ api (gh-object-list-reader (oref api label-cls)) "GET"
+ (format "/repos/%s/%s/labels" user repo )))
+
+(cl-defmethod gh-issues-label-new ((api gh-issues-api) user repo req)
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api label-cls)) "POST"
+ (format "/repos/%s/%s/labels" user repo)
+ (gh-issues-label-req-to-update req)))
+
+(cl-defmethod gh-issues-label-update ((api gh-issues-api) user repo req)
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api label-cls)) "POST"
+ (format "/repos/%s/%s/labels/%s" user repo (oref req :name))
+ (gh-issues-label-req-to-update req)))
+
+(cl-defmethod gh-issues-label-delete ((api gh-issues-api) user repo name)
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api label-cls)) "DELETE"
+ (format "/repos/%s/%s/labels/%s" user repo name)))
+
+
+(cl-defmethod gh-issues-labels-in-issue ((api gh-issues-api) user repo
+ issue-or-issue-id)
+ (let ((issue-id (gh-issues--issue-id issue-or-issue-id)))
+ (gh-api-authenticated-request
+ api (gh-object-list-reader (oref api label-cls)) "GET"
+ (format "/repos/%s/%s/issues/%s/labels" user repo issue-id))))
+
+(cl-defmethod gh-issues-labels-add-to-issue ((api gh-issues-api) user repo
+ issue-or-issue-id labels)
+ (let ((issue-id (gh-issues--issue-id issue-or-issue-id)))
+ (gh-api-authenticated-request
+ api (gh-object-list-reader (oref api label-cls)) "PUT"
+ (format "/repos/%s/%s/issues/%s/labels" user repo issue-id)
+ (mapcar #'gh-issues--label-name labels))))
+
+(cl-defmethod gh-issues-labels-remove-all-from-issue ((api gh-issues-api) user repo
+ issue-or-issue-id )
+ (let ((issue-id (gh-issues--issue-id issue-or-issue-id)))
+ (gh-api-authenticated-request
+ api (lambda (x) x) "DELETE"
+ (format "/repos/%s/%s/issues/%s/labels" user repo issue-id))))
+
+(cl-defmethod gh-issues-labels-in-milestone ((api gh-issues-api) user repo
+ milestone-or-milestone-id)
+ (let ((milestone-id (gh-issues--milestone-id milestone-or-milestone-id)))
+ (gh-api-authenticated-request
+ api (gh-object-list-reader (oref api label-cls)) "GET"
+ (format "/repos/%s/%s/milestones/%s/labels" user repo milestone-id))))
+
+;;; Comments
+
+(cl-defmethod gh-issues-comments-list ((api gh-issues-api) user repo issue-id)
+ (gh-comments-list api (format "/repos/%s/%s/issues/%s" user repo issue-id)))
+
+(cl-defmethod gh-issues-comments-get ((api gh-issues-api) user repo comment-id)
+ (gh-comments-get api (format "/repos/%s/%s/issues" user repo) comment-id))
+
+(cl-defmethod gh-issues-comments-update ((api gh-issues-api)
+ user repo comment-id comment)
+ (gh-comments-update api (format "/repos/%s/%s/issues" user repo)
+ comment-id comment))
+
+(cl-defmethod gh-issues-comments-new ((api gh-issues-api)
+ user repo issue-id comment)
+ (gh-comments-new api (format "/repos/%s/%s/issues/%s" user repo issue-id)
+ comment))
+
+(cl-defmethod gh-issues-comments-delete ((api gh-issues-api) user repo comment-id)
+ (gh-comments-delete api (format "/repos/%s/%s/issues" user repo) comment-id))
+
+;;; helpers
+
+(defun gh-issues--issue-id (issue-or-issue-id)
+ (if (eieio-object-p issue-or-issue-id)
+ (oref issue-or-issue-id :id)
+ issue-or-issue-id))
+
+(defun gh-issues--milestone-id (milestone-or-milestone-id)
+ (if (eieio-object-p milestone-or-milestone-id)
+ (oref milestone-or-milestone-id :id)
+ milestone-or-milestone-id))
+
+(defun gh-issues--label-name (label-or-label-name)
+ (if (eieio-object-p label-or-label-name)
+ (oref label-or-label-name :name)
+ label-or-label-name))
+
+
+(provide 'gh-issues)
+;;; gh-issues.el ends here
+
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
--- /dev/null
+;;; gh-oauth.el --- oauth module for gh.el -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2012 Yann Hodique
+
+;; Author: Yann Hodique <yann.hodiqueNOSPAMgmail.com>
+;; Keywords:
+
+;; This file 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 2, or (at your option)
+;; any later version.
+
+;; This file 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 GNU Emacs; see the file COPYING. If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'eieio)
+
+(require 'gh-api)
+(require 'gh-auth)
+(require 'gh-common)
+
+(defclass gh-oauth-api (gh-api-v3)
+ ((auth-cls :allocation :class :initform gh-oauth-authorization))
+ "OAuth API")
+
+(defclass gh-oauth-password-authenticator (gh-password-authenticator)
+ ((remember :allocation :class :initform nil)))
+
+(cl-defmethod initialize-instance ((api gh-oauth-api) &rest args)
+ ;; force password authentication for this API
+ (let ((gh-api-v3-authenticator 'gh-oauth-password-authenticator))
+ (cl-call-next-method)))
+
+(gh-defclass gh-oauth-authorization (gh-ref-object)
+ ((scopes :initarg :scopes)
+ (token :initarg :token)
+ (app :initarg :app :initform nil :marshal-type gh-oauth-app)
+ (updated-at :initarg :updated-at)
+ (created-at :initarg :created-at)))
+
+(gh-defclass gh-oauth-app (gh-object)
+ ((url :initarg :url)
+ (name :initarg :name)))
+
+(cl-defmethod gh-oauth-auth-list ((api gh-oauth-api))
+ (gh-api-authenticated-request
+ api (gh-object-list-reader (oref api auth-cls)) "GET"
+ (format "/authorizations")))
+
+(cl-defmethod gh-oauth-auth-get ((api gh-oauth-api) id)
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api auth-cls)) "GET"
+ (format "/authorizations/%s" id)))
+
+(cl-defmethod gh-oauth-auth-new ((api gh-oauth-api) &optional scopes)
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api auth-cls)) "POST"
+ (format "/authorizations") (list (cons 'scopes scopes)
+ (cons 'note (format "gh.el - %s"
+ (system-name))))))
+
+(cl-defmethod gh-oauth-auth-update ((api gh-oauth-api) id &optional scopes)
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api auth-cls)) "PATCH"
+ (format "/authorizations/%s" id) (list (cons 'scopes scopes))))
+
+(cl-defmethod gh-oauth-auth-delete ((api gh-oauth-api) id)
+ (gh-api-authenticated-request
+ api nil "DELETE" (format "/authorizations/%s" id)))
+
+(provide 'gh-oauth)
+;;; gh-oauth.el ends here
+
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
--- /dev/null
+;;; gh-org.el --- orgs module for gh.el -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2012 Yann Hodique
+
+;; Author: Yann Hodique <yann.hodiqueNOSPAMgmail.com>
+;; Keywords:
+
+;; This file 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 2, or (at your option)
+;; any later version.
+
+;; This file 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 GNU Emacs; see the file COPYING. If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'eieio)
+
+(require 'gh-api)
+(require 'gh-auth)
+(require 'gh-common)
+
+(defclass gh-orgs-api (gh-api-v3)
+ ((org-cls :allocation :class :initform gh-orgs-org))
+ "Orgs API")
+
+(gh-defclass gh-orgs-org-stub (gh-ref-object)
+ ((login :initarg :login)
+ (avatar-url :initarg :avatar-url)
+ (description :initarg :description)))
+
+(gh-defclass gh-orgs-plan (gh-object)
+ ((name :initarg :name)
+ (space :initarg :space)
+ (private-repos :initarg :private-repos)))
+
+(gh-defclass gh-orgs-org (gh-orgs-org-stub)
+ ((name :initarg :name)
+ (company :initarg :company)
+ (blog :initarg :blog)
+ (location :initarg :location)
+ (email :initarg :email)
+ (public-repos :initarg :public-repos)
+ (public-gists :initarg :public-gists)
+ (followers :initarg :followers)
+ (following :initarg :following)
+ (created-at :initarg :created-at)
+ (type :initarg :type)
+ (total-private-repos :initarg :total-private-repos)
+ (owned-private-repos :initarg :owned-private-repos)
+ (private-gists :initarg :private-gists)
+ (disk-usage :initarg :disk-usage)
+ (collaborators :initarg :collaborators)
+ (billing-email :initarg :billing-email)
+ (plan :initarg :plan :initform nil :marshal-type gh-orgs-plan))
+ "Class for GitHub organizations")
+
+(cl-defmethod gh-orgs-org-to-obj ((org gh-orgs-org))
+ `(,@(when (slot-boundp org :billing-email)
+ (list (cons "billing_email" (oref org :billing-email))))
+ ,@(when (slot-boundp org :blog)
+ (list (cons "blog" (oref org :blog))))
+ ,@(when (slot-boundp org :company)
+ (list (cons "company" (oref org :company))))
+ ,@(when (slot-boundp org :email)
+ (list (cons "email" (oref org :email))))
+ ,@(when (slot-boundp org :location)
+ (list (cons "location" (oref org :location))))
+ ,@(when (slot-boundp org :name)
+ (list (cons "name" (oref org :name))))))
+
+(cl-defmethod gh-orgs-list ((api gh-orgs-api) &optional username)
+ (gh-api-authenticated-request
+ api (gh-object-list-reader (oref api org-cls)) "GET"
+ (format "/users/%s/orgs" (or username (gh-api-get-username api)))))
+
+(cl-defmethod gh-orgs-get ((api gh-orgs-api) org)
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api org-cls)) "GET"
+ (format "/orgs/%s" org)))
+
+(cl-defmethod gh-orgs-update ((api gh-orgs-api) org-obj)
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api org-cls)) "PATCH"
+ (format "/orgs/%s" (oref org-obj :login))
+ (apply 'gh-orgs-org-to-obj org-obj nil)))
+
+(provide 'gh-orgs)
+;;; gh-org.el ends here
+
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
--- /dev/null
+;; -*- no-byte-compile: t; lexical-binding: nil -*-
+(define-package "gh" "20260210.1535"
+ "Github API client libraries."
+ '((emacs "25.1")
+ (pcache "0.4.2")
+ (logito "0.1")
+ (marshal "0.9.0")
+ (cl-lib "0.3"))
+ :url "https://github.com/sigma/gh.el"
+ :commit "b1551245d3404eac6394abaebe1a9e0b2c504235"
+ :revdesc "b1551245d340"
+ :authors '(("Yann Hodique" . "yhodiqueNOSPAMgmail.com"))
+ :maintainers '(("Yann Hodique" . "yhodiqueNOSPAMgmail.com")))
--- /dev/null
+;;; gh-profile.el --- profile support for gh.el -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2013 Yann Hodique
+
+;; Author: Yann Hodique <yann.hodiqueNOSPAMgmail.com>
+;; Keywords:
+
+;; This file 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 2, or (at your option)
+;; any later version.
+
+;; This file 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 GNU Emacs; see the file COPYING. If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'rx)
+(require 'url-parse)
+
+(defgroup gh-profile nil
+ "Github profile."
+ :group 'gh)
+
+(defun gh-profile-remote-regexp (domain)
+ (eval
+ `(rx bol (or ,(concat "git@" domain ":")
+ (and (or "git" "ssh" "http" "https") "://"
+ (* nonl) (? "@") ,domain "/"))
+ (and (group (* nonl)) "/" (group (* nonl))) (? ".git"))))
+
+(defcustom gh-profile-alist `(("github"
+ :url "https://api.github.com"
+ :remote-regexp
+ ,(gh-profile-remote-regexp "github.com")))
+ "List of profiles for Github access. List every Github
+Enterprise server and/or Github accounts you have access
+to here."
+ :type '(alist :key-type string
+ :value-type (plist :key-type (choice (const :url)
+ (const :username)
+ (const :password)
+ (const :token)
+ (const :remote-regexp))
+ :value-type string))
+ :group 'gh-profile)
+
+(defun gh-profile-get-remote-regexp (profile)
+ (let* ((profile-plist (cdr (assoc profile gh-profile-alist)))
+ (regexp (plist-get profile-plist :remote-regexp)))
+ (if regexp
+ regexp
+ ;; try to guess remote format (just use the hostname)
+ (let* ((url (url-generic-parse-url (plist-get profile-plist :url)))
+ (host (url-host url)))
+ (gh-profile-remote-regexp host)))))
+
+(defcustom gh-profile-default-profile "github"
+ "Default profile. This needs to be a key present in
+ `gh-profile-alist'"
+ :type 'string
+ :group 'gh-profile)
+
+(defun gh-profile-default-profile ()
+ gh-profile-default-profile)
+
+(defvar gh-profile-current-profile nil)
+(make-variable-buffer-local 'gh-profile-current-profile)
+
+(defun gh-profile-current-profile ()
+ (or gh-profile-current-profile
+ (gh-profile-default-profile)))
+
+(defun gh-profile-url ()
+ (plist-get (cdr (assoc (gh-profile-current-profile)
+ gh-profile-alist)) :url))
+
+(defun gh-profile-completing-read ()
+ (let ((profiles (mapcar #'car gh-profile-alist)))
+ (if (> (length profiles) 1)
+ (completing-read "Github profile: " profiles nil t nil nil (cl-first profiles))
+ (car profiles))))
+
+(defun gh-profile-get-remote-profile (remote-url)
+ (cl-loop for (id . props) in gh-profile-alist
+ if (string-match (gh-profile-get-remote-regexp id)
+ remote-url)
+ return id))
+
+(provide 'gh-profile)
+;;; gh-profile.el ends here
--- /dev/null
+;;; gh-pull-comments.el --- pull request comments api for github -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2014 Toni Reina
+
+;; Author: Toni Reina <areina0NOSPAMgmail.com>
+;; Keywords:
+
+;; This program 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.
+
+;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; TODOS:
+;; * Support listing all comments in a repository
+
+;; Basic usage:
+
+;; (setf api (gh-pull-comments-api "api" :sync nil :cache nil :num-retries 1))
+;; (setf comments (gh-pull-comments-list api "user" "repo" "pull request id"))
+;; (setq my-comment (make-instance 'gh-pull-comments-comment
+;; :body "This is great!"
+;; :path "README.md"
+;; :position 2
+;; :commit-id "commit sha"))
+;; (gh-pull-comments-new api "user" "repo" "pull request id" my-comment)
+
+;;; Code:
+
+(require 'eieio)
+
+(require 'gh-api)
+(require 'gh-auth)
+(require 'gh-common)
+
+(require 'gh-pulls)
+
+(let ((ver "1.0.0"))
+ (define-obsolete-function-alias
+ 'gh-pull-comments-api 'gh-pulls-api ver)
+ (define-obsolete-function-alias
+ 'gh-pull-comments-comment 'gh-pulls-comment ver)
+
+ (define-obsolete-function-alias
+ 'gh-pull-comments-req-to-update 'gh-comment-req-to-update ver)
+ (define-obsolete-function-alias
+ 'gh-pull-comments-req-to-create 'gh-pulls-comment-req-to-create ver)
+
+ (define-obsolete-function-alias
+ 'gh-pull-comments-list 'gh-pulls-comments-list ver)
+ (define-obsolete-function-alias
+ 'gh-pull-comments-get 'gh-pulls-comments-get ver)
+ (define-obsolete-function-alias
+ 'gh-pull-comments-update 'gh-pulls-comments-update ver)
+ (define-obsolete-function-alias
+ 'gh-pull-comments-new 'gh-pulls-comments-new ver)
+ (define-obsolete-function-alias
+ 'gh-pull-comments-delete 'gh-pulls-comments-delete ver))
+
+(provide 'gh-pull-comments)
+;;; gh-pull-comments.el ends here
+
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
--- /dev/null
+;;; gh-pulls.el --- pull requests module for gh.el -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2011 Yann Hodique
+
+;; Author: Yann Hodique <yann.hodiqueNOSPAMgmail.com>
+;; Keywords:
+
+;; This file 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 2, or (at your option)
+;; any later version.
+
+;; This file 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 GNU Emacs; see the file COPYING. If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'eieio)
+
+(require 'gh-api)
+(require 'gh-auth)
+(require 'gh-comments)
+(require 'gh-common)
+
+(require 'gh-repos)
+
+(defclass gh-pulls-cache (gh-cache)
+ ((invalidation-chain :allocation :class
+ :initform '(("^/repos/.*/.*/pulls$" . "\0")
+ ("^/repos/.*/.*/pulls/.*$" . "\0")))))
+
+(defclass gh-pulls-api (gh-api-v3 gh-comments-api-mixin)
+ ((cache-cls :allocation :class :initform gh-pulls-cache)
+
+ (req-cls :allocation :class :initform gh-pulls-request)
+ (comment-cls :allocation :class :initform gh-pulls-comment))
+ "Git pull requests API")
+
+(gh-defclass gh-pulls-comment (gh-comment)
+ ((path :initarg :path)
+ (diff-hunk :initarg :diff-hunk)
+ (position :initarg :position)
+ (original-position :initarg :original-position)
+ (commit-id :initarg :commit-id)
+ (original-commit-id :initarg :original-commit-id)
+ (in-reply-to :initarg :in-reply-to :initform nil)))
+
+(cl-defmethod gh-pulls-comment-req-to-create ((req gh-pulls-comment))
+ (let ((in-reply-to (oref req in-reply-to))
+ (to-update `(("body" . ,(oref req body)))))
+ (if in-reply-to
+ (nconc to-update `(("in_reply_to" . ,in-reply-to)))
+ (nconc to-update `(("commit_id" . ,(oref req commit-id))
+ ("path" . ,(oref req path))
+ ("position" . ,(oref req position)))))
+ to-update))
+
+(gh-defclass gh-pulls-request-stub (gh-ref-object)
+ ((diff-url :initarg :diff-url)
+ (patch-url :initarg :patch-url)
+ (issue-url :initarg :issue-url)
+ (number :initarg :number)
+ (state :initarg :state)
+ (title :initarg :title)
+ (body :initarg :body)
+ (created-at :initarg :created-at)
+ (updated-at :initarg :updated-at)
+ (closed-at :initarg :closed-at)
+ (merged-at :initarg :merged-at)
+ (head :initarg :head :initform nil :marshal-type gh-repos-ref)
+ (base :initarg :base :initform nil :marshal-type gh-repos-ref)))
+
+(gh-defclass gh-pulls-request (gh-pulls-request-stub)
+ ((merged :initarg :merged)
+ (mergeable :initarg :mergeable)
+ (merged-by :initarg :merged-by)
+ (comments :initarg :comments)
+ (user :initarg :user :initform nil :marshal-type gh-user)
+ (commits :initarg :commits)
+ (additions :initarg :additions)
+ (deletions :initarg :deletions)
+ (changed-files :initarg :changed-files))
+ "Git pull requests API")
+
+(cl-defmethod gh-pulls-req-to-new ((req gh-pulls-request))
+ (let ((head (oref req :head))
+ (base (oref req :base)))
+ `(("title" . ,(oref req :title))
+ ("body" . ,(oref req :body))
+ ("head" . ,(or (oref head :ref) (oref head :sha)))
+ ("base" . ,(or (oref base :ref) (oref base :sha))))))
+
+(cl-defmethod gh-pulls-req-to-update ((req gh-pulls-request-stub))
+ `(("title" . ,(oref req :title))
+ ("body" . ,(oref req :body))
+ ("state" . ,(oref req :state))))
+
+(cl-defmethod gh-pulls-list ((api gh-pulls-api) user repo)
+ (gh-api-authenticated-request
+ api (gh-object-list-reader (oref api req-cls)) "GET"
+ (format "/repos/%s/%s/pulls" user repo)))
+
+(cl-defmethod gh-pulls-get ((api gh-pulls-api) user repo id)
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api req-cls)) "GET"
+ (format "/repos/%s/%s/pulls/%s" user repo id)))
+
+(cl-defmethod gh-pulls-new ((api gh-pulls-api) user repo req)
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api req-cls)) "POST"
+ (format "/repos/%s/%s/pulls" user repo)
+ (gh-pulls-req-to-new req)))
+
+(cl-defmethod gh-pulls-update ((api gh-pulls-api) user repo id req)
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api req-cls)) "PATCH"
+ (format "/repos/%s/%s/pulls/%s" user repo id)
+ (gh-pulls-req-to-update req)))
+
+;;; Comments
+
+(cl-defmethod gh-pulls-comments-list ((api gh-pulls-api) user repo pull-id)
+ (gh-comments-list api (format "/repos/%s/%s/pulls/%s" user repo pull-id)))
+
+(cl-defmethod gh-pulls-comments-get ((api gh-pulls-api) user repo comment-id)
+ (gh-comments-get api (format "/repos/%s/%s/pulls" user repo) comment-id))
+
+(cl-defmethod gh-pulls-comments-update ((api gh-pulls-api)
+ user repo comment-id comment)
+ (gh-comments-update api (format "/repos/%s/%s/pulls" user repo)
+ comment-id (gh-comment-req-to-update comment)))
+
+(cl-defmethod gh-pulls-comments-new ((api gh-pulls-api)
+ user repo pull-id comment)
+ (gh-comments-new api (format "/repos/%s/%s/pulls/%s" user repo pull-id)
+ (gh-pulls-comment-req-to-create comment)))
+
+(cl-defmethod gh-pulls-comments-delete ((api gh-pulls-api) user repo comment-id)
+ (gh-comments-delete api (format "/repos/%s/%s/pulls" user repo) comment-id))
+
+(provide 'gh-pulls)
+;;; gh-pulls.el ends here
+
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
--- /dev/null
+;;; gh-repos.el --- repos module for gh.el -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2011 Yann Hodique
+
+;; Author: Yann Hodique <yann.hodiqueNOSPAMgmail.com>
+;; Keywords:
+
+;; This file 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 2, or (at your option)
+;; any later version.
+
+;; This file 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 GNU Emacs; see the file COPYING. If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'eieio)
+
+(require 'gh-api)
+(require 'gh-auth)
+(require 'gh-common)
+
+(defclass gh-repos-api (gh-api-v3)
+ ((repo-cls :allocation :class :initform gh-repos-repo)
+ (user-cls :allocation :class :initform gh-user))
+ "Repos API")
+
+(gh-defclass gh-repos-repo-stub (gh-object)
+ ((name :initarg :name)
+ (description :initarg :description)
+ (homepage :initarg :homepage)
+ (private :initarg :private))
+ "Class for user-created repository objects")
+
+(gh-defclass gh-repos-repo (gh-ref-object gh-repos-repo-stub)
+ ((clone-url :initarg :clone-url)
+ (git-url :initarg :git-url)
+ (ssh-url :initarg :ssh-url)
+ (svn-url :initarg :svn-url)
+ (mirror-url :initarg :mirror-url)
+ (owner :initarg :owner :initform nil :marshal-type gh-user)
+ (full-name :initarg :full-name)
+ (language :initarg :language)
+ (fork :initarg :fork)
+ (forks :initarg :forks)
+ (forks-count :initarg :forks-count)
+ (watchers :initarg :watchers)
+ (watchers-count :initarg :watchers-count)
+ (stargazers-count :initarg :stargazers-count)
+ (size :initarg :size)
+ (master-branch :initarg :master-branch)
+ (open-issues :initarg :open-issues)
+ (pushed-at :initarg :pushed-at)
+ (created-at :initarg :created-at)
+ (updated-at :initarg :updated-at)
+ (organisation :initarg :organisation :initform nil :marshal-type gh-user)
+ (parent :initarg :parent :marshal-type gh-repos-repo)
+ (source :initarg :source :marshal-type gh-repos-repo)
+ (has-issues :initarg :has-issues)
+ (has-wiki :initarg :has-wiki)
+ (has-downloads :initarg :has-downloads))
+ "Class for GitHub repositories")
+
+(gh-defclass gh-repos-ref (gh-object)
+ ((label :initarg :label)
+ (ref :initarg :ref :initform nil)
+ (sha :initarg :sha :initform nil)
+ (user :initarg :user :initform nil :marshal-type gh-user)
+ (repo :initarg :repo :initform nil :marshal-type gh-repos-repo)))
+
+(cl-defmethod gh-repos-user-list ((api gh-repos-api) &optional username)
+ (gh-api-authenticated-request
+ api (gh-object-list-reader (oref api repo-cls)) "GET"
+ (format "/users/%s/repos" (or username (gh-api-get-username api)))))
+
+(cl-defmethod gh-repos-org-list ((api gh-repos-api) org)
+ (gh-api-authenticated-request
+ api (gh-object-list-reader (oref api repo-cls)) "GET"
+ (format "/orgs/%s/repos" org)))
+
+(cl-defmethod gh-repos-repo-to-obj ((repo gh-repos-repo-stub)
+ &rest caps)
+ (let ((has_issues (plist-member caps :issues))
+ (has_wiki (plist-member caps :wiki))
+ (has_downloads (plist-member caps :downloads)))
+ `(("name" . ,(oref repo :name))
+ ,@(when (slot-boundp repo :homepage)
+ (list (cons "homepage" (oref repo :homepage))))
+ ,@(when (slot-boundp repo :description)
+ (list (cons "description" (oref repo :description))))
+ ,@(when (slot-boundp repo :private)
+ (list (cons "public" (not (oref repo :private)))))
+ ,@(when has_issues
+ (list (cons "has_issues" (plist-get caps :issues))))
+ ,@(when has_wiki
+ (list (cons "has_wiki" (plist-get caps :wiki))))
+ ,@(when has_downloads
+ (list (cons "has_downloads" (plist-get caps :downloads)))))))
+
+(cl-defmethod gh-repos-repo-new ((api gh-repos-api) repo-stub
+ &optional org &rest caps)
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api repo-cls)) "POST"
+ (if org (format "/orgs/%s/repos" org)
+ "/user/repos")
+ (apply 'gh-repos-repo-to-obj repo-stub caps)))
+
+(cl-defmethod gh-repos-repo-get ((api gh-repos-api) repo-id &optional user)
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api repo-cls)) "GET"
+ (format "/repos/%s/%s"
+ (or user (gh-api-get-username api))
+ repo-id)))
+
+(cl-defmethod gh-repos-repo-update ((api gh-repos-api) repo-stub
+ &optional user &rest caps)
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api repo-cls)) "PATCH"
+ (format "/repos/%s/%s"
+ (or user (gh-api-get-username api))
+ (oref repo-stub :name))
+ (apply 'gh-repos-repo-to-obj repo-stub caps)))
+
+(cl-defmethod gh-repos-repo-rename ((api gh-repos-api) repo-stub new-name
+ &optional user)
+ (let ((new-stub (make-instance 'gh-repos-repo-stub :name new-name)))
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api repo-cls)) "PATCH"
+ (format "/repos/%s/%s"
+ (or user (gh-api-get-username api))
+ (oref repo-stub :name))
+ (gh-repos-repo-to-obj new-stub))))
+
+(cl-defmethod gh-repos-repo-delete ((api gh-repos-api) repo-id
+ &optional user)
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api repo-cls)) "DELETE"
+ (format "/repos/%s/%s"
+ (or user (gh-api-get-username api))
+ repo-id)))
+
+;; TODO gh-repos-repo-move
+
+(cl-defmethod gh-repos-repo-contributors ((api gh-repos-api) repo)
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api repo-cls)) "GET"
+ (format "/repos/%s/%s/contributors"
+ (oref (oref repo :owner) :login)
+ (oref repo :name))))
+
+;;; TODO: generate some useful objects with the return values
+
+(cl-defmethod gh-repos-repo-languages ((api gh-repos-api) repo)
+ (gh-api-authenticated-request
+ api nil "GET" (format "/repos/%s/%s/languages"
+ (oref (oref repo :owner) :login)
+ (oref repo :name))))
+
+(cl-defmethod gh-repos-repo-teams ((api gh-repos-api) repo)
+ (gh-api-authenticated-request
+ api nil "GET" (format "/repos/%s/%s/teams"
+ (oref (oref repo :owner) :login)
+ (oref repo :name))))
+
+(cl-defmethod gh-repos-repo-tags ((api gh-repos-api) repo)
+ (gh-api-authenticated-request
+ api nil "GET" (format "/repos/%s/%s/tags"
+ (oref (oref repo :owner) :login)
+ (oref repo :name))))
+
+(cl-defmethod gh-repos-repo-branches ((api gh-repos-api) repo)
+ (gh-api-authenticated-request
+ api nil "GET" (format "/repos/%s/%s/branches"
+ (oref (oref repo :owner) :login)
+ (oref repo :name))))
+
+;;; TODO gh-repos-repo-branch-commits
+
+;;; Collaborators sub-API
+
+(cl-defmethod gh-repos-collaborators-list ((api gh-repos-api) repo)
+ (gh-api-authenticated-request
+ api (gh-object-list-reader (oref api user-cls)) "GET" (format "/repos/%s/%s/collaborators"
+ (oref (oref repo :owner) :login)
+ (oref repo :name))))
+
+(cl-defmethod gh-repos-collaborators-p ((api gh-repos-api) repo user)
+ (eq (oref (gh-api-authenticated-request
+ api nil "GET"
+ (format "/repos/%s/%s/collaborators/%s"
+ (oref (oref repo :owner) :login)
+ (oref repo :name)
+ user))
+ :http-status)
+ 204))
+
+(cl-defmethod gh-repos-collaborators-add ((api gh-repos-api) repo user)
+ (gh-api-authenticated-request
+ api nil "PUT"
+ (format "/repos/%s/%s/collaborators/%s"
+ (oref (oref repo :owner) :login)
+ (oref repo :name)
+ user)))
+
+(cl-defmethod gh-repos-collaborators-delete ((api gh-repos-api) repo user)
+ (gh-api-authenticated-request
+ api nil "DELETE"
+ (format "/repos/%s/%s/collaborators/%s"
+ (oref (oref repo :owner) :login)
+ (oref repo :name)
+ user)))
+
+;;; TODO Comments sub-API
+;;; TODO Commits sub-API
+;;; TODO Contents sub-API
+;;; TODO Downloads sub-API
+
+;;; Forks sub-API
+
+(cl-defmethod gh-repos-forks-list ((api gh-repos-api) repo &optional recursive)
+ (let ((resp (gh-api-authenticated-request
+ api (gh-object-list-reader (oref api repo-cls)) "GET"
+ (format "/repos/%s/%s/forks"
+ (oref (oref repo :owner) :login)
+ (oref repo :name)))))
+ (when recursive
+ (let ((forks (oref resp :data)))
+ (oset resp :data
+ (apply 'nconc forks
+ (mapcar
+ (lambda (f)
+ (oref (gh-repos-forks-list api f t) data))
+ forks)))))
+ resp))
+
+(cl-defmethod gh-repos-fork ((api gh-repos-api) repo &optional org)
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api repo-cls)) "POST"
+ (format "/repos/%s/%s/forks"
+ (oref (oref repo :owner) :login)
+ (oref repo :name))
+ nil (when org `(("org" . ,org)))))
+
+;;; TODO Keys sub-API
+;;; TODO Hooks sub-API
+;;; TODO Merging sub-API
+
+;;; Starring sub-API
+
+(cl-defmethod gh-repos-stargazers ((api gh-repos-api) repo)
+ (gh-api-authenticated-request
+ api (gh-object-list-reader (oref api user-cls)) "GET"
+ (format "/repos/%s/%s/stargazers"
+ (oref (oref repo :owner) :login)
+ (oref repo :name))))
+
+(cl-defmethod gh-repos-starred-list ((api gh-repos-api) &optional username)
+ (gh-api-authenticated-request
+ api (gh-object-list-reader (oref api repo-cls)) "GET"
+ (format "/users/%s/starred" (or username (gh-api-get-username api)))))
+
+(cl-defmethod gh-repos-starred-p ((api gh-repos-api) repo)
+ (eq (oref (gh-api-authenticated-request
+ api nil "GET"
+ (format "/user/starred/%s/%s"
+ (oref (oref repo :owner) :login)
+ (oref repo :name)))
+ :http-status)
+ 204))
+
+(cl-defmethod gh-repos-star ((api gh-repos-api) repo)
+ (gh-api-authenticated-request
+ api nil "PUT"
+ (format "/user/starred/%s/%s"
+ (oref (oref repo :owner) :login)
+ (oref repo :name))))
+
+(cl-defmethod gh-repos-unstar ((api gh-repos-api) repo)
+ (gh-api-authenticated-request
+ api nil "DELETE"
+ (format "/user/starred/%s/%s"
+ (oref (oref repo :owner) :login)
+ (oref repo :name))))
+
+;;; TODO Statuses sub-API
+
+;;; Watching sub-API
+
+(cl-defmethod gh-repos-watchers ((api gh-repos-api) repo)
+ (gh-api-authenticated-request
+ api (gh-object-list-reader (oref api user-cls)) "GET"
+ (format "/repos/%s/%s/subscribers"
+ (oref (oref repo :owner) :login)
+ (oref repo :name))))
+
+(cl-defmethod gh-repos-watched-list ((api gh-repos-api) &optional username)
+ (gh-api-authenticated-request
+ api (gh-object-list-reader (oref api repo-cls)) "GET"
+ (format "/users/%s/subscriptions"
+ (or username (gh-api-get-username api)))))
+
+(cl-defmethod gh-repos-watched-p ((api gh-repos-api) repo)
+ (eq (oref (gh-api-authenticated-request
+ api nil "GET"
+ (format "/user/subscriptions/%s/%s"
+ (oref (oref repo :owner) :login)
+ (oref repo :name)))
+ :http-status)
+ 204))
+
+(cl-defmethod gh-repos-watch ((api gh-repos-api) repo)
+ (gh-api-authenticated-request
+ api nil "PUT"
+ (format "/user/subscriptions/%s/%s"
+ (oref (oref repo :owner) :login)
+ (oref repo :name))))
+
+(cl-defmethod gh-repos-unwatch ((api gh-repos-api) repo)
+ (gh-api-authenticated-request
+ api nil "DELETE"
+ (format "/user/subscriptions/%s/%s"
+ (oref (oref repo :owner) :login)
+ (oref repo :name))))
+
+(provide 'gh-repos)
+;;; gh-repos.el ends here
+
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
--- /dev/null
+;;; gh-search.el --- repository search for gh.el -*- lexical-binding: t; -*-
+;; Copyright (C) 2016 Ivan Malison
+
+;; Author: Ivan Malison <IvanMalisonNOSPAMgmail.com>
+
+;; This program 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.
+
+;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'gh-users)
+(require 'gh-repos)
+
+(defclass gh-search-api (gh-api-v3)
+ ((repo-cls :allocation :class :initform gh-repos-repo)
+ (user-cls :allocation :class :initform gh-users-user)))
+
+(defmacro gh-search-method-builder (method-name uri process-result-function)
+ `(cl-defmethod ,method-name ((search-api gh-search-api)
+ query-string &optional page-limit
+ &rest additional-arguments)
+ (unless (and (stringp query-string) (> (length query-string) 1))
+ (error "a non-empty query string must be provided to github search"))
+ (gh-api-authenticated-request
+ search-api
+ (apply-partially (quote ,process-result-function) search-api)
+ "GET" ,uri nil
+ `((q . ,query-string) ,@additional-arguments) page-limit)))
+
+(defmacro gh-search-process-method-builder (method-name class-symbol)
+ `(cl-defmethod ,method-name ((search-api gh-search-api) data)
+ (unless (listp data)
+ (error "Did not recieve a list from the search query"))
+ (let ((items (assoc 'items data)))
+ (unless items
+ (error "Search query did not return items"))
+ (gh-object-list-read (oref search-api ,class-symbol) (cdr items)))))
+
+(gh-search-process-method-builder gh-process-repo-search-result repo-cls)
+(gh-search-process-method-builder gh-process-user-search-result user-cls)
+(gh-search-method-builder gh-search-repos "/search/repositories"
+ gh-process-repo-search-result)
+(gh-search-method-builder gh-search-users "/search/users"
+ gh-process-user-search-result)
+
+(provide 'gh-search)
+;;; gh-search.el ends here
--- /dev/null
+;;; gh-url.el --- url wrapper for gh.el -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2012 Yann Hodique
+
+;; Author: Yann Hodique <yann.hodiqueNOSPAMgmail.com>
+;; Keywords:
+
+;; This file 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 2, or (at your option)
+;; any later version.
+
+;; This file 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 GNU Emacs; see the file COPYING. If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'eieio)
+
+(require 'url-http)
+
+(defclass gh-url-request ()
+ ((method :initarg :method :type string)
+ (url :initarg :url :type string)
+ (query :initarg :query :initform nil)
+ (headers :initarg :headers :initform nil)
+ (data :initarg :data :initform "" :type string)
+ (async :initarg :async :initform nil)
+ (num-retries :initarg :num-retries :initform 0)
+ (install-callbacks :initarg :install-callbacks :initform nil)
+
+ (default-response-cls :allocation :class :initform gh-url-response)))
+
+(defclass gh-url-response ()
+ ((data-received :initarg :data-received :initform nil)
+ (data :initarg :data :initform nil)
+ (headers :initarg :headers :initform nil)
+ (http-status :initarg :http-status :initform nil)
+ (callbacks :initarg :callbacks :initform nil)
+ (transform :initarg :transform :initform nil)
+ (-req :initarg :-req :initform nil)))
+
+(cl-defmethod gh-url-response-set-data ((resp gh-url-response) data)
+ (let ((transform (oref resp :transform)))
+ (oset resp :data
+ (if transform
+ (funcall transform data)
+ data))
+ (oset resp :data-received t)))
+
+(defclass gh-url-callback ()
+ nil)
+
+(cl-defmethod gh-url-callback-run ((cb gh-url-callback) resp)
+ nil)
+
+(cl-defmethod gh-url-response-run-callbacks ((resp gh-url-response))
+ (let ((copy-list (lambda (list)
+ (if (consp list)
+ (let ((res nil))
+ (while (consp list) (push (pop list) res))
+ (prog1 (nreverse res) (setcdr res list)))
+ (car list)))))
+ (let ((data (oref resp :data)))
+ (dolist (cb (funcall copy-list (oref resp :callbacks)))
+ (cond ((and (object-p cb)
+ (object-of-class-p cb 'gh-url-callback))
+ (gh-url-callback-run cb resp))
+ ((or (functionp cb) (symbolp cb))
+ (funcall cb data))
+ (t (apply (car cb) data (cdr cb))))
+ (object-remove-from-list resp :callbacks cb))))
+ resp)
+
+(cl-defmethod gh-url-add-response-callback ((resp gh-url-response) callback)
+ (object-add-to-list resp :callbacks callback t)
+ (if (oref resp :data-received)
+ (gh-url-response-run-callbacks resp)
+ resp))
+
+;;; code borrowed from nicferrier's web.el
+(defun gh-url-parse-headers (data)
+ (let* ((headers nil)
+ (header-lines (split-string data "\n"))
+ (status-line (car header-lines)))
+ (when (string-match
+ "HTTP/\\([0-9.]+\\) \\([0-9]\\{3\\}\\)\\( \\(.*\\)\\)*"
+ status-line)
+ (push (cons 'status-version (match-string 1 status-line)) headers)
+ (push (cons 'status-code (match-string 2 status-line)) headers)
+ (push (cons 'status-string
+ (or (match-string 4 status-line) ""))
+ headers))
+ (cl-loop for line in (cdr header-lines)
+ if (string-match
+ "^\\([A-Za-z0-9.-]+\\):[ ]*\\(.*\\)"
+ line)
+ do
+ (let ((name (match-string 1 line))
+ (value (match-string 2 line)))
+ (push (cons name value) headers)))
+ headers))
+
+(cl-defmethod gh-url-response-finalize ((resp gh-url-response))
+ (when (oref resp :data-received)
+ (gh-url-response-run-callbacks resp)))
+
+(cl-defmethod gh-url-response-init ((resp gh-url-response)
+ buffer)
+ (declare (special url-http-end-of-headers))
+ (unwind-protect
+ (with-current-buffer buffer
+ (let ((headers (gh-url-parse-headers
+ (buffer-substring
+ (point-min) (1+ url-http-end-of-headers)))))
+ (oset resp :headers headers)
+ (oset resp :http-status (read (cdr (assoc 'status-code headers)))))
+ (goto-char (1+ url-http-end-of-headers))
+ (let ((raw (buffer-substring (point) (point-max))))
+ (gh-url-response-set-data resp raw)))
+ (kill-buffer buffer))
+ (gh-url-response-finalize resp)
+ resp)
+
+(defun gh-url-set-response (status req-resp)
+ (set-buffer-multibyte t)
+ (cl-destructuring-bind (req resp) req-resp
+ (let ((responses-req (clone req))
+ (num (oref req :num-retries)))
+ (oset resp :-req responses-req)
+ (if (or (null num) (zerop num))
+ (gh-url-response-init resp (current-buffer))
+ (condition-case err
+ (gh-url-response-init resp (current-buffer))
+ (error
+ (oset req :num-retries (1- num))
+ (gh-url-run-request req resp)))))))
+
+(defun gh-url-form-encode (form)
+ (mapconcat (lambda (x) (format "%s=%s" (car x) (cdr x)))
+ form "&"))
+
+(defun gh-url-params-encode (form)
+ (concat "?" (gh-url-form-encode form)))
+
+(cl-defmethod gh-url-run-request ((req gh-url-request) &optional resp)
+ (let ((url-registered-auth-schemes
+ '(("basic" ignore . 4))) ;; don't let default handlers kick in
+ (url-privacy-level 'high)
+ (url-user-agent (format "User-Agent: URL/%s\r\n"
+ url-version))
+ (url-request-method (oref req :method))
+ (url-request-data (oref req :data))
+ (url-request-extra-headers (oref req :headers))
+ (url (concat (oref req :url)
+ (let ((params (oref req :query)))
+ (if params
+ (gh-url-params-encode params)
+ "")))))
+ (if (oref req :async)
+ (let* ((resp (or resp (make-instance (oref req default-response-cls))))
+ (req-resp (list req resp)))
+ (with-current-buffer
+ (url-retrieve url 'gh-url-set-response (list req-resp))
+ (set (make-local-variable 'url-registered-auth-schemes)
+ url-registered-auth-schemes)))
+ (let* ((resp (or resp (make-instance (oref req default-response-cls))))
+ (req-resp (list req resp)))
+ (with-current-buffer (url-retrieve-synchronously url)
+ (gh-url-set-response nil req-resp)))))
+ (mapc (lambda (cb)
+ (gh-url-add-response-callback resp cb))
+ (oref req :install-callbacks))
+ resp)
+
+(provide 'gh-url)
+;;; gh-url.el ends here
--- /dev/null
+;;; gh-users.el --- users module for gh.el -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2013 Yann Hodique
+
+;; Author: Yann Hodique <yann.hodiqueNOSPAMgmail.com>
+;; Keywords:
+
+;; This file 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 2, or (at your option)
+;; any later version.
+
+;; This file 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 GNU Emacs; see the file COPYING. If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'eieio)
+
+(require 'gh-api)
+(require 'gh-auth)
+(require 'gh-common)
+
+(defclass gh-users-api (gh-api-v3)
+ ((users-cls :allocation :class :initform gh-users-user))
+ "Users API")
+
+(gh-defclass gh-users-user (gh-user)
+ ((gravatar-id :initarg :gravatar-id)
+ (html-url :initarg :html-url)
+ (followers-url :initarg :followers-url)
+ (following-url :initarg :following-url)
+ (gists-url :initarg :gists-url)
+ (starred-url :initarg :starred-url)
+ (subscriptions-url :initarg :subscriptions-url)
+ (organizations-url :initarg :organizations-url)
+ (repos-url :initarg :repos-url)
+ (events-url :initarg :events-url)
+ (received-events-url :initarg :received-events-url)
+ (type :initarg :type)
+ (site-admin :initarg :site-admin)
+ (name :initarg :name)
+ (company :initarg :company)
+ (blog :initarg :blog)
+ (location :initarg :location)
+ (email :initarg :email)
+ (hireable :initarg :hireable)
+ (bio :initarg :bio)
+ (public-repos :initarg :public-repos)
+ (public-gists :initarg :public-gists)
+ (followers :initarg :followers)
+ (following :initarg :following)
+ (created-at :initarg :created-at)
+ (update-at :initarg :update-at)))
+
+(cl-defmethod gh-users-get ((api gh-users-api) &optional username)
+ (gh-api-authenticated-request
+ api (gh-object-reader (oref api users-cls)) "GET"
+ (if username
+ (format "/users/%s" username)
+ "/user")))
+
+(cl-defmethod gh-users-list ((api gh-users-api))
+ (gh-api-authenticated-request
+ api (gh-object-list-reader (oref api users-cls)) "GET"
+ "/users"))
+
+(provide 'gh-users)
+;;; gh-users.el ends here
--- /dev/null
+;;; gh.el --- Github API client libraries -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2011 Yann Hodique
+
+;; Author: Yann Hodique <yhodiqueNOSPAMgmail.com>
+;; Keywords:
+;; Homepage: https://github.com/sigma/gh.el
+;; Package-Version: 20260210.1535
+;; Package-Revision: b1551245d340
+;; Package-Requires: ((emacs "25.1") (pcache "0.4.2") (logito "0.1") (marshal "0.9.0") (cl-lib "0.3"))
+
+;; This file 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 2, or (at your option)
+;; any later version.
+
+;; This file 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 GNU Emacs; see the file COPYING. If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'gh-gist)
+(require 'gh-pulls)
+(require 'gh-issues)
+(require 'gh-users)
+
+(provide 'gh)
+;;; gh.el ends here
+
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End: