From e7c840447ee850221799eba6fae4db8e5e932622 Mon Sep 17 00:00:00 2001 From: Andreas Gerler Date: Tue, 13 Nov 2018 12:07:06 +0100 Subject: [PATCH] update ghub. Signed-off-by: Andreas Gerler --- elpa/ghub-20180821.1430/ghub-graphql.el | 65 --- elpa/ghub-20180821.1430/ghub-pkg.el | 13 - elpa/ghub-20181110.1845/buck.el | 128 +++++ .../dir | 0 .../ghub-autoloads.el | 31 +- elpa/ghub-20181110.1845/ghub-graphql.el | 442 ++++++++++++++++ elpa/ghub-20181110.1845/ghub-pkg.el | 9 + .../ghub.el | 219 +++++--- .../ghub.info | 479 ++++++++++++++---- .../glab.el | 0 elpa/ghub-20181110.1845/gogs.el | 140 +++++ elpa/ghub-20181110.1845/gtea.el | 140 +++++ 12 files changed, 1438 insertions(+), 228 deletions(-) delete mode 100644 elpa/ghub-20180821.1430/ghub-graphql.el delete mode 100644 elpa/ghub-20180821.1430/ghub-pkg.el create mode 100644 elpa/ghub-20181110.1845/buck.el rename elpa/{ghub-20180821.1430 => ghub-20181110.1845}/dir (100%) rename elpa/{ghub-20180821.1430 => ghub-20181110.1845}/ghub-autoloads.el (66%) create mode 100644 elpa/ghub-20181110.1845/ghub-graphql.el create mode 100644 elpa/ghub-20181110.1845/ghub-pkg.el rename elpa/{ghub-20180821.1430 => ghub-20181110.1845}/ghub.el (80%) rename elpa/{ghub-20180821.1430 => ghub-20181110.1845}/ghub.info (67%) rename elpa/{ghub-20180821.1430 => ghub-20181110.1845}/glab.el (100%) create mode 100644 elpa/ghub-20181110.1845/gogs.el create mode 100644 elpa/ghub-20181110.1845/gtea.el diff --git a/elpa/ghub-20180821.1430/ghub-graphql.el b/elpa/ghub-20180821.1430/ghub-graphql.el deleted file mode 100644 index 8f24fb56..00000000 --- a/elpa/ghub-20180821.1430/ghub-graphql.el +++ /dev/null @@ -1,65 +0,0 @@ -;;; ghub-graphql.el --- access Github API using GrapthQL -*- lexical-binding: t -*- - -;; Copyright (C) 2016-2018 Jonas Bernoulli - -;; Author: Jonas Bernoulli -;; Homepage: https://github.com/magit/ghub - -;; This file is not part of GNU Emacs. - -;; 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 3, 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. - -;; For a copy of the GPL see https://www.gnu.org/licenses/gpl.txt. - -;;; Code: - -(require 'ghub) - -(cl-defun ghub-graphql (graphql &optional variables - &key username auth host - silent - callback errorback value extra) - "Make a GraphQL request using GRAPHQL and VARIABLES. -Return the response as a JSON-like alist. Even if the response -contains `errors', do not raise an error. GRAPHQL is a GraphQL -string. VARIABLES is a JSON-like alist. The other arguments -behave as for `ghub-request' (which see)." - (cl-assert (stringp graphql)) - (cl-assert (not (stringp variables))) - (ghub-request "POST" "/graphql" nil :payload - (json-encode `(("query" . ,graphql) - ,@(and variables `(("variables" ,@variables))))) - :silent silent - :username username :auth auth :host host - :callback callback :errorback errorback - :extra extra :value value)) - -(cl-defun ghub-graphql-rate-limit (&key username auth host) - "Return rate limit information." - (let-alist (ghub-graphql - "query { rateLimit { limit cost remaining resetAt }}" - nil :username username :auth auth :host host) - .data.rateLimit)) - -(cl-defun ghub-repository-id (owner name &key username auth host) - "Return the id of the repository specified by OWNER, NAME and HOST." - (let-alist (ghub-graphql - "query ($owner:String!, $name:String!) { - repository(owner:$owner, name:$name) { id } - }" - `((owner . ,owner) - (name . ,name)) - :username username :auth auth :host host) - .data.repository.id)) - -;;; _ -(provide 'ghub-graphql) -;;; ghub-graphql.el ends here diff --git a/elpa/ghub-20180821.1430/ghub-pkg.el b/elpa/ghub-20180821.1430/ghub-pkg.el deleted file mode 100644 index bdb8ea6c..00000000 --- a/elpa/ghub-20180821.1430/ghub-pkg.el +++ /dev/null @@ -1,13 +0,0 @@ -(define-package "ghub" "20180821.1430" "minuscule client library for the Github API" - '((emacs "24.4") - (let-alist "1.0.5")) - :keywords - '("tools") - :authors - '(("Jonas Bernoulli" . "jonas@bernoul.li")) - :maintainer - '("Jonas Bernoulli" . "jonas@bernoul.li") - :url "https://github.com/magit/ghub") -;; Local Variables: -;; no-byte-compile: t -;; End: diff --git a/elpa/ghub-20181110.1845/buck.el b/elpa/ghub-20181110.1845/buck.el new file mode 100644 index 00000000..141ea900 --- /dev/null +++ b/elpa/ghub-20181110.1845/buck.el @@ -0,0 +1,128 @@ +;;; buck.el --- minuscule client library for the Bitbucket API -*- lexical-binding: t -*- + +;; Copyright (C) 2016-2018 Jonas Bernoulli + +;; Author: Jonas Bernoulli +;; Homepage: https://github.com/magit/ghub +;; Keywords: tools + +;; This file is not part of GNU Emacs. + +;; 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 3, 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. + +;; For a copy of the GPL see https://www.gnu.org/licenses/gpl.txt. + +;;; Commentary: + +;; Buck is a library that provides basic support for using the Bitbucket API +;; from Emacs packages. It abstracts access to API resources using only +;; a handful of functions that are not resource-specific. + +;; This library is implemented on top of Ghub. Unlike Ghub, Buck does +;; not support the guided creation of tokens because Bitbucket lacks the +;; features that would be necessary to implement that. Users have to +;; create tokens through the web interface. + +;;; Code: + +(require 'ghub) + +(defconst buck-default-host "api.bitbucket.org/2.0" + "The default host that is used if `buck.host' is not set.") + +;; HEAD and PATCH are not supported according to +;; https://developer.atlassian.com/bitbucket/api/2/reference/meta/uri-uuid + +(cl-defun buck-get (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `GET' request for RESOURCE, with optional query PARAMS. +Like calling `ghub-request' (which see) with \"GET\" as METHOD +and `bitbucket' as FORGE." + (ghub-request "GET" resource params :forge 'bitbucket + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun buck-put (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `PUT' request for RESOURCE, with optional payload PARAMS. +Like calling `ghub-request' (which see) with \"PUT\" as METHOD +and `bitbucket' as FORGE." + (ghub-request "PUT" resource params :forge 'bitbucket + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun buck-post (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `POST' request for RESOURCE, with optional payload PARAMS. +Like calling `ghub-request' (which see) with \"POST\" as METHOD +and `bitbucket' as FORGE." + (ghub-request "POST" resource params :forge 'bitbucket + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun buck-delete (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `DELETE' request for RESOURCE, with optional payload PARAMS. +Like calling `ghub-request' (which see) with \"DELETE\" as METHOD +and `bitbucket' as FORGE." + (ghub-request "DELETE" resource params :forge 'bitbucket + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun buck-request (method resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a request for RESOURCE and return the response body. +Like calling `ghub-request' (which see) with `bitbucket' as FORGE." + (ghub-request method resource params :forge 'bitbucket + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun buck-repository-id (owner name &key username auth host) + "Return the id of the repository specified by OWNER, NAME and HOST." + (substring (cdr (assq 'uuid + (buck-get (format "/repositories/%s/%s" owner name) + nil + :username username :auth auth :host host))) + 1 -1)) + +;;; _ +(provide 'buck) +;;; buck.el ends here diff --git a/elpa/ghub-20180821.1430/dir b/elpa/ghub-20181110.1845/dir similarity index 100% rename from elpa/ghub-20180821.1430/dir rename to elpa/ghub-20181110.1845/dir diff --git a/elpa/ghub-20180821.1430/ghub-autoloads.el b/elpa/ghub-20181110.1845/ghub-autoloads.el similarity index 66% rename from elpa/ghub-20180821.1430/ghub-autoloads.el rename to elpa/ghub-20181110.1845/ghub-autoloads.el index d8d4fbcc..2785cba7 100644 --- a/elpa/ghub-20180821.1430/ghub-autoloads.el +++ b/elpa/ghub-20181110.1845/ghub-autoloads.el @@ -5,6 +5,13 @@ (add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path)))) + +;;;### (autoloads nil "buck" "buck.el" (0 0 0 0)) +;;; Generated autoloads from buck.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "buck" '("buck-default-host"))) + +;;;*** ;;;### (autoloads nil "ghub" "ghub.el" (0 0 0 0)) ;;; Generated autoloads from ghub.el @@ -40,6 +47,13 @@ and call `auth-source-forget+'. (if (fboundp 'register-definition-prefixes) (register-definition-prefixes "ghub" '("auth-source-netrc-parse-next-interesting@save-match-data" "ghub-"))) +;;;*** + +;;;### (autoloads nil "ghub-graphql" "ghub-graphql.el" (0 0 0 0)) +;;; Generated autoloads from ghub-graphql.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "ghub-graphql" '("ghub-"))) + ;;;*** ;;;### (autoloads nil "glab" "glab.el" (0 0 0 0)) @@ -49,8 +63,21 @@ and call `auth-source-forget+'. ;;;*** -;;;### (autoloads nil nil ("ghub-graphql.el" "ghub-pkg.el") (0 0 -;;;;;; 0 0)) +;;;### (autoloads nil "gogs" "gogs.el" (0 0 0 0)) +;;; Generated autoloads from gogs.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "gogs" '("gogs-default-host"))) + +;;;*** + +;;;### (autoloads nil "gtea" "gtea.el" (0 0 0 0)) +;;; Generated autoloads from gtea.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "gtea" '("gtea-default-host"))) + +;;;*** + +;;;### (autoloads nil nil ("ghub-pkg.el") (0 0 0 0)) ;;;*** diff --git a/elpa/ghub-20181110.1845/ghub-graphql.el b/elpa/ghub-20181110.1845/ghub-graphql.el new file mode 100644 index 00000000..0f907cb0 --- /dev/null +++ b/elpa/ghub-20181110.1845/ghub-graphql.el @@ -0,0 +1,442 @@ +;;; ghub-graphql.el --- access Github API using GrapthQL -*- lexical-binding: t -*- + +;; Copyright (C) 2016-2018 Jonas Bernoulli + +;; Author: Jonas Bernoulli +;; Homepage: https://github.com/magit/ghub + +;; This file is not part of GNU Emacs. + +;; 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 3, 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. + +;; For a copy of the GPL see https://www.gnu.org/licenses/gpl.txt. + +;;; Code: + +(require 'dash) +(require 'ghub) +(require 'graphql) +(require 'treepy) + +(eval-when-compile + (require 'subr-x)) + +;;; Api + +(cl-defun ghub-graphql (graphql &optional variables + &key username auth host + silent + callback errorback value extra) + "Make a GraphQL request using GRAPHQL and VARIABLES. +Return the response as a JSON-like alist. Even if the response +contains `errors', do not raise an error. GRAPHQL is a GraphQL +string. VARIABLES is a JSON-like alist. The other arguments +behave as for `ghub-request' (which see)." + (cl-assert (stringp graphql)) + (cl-assert (not (stringp variables))) + (ghub-request "POST" "/graphql" nil :payload + (json-encode `(("query" . ,graphql) + ,@(and variables `(("variables" ,@variables))))) + :silent silent + :username username :auth auth :host host + :callback callback :errorback errorback + :extra extra :value value)) + +(cl-defun ghub-graphql-rate-limit (&key username auth host) + "Return rate limit information." + (let-alist (ghub-graphql + "query { rateLimit { limit cost remaining resetAt }}" + nil :username username :auth auth :host host) + .data.rateLimit)) + +(cl-defun ghub--repository-id (owner name &key username auth host) + "Return the id of the repository specified by OWNER, NAME and HOST." + (let-alist (ghub-graphql + "query ($owner:String!, $name:String!) { + repository(owner:$owner, name:$name) { id } + }" + `((owner . ,owner) + (name . ,name)) + :username username :auth auth :host host) + .data.repository.id)) + +;;; Api (drafts) + +(defconst ghub-fetch-repository + '(query + (repository + [(owner $owner String!) + (name $name String!)] + name + id + createdAt + updatedAt + nameWithOwner + description + (defaultBranchRef name) + isArchived + isFork + isLocked + isMirror + isPrivate + hasIssuesEnabled + hasWikiEnabled + (licenseInfo name) + (stargazers totalCount) + (watchers totalCount) + (assignableUsers [(:edges t)] + id + login + name) + (issues [(:edges t) + (:singular issue number) + (orderBy ((field . UPDATED_AT) (direction . DESC)))] + number + state + (author login) + title + createdAt + updatedAt + closedAt + locked + (milestone id) + body + (assignees [(:edges t)] + id) + (comments [(:edges t)] + databaseId + (author login) + createdAt + updatedAt + body) + (labels [(:edges t)] + id)) + (labels [(:edges t) + (:singular label id)] + id + name + color + description) + (pullRequests [(:edges t) + (:singular pullRequest number) + (orderBy ((field . UPDATED_AT) (direction . DESC)))] + number + state + (author login) + title + createdAt + updatedAt + closedAt + mergedAt + locked + maintainerCanModify + isCrossRepository + (milestone id) + body + (baseRef name + (repository nameWithOwner)) + (headRef name + (repository (owner login) + nameWithOwner)) + (assignees [(:edges t)] + id) + (comments [(:edges t)] + databaseId + (author login) + createdAt + updatedAt + body) + (labels [(:edges t)] + id))))) + +(cl-defun ghub-fetch-repository (owner name callback + &optional until + &key username auth host forge) + "Asynchronously fetch forge data about the specified repository. +Once all data has been collected, CALLBACK is called with the +data as the only argument." + (ghub--graphql-vacuum ghub-fetch-repository + `((owner . ,owner) + (name . ,name)) + callback until + :narrow '(repository) + :username username + :auth auth + :host host + :forge forge)) + +(cl-defun ghub-fetch-issue (owner name number callback + &optional until + &key username auth host forge) + "Asynchronously fetch forge data about the specified issue. +Once all data has been collected, CALLBACK is called with the +data as the only argument." + (ghub--graphql-vacuum (ghub--graphql-prepare-query + ghub-fetch-repository + `(repository issues (issue . ,number))) + `((owner . ,owner) + (name . ,name)) + callback until + :narrow '(repository issue) + :username username + :auth auth + :host host + :forge forge)) + +(cl-defun ghub-fetch-pullreq (owner name number callback + &optional until + &key username auth host forge) + "Asynchronously fetch forge data about the specified pull-request. +Once all data has been collected, CALLBACK is called with the +data as the only argument." + (ghub--graphql-vacuum (ghub--graphql-prepare-query + ghub-fetch-repository + `(repository pullRequests (pullRequest . ,number))) + `((owner . ,owner) + (name . ,name)) + callback until + :narrow '(repository pullRequest) + :username username + :auth auth + :host host + :forge forge)) + +;;; Internal + +(cl-defstruct (ghub--graphql-req + (:include ghub--req) + (:constructor ghub--make-graphql-req) + (:copier nil)) + (query nil :read-only t) + (variables nil :read-only t) + (until nil :read-only t) + (pages 0 :read-only nil)) + +(cl-defun ghub--graphql-vacuum (query variables callback + &optional until + &key narrow username auth host forge) + "Make a GraphQL request using QUERY and VARIABLES. +See Info node `(ghub)GraphQL Support'." + (unless host + (setq host (ghub--host forge))) + (unless (or username (stringp auth) (eq auth 'none)) + (setq username (ghub--username host forge))) + (ghub--graphql-retrieve + (ghub--make-graphql-req + :url (url-generic-parse-url (concat "https://" host "/graphql")) + :method "POST" + :headers (ghub--headers nil host auth username forge) + :handler 'ghub--graphql-handle-response + :query query + :variables variables + :until until + :callback (if narrow + (lambda (data) + (let ((path narrow) key) + (while (setq key (pop path)) + (setq data (cdr (assq key data))))) + (funcall callback data)) + callback)))) + +(cl-defun ghub--graphql-retrieve (req &optional lineage cursor) + (let ((p (cl-incf (ghub--graphql-req-pages req)))) + (when (> p 1) + (message "Fetching page %s..." p))) + (ghub--retrieve + (let ((json-false nil)) + (ghub--encode-payload + `((query . ,(ghub--graphql-encode + (ghub--graphql-prepare-query + (ghub--graphql-req-query req) + lineage cursor))) + (variables . ,(ghub--graphql-req-variables req))))) + req)) + +(defun ghub--graphql-prepare-query (query &optional lineage cursor) + (when lineage + (setq query (ghub--graphql-narrow-query query lineage cursor))) + (let ((loc (ghub--alist-zip query)) + variables) + (cl-block nil + (while t + (let ((node (treepy-node loc))) + (when (vectorp node) + (let ((alist (cl-coerce node 'list)) + vars) + (when (assq :edges alist) + (push (list 'first 100) vars) + (setq loc (treepy-up loc)) + (setq node (treepy-node loc)) + (setq loc (treepy-replace + loc `(,(car node) + ,(cadr node) + (pageInfo endCursor hasNextPage) + (edges (node ,@(cddr node)))))) + (setq loc (treepy-down loc)) + (setq loc (treepy-next loc))) + (dolist (elt alist) + (cond ((keywordp (car elt))) + ((= (length elt) 3) + (push (list (nth 0 elt) + (nth 1 elt)) vars) + (push (list (nth 1 elt) + (nth 2 elt)) variables)) + ((= (length elt) 2) + (push elt vars)))) + (setq loc (treepy-replace loc (cl-coerce vars 'vector)))))) + (if (treepy-end-p loc) + (let ((node (copy-sequence (treepy-node loc)))) + (when variables + (push (cl-coerce variables 'vector) + (cdr node))) + (cl-return node)) + (setq loc (treepy-next loc))))))) + +(defun ghub--graphql-handle-response (status req) + (let ((buffer (current-buffer))) + (unwind-protect + (progn + (set-buffer-multibyte t) + (let* ((headers (ghub--handle-response-headers status req)) + (payload (ghub--handle-response-payload req)) + (payload (ghub--handle-response-error status payload req)) + (err (plist-get status :error)) + (errors (cdr (assq 'errors payload))) + (errors (and errors + (cons 'ghub-graphql-error errors))) + (data (assq 'data payload)) + (value (ghub--req-value req))) + (setf (ghub--req-value req) value) + (if (or err errors) + (if-let ((errorback (ghub--req-errorback req))) + (funcall errorback (or err errors) headers status req) + (ghub--signal-error (or err errors))) + (ghub--graphql-walk-response value data req)))) + (when (buffer-live-p buffer) + (kill-buffer buffer))))) + +(defun ghub--graphql-walk-response (loc data req) + (if (not loc) + (setf (ghub--req-value req) + (setq loc (ghub--alist-zip data))) + (setq data (ghub--graphql-narrow-data data (ghub--graphql-lineage loc))) + (setf (alist-get 'edges data) + (append (alist-get 'edges (treepy-node loc)) + (or (alist-get 'edges data) + (error "BUG: Expected new nodes")))) + (setq loc (treepy-replace loc data))) + (cl-block nil + (while t + (when (eq (car-safe (treepy-node loc)) 'edges) + (setq loc (treepy-up loc)) + (pcase-let ((`(,key . ,val) (treepy-node loc))) + (let-alist val + (let* ((cursor (and .pageInfo.hasNextPage + .pageInfo.endCursor)) + (until (cdr (assq (intern (format "%s-until" key)) + (ghub--graphql-req-until req)))) + (nodes (mapcar #'cdar .edges)) + (nodes (if until + (--take-while + (or (string> (cdr (assq 'updatedAt it)) until) + (setq cursor nil)) + nodes) + nodes))) + (if cursor + (progn + (setf (ghub--req-value req) loc) + (ghub--graphql-retrieve req + (ghub--graphql-lineage loc) + cursor) + (cl-return)) + (setq loc (treepy-replace loc (cons key nodes)))))))) + (if (not (treepy-end-p loc)) + (setq loc (treepy-next loc)) + (funcall (ghub--req-callback req) + (treepy-root loc)) + (cl-return))))) + +(defun ghub--graphql-lineage (loc) + (let (lineage) + (while (treepy-up loc) + (push (car (treepy-node loc)) lineage) + (setq loc (treepy-up loc))) + lineage)) + +(defun ghub--graphql-narrow-data (data lineage) + (let (key) + (while (setq key (pop lineage)) + (if (consp (car lineage)) + (progn (pop lineage) + (setf data (cadr data))) + (setq data (assq key (cdr data)))))) + data) + +(defun ghub--graphql-narrow-query (query lineage cursor) + (if (consp (car lineage)) + (let* ((child (cddr query)) + (alist (cl-coerce (cadr query) 'list)) + (single (cdr (assq :singular alist)))) + `(,(car single) + ,(vector (list (cadr single) (cdr (car lineage)))) + ,@(if (cdr lineage) + (ghub--graphql-narrow-query child (cdr lineage) cursor) + child))) + (let* ((child (or (assq (car lineage) (cdr query)) + (cl-find-if (lambda (c) + (and (listp c) + (vectorp (cadr c)) + (eq (cadr (assq :singular + (cl-coerce (cadr c) + 'list))) + (car lineage)))) + (cdr query)))) + (object (car query)) + (args (and (vectorp (cadr query)) + (cadr query)))) + `(,object + ,@(and args (list args)) + ,(cond ((cdr lineage) + (ghub--graphql-narrow-query child (cdr lineage) cursor)) + (cursor + `(,(car child) + ,(vconcat `((after ,cursor)) + (cadr child)) + ,@(cddr child))) + (t + child)))))) + +(defun ghub--graphql-encode (g) + (if (symbolp g) + (symbol-name g) + (let* ((object (car g)) + (args (and (vectorp (cadr g)) + (cl-coerce (cadr g) 'list))) + (fields (if args (cddr g) (cdr g)))) + (concat + (graphql--encode-object object) + (and args + (format " (\n%s)" + (mapconcat (pcase-lambda (`(,key ,val)) + (graphql--encode-argument key val)) + args ",\n"))) + (and fields + (format " {\n%s\n}" + (mapconcat #'ghub--graphql-encode fields "\n"))))))) + +(defun ghub--alist-zip (root) + (let ((branchp (lambda (elt) (and (listp elt) (listp (cdr elt))))) + (make-node (lambda (_ children) children))) + (treepy-zipper branchp #'identity make-node root))) + +;;; _ +(provide 'ghub-graphql) +;;; ghub-graphql.el ends here diff --git a/elpa/ghub-20181110.1845/ghub-pkg.el b/elpa/ghub-20181110.1845/ghub-pkg.el new file mode 100644 index 00000000..69c8a922 --- /dev/null +++ b/elpa/ghub-20181110.1845/ghub-pkg.el @@ -0,0 +1,9 @@ +(define-package "ghub" "20181110.1845" "Minuscule client libraries for Git forge APIs." + '((emacs "25.1") + (dash "2.14.1") + (graphql "0.1.1") + (let-alist "1.0.5") + (treepy "1.0.0"))) +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/elpa/ghub-20180821.1430/ghub.el b/elpa/ghub-20181110.1845/ghub.el similarity index 80% rename from elpa/ghub-20180821.1430/ghub.el rename to elpa/ghub-20181110.1845/ghub.el index c1f861f6..cde8c87c 100644 --- a/elpa/ghub-20180821.1430/ghub.el +++ b/elpa/ghub-20181110.1845/ghub.el @@ -1,11 +1,10 @@ -;;; ghub.el --- minuscule client library for the Github API -*- lexical-binding: t -*- +;;; ghub.el --- minuscule client libraries for Git forge APIs -*- lexical-binding: t -*- ;; Copyright (C) 2016-2018 Jonas Bernoulli ;; Author: Jonas Bernoulli ;; Homepage: https://github.com/magit/ghub ;; Keywords: tools -;; Package-Requires: ((emacs "24.4") (let-alist "1.0.5")) ;; This file is not part of GNU Emacs. @@ -23,22 +22,30 @@ ;;; Commentary: -;; Ghub is a library that provides basic support for using the Github API -;; from Emacs packages. It abstracts access to API resources using only -;; a handful of functions that are not resource-specific. +;; Ghub provides basic support for using the APIs of various Git forges +;; from Emacs packages. Originally it only supported the Github REST +;; API, but now it also supports the Github GraphQL API as well as the +;; REST APIs of Gitlab, Gitea, Gogs and Bitbucket. -;; Ghub handles the creation, storage and use of access tokens using a -;; setup wizard to make it easier for users to get started and to reduce -;; the support burden imposed on package maintainers. It also comes with -;; a comprehensive manual to address the cases when things don't just -;; work as expected or in case you don't want to use the wizard. +;; Ghub abstracts access to API resources using only a handful of basic +;; functions such as `ghub-get'. These are convenience wrappers around +;; `ghub-request'. Additional forge-specific wrappers like `glab-put', +;; `gtea-put', `gogs-post' and `buck-delete' are also available. Ghub +;; does not provide any resource-specific functions, with the exception +;; of `FORGE-repository-id'. + +;; When accessing Github, then Ghub handles the creation and storage of +;; access tokens using a setup wizard to make it easier for users to get +;; started. The tokens for other forges have to be created manually. ;; Ghub is intentionally limited to only provide these two essential ;; features — basic request functions and guided setup — to avoid being ;; too opinionated, which would hinder wide adoption. It is assumed that ;; wide adoption would make life easier for users and maintainers alike, -;; because then all packages that talk to the Github API could be -;; configured the same way. +;; because then all packages that talk to forge APIs could be configured +;; the same way. + +;; Please consult the manual (info "ghub") for more information. ;;; Code: @@ -50,7 +57,8 @@ (require 'url-auth) (require 'url-http) -(eval-when-compile (require 'subr-x)) +(eval-when-compile + (require 'subr-x)) (defvar url-callback-arguments) (defvar url-http-end-of-headers) @@ -94,6 +102,7 @@ used instead.") (:constructor ghub--make-req) (:copier nil)) (url nil :read-only nil) + (forge nil :read-only t) (silent nil :read-only t) (method nil :read-only t) (headers nil :read-only t) @@ -327,6 +336,7 @@ Both callbacks are called with four arguments. :url (url-generic-parse-url (concat "https://" host resource (and query (concat "?" (ghub--url-encode-params query))))) + :forge forge :silent silent ;; Encode in case caller used (symbol-name 'GET). #35 :method (encode-coding-string method 'utf-8) @@ -350,11 +360,11 @@ already completed. If there is no next page, then return nil. Callbacks are called with four arguments (see `ghub-request'). The forth argument is a `ghub--req' struct, intended to be passed -to this function. A callbacks may use the struct's `extra' slot +to this function. A callback may use the struct's `extra' slot to pass additional information to the callback that will be called after the next request has finished. Use the function `ghub-req-extra' to get and set the value of this slot." - (and (assq 'next (ghub-response-link-relations)) + (and (assq 'next (ghub-response-link-relations req)) (or (ghub--retrieve nil req) t))) (cl-defun ghub-wait (resource &optional duration &key username auth host) @@ -385,16 +395,41 @@ See `ghub-request' for information about the other arguments." (cl-incf total wait)) (sit-for (setq total 2)))))))) -(defun ghub-response-link-relations (&optional headers) +(defun ghub-response-link-relations (req &optional headers payload) "Return an alist of link relations in HEADERS. -If optional HEADERS is nil, then return those -in `ghub-response-headers'." - (let ((rels (cdr (assoc "Link" (or headers ghub-response-headers))))) - (and rels (mapcar (lambda (elt) - (pcase-let ((`(,url ,rel) (split-string elt "; "))) - (cons (intern (substring rel 5 -1)) - (substring url 1 -1)))) - (split-string rels ", "))))) +If optional HEADERS is nil, then return those that were +previously stored in the variable `ghub-response-headers'. + +When accessing a Bitbucket instance then the link relations +are in PAYLOAD instead of HEADERS, making their API merely +RESTish and forcing this function to append those relations +to the value of `ghub-response-headers', for later use when +this function is called with nil for PAYLOAD." + (if (eq (ghub--req-forge req) 'bitbucket) + (if payload + (let* ((page (cl-mapcan (lambda (key) + (when-let ((elt (assq key payload))) + (list elt))) + '(size page pagelen next previous))) + (headers (cons (cons 'link-alist page) headers))) + (if (and req (or (ghub--req-callback req) + (ghub--req-errorback req))) + (setq-local ghub-response-headers headers) + (setq-default ghub-response-headers headers)) + page) + (cdr (assq 'link-alist ghub-response-headers))) + (when-let ((rels (cdr (assoc "Link" (or headers ghub-response-headers))))) + (mapcar (lambda (elt) + (pcase-let ((`(,url ,rel) (split-string elt "; "))) + (cons (intern (substring rel 5 -1)) + (substring url 1 -1)))) + (split-string rels ", "))))) + +(cl-defun ghub-repository-id (owner name &key username auth host forge) + "Return the id of the specified repository." + (let ((fn (intern (format "%s-repository-id" (or forge 'ghub))))) + (funcall (if (eq fn 'ghub-repository-id) 'ghub--repository-id fn) + owner name :username username :auth auth :host host))) ;;;; Internal @@ -433,14 +468,13 @@ in `ghub-response-headers'." (headers (ghub--handle-response-headers status req)) (payload (ghub--handle-response-payload req)) (payload (ghub--handle-response-error status payload req)) - (value (nconc (ghub--req-value req) payload)) + (value (ghub--handle-response-value payload req)) (next (cdr (assq 'next (ghub-response-link-relations - headers))))) + req headers payload))))) (when (numberp unpaginate) (cl-decf unpaginate)) (setf (ghub--req-url req) (url-generic-parse-url next)) - (setf (ghub--req-value req) value) (setf (ghub--req-unpaginate req) unpaginate) (or (and next unpaginate @@ -501,6 +535,14 @@ in `ghub-response-headers'." (signal 'ghub-error data)) (signal symb data)))) +(defun ghub--handle-response-value (payload req) + (setf (ghub--req-value req) + (nconc (ghub--req-value req) + (if-let ((nested (and (eq (ghub--req-forge req) 'bitbucket) + (assq 'values payload)))) + (cdr nested) + payload)))) + (defun ghub--handle-response-payload (req) (funcall (or (ghub--req-reader req) 'ghub--read-json-payload) @@ -634,22 +676,24 @@ and call `auth-source-forget+'." (setq username (ghub--username host forge))) (lambda () (if (eq auth 'basic) - (if (eq forge 'gitlab) - (error "Gitlab does not support basic authentication") - (cons (cons "Authorization" (ghub--basic-auth host username)) - headers)) + (cons (cons "Authorization" (ghub--basic-auth host username)) + headers) (cons (ghub--auth host auth username forge) headers))))) (defun ghub--auth (host auth &optional username forge) (unless username (setq username (ghub--username host))) (if (eq auth 'basic) - (if (eq forge 'gitlab) - (error "Gitlab does not support basic authentication") - (cons "Authorization" (ghub--basic-auth host username))) - (cons (if (eq forge 'gitlab) - "Private-Token" - "Authorization") + (cl-ecase forge + ((nil github gitea gogs bitbucket) + (cons "Authorization" (ghub--basic-auth host username))) + (gitlab + (error "Gitlab does not support basic authentication"))) + (cons (cl-ecase forge + ((nil github gitea gogs bitbucket) + "Authorization") + (gitlab + "Private-Token")) (concat (and (not (eq forge 'gitlab)) "token ") (encode-coding-string @@ -702,27 +746,57 @@ and call `auth-source-forget+'." ;; end for Emacs releases before 26.1. See #24, #64. (auth-source-forget (list :host host :user user :max 1)) (and (not nocreate) - (if (eq forge 'gitlab) - (error - (concat - "Required Gitlab token does not exist. See " - "https://magit.vc/manual/ghub/Gitlab-Support.html " - "for instructions.")) - (ghub--confirm-create-token host username package))))))) + (cl-ecase forge + ((nil github) + (ghub--confirm-create-token host username package)) + ((gitlab gitea gogs bitbucket) + (error "Required %s token (%S for %S) does not exist. +See https://magit.vc/manual/ghub/Support-for-Other-Forges.html for instructions." + (capitalize (symbol-name forge)) + user host)))))))) (if (functionp token) (funcall token) token))) (defun ghub--host (&optional forge) - (if (eq forge 'gitlab) - (or (ignore-errors (car (process-lines "git" "config" "gitlab.host"))) - (bound-and-true-p glab-default-host)) - (or (ignore-errors (car (process-lines "git" "config" "github.host"))) - ghub-default-host))) + (cl-ecase forge + ((nil github) + (or (ignore-errors (car (process-lines "git" "config" "github.host"))) + ghub-default-host)) + (gitlab + (or (ignore-errors (car (process-lines "git" "config" "gitlab.host"))) + (bound-and-true-p glab-default-host))) + (gitea + (or (ignore-errors (car (process-lines "git" "config" "gitea.host"))) + (bound-and-true-p gtea-default-host))) + (gogs + (or (ignore-errors (car (process-lines "git" "config" "gogs.host"))) + (bound-and-true-p gogs-default-host))) + (bitbucket + (or (ignore-errors (car (process-lines "git" "config" "bitbucket.host"))) + (bound-and-true-p buck-default-host))))) (defun ghub--username (host &optional forge) - (let ((var (cond ((string-prefix-p "api.github.com" host) "github.user") - ((string-prefix-p "gitlab.com/api" host) "gitlab.user") - ((eq forge 'gitlab) (format "gitlab.%s.user" host)) - (t (format "github.%s.user" host))))) + (let ((var + (cl-ecase forge + ((nil github) + (if (equal host ghub-default-host) + "github.user" + (format "github.%s.user" host))) + (gitlab + (if (equal host "gitlab.com/api/v4") + "gitlab.user" + (format "gitlab.%s.user" host))) + (bitbucket + (if (equal host "api.bitbucket.org/2.0") + "bitbucket.user" + (format "bitbucket.%s.user" host))) + (gitea + (when (zerop (call-process "git" nil nil nil "config" "gitea.host")) + (error "gitea.host is set but always ignored")) + (format "gitea.%s.user" host)) + (gogs + (when (zerop (call-process "git" nil nil nil "config" "gogs.host")) + (error "gogs.host is set but always ignored")) + (format "gogs.%s.user" host))))) (condition-case nil (car (process-lines "git" "config" var)) (error @@ -783,15 +857,36 @@ WARNING: The token will be stored unencrypted in %S. If you don't want that, you have to abort and customize the `auth-sources' option.\n" (car auth-sources)) "")))) - (progn - (when (ghub--get-token-id host username package) - (if (yes-or-no-p - (format - "A token named %S\nalready exists on Github. Replace it?" - ident)) - (ghub--delete-token host username package) - (user-error "Abort"))) - (ghub-create-token host username package scopes)) + (condition-case ghub--create-token-error + ;; Naively attempt to create the token since the user told us to + (ghub-create-token host username package scopes) + ;; The API _may_ respond with the fact that a token of the name + ;; we wanted already exists. At this point we're out of luck. We + ;; don't have a token (otherwise why would we be here?) and, if + ;; the user is using SMS 2FA, we have no way of telling GitHub + ;; to send a new 2FA code to the user other than sending a POST + ;; to /authorizations which is ugly. + ;; + ;; If they are not using SMS 2FA then we could try to delete the + ;; existing token (which will require them to hand us another + ;; OTP for the delete request) and then call create again, + ;; possibly requiring _another_ OTP if they don't do things fast + ;; enough, but this is only because non-SMS 2FA doesn't require + ;; any action on GitHub's part. + ;; + ;; GitHub does hand us a header that indicates what type of 2FA + ;; is in use, but it's not currently available in this location + ;; and would make the following code which is already quite + ;; complicated even more complicated. So in the interest of + ;; simplicity it's better to error out here and ask the user to + ;; take action. This situation should almost never arise anyway. + (ghub-http-error + (if (string-equal (let-alist (nth 3 ghub--create-token-error) + (car .errors.code)) + "already_exists") + (error "\ +A token named %S already exists on Github. \ +Please visit https://github.com/settings/tokens and delete it." ident)))) (user-error "Abort")))) (defun ghub--get-token-id (host username package) diff --git a/elpa/ghub-20180821.1430/ghub.info b/elpa/ghub-20181110.1845/ghub.info similarity index 67% rename from elpa/ghub-20180821.1430/ghub.info rename to elpa/ghub-20181110.1845/ghub.info index dec230de..d1e1d05b 100644 --- a/elpa/ghub-20180821.1430/ghub.info +++ b/elpa/ghub-20181110.1845/ghub.info @@ -11,6 +11,7 @@ This is ghub.info, produced by makeinfo version 6.5 from ghub.texi. 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. + INFO-DIR-SECTION Emacs START-INFO-DIR-ENTRY * Ghub: (ghub). Minuscule client library for the Github API. @@ -22,24 +23,30 @@ File: ghub.info, Node: Top, Next: Introduction, Up: (dir) Ghub User and Developer Manual ****************************** -Ghub is a library that provides basic support for using the Github API -from Emacs packages. It abstracts access to API resources using only a -handful of functions that are not resource-specific. +Ghub provides basic support for using the APIs of various Git forges +from Emacs packages. Originally it only supported the Github REST API, +but now it also supports the Github GraphQL API as well as the REST APIs +of Gitlab, Gitea, Gogs and Bitbucket. + + Ghub abstracts access to API resources using only a handful of basic +functions such as ‘ghub-get‘. These are convenience wrappers around +‘ghub-request‘. Additional forge-specific wrappers like ‘glab-put‘, +‘gtea-put‘, ‘gogs-post‘ and ‘buck-delete‘ are also available. Ghub does +not provide any resource-specific functions, with the exception of +‘FORGE-repository-id‘. - Ghub handles the creation, storage and use of access tokens using a -setup wizard to make it easier for users to get started and to reduce -the support burden imposed on package maintainers. It also comes with a -comprehensive manual to address the cases when things don’t just work as -expected or in case you don’t want to use the wizard. + When accessing Github, then Ghub handles the creation and storage of +access tokens using a setup wizard to make it easier for users to get +started. The tokens for other forges have to be created manually. Ghub is intentionally limited to only provide these two essential features — basic request functions and guided setup — to avoid being too opinionated, which would hinder wide adoption. It is assumed that wide adoption would make life easier for users and maintainers alike, because -then all packages that talk to the Github API could be configured the -same way. +then all packages that talk to forge APIs could be configured the same +way. -This manual is for Ghub version 2.0.1 (v2.0.1-10-g85b5ae3+1). +This manual is for Ghub version 3.0.0 (v3.0.0-2-g8dbf6b2+1). Copyright (C) 2017-2018 Jonas Bernoulli @@ -60,7 +67,8 @@ This manual is for Ghub version 2.0.1 (v2.0.1-10-g85b5ae3+1). * Using Ghub in Personal Scripts:: * Using Ghub in a Package:: * API:: -* Gitlab Support:: +* GraphQL Support:: +* Support for Other Forges:: — The Detailed Node Listing — @@ -77,6 +85,11 @@ API * Authentication:: * Configuration Variables:: +Support for Other Forges + +* Forge Functions and Variables:: +* Forge Limitations and Notes:: +  File: ghub.info, Node: Introduction, Next: Getting Started, Prev: Top, Up: Top @@ -84,22 +97,28 @@ File: ghub.info, Node: Introduction, Next: Getting Started, Prev: Top, Up: T 1 Introduction ************** -Ghub is a library that provides basic support for using the Github API -from Emacs packages. It abstracts access to API resources using only a -handful of functions that are not resource-specific. +Ghub provides basic support for using the APIs of various Git forges +from Emacs packages. Originally it only supported the Github REST API, +but now it also supports the Github GraphQL API as well as the REST APIs +of Gitlab, Gitea, Gogs and Bitbucket. + + Ghub abstracts access to API resources using only a handful of basic +functions such as ‘ghub-get‘. These are convenience wrappers around +‘ghub-request‘. Additional forge-specific wrappers like ‘glab-put‘, +‘gtea-put‘, ‘gogs-post‘ and ‘buck-delete‘ are also available. Ghub does +not provide any resource-specific functions, with the exception of +‘FORGE-repository-id‘. - Ghub handles the creation, storage and use of access tokens using a -setup wizard to make it easier for users to get started and to reduce -the support burden imposed on package maintainers. It also comes with a -comprehensive manual to address the cases when things don’t just work as -expected or in case you don’t want to use the wizard. + When accessing Github, then Ghub handles the creation and storage of +access tokens using a setup wizard to make it easier for users to get +started. The tokens for other forges have to be created manually. Ghub is intentionally limited to only provide these two essential features — basic request functions and guided setup — to avoid being too opinionated, which would hinder wide adoption. It is assumed that wide adoption would make life easier for users and maintainers alike, because -then all packages that talk to the Github API could be configured the -same way. +then all packages that talk to forge APIs could be configured the same +way. Fancier interfaces can be implemented on top of Ghub, and one such wrapper — named simply Ghub+ — has already been implemented. The @@ -141,11 +160,11 @@ Each package that uses Ghub uses its own token. Despite that, chances are good that after successfully configuring one package you can just start using another package pretty much instantly. - If the necessary token is not available when a package makes an API -request, then a setup wizard pops up, and after answering a few -questions you are good to go. Even the request that caused the wizard -to be summoned should succeed and for most users this should be true -even when configuring the very first token. + If the necessary token to access a Github instance is not available +when a package makes an API request, then a setup wizard pops up, and +after answering a few questions you are good to go. Even the request +that caused the wizard to be summoned should succeed and for most users +this should be true even when configuring the very first token. However, in some situations some manual configuration is necessary *before* using the wizard, or the wizard cannot be used at all: @@ -154,24 +173,32 @@ even when configuring the very first token. create tokens manually as described in *note Manually Creating and Storing a Token::. - • If you want to access Gitlab.com or another Gitlab instance, then - you have to create the token manually as describe in *note Manually - Creating and Storing a Token::. Also see *note Gitlab Support::. + • Unfortunately only Github supports the creation of tokens by using + the API. If you want to access another forge, then you have to + create the token manually as describe in *note Manually Creating + and Storing a Token::. Also see *note Support for Other Forges::. • If you want to access a Github Enterprise instance, then you have - to tell Ghub about that before the wizard makes its appearance by - setting the Git variable ‘github.host’. You also have to tell Ghub - your username for that instance using the variable - ‘github.HOST.user’ even if it is the same as on Github.com. + to tell Ghub about it before the wizard makes its appearance by + setting the Git variable ‘github.host’. For example, if your + company’s GitHub Enterprise instance is hosted at + ‘git.example.com’, then you should set ‘github.host’ to + ‘git.example.com/api/v3’ to use the JSON API. You also have to + tell Ghub your username for that instance using the variable + ‘github.HOST.user’ (e.g. ‘github.git.example.com/api/v3.user’) + even if it is the same as on Github.com. While ‘github.host’ + should be set per-repository to allow Ghub to interface with both a + GitHub Enterprise instance and GitHub.com, setting GitHub + Enterprise users globally is recommended. • If the variable ‘github.user’ (or ‘github.HOST.user’ for an Enterprise instance) is unset when the wizard is first summoned, then you are asked to provide your username. That value is then stored *globally* to avoid having to ask you that question once per - repository. If you have multiple accounts on Github.com (or an - Enterprise instance), then you have to explicitly tell Ghub about - that. This can be done by setting the repository-local values of - the appropriate variable *before* the wizard is invoked. + repository. If you have multiple accounts on Github.com (or a + Github Enterprise instance), then you have to explicitly tell Ghub + about that. This can be done by setting the repository-local + values of the appropriate variable *before* the wizard is invoked. • You might forget to do the above, which is why it is important to carefully read the output of the wizard. If it turns out that you @@ -312,7 +339,7 @@ of the doubts that you might have: WARNING: The token will be stored unencrypted in "~/.authinfo". If you don't want that, you have to abort and customize - the `auth-sources' option.\n\n" (car auth-sources)) + the `auth-sources' option. Whether that is something that needs fixing, is up to you. If your answer is yes, then you should abort and see *note How Ghub uses @@ -517,15 +544,27 @@ behalf of which package a request is being made by passing the symbol Scopes for USERNAME^PACKAGE@HOST: (SCOPE...)  -File: ghub.info, Node: API, Next: Gitlab Support, Prev: Using Ghub in a Package, Up: Top +File: ghub.info, Node: API, Next: GraphQL Support, Prev: Using Ghub in a Package, Up: Top 5 API ***** This section describes the Ghub API. In other words it describes the -public functions and variables provided by the Ghub library and not the -Github API that can be accessed by using those functions. The latter is -documented at . +public functions and variables provided by the Ghub package and not the +APIs of the supported forges, which can be accessed by using those +functions. The forge APIs are documented at: + + • Github: + + • Gitlab: + + • Gitea: and + + + • Gogs: + + • Bitbucket: + * Menu: @@ -674,7 +713,7 @@ File: ghub.info, Node: Making Requests, Next: Authentication, Up: API Callbacks are called with four arguments (see ‘ghub-request’). The forth argument is a ‘ghub--req’ struct, intended to be passed to - this function. A callbacks may use the struct’s ‘extra’ slot to + this function. A callback may use the struct’s ‘extra’ slot to pass additional information to the callback that will be called after the next request. Use the function ‘ghub-req-extra’ to get and set the value of that slot. @@ -714,12 +753,18 @@ File: ghub.info, Node: Making Requests, Next: Authentication, Up: API To access the response headers use this variable after ‘ghub-request’ has returned. - -- Function: ghub-response-link-relations headers + -- Function: ghub-response-link-relations req headers payload This function returns an alist of the link relations in ‘HEADERS’, or if optional ‘HEADERS’ is nil, then those in ‘ghub-response-headers’. + When accessing a Bitbucket instance then the link relations are in + ‘PAYLOAD’ instead of ‘HEADERS’, making their API merely RESTish and + forcing this function to append those relations to the value of + ‘ghub-response-headers’, for later use when this function is called + with ‘nil’ for ‘PAYLOAD’. + -- Variable: ghub-override-system-name If non-nil, the value of this variable is used to override the @@ -940,59 +985,321 @@ machine, which is done using a lisp variable. value returned by ‘system-name’.  -File: ghub.info, Node: Gitlab Support, Prev: API, Up: Top +File: ghub.info, Node: GraphQL Support, Next: Support for Other Forges, Prev: API, Up: Top + +6 GraphQL Support +***************** + + -- Function: ghub-graphql graphql &optional variables &key username + auth host callback silent callback errorback value extra + + This function makes a GraphQL request using ‘GRAPHQL’ and + ‘VARIABLES’ as inputs. ‘GRAPHQL’ is a GraphQL string. ‘VARIABLES’ + is a JSON-like alist. The other arguments behave as for + ‘ghub-request’ (which see). + + The response is returned as a JSON-like alist. Even if the + response contains ‘errors’, this function does not raise an error. + Cursor-handling is likewise left to the caller. + + ‘ghub-graphql’ is a thin convenience wrapper around ‘ghub-request’, +similar to ‘ghub-post’ and friends. While the latter only hard-code the +value of the ‘METHOD’ argument, the former also hard-codes ‘RESOURCE’ +and constructs ‘PAYLOAD’ from ‘GRAPHEQL’ and ‘VARIABLES’. It also drops +‘UNPAGINATE’, ‘NOERROR’, ‘READER’ (internal functions expect alist-ified +JSON) and ‘FORGE’ (only Github currently supports GraphQL). + + ‘ghub-graphql’ does not account for the fact that pagination works +differently in GraphQL than it does in REST, so users of this function +have to deal with that themselves. Likewise error handling works +differently and has to be done by the caller too. + + An early attempt at implementing automatic unpaginating for GraphQL +can be found in the ‘faithful-graphql’ branch, provided I haven’t +deleted that by now. On that branch I try to do things as intended by +the designers of GraphQL, using variables and fragments, and drowning in +a sea of boilerplate. + + The problem with that approach is that it only works for applications +that fetch specific information on demand and actually want things to be +paginated. I am convinced that GraphQL is very nice for web apps. + + However the Forge package for which I am implementing all of this has +very different needs. It wants to fetch "all the data" and "cache" it +locally, so that it is available even when there is no internet +connection. GraphQL was designed around the idea that you should be +able to "ask for what you need and get exactly that". But when that +boils down to "look, if I persist, then you are going to hand me over +all the data anyway, so just caught it up already", then things start to +fall apart. If Github’s GraphQL allowed pagination to be turned off +completely, then teaching ‘ghub-graphql’ about error handling would be +enough. + + But it doesn’t and when doing things as intended, then that leads to +huge amounts of repetitive boilerplate, which is so boring to write that +doing it without introducing bugs left and right is near impossible; so +I decided to give up on GraphQL variables, fragments and conditions, and +instead implement something more powerful, though also more opinionated. + + -- Function: ghub--graphql-vacuum query variables callback &optional + until &key narrow username auth host forge + + This function is an opinionated alternative to ‘ghub-graphql’. It + relies and dark magic to get the job done. + + It makes an initial request using ‘QUERY’. It then looks for + paginated edges in the returned data and makes more requests to + resolve them. In order to do so it automatically transforms the + initial ‘QUERY’ into another query suitable for that particular + edge. The data retrieved by subsequent requests is then injected + into the data of the original request before that is returned or + passed to the callback. If subsequently retrieved data features + new paginated edges, then those are followed recursively. + + The end result is essentially the same as using ‘ghub-graphql’, if + only it were possible to say "do not paginate anything". The + implementation is much more complicated because it is not possible + to do that. + + ‘QUERY’ is a GraphQL query expressed as an s-expression. The + ‘graphql’ package is used to turn that into a GraphQL query string, + but the format is somewhat different than as documented for that + package. Also only a subset of the GraphQL features are supported; + fragments for example are not, and magical stuff happens to + variables. This is not documented yet, I am afraid. Look at + existing callers. + + ‘VARIABLES’ is a JSON-like alist as for ‘ghub-graphql’. + + ‘UNTIL’ is an alist ‘((EDGE-until . VALUE)...)’. When unpaginating + ‘EDGE’ try not to fetch beyond the element whose first field has + the value ‘VALUE’ and remove that element as well as all "lesser" + elements from the retrieved data if necessary. Look at + ‘forge--pull-repository’ for an example. This is only useful if + you "cache" the response locally and want to avoid fetching data + again that you already have. + + Other arguments behave as for ‘ghub-graphql’ and ‘ghub-request’, + more or less. + + Using ‘ghub--graphql-vacuum’, the following resource specific +functions are implemented. These functions are not part of the public +API yet and are very much subject to change. + + -- Function: ghub-fetch-repository owner name callback &optional until + &key username auth host forge + + This function asynchronously fetches forge data about the specified + repository. Once all data has been collected, ‘CALLBACK’ is called + with the data as the only argument. + + -- Function: ghub-fetch-issue owner name callback &optional until &key + username auth host forge + + This function asynchronously fetches forge data about the specified + issue. Once all data has been collected, ‘CALLBACK’ is called with + the data as the only argument. + + -- Function: ghub-fetch-pullreq owner name callback &optional until + &key username auth host forge + + This function asynchronously fetches forge data about the specified + pull-request. Once all data has been collected, ‘CALLBACK’ is + called with the data as the only argument. + + Note that in order to avoid duplication all of these functions base +their initial query on the query stored in ‘ghub-fetch-repository’. The +latter two pass that query through ‘ghub--graphql-prepare-query’, which +then used ‘ghub--graphql-narrow-query’ to remove parts the caller is not +interested in. These two functions are also used internally, when +unpaginating, but as demonstrated here they can be useful even before +making an initial request. + + +File: ghub.info, Node: Support for Other Forges, Prev: GraphQL Support, Up: Top + +7 Support for Other Forges +************************** + +* Menu: + +* Forge Functions and Variables:: +* Forge Limitations and Notes:: + + +File: ghub.info, Node: Forge Functions and Variables, Next: Forge Limitations and Notes, Up: Support for Other Forges + +7.1 Forge Functions and Variables +================================= + +Originally Ghub supported only Github but now it also supports Gitlab, +Gitea, Gogs and Bitbucket. The function ‘ghub-request’ and all the +‘ghub-METHOD’ convenience wrappers default to acting on a Github forge +but can be told to act on another forge using their FORGE argument. + + The FORGE argument only specifies what kind of forge to act on, not +which instance. The HOST argument can be used to select the instance. +For some forges a default instance is defined: + + • Forge ‘github’ defaults to host ‘api.github.com’. + + • Forge ‘gitlab’ defaults to host ‘gitlab.com/api/v4’. + + • Forge ‘bitbucket’ defaults to host ‘api.bitbucket.org/2.0’. + + • No canonical host exists for the ‘gitea’ and ‘gogs’ forges and + ‘localhost:3000/api/v1’ is used as the default host in both cases. + + Together the FORGE and HOST arguments specify the forge type and +instance. In addition to that, it is also necessary to specify on whose +behalf the request is being made, which can be done using the USERNAME +and AUTH arguments. + + Having to specify these arguments for every request is inconvenient. +Additional variables and convenience functions can be used to make that +unnecessary in most cases. + + These variables can be set globally and/or for a specific repository +as explained in *note Configuration Variables:: with a focus on Github +instances. To summarize: + + • For the Git variable ‘github.user’ specifies + the user. + + • For another ‘github’ instance the Git variable ‘github.HOST.user’ + specifies the user. The HOST in that variable name is the same as + the value of the HOST argument of the called function. + + • Instead of specifying the HOST in every function call, the Git + variable ‘github.host’ can be used. This should only be set + locally. + +For ‘gitlab’ and ‘bitbucket’ forges similar variables are available: + + • ‘gitlab.user’ specifies the user. + + • ‘gitlab.HOST.user’ specifies the user for the HOST ‘gitlab’ + instance. + + • ‘gitlab.host’ specifies the ‘gitlab’ host, unless the HOST argument + is non-nil + + • ‘bitbucket.user’ specifies the user. + + • ‘bitbucket.HOST.user’ specifies the user for the HOST ‘bitbucket’ + instance. + + • ‘bitbucket.host’ specifies the ‘bitbucket’ host, unless the HOST + argument is non-nil. + + For ‘gitea’ and ‘gogs’ forges some similar variables are available, +however for some of the ‘ghub.*’ variables no equivalent variable exist +for these two forges: + + • ‘gitea.user’ is *not* used because no canonical ‘gitea’ instance + exists. + + • ‘gitea.HOST.user’ specifies the user for the HOST ‘gitea’ instance. + + • ‘gitea.host’ specifies the ‘gitea’ host, unless the HOST argument + is non-nil + + • ‘gogs.user’ is *not* used because no canonical ‘gitea’ instance + exists. + + • ‘gogs.HOST.user’ specifies the user for the HOST ‘gogs’ instance. + + • ‘gogs.host’ specifies the ‘gogs’ host, unless the HOST argument is + non-nil + + ‘ghub-request’ and ‘ghub-METHOD’ can be used to make a request for +any of the supported forge types, but except when making a request for a +‘github’ instance, then that requires the use of the FORGE argument. + + To avoid that, functions named ‘FORGE-request’ and ‘FORGE-METHOD’ are +also available. The following forms are equivalent, for example: + + (ghub-get ... :auth 'PACKAGE :forge 'gitlab) + (glab-get ... :auth 'PACKAGE) + + These forms would remain equivalent even if you did not specify a +value for the AUTH arguments — but you should not do that if you plan to +share your code with others (see *note Using Ghub in a Package::). If +you do omit AUTH, then the request is made on behalf of the ‘ghub’ +package, *regardless* of the symbol prefix of the function you use to do +so. + + All ‘FORGE-request’ and ‘FORGE-METHOD’ functions, including but not +limited to ‘ghub-METHOD’, are very simple wrappers around +‘ghub-request’. They take fewer arguments than ‘ghub-request’ and +instead pass constant values for the arguments METHOD and/or FORGE. + + +File: ghub.info, Node: Forge Limitations and Notes, Prev: Forge Functions and Variables, Up: Support for Other Forges + +7.2 Forge Limitations and Notes +=============================== + + • The token creation wizard is only available for ‘github’ forges, + because all other forges do not support using the API to create an + API token. As a consequence, if the user makes a request and the + necessary token cannot be found, then that results in an error. + Tokens can be created at: + + • Gitlab: + + • Bitbucket: + + + • Gitea: -6 Gitlab Support -**************** + • Gogs: -Support for Gitlab.com and other Gitlab instances is implemented in the -library ‘glab.el’. This library is build on top of ‘ghub.el’ and is -maintained in the same repository, but it is distributed as a separate -package. + Also see *note Manually Creating and Storing a Token:: and *note + How Ghub uses Auth-Source::. - When accessing Gitlab.com or another Gitlab instance, use -‘glab-request’ instead of ‘ghub-request’, ‘glab-get’ instead of -‘ghub-get’, etc. Likewise use the Git variables in the ‘gitlab’ group -instead of those in the ‘github’ group, i.e. ‘gitlab.user’, -‘gitlab.HOST.user’ and ‘gitlab.host’. + • As mentioned in the previous node, the variables ‘gitea.host’ and + ‘gogs.host’ are not taken into account. - The Gitlab API cannot be used to create tokens, so Glab cannot -provide a setup wizard like Ghub does. As a consequence, if the user -makes a request and the necessary token cannot be found, then that -results in an error. + • Gitea and Gogs do not support limiting a token to certain scopes. - You have to manually create and store the necessary tokens. Tokens -can be created at , -or the equivalent URL for another Gitlab instance. To store the token -locally, follow the instructions in *note Manually Creating and Storing -a Token:: and *note How Ghub uses Auth-Source::. + • The Bitbucket API is fairly broken. Some resources only work if a + slash is appended while others only work if no slash is appended. + I am unable to access any private repositories and some resources + don’t work for me at all. Also the API is only RESTish; pagination + information is part of the response body instead of the header. + Due to such issues it is possible that I will eventually have to + remove support for Bitbucket altogether. - Packages that use Glab can define ‘PACKAGE-gitlab-token-scopes’ for -documentation purposes. But unlike ‘PACKAGE-github-token-scopes’, which -is used by the setup wizard, this is optional. + • The Gitlab API documentation is not always accurate, though I don’t + have an example at hand. It also isn’t structured well, making it + occationally difficult to find the information one is looking for. - And a random hint: where you would use ‘user/repo’ when accessing -Github, you have to use ‘user%2Frepo’ when accessing Gitlab, e.g.: + • Where one would use ‘user/repo’ when accessing another forge, one + has to use ‘user%2Frepo’ when accessing Gitlab, e.g.: - (glab-get "/projects/python-mode-devs%2Fpython-mode") + (glab-get "/projects/python-mode-devs%2Fpython-mode")  Tag Table: -Node: Top763 -Node: Introduction2838 -Node: Getting Started5562 -Node: Setting the Username8620 -Node: Interactively Creating and Storing a Token10045 -Node: Manually Creating and Storing a Token15710 -Node: How Ghub uses Auth-Source16933 -Node: Using Ghub in Personal Scripts18866 -Node: Using Ghub in a Package20322 -Node: API22940 -Node: Making Requests23391 -Node: Authentication37080 -Node: Configuration Variables38925 -Node: Gitlab Support42645 +Node: Top764 +Node: Introduction3279 +Node: Getting Started6321 +Node: Setting the Username9944 +Node: Interactively Creating and Storing a Token11369 +Node: Manually Creating and Storing a Token17009 +Node: How Ghub uses Auth-Source18232 +Node: Using Ghub in Personal Scripts20165 +Node: Using Ghub in a Package21621 +Node: API24239 +Node: Making Requests25036 +Node: Authentication39075 +Node: Configuration Variables40920 +Node: GraphQL Support44640 +Node: Support for Other Forges51305 +Node: Forge Functions and Variables51522 +Node: Forge Limitations and Notes56041  End Tag Table diff --git a/elpa/ghub-20180821.1430/glab.el b/elpa/ghub-20181110.1845/glab.el similarity index 100% rename from elpa/ghub-20180821.1430/glab.el rename to elpa/ghub-20181110.1845/glab.el diff --git a/elpa/ghub-20181110.1845/gogs.el b/elpa/ghub-20181110.1845/gogs.el new file mode 100644 index 00000000..0fbac46e --- /dev/null +++ b/elpa/ghub-20181110.1845/gogs.el @@ -0,0 +1,140 @@ +;;; gogs.el --- minuscule client library for the Gogs API -*- lexical-binding: t -*- + +;; Copyright (C) 2016-2018 Jonas Bernoulli + +;; Author: Jonas Bernoulli +;; Homepage: https://github.com/magit/ghub +;; Keywords: tools + +;; This file is not part of GNU Emacs. + +;; 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 3, 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. + +;; For a copy of the GPL see https://www.gnu.org/licenses/gpl.txt. + +;;; Commentary: + +;; Gogs is a library that provides basic support for using the Gogs API +;; from Emacs packages. It abstracts access to API resources using only +;; a handful of functions that are not resource-specific. + +;; This library is implemented on top of Ghub. Unlike Ghub, Gogs does +;; not support the guided creation of tokens because Gogs lacks the +;; features that would be necessary to implement that. Users have to +;; create tokens through the web interface. + +;;; Code: + +(require 'ghub) + +(defconst gogs-default-host "localhost:3000/api/v1" + "The default host that is used if `gogs.host' is not set.") + +;; HEAD does not appear to be supported. + +(cl-defun gogs-get (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `GET' request for RESOURCE, with optional query PARAMS. +Like calling `ghub-request' (which see) with \"GET\" as METHOD +and `gogs' as FORGE." + (ghub-request "GET" resource params :forge 'gogs + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun gogs-put (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `PUT' request for RESOURCE, with optional payload PARAMS. +Like calling `ghub-request' (which see) with \"PUT\" as METHOD +and `gogs' as FORGE." + (ghub-request "PUT" resource params :forge 'gogs + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun gogs-post (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `POST' request for RESOURCE, with optional payload PARAMS. +Like calling `ghub-request' (which see) with \"POST\" as METHOD +and `gogs' as FORGE." + (ghub-request "POST" resource params :forge 'gogs + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun gogs-patch (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `PATCH' request for RESOURCE, with optional payload PARAMS. +Like calling `ghub-request' (which see) with \"PATCH\" as METHOD +and `gogs' as FORGE." + (ghub-request "PATCH" resource params :forge 'gogs + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun gogs-delete (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `DELETE' request for RESOURCE, with optional payload PARAMS. +Like calling `ghub-request' (which see) with \"DELETE\" as METHOD +and `gogs' as FORGE." + (ghub-request "DELETE" resource params :forge 'gogs + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun gogs-request (method resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a request for RESOURCE and return the response body. +Like calling `ghub-request' (which see) with `gogs' as FORGE." + (ghub-request method resource params :forge 'gogs + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun gogs-repository-id (owner name &key username auth host) + "Return the id of the repository specified by OWNER, NAME and HOST." + (number-to-string + (cdr (assq 'id (gogs-get (format "/repos/%s/%s" owner name) + nil :username username :auth auth :host host))))) + +;;; _ +(provide 'gogs) +;;; gogs.el ends here diff --git a/elpa/ghub-20181110.1845/gtea.el b/elpa/ghub-20181110.1845/gtea.el new file mode 100644 index 00000000..07ca2909 --- /dev/null +++ b/elpa/ghub-20181110.1845/gtea.el @@ -0,0 +1,140 @@ +;;; gtea.el --- minuscule client library for the Gitea API -*- lexical-binding: t -*- + +;; Copyright (C) 2016-2018 Jonas Bernoulli + +;; Author: Jonas Bernoulli +;; Homepage: https://github.com/magit/ghub +;; Keywords: tools + +;; This file is not part of GNU Emacs. + +;; 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 3, 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. + +;; For a copy of the GPL see https://www.gnu.org/licenses/gpl.txt. + +;;; Commentary: + +;; Gtea is a library that provides basic support for using the Gitea API +;; from Emacs packages. It abstracts access to API resources using only +;; a handful of functions that are not resource-specific. + +;; This library is implemented on top of Ghub. Unlike Ghub, Gtea does +;; not support the guided creation of tokens because Gitea lacks the +;; features that would be necessary to implement that. Users have to +;; create tokens through the web interface. + +;;; Code: + +(require 'ghub) + +(defconst gtea-default-host "localhost:3000/api/v1" + "The default host that is used if `gtea.host' is not set.") + +;; HEAD does not appear to be supported. + +(cl-defun gtea-get (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `GET' request for RESOURCE, with optional query PARAMS. +Like calling `ghub-request' (which see) with \"GET\" as METHOD +and `gitea' as FORGE." + (ghub-request "GET" resource params :forge 'gitea + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun gtea-put (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `PUT' request for RESOURCE, with optional payload PARAMS. +Like calling `ghub-request' (which see) with \"PUT\" as METHOD +and `gitea' as FORGE." + (ghub-request "PUT" resource params :forge 'gitea + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun gtea-post (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `POST' request for RESOURCE, with optional payload PARAMS. +Like calling `ghub-request' (which see) with \"POST\" as METHOD +and `gitea' as FORGE." + (ghub-request "POST" resource params :forge 'gitea + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun gtea-patch (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `PATCH' request for RESOURCE, with optional payload PARAMS. +Like calling `ghub-request' (which see) with \"PATCH\" as METHOD +and `gitea' as FORGE." + (ghub-request "PATCH" resource params :forge 'gitea + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun gtea-delete (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `DELETE' request for RESOURCE, with optional payload PARAMS. +Like calling `ghub-request' (which see) with \"DELETE\" as METHOD +and `gitea' as FORGE." + (ghub-request "DELETE" resource params :forge 'gitea + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun gtea-request (method resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a request for RESOURCE and return the response body. +Like calling `ghub-request' (which see) with `gitea' as FORGE." + (ghub-request method resource params :forge 'gitea + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun gtea-repository-id (owner name &key username auth host) + "Return the id of the repository specified by OWNER, NAME and HOST." + (number-to-string + (cdr (assq 'id (gtea-get (format "/repos/%s/%s" owner name) + nil :username username :auth auth :host host))))) + +;;; _ +(provide 'gtea) +;;; gtea.el ends here -- 2.47.3