diff options
Diffstat (limited to 'configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858')
16 files changed, 0 insertions, 3279 deletions
diff --git a/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/buck.el b/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/buck.el deleted file mode 100644 index 141ea90001ad..000000000000 --- a/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/buck.el +++ /dev/null @@ -1,128 +0,0 @@ -;;; buck.el --- minuscule client library for the Bitbucket API -*- lexical-binding: t -*- - -;; Copyright (C) 2016-2018 Jonas Bernoulli - -;; Author: Jonas Bernoulli <jonas@bernoul.li> -;; 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/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/buck.elc b/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/buck.elc deleted file mode 100644 index 0c4a764934e2..000000000000 --- a/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/buck.elc +++ /dev/null Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/dir b/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/dir deleted file mode 100644 index 8392fa02fef6..000000000000 --- a/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/dir +++ /dev/null @@ -1,18 +0,0 @@ -This is the file .../info/dir, which contains the -topmost node of the Info hierarchy, called (dir)Top. -The first time you invoke Info you start off looking at this node. - -File: dir, Node: Top This is the top of the INFO tree - - This (the Directory node) gives a menu of major topics. - Typing "q" exits, "H" lists all Info commands, "d" returns here, - "h" gives a primer for first-timers, - "mEmacs<Return>" visits the Emacs manual, etc. - - In Emacs, you can click mouse button 2 on a menu item or cross reference - to select it. - -* Menu: - -Emacs -* Ghub: (ghub). Minuscule client library for the Github API. diff --git a/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/ghub-autoloads.el b/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/ghub-autoloads.el deleted file mode 100644 index 0b63d4e6ffc5..000000000000 --- a/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/ghub-autoloads.el +++ /dev/null @@ -1,50 +0,0 @@ -;;; ghub-autoloads.el --- automatically extracted autoloads -;; -;;; Code: -(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path)))) - -;;;### (autoloads nil "ghub" "ghub.el" (23450 31865 461474 716000)) -;;; Generated autoloads from ghub.el - -(autoload 'ghub-create-token "ghub" "\ -Create, store and return a new token. - -HOST is the Github instance, usually \"api.github.com\". -USERNAME is the name of a user on that instance. -PACKAGE is the package that will use the token. -SCOPES are the scopes the token is given access to. - -\(fn HOST USERNAME PACKAGE SCOPES)" t nil) - -(autoload 'ghub-token-scopes "ghub" "\ -Return and echo the scopes of the specified token. -This is intended for debugging purposes only. The user -has to provide several values including their password. - -\(fn HOST USERNAME PACKAGE)" t nil) - -(autoload 'ghub-clear-caches "ghub" "\ -Clear all caches that might negatively affect Ghub. - -If a library that is used by Ghub caches incorrect information -such as a mistyped password, then that can prevent Ghub from -asking the user for the correct information again. - -Set `url-http-real-basic-auth-storage' to nil -and call `auth-source-forget+'. - -\(fn)" t nil) - -;;;*** - -;;;### (autoloads nil nil ("buck.el" "ghub-graphql.el" "ghub-pkg.el" -;;;;;; "glab.el" "gogs.el" "gtea.el") (23450 31865 473791 939000)) - -;;;*** - -;; Local Variables: -;; version-control: never -;; no-byte-compile: t -;; no-update-autoloads: t -;; End: -;;; ghub-autoloads.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/ghub-graphql.el b/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/ghub-graphql.el deleted file mode 100644 index b73329f410e5..000000000000 --- a/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/ghub-graphql.el +++ /dev/null @@ -1,428 +0,0 @@ -;;; ghub-graphql.el --- access Github API using GrapthQL -*- lexical-binding: t -*- - -;; Copyright (C) 2016-2018 Jonas Bernoulli - -;; Author: Jonas Bernoulli <jonas@bernoul.li> -;; 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 'subr-x) -(require 'treepy) - -;;; 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) - (issues [(:edges t) - (:singular issue number) - (orderBy ((field . UPDATED_AT) (direction . DESC)))] - number - state - (author login) - title - createdAt - updatedAt - closedAt - locked - (milestone id) - body - (comments [(:edges t)] - databaseId - (author login) - createdAt - updatedAt - body)) - (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)) - (comments [(:edges t)] - databaseId - (author login) - createdAt - updatedAt - body))))) - -(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/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/ghub-graphql.elc b/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/ghub-graphql.elc deleted file mode 100644 index 30289de75abc..000000000000 --- a/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/ghub-graphql.elc +++ /dev/null Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/ghub-pkg.el b/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/ghub-pkg.el deleted file mode 100644 index c51636550dac..000000000000 --- a/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/ghub-pkg.el +++ /dev/null @@ -1,9 +0,0 @@ -(define-package "ghub" "20180911.1858" "Minuscule client libraries for Git forge APIs." - '((emacs "24.4") - (dash "2.14.1") - (graphql "0") - (let-alist "1.0.5") - (treepy "0.1.0"))) -;; Local Variables: -;; no-byte-compile: t -;; End: diff --git a/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/ghub.el b/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/ghub.el deleted file mode 100644 index 6d9ce8275576..000000000000 --- a/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/ghub.el +++ /dev/null @@ -1,912 +0,0 @@ -;;; ghub.el --- minuscule client libraries for Git forge APIs -*- lexical-binding: t -*- - -;; Copyright (C) 2016-2018 Jonas Bernoulli - -;; Author: Jonas Bernoulli <jonas@bernoul.li> -;; 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: - -;; 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'. - -;; 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 forge APIs could be configured -;; the same way. - -;; Please consult the manual (info "ghub") for more information. - -;;; Code: - -(require 'auth-source) -(require 'cl-lib) -(require 'json) -(require 'let-alist) -(require 'url) -(require 'url-auth) -(require 'url-http) - -(eval-when-compile (require 'subr-x)) - -(defvar url-callback-arguments) -(defvar url-http-end-of-headers) -(defvar url-http-extra-headers) -(defvar url-http-response-status) - -;;; Settings - -(defconst ghub-default-host "api.github.com" - "The default host that is used if `ghub.host' is not set.") - -(defvar ghub-github-token-scopes '(repo) - "The Github API scopes that your private tools need. - -The token that is created based on the value of this variable -is used when `ghub-request' (or one of its wrappers) is called -without providing a value for AUTH. Packages should always -identify themselves using that argument, but when you use Ghub -directly in private tools, then that is not necessary and the -request is made on behalf of the `ghub' package itself, aka on -behalf of some private tool. - -By default the only requested scope is `repo' because that is -sufficient as well as required for most common uses. This and -other scopes are documented at URL `https://magit.vc/goto/2e586d36'. - -If your private tools need other scopes, then you have to add -them here *before* creating the token. Alternatively you can -edit the scopes of an existing token using the web interface -at URL `https://github.com/settings/tokens'.") - -(defvar ghub-override-system-name nil - "If non-nil, the string used to identify the local machine. -If this is nil, then the value returned by `system-name' is -used instead.") - -;;; Request -;;;; Object - -(cl-defstruct (ghub--req - (: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) - (handler nil :read-only t) - (unpaginate nil :read-only nil) - (noerror nil :read-only t) - (reader nil :read-only t) - (callback nil :read-only t) - (errorback nil :read-only t) - (value nil :read-only nil) - (extra nil :read-only nil)) - -(defalias 'ghub-req-extra 'ghub--req-extra) - -;;;; API - -(define-error 'ghub-error "Ghub/Url Error" 'error) -(define-error 'ghub-http-error "HTTP Error" 'ghub-error) - -(defvar ghub-response-headers nil - "The headers returned in response to the last request. -`ghub-request' returns the response body and stores the -response headers in this variable.") - -(cl-defun ghub-head (resource &optional params - &key query payload headers - silent unpaginate noerror reader - username auth host - callback errorback extra) - "Make a `HEAD' request for RESOURCE, with optional query PARAMS. -Like calling `ghub-request' (which see) with \"HEAD\" as METHOD." - (ghub-request "HEAD" resource params - :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 ghub-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." - (ghub-request "GET" resource params - :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 ghub-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." - (ghub-request "PUT" resource params - :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 ghub-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." - (ghub-request "POST" resource params - :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 ghub-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." - (ghub-request "PATCH" resource params - :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 ghub-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." - (ghub-request "DELETE" resource params - :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 ghub-request (method resource &optional params - &key query payload headers - silent unpaginate noerror reader - username auth host forge - callback errorback value extra) - "Make a request for RESOURCE and return the response body. - -Also place the response header in `ghub-response-headers'. - -METHOD is the HTTP method, given as a string. -RESOURCE is the resource to access, given as a string beginning - with a slash. - -PARAMS, QUERY, PAYLOAD and HEADERS are alists used to specify - data. The Github API documentation is vague on how data has - to be transmitted and for a particular resource usually just - talks about \"parameters\". Generally speaking when the METHOD - is \"HEAD\" or \"GET\", then they have to be transmitted as a - query, otherwise as a payload. -Use PARAMS to automatically transmit like QUERY or PAYLOAD would - depending on METHOD. -Use QUERY to explicitly transmit data as a query. -Use PAYLOAD to explicitly transmit data as a payload. - Instead of an alist, PAYLOAD may also be a string, in which - case it gets encoded as UTF-8 but is otherwise transmitted as-is. -Use HEADERS for those rare resources that require that the data - is transmitted as headers instead of as a query or payload. - When that is the case, then the API documentation usually - mentions it explicitly. - -If SILENT is non-nil, then don't message progress reports and - the like. - -If UNPAGINATE is t, then make as many requests as necessary to - get all values. If UNPAGINATE is a natural number, then get - at most that many pages. For any other non-nil value raise - an error. -If NOERROR is non-nil, then do not raise an error if the request - fails and return nil instead. If NOERROR is `return', then - return the error payload instead of nil. -If READER is non-nil, then it is used to read and return from the - response buffer. The default is `ghub--read-json-payload'. - For the very few resources that do not return JSON, you might - want to use `ghub--decode-payload'. - -If USERNAME is non-nil, then make a request on behalf of that - user. It is better to specify the user using the Git variable - `github.user' for \"api.github.com\", or `github.HOST.user' if - connecting to a Github Enterprise instance. - -Each package that uses `ghub' should use its own token. If AUTH - is nil, then the generic `ghub' token is used instead. This - is only acceptable for personal utilities. A packages that - is distributed to other users should always use this argument - to identify itself, using a symbol matching its name. - - Package authors who find this inconvenient should write a - wrapper around this function and possibly for the - method-specific functions as well. - - Some symbols have a special meaning. `none' means to make an - unauthorized request. `basic' means to make a password based - request. If the value is a string, then it is assumed to be - a valid token. `basic' and an explicit token string are only - intended for internal and debugging uses. - - If AUTH is a package symbol, then the scopes are specified - using the variable `AUTH-github-token-scopes'. It is an error - if that is not specified. See `ghub-github-token-scopes' for - an example. - -If HOST is non-nil, then connect to that Github instance. This - defaults to \"api.github.com\". When a repository is connected - to a Github Enterprise instance, then it is better to specify - that using the Git variable `github.host' instead of using this - argument. - -If FORGE is `gitlab', then connect to Gitlab.com or, depending - on HOST, to another Gitlab instance. This is only intended for - internal use. Instead of using this argument you should use - function `glab-request' and other `glab-*' functions. - -If CALLBACK and/or ERRORBACK is non-nil, then make one or more - asynchronous requests and call CALLBACK or ERRORBACK when - finished. If an error occurred, then call ERRORBACK, or if - that is nil, then CALLBACK. When no error occurred then call - CALLBACK. When making asynchronous requests, then no errors - are signaled, regardless of the value of NOERROR. - -Both callbacks are called with four arguments. - 1. For CALLBACK, the combined value of the retrieved pages. - For ERRORBACK, the error that occured when retrieving the - last page. - 2. The headers of the last page as an alist. - 3. Status information provided by `url-retrieve'. Its `:error' - property holds the same information as ERRORBACK's first - argument. - 4. A `ghub--req' struct, which can be passed to `ghub-continue' - (which see) to retrieve the next page, if any." - (cl-assert (or (booleanp unpaginate) (natnump unpaginate))) - (unless (string-prefix-p "/" resource) - (setq resource (concat "/" resource))) - (unless host - (setq host (ghub--host forge))) - (unless (or username (stringp auth) (eq auth 'none)) - (setq username (ghub--username host forge))) - (cond ((not params)) - ((member method '("GET" "HEAD")) - (when query - (error "PARAMS and QUERY are mutually exclusive for METHOD %S" - method)) - (setq query params)) - (t - (when payload - (error "PARAMS and PAYLOAD are mutually exclusive for METHOD %S" - method)) - (setq payload params))) - (when (or callback errorback) - (setq noerror t)) - (ghub--retrieve - (ghub--encode-payload payload) - (ghub--make-req - :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) - :headers (ghub--headers headers host auth username forge) - :handler 'ghub--handle-response - :unpaginate unpaginate - :noerror noerror - :reader reader - :callback callback - :errorback errorback - :value value - :extra extra))) - -(defun ghub-continue (req) - "If there is a next page, then retrieve that. - -This function is only intended to be called from callbacks. If -there is a next page, then retrieve that and return the buffer -that the result will be loaded into, or t if the process has -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 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 req)) - (or (ghub--retrieve nil req) t))) - -(cl-defun ghub-wait (resource &optional duration &key username auth host) - "Busy-wait up to DURATION seconds for RESOURCE to become available. - -DURATION specifies how many seconds to wait at most. It defaults -to 64 seconds. The first attempt is made immediately, the second -after two seconds, and each subsequent attempt is made after -waiting as long again as we already waited between all preceding -attempts combined. - -See `ghub-request' for information about the other arguments." - (unless duration - (setq duration 64)) - (with-local-quit - (let ((total 0)) - (while (not (ghub-get resource nil - :noerror t - :username username - :auth auth - :host host)) - (message "Waited (%3ss of %ss) for %s..." total duration resource) - (if (= total duration) - (error "Github is taking too long to create %s" resource) - (if (> total 0) - (let ((wait (min total (- duration total)))) - (sit-for wait) - (cl-incf total wait)) - (sit-for (setq total 2)))))))) - -(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 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 ", "))))) - -;;;; Internal - -(cl-defun ghub--retrieve (payload req) - (let ((url-request-extra-headers - (let ((headers (ghub--req-headers req))) - (if (functionp headers) (funcall headers) headers))) - (url-request-method (ghub--req-method req)) - (url-request-data payload) - (url-show-status nil) - (url (ghub--req-url req)) - (handler (ghub--req-handler req)) - (silent (ghub--req-silent req))) - (if (or (ghub--req-callback req) - (ghub--req-errorback req)) - (url-retrieve url handler (list req) silent) - ;; When this function has already been called, then it is a - ;; no-op. Otherwise it sets `url-registered-auth-schemes' among - ;; other things. If we didn't ensure that it has been run, then - ;; `url-retrieve-synchronously' would do it, which would cause - ;; the value that we let-bind below to be overwritten, and the - ;; "default" value to be lost outside the let-binding. - (url-do-setup) - (with-current-buffer - (let ((url-registered-auth-schemes - '(("basic" ghub--basic-auth-errorback . 10)))) - (url-retrieve-synchronously url silent)) - (funcall handler (car url-callback-arguments) req))))) - -(defun ghub--handle-response (status req) - (let ((buffer (current-buffer))) - (unwind-protect - (progn - (set-buffer-multibyte t) - (let* ((unpaginate (ghub--req-unpaginate req)) - (headers (ghub--handle-response-headers status req)) - (payload (ghub--handle-response-payload req)) - (payload (ghub--handle-response-error status payload req)) - (value (ghub--handle-response-value payload req)) - (next (cdr (assq 'next (ghub-response-link-relations - req headers payload))))) - (when (numberp unpaginate) - (cl-decf unpaginate)) - (setf (ghub--req-url req) - (url-generic-parse-url next)) - (setf (ghub--req-unpaginate req) unpaginate) - (or (and next - unpaginate - (or (eq unpaginate t) - (> unpaginate 0)) - (ghub-continue req)) - (let ((callback (ghub--req-callback req)) - (errorback (ghub--req-errorback req)) - (err (plist-get status :error))) - (cond ((and err errorback) - (funcall errorback err headers status req)) - (callback - (funcall callback value headers status req)) - (t value)))))) - (when (buffer-live-p buffer) - (kill-buffer buffer))))) - -(defun ghub--handle-response-headers (status req) - (goto-char (point-min)) - (forward-line 1) - (let (headers) - (while (re-search-forward "^\\([^:]*\\): \\(.+\\)" - url-http-end-of-headers t) - (push (cons (match-string 1) - (match-string 2)) - headers)) - (setq headers (nreverse headers)) - (unless url-http-end-of-headers - (error "BUG: missing headers %s" (plist-get status :error))) - (goto-char (1+ url-http-end-of-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)) - headers)) - -(defun ghub--handle-response-error (status payload req) - (let ((noerror (ghub--req-noerror req)) - (err (plist-get status :error))) - (if err - (if noerror - (if (eq noerror 'return) - payload - (setcdr (last err) (list payload)) - nil) - (ghub--signal-error err payload)) - payload))) - -(defun ghub--signal-error (err &optional payload) - (pcase-let ((`(,symb . ,data) err)) - (if (eq symb 'error) - (if (eq (car-safe data) 'http) - (signal 'ghub-http-error - (let ((code (car (cdr-safe data)))) - (list code - (nth 2 (assq code url-http-codes)) - payload))) - (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) - url-http-response-status)) - -(defun ghub--read-json-payload (_status) - (let ((raw (ghub--decode-payload))) - (and raw - (condition-case nil - (let ((json-object-type 'alist) - (json-array-type 'list) - (json-key-type 'symbol) - (json-false nil) - (json-null nil)) - (json-read-from-string raw)) - (json-readtable-error - `((message - . ,(if (looking-at "<!DOCTYPE html>") - (if (re-search-forward - "<p>\\(?:<strong>\\)?\\([^<]+\\)" nil t) - (match-string 1) - "error description missing") - (string-trim (buffer-substring (point) (point-max))))) - (documentation_url - . "https://github.com/magit/ghub/wiki/Github-Errors"))))))) - -(defun ghub--decode-payload (&optional _status) - (and (not (eobp)) - (decode-coding-string - (buffer-substring-no-properties (point) (point-max)) - 'utf-8))) - -(defun ghub--encode-payload (payload) - (and payload - (progn - (unless (stringp payload) - (setq payload (json-encode-list payload))) - (encode-coding-string payload 'utf-8)))) - -(defun ghub--url-encode-params (params) - (mapconcat (lambda (param) - (pcase-let ((`(,key . ,val) param)) - (concat (url-hexify-string (symbol-name key)) "=" - (if (integerp val) - (number-to-string val) - (url-hexify-string val))))) - params "&")) - -;;; Authentication -;;;; API - -;;;###autoload -(defun ghub-create-token (host username package scopes) - "Create, store and return a new token. - -HOST is the Github instance, usually \"api.github.com\". -USERNAME is the name of a user on that instance. -PACKAGE is the package that will use the token. -SCOPES are the scopes the token is given access to." - (interactive - (pcase-let ((`(,host ,username ,package) - (ghub--read-triplet))) - (list host username package - (split-string - (read-string - "Scopes (separated by commas): " - (mapconcat #'symbol-name - (symbol-value - (intern (format "%s-github-token-scopes" package))) - ",")) - "," t "[\s\t]+")))) - (let ((user (ghub--ident username package))) - (cl-destructuring-bind (save token) - (ghub--auth-source-get (list :save-function :secret) - :create t :host host :user user - :secret - (cdr (assq 'token - (ghub-post - "/authorizations" - `((scopes . ,scopes) - (note . ,(ghub--ident-github package))) - :username username :auth 'basic :host host)))) - ;; Build-in back-ends return a function that does the actual - ;; saving, while for some third-party back-ends ":create t" - ;; is enough. - (when (functionp save) - (funcall save)) - ;; If the Auth-Source cache contains the information that there - ;; is no value, then setting the value does not invalidate that - ;; now incorrect information. - (auth-source-forget (list :host host :user user)) - token))) - -;;;###autoload -(defun ghub-token-scopes (host username package) - "Return and echo the scopes of the specified token. -This is intended for debugging purposes only. The user -has to provide several values including their password." - (interactive (ghub--read-triplet)) - (let ((scopes - (cdr (assq 'scopes (ghub--get-token-plist host username package))))) - (when (called-interactively-p 'any) - ;; Also show the input values to make it easy for package - ;; authors to verify that the user has done it correctly. - (message "Scopes for %s@%s: %S" - (ghub--ident username package) - host scopes)) - scopes)) - -;;;###autoload -(defun ghub-clear-caches () - "Clear all caches that might negatively affect Ghub. - -If a library that is used by Ghub caches incorrect information -such as a mistyped password, then that can prevent Ghub from -asking the user for the correct information again. - -Set `url-http-real-basic-auth-storage' to nil -and call `auth-source-forget+'." - (interactive) - (setq url-http-real-basic-auth-storage nil) - (auth-source-forget+)) - -;;;; Internal - -(defun ghub--headers (headers host auth username forge) - (push (cons "Content-Type" "application/json") headers) - (if (eq auth 'none) - headers - (unless (or username (stringp auth)) - (setq username (ghub--username host forge))) - (lambda () - (if (eq auth 'basic) - (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) - (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 - (cl-typecase auth - (string auth) - (null (ghub--token host username 'ghub nil forge)) - (symbol (ghub--token host username auth nil forge)) - (t (signal 'wrong-type-argument - `((or stringp symbolp) ,auth)))) - 'utf-8))))) - -(defun ghub--basic-auth (host username) - (let ((url (url-generic-parse-url (concat "https://" host)))) - (setf (url-user url) username) - (url-basic-auth url t))) - -(defun ghub--basic-auth-errorback (url &optional prompt _overwrite _realm _args) - ;; This gets called twice. Do nothing the first time, - ;; when PROMPT is nil. See `url-get-authentication'. - (when prompt - (if (assoc "X-GitHub-OTP" (ghub--handle-response-headers nil nil)) - (progn - (setq url-http-extra-headers - `(("Content-Type" . "application/json") - ("X-GitHub-OTP" . ,(ghub--read-2fa-code)) - ;; Without "Content-Type" and "Authorization". - ;; The latter gets re-added from the return value. - ,@(cddr url-http-extra-headers))) - ;; Return the cached values, they are correct. - (url-basic-auth url nil nil nil)) - ;; Remove the invalid cached values and fail, which - ;; is better than the invalid values sticking around. - (setq url-http-real-basic-auth-storage - (cl-delete (format "%s:%d" (url-host url) (url-port url)) - url-http-real-basic-auth-storage - :test #'equal :key #'car)) - nil))) - -(defun ghub--token (host username package &optional nocreate forge) - (let* ((user (ghub--ident username package)) - (token - (or (car (ghub--auth-source-get (list :secret) - :host host :user user)) - (progn - ;; Auth-Source caches the information that there is no - ;; value, but in our case that is a situation that needs - ;; fixing so we want to keep trying by invalidating that - ;; information. - ;; The (:max 1) is needed and has to be placed at the - ;; end for Emacs releases before 26.1. See #24, #64. - (auth-source-forget (list :host host :user user :max 1)) - (and (not nocreate) - (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) - (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 ((equal host ghub-default-host) - "github.user") - ((equal host (bound-and-true-p glab-default-host)) - "gitlab.user") - ((equal host (bound-and-true-p buck-default-host)) - "bitbucket.user") - ((eq forge 'github) (format "github.%s.user" host)) - ((eq forge 'gitlab) (format "gitlab.%s.user" host)) - ((eq forge 'bitbucket) (format "bitbucket.%s.user" host)) - ((eq forge 'gitea) (format "gitea.%s.user" host)) - ((eq forge 'gogs) (format "gogs.%s.user" host))))) - (condition-case nil - (car (process-lines "git" "config" var)) - (error - (let ((user (read-string - (format "Git variable `%s' is unset. Set to: " var)))) - (or (and user (progn (call-process "git" nil nil nil - "config" "--global" var user) - user)) - (user-error "Abort"))))))) - -(defun ghub--ident (username package) - (format "%s^%s" username package)) - -(defun ghub--ident-github (package) - (format "Emacs package %s @ %s" - package - (or ghub-override-system-name (system-name)))) - -(defun ghub--package-scopes (package) - (let ((var (intern (format "%s-github-token-scopes" package)))) - (if (boundp var) - (symbol-value var) - (error "%s fails to define %s" package var)))) - -(defun ghub--confirm-create-token (host username package) - (let* ((ident (ghub--ident-github package)) - (scopes (ghub--package-scopes package)) - (max-mini-window-height 40)) - (if (let ((message-log-max nil)) - (yes-or-no-p - (format - "Such a Github API token is not available: - - Host: %s - User: %s - Package: %s - - Scopes requested in `%s-github-token-scopes':\n%s - Store on Github as:\n %S - Store locally according to option `auth-sources':\n %S -%s -If in doubt, then abort and first view the section of the Ghub -documentation called \"Manually Creating and Storing a Token\". - -Otherwise confirm and then provide your Github username and -password at the next two prompts. Depending on the backend -you might have to provide a passphrase and confirm that you -really want to save the token. - -Create and store such a token? " - host username package package - (mapconcat (lambda (scope) (format " %s" scope)) scopes "\n") - ident auth-sources - (if (and (stringp (car auth-sources)) - (not (string-suffix-p ".gpg" (car auth-sources)))) - (format " -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)) - (user-error "Abort")))) - -(defun ghub--get-token-id (host username package) - (let ((ident (ghub--ident-github package))) - (cl-some (lambda (x) - (let-alist x - (and (equal .app.name ident) .id))) - (ghub-get "/authorizations" - '((per_page . 100)) - :unpaginate t - :username username :auth 'basic :host host)))) - -(defun ghub--get-token-plist (host username package) - (ghub-get (format "/authorizations/%s" - (ghub--get-token-id host username package)) - nil :username username :auth 'basic :host host)) - -(defun ghub--delete-token (host username package) - (ghub-delete (format "/authorizations/%s" - (ghub--get-token-id host username package)) - nil :username username :auth 'basic :host host)) - -(defun ghub--read-triplet () - (let ((host (read-string "Host: " (ghub--host)))) - (list host - (read-string "Username: " (ghub--username host)) - (intern (read-string "Package: " "ghub"))))) - -(defvar ghub--2fa-cache nil) - -(defun ghub--read-2fa-code () - (let ((code (read-number "Two-factor authentication code: " - (and ghub--2fa-cache - (< (float-time (time-subtract - (current-time) - (cdr ghub--2fa-cache))) - 25) - (car ghub--2fa-cache))))) - (setq ghub--2fa-cache (cons code (current-time))) - (number-to-string code))) - -(defun ghub--auth-source-get (keys &rest spec) - (declare (indent 1)) - (let ((plist (car (apply #'auth-source-search - (append spec (list :max 1)))))) - (mapcar (lambda (k) - (plist-get plist k)) - keys))) - -(advice-add 'auth-source-netrc-parse-next-interesting :around - 'auth-source-netrc-parse-next-interesting@save-match-data) -(defun auth-source-netrc-parse-next-interesting@save-match-data (fn) - "Save match-data for the benefit of caller `auth-source-netrc-parse-one'. -Without wrapping this function in `save-match-data' the caller -won't see the secret from a line that is followed by a commented -line." - (save-match-data (funcall fn))) - -;;; _ -(provide 'ghub) -(require 'ghub-graphql) -;;; ghub.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/ghub.elc b/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/ghub.elc deleted file mode 100644 index 702ae88a547c..000000000000 --- a/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/ghub.elc +++ /dev/null Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/ghub.info b/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/ghub.info deleted file mode 100644 index 8b53985fe96c..000000000000 --- a/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/ghub.info +++ /dev/null @@ -1,1301 +0,0 @@ -This is ghub.info, produced by makeinfo version 6.5 from ghub.texi. - - Copyright (C) 2017-2018 Jonas Bernoulli <jonas@bernoul.li> - - You can redistribute this document 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 document 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. -INFO-DIR-SECTION Emacs -START-INFO-DIR-ENTRY -* Ghub: (ghub). Minuscule client library for the Github API. -END-INFO-DIR-ENTRY - - -File: ghub.info, Node: Top, Next: Introduction, Up: (dir) - -Ghub User and Developer Manual -****************************** - -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‘. - - 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 forge APIs could be configured the same -way. - -This manual is for Ghub version 2.0.1 (v2.0.1-48-g87701ea+1). - - Copyright (C) 2017-2018 Jonas Bernoulli <jonas@bernoul.li> - - You can redistribute this document 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 document 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. - -* Menu: - -* Introduction:: -* Getting Started:: -* Using Ghub in Personal Scripts:: -* Using Ghub in a Package:: -* API:: -* GraphQL Support:: -* Support for Other Forges:: - -— The Detailed Node Listing — - -Getting Started - -* Setting the Username:: -* Interactively Creating and Storing a Token:: -* Manually Creating and Storing a Token:: -* How Ghub uses Auth-Source:: - -API - -* Making Requests:: -* 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 - -1 Introduction -************** - -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‘. - - 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 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 -benefit of basing various opinionated interfaces on top of a single -library that provides only the core functionality is that choosing the -programming interface no longer dictates how access tokens are handled. -Users can then use multiple packages that access the Github API without -having to learn the various incompatible ways packages expect the -appropriate token to be made available to them. - - Ghub uses the built-in ‘auth-source’ library to store access tokens. -That library is very flexible and supports multiple backends, which -means that it is up to the user how secrets are stored. They can, among -other things, choose between storing secrets in plain text for ease of -use, or encrypted for better security. - - Previously (as in until this library is widely adopted) it was up to -package authors to decide if things should be easy or secure. (Note -that ‘auth-source’ defaults to "easy" — you have been warned.) - - Ghub expects package authors to use a dedicated access token instead -of sharing a single token between all packages that rely on it. That -means that users cannot configure Ghub once and later start using a new -package without any additional setup. But Ghub helps with that. - - When the user invokes some command that ultimately results in -‘ghub-request’ being called and the appropriate token is not available -yet, then the user is guided through the process of creating and storing -a new token, and at the end of that process the request is carried out -as if the token had been available to begin with. - - -File: ghub.info, Node: Getting Started, Next: Using Ghub in Personal Scripts, Prev: Introduction, Up: Top - -2 Getting Started -***************** - -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 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: - - • If you don’t want to use the wizard then you don’t have to and can - create tokens manually as described in *note Manually Creating and - Storing a Token::. - - • 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. - - • 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 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 - forgot to set a variable, then you must abort, set the variable, - and repeat the request to trigger the wizard again. - - • The setup wizard should work even if you have enabled two-factor - authentication. However if your Github Enterprise instance - enforces Single Sign-On as an additional security measure, then you - are out of luck and have to create the token manually as described - in *note Manually Creating and Storing a Token::. - - The variables mentioned above — and others — are documented in *note -Configuration Variables:: and the setup wizard is documented in *note -Interactively Creating and Storing a Token::. - -* Menu: - -* Setting the Username:: -* Interactively Creating and Storing a Token:: -* Manually Creating and Storing a Token:: -* How Ghub uses Auth-Source:: - - -File: ghub.info, Node: Setting the Username, Next: Interactively Creating and Storing a Token, Up: Getting Started - -2.1 Setting the Username -======================== - -If you haven’t set the Git variable ‘github.user’ yet when making a -request, then you will be asked: - - Git variable `github.user' is unset. Set to: - - You are expected to provide your Github username here. The provided -value will be saved globally (using ‘git config --global github.user -USERNAME’). - - If you need to identify as another user in a particular repository, -then you have to set that variable locally, *before* making a request: - - cd /path/to/repo - git config github.user USERNAME - - For Github Enterprise instances you have to specify where the API can -be accessed *before* you try to access it and a different variable has -to be used to set the username. For example if the API is available at -‘https://example.com/api/v3’, then you should do this: - - # Do this once - git config --global github.example.com/api/v3.user EMPLOYEE - - # Do this for every corporate repository - cd /path/to/repo - git config github.host example.com/api/v3 - - If you do not set ‘github.example.com/api/v3.user’, then you will be -asked to provide the value when trying to make a request, but you do -have to manually set ‘github.host’, or Ghub assumes that you are trying -to access ‘api.github.com’. - - -File: ghub.info, Node: Interactively Creating and Storing a Token, Next: Manually Creating and Storing a Token, Prev: Setting the Username, Up: Getting Started - -2.2 Interactively Creating and Storing a Token -============================================== - -Ghub uses a different token for every package as well as for every -machine from which you access the Github API (and obviously also for -every Github instance and user). This allows packages to only request -the scopes that they actually need and also gives users the opportunity -to refuse access to certain scopes if they expect to not use the -features that need them. - - Usually you don’t have to worry about creating and storing a token -yourself and can just make a request. Note however that you don’t have -to use the setup wizard described below. Alternatively you can perform -the setup manually as described in the next section. - - If you make a request and the required token is not available yet, -then the setup wizard will first ask you something like this: - - Such a Github API token is not available: - - Host: api.github.com - User: USERNAME - Package: PACKAGE - - Scopes requested in `PACKAGE-github-token-scopes': - repo - Store on Github as: - "Emacs package PACKAGE @ LOCAL-MACHINE" - Store locally according to option `auth-sources': - ("~/.authinfo" "~/.authinfo.gpg" "~/.netrc") - - If in doubt, then abort and first view the section of the Ghub - documentation called "Manually Creating and Storing a Token". - - Create and store such a token? (yes or no) - - If you don’t have any doubts, then answer "yes". Lets address some -of the doubts that you might have: - - • ‘Host’ usually is "api.github.com" and that is usually what you - want. If you are trying to access a Github Enterprise instance, - then it should be something else and you have to set the value - manually before the setup wizard is summoned, as described in the - parent section. - - • ‘User’ should be your Github.com (or Github Enterprise instance) - username. If it is something else and it doesn’t look like a - simple typo, then you should read the parent section again. In - either case you have to abort. - - • ‘Package’ should be the name of the package you are using to access - the Github API. - - If it is ‘ghub’, then the package author disregarded that - convention and you should probably report a bug in the issue - tracker of that package. - - Or you yourself are using ‘ghub-request’ or one of its wrappers - directly, in which case this is expected and perfectly fine. In - that case you might however want to abort and change the value of - the variable ‘ghub-github-token-scopes’ before triggering the - wizard again. - - • Each ‘PACKAGE’ has to specify the tokens that it needs using a - variable named ‘PACKAGE-github-token-scopes’. The doc-string of - that variable should document why the various scopes are needed. - - The meaning of the various scopes are documented at - <https://magit.vc/goto/f63aeb0a>. - - • The value of ‘auth-sources’ is shown. The default value causes - secrets to be stored in plain text. Because this might be - unexpected, Ghub additionally displays a warning when appropriate. - - 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. - - 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 - Auth-Source:: for instructions on how to save the token more - securely. - - • When creating a token it is necessary to provide a token - description. Ghub uses descriptions that have the form "Emacs - package PACKAGE @ LOCAL-MACHINE". - - Github uses the token description to identify the token, not merely - as something useful to humans. Token descriptions therefore have - to be unique and in rare cases you get an additional prompt, asking - you something like: - - A token named "Emacs package PACKAGE @ LOCAL-MACHINE" - already exists on Github. Replace it? - - You might see this message when you have lost the old token and - want to replace it with a new one, in which case you should - obviously just proceed. - - Or two of your computers have the same hostname, which is bad - practice because it gains you nothing but leads to issues such as - this. Or you are dual-booting on this machine and use the same - hostname in all operating systems, which is a somewhat reasonable - thing to do, but never-the-less leads to issues like this. - - In either case you will have to use something other than the value - returned by ‘system-name’ to identify the current machine or - operating system. Or you can continue to identify different things - using the same identifier, in which case you have to manually - distribute the token. - - The former is recommended and also easier to do, using the variable - ‘ghub-override-system-name’. See *note Configuration Variables:: - for details. - - After the above prompt you are also asked for you username and -password. If you have enabled two-factor authentication, then you also -have to provide the authentication code at least twice. If you make -sure the code is still good for a while when asked for it first, then -you can just press ‘RET’ at the later prompt(s). - - -File: ghub.info, Node: Manually Creating and Storing a Token, Next: How Ghub uses Auth-Source, Prev: Interactively Creating and Storing a Token, Up: Getting Started - -2.3 Manually Creating and Storing a Token -========================================= - -If you cannot or don’t want to use the wizard then you have to (1) -figure out what scopes a package wants, (2) create such a token using -the web interface and (3) store the token where Ghub expects to find it. - - A package named ‘PACKAGE’ has to specify the scopes that it wants in -the variable named ‘PACKAGE-ghub-token-scopes’. The doc-string of such -variables should document what the various scopes are needed for. - - To create or edit a token go to <https://github.com/settings/tokens>. -For Gitlab.com use <https://gitlab.com/profile/personal_access_tokens>. - - Finally store the token in a place where Ghub looks for it, as -described in *note How Ghub uses Auth-Source::. - - If you store the token in a file like ‘~/.authinfo’, then note that -‘auth-source’’s parsing of that file is brittle. Make sure the file -ends with a newline character, that there are no empty or invalid lines, -and that all comments are prefixed with ‘#’. - - -File: ghub.info, Node: How Ghub uses Auth-Source, Prev: Manually Creating and Storing a Token, Up: Getting Started - -2.4 How Ghub uses Auth-Source -============================= - -Please see *note (auth)Top:: for all the gory details about Auth-Source. -Some Ghub-specific information and important notes follow. - - The variable ‘auth-sources’ controls how and where Auth-Source stores -new secrets and where it looks for known secrets. The default value is -‘("~/.authinfo" "~/.authinfo.gpg" "~/.netrc")’, which means that it -looks in all of these files in order to find secrets and that it stores -new secrets in ‘~/.authinfo’ because that is the first element of the -list. It doesn’t matter which files already do or don’t exist when -storing a new secret, the first file is always used. - - Secrets are stored in ‘~/.authinfo’ in plain text. If you don’t want -that (good choice), then you have to customize ‘auth-sources’, e.g. by -flipping the positions of the first two elements. - - Auth-Source also supports storing secrets in various key-chains. -Refer to its documentation for more information. - - Some Auth-Source backends only support storing three values per -entry, the "machine", the "login" and the "password". Because Ghub uses -separate tokens for each package, it has to squeeze four values into -those three slots, and it does that by using "USERNAME^PACKAGE" as the -"login". - - Assuming your username is "ziggy",the package is named "stardust", -and you want to access *Github.com* an entry in one of the three -mentioned files would then look like this: - - machine api.github.com login ziggy^stardust password 012345abcdef... - - Assuming your username is "ziggy",the package is named "stardust", -and you want to access *Gitlab.com* an entry in one of the three -mentioned files would then look like this: - - machine gitlab.com/api/v4 login ziggy^stardust password 012345abcdef... - - -File: ghub.info, Node: Using Ghub in Personal Scripts, Next: Using Ghub in a Package, Prev: Getting Started, Up: Top - -3 Using Ghub in Personal Scripts -******************************** - -You can use ‘ghub-request’ and its wrapper functions in your personal -scripts, of course. Unlike when you use Ghub from a package that you -distribute for others to use, you don’t have to specify a package in -personal scripts. - - ;; This is perfectly acceptable in personal scripts ... - (ghub-get "/user") - - ;; ... and actually equal to - (ghub-get "/user" nil :auth 'ghub) - - ;; In packages you have to specify the package using AUTH. - (ghub-get "/user" nil :auth 'foobar) - - When you do not specify the ‘AUTH’ argument, then a request is made -on behalf of the ‘ghub’ package itself. Like for any package that uses -Ghub, ‘ghub’ has to declare what scopes it needs, using, in this case, -the variable ‘ghub-github-token-scopes’. - - The default value of that variable is ‘(repo)’ and you might want to -add additional scopes. You can later add additional scopes to an -existing token, using the web interface at -<https://github.com/settings/tokens>. - - If you do that, then you might want to also set the variable -accordingly, but note that Ghub only consults that when *creating* a new -token. If you want to know a token’s effective scopes use the command -‘ghub-token-scopes’, described in the next section. - - -File: ghub.info, Node: Using Ghub in a Package, Next: API, Prev: Using Ghub in Personal Scripts, Up: Top - -4 Using Ghub in a Package -************************* - -Every package should use its own token. This allows you as the author -of some package to only request access to API scopes that are actually -needed, which in turn might make it easier for users to trust your -package not to do unwanted things. - - The scopes used by ‘PACKAGE’ have to be defined using the variable -‘PACKAGE-github-token-scopes’, and you have to tell ‘ghub-request’ on -behalf of which package a request is being made by passing the symbol -‘PACKAGE’ as the value of its ‘AUTH’ argument. - - (ghub-request "GET" "/user" nil :auth 'PACKAGE) - - -- Variable: PACKAGE-github-token-scopes - - This variable defines the token scopes requested by the package - named ‘PACKAGE’. The doc-string should explain what the various - scopes are needed for to prevent users from giving ‘PACKAGE’ fewer - permissions than it absolutely needs and also to give them greater - confidence that ‘PACKAGE’ is only requesting the permissions that - it actually needs. - - The value of this variable does not necessarily correspond to the - scopes that the respective token actually gives access to. There - is nothing that prevents users from changing the value *after* - creating the token or from editing the token’s scopes later on. - - So it is pointless to check the value of this variable before - making a request. You also should not query the API to reliably - determine the supported tokens before making a query. Doing the - latter would mean that every request becomes two requests and that - the first request would have to be done using the user’s password - instead of a token. - - -- Command: ghub-token-scopes - - Because we cannot be certain that the user hasn’t messed up the - scopes, Ghub provides this command to make it easy to debug such - issues without having to rely on users being thoughtful enough to - correctly determine the used scopes manually. - - Just tell users to run ‘M-x ghub-token-scopes’ and to provide the - correct values for the ‘HOST’, ‘USERNAME’ and ‘PACKAGE’ when - prompted, and to then post the output. - - It is to be expected that users will occasionally mess that up so - this command outputs not only the scopes but also the user input so - that you can have greater confidence in the validity of the user’s - answer. - - Scopes for USERNAME^PACKAGE@HOST: (SCOPE...) - - -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 package and not the -APIs of the supported forges, which can be accessed by using those -functions. The forge APIs are documented at: - - • Github: <https://developer.github.com/v3> - - • Gitlab: <https://docs.gitlab.com/ee/api/README.html> - - • Gitea: <https://docs.gitea.io/en-us/api-usage> and - <https://try.gitea.io/api/swagger> - - • Gogs: <https://github.com/gogs/go-gogs-client/wiki> - - • Bitbucket: - <https://developer.atlassian.com/bitbucket/api/2/reference> - -* Menu: - -* Making Requests:: -* Authentication:: -* Configuration Variables:: - - -File: ghub.info, Node: Making Requests, Next: Authentication, Up: API - -5.1 Making Requests -=================== - - -- Function: ghub-request method resource &optional params &key query - payload headers unpaginate noerror reader username auth host - callback errorback url value error extra method* - - This function makes a request for ‘RESOURCE’ using ‘METHOD’. - ‘PARAMS’, ‘QUERY’, ‘PAYLOAD’ and/or ‘HEADERS’ are alists holding - additional request data. The response body is returned and the - response header is stored in the variable ‘ghub-response-headers’. - - • ‘METHOD’ is the HTTP method, given as a string. - - • ‘RESOURCE’ is the resource to access, given as a string - beginning with a slash. - - • ‘PARAMS’, ‘QUERY’, ‘PAYLOAD’ and ‘HEADERS’ are alists and are - used to specify request data. All these arguments are alists - that resemble the JSON expected and returned by the Github - API. The keys are symbols and the values stored in the ‘cdr’ - (not the ‘cadr’) can be strings, integers, or lists of strings - and integers. - - The Github API documentation is vague on how data has to be - transmitted and for a particular resource usually just talks - about "parameters". Generally speaking when the ‘METHOD’ is - "HEAD" or "GET", then they have to be transmitted as a query, - otherwise as a payload. - - • Use ‘PARAMS’ to automatically transmit like ‘QUERY’ or - ‘PAYLOAD’ would depending on ‘METHOD’. - - • Use ‘QUERY’ to explicitly transmit data as a query. - - • Use ‘PAYLOAD’ to explicitly transmit data as a payload. - Instead of an alist, ‘PAYLOAD’ may also be a string, in - which case it gets encoded as UTF-8 but is otherwise - transmitted as-is. - - • Use ‘HEADERS’ for those rare resources that require that - the data is transmitted as headers instead of as a query - or payload. When that is the case, then the Github API - documentation usually mentions it explicitly. - - • If ‘SILENT’ is non-nil, then progress reports and the like are - not messaged. - - • If ‘UNPAGINATE’ is t, then this function make as many requests - as necessary to get all values. If ‘UNPAGINATE’ is a natural - number, then it gets at most that many pages. For any other - non-nil value it raises an error. - - • If ‘NOERROR’ is non-nil, then no error is raised if the - request fails and ‘nil’ is returned instead. If ‘NOERROR’ is - ‘return’, then the error payload is returned instead of ‘nil’. - - • If ‘READER’ is non-nil, then it is used to read and return - from the response buffer. The default is - ‘ghub--read-json-payload’. For the very few resources that do - not return JSON, you might want to use ‘ghub--decode-payload’. - - • If ‘USERNAME’ is non-nil, then the request is made on behalf - of that user. It is better to specify the user using the Git - variable ‘github.user’ for "api.github.com", or - ‘github.HOST.user’ if connecting to a Github Enterprise - instance. - - • Each package that uses Ghub should use its own token. If - ‘AUTH’ is ‘nil’ or unspecified, then the generic ‘ghub’ token - is used instead. This is only acceptable for personal - utilities. A packages that is distributed to other users - should always use this argument to identify itself, using a - symbol matching its name. - - Package authors who find this inconvenient should write a - wrapper around this function and possibly for the - method-specific functions as well. - - Beside ‘nil’, some other symbols have a special meaning too. - ‘none’ means to make an unauthorized request. ‘basic’ means - to make a password based request. If the value is a string, - then it is assumed to be a valid token. ‘basic’ and an - explicit token string are only intended for internal and - debugging uses. - - If ‘AUTH’ is a package symbol, then the scopes are specified - using the variable ‘AUTH-github-token-scopes’. It is an error - if that is not specified. See ‘ghub-github-token-scopes’ for - an example. - - • If ‘HOST’ is non-nil, then connect to that Github instance. - This defaults to "api.github.com". When a repository is - connected to a Github Enterprise instance, then it is better - to specify that using the Git variable ‘github.host’ instead - of using this argument. - - • If ‘FORGE’ is ‘gitlab’, then connect to Gitlab.com or, - depending on ‘HOST’, to another Gitlab instance. This is only - intended for internal use. Instead of using this argument you - should use function ‘glab-request’ and other ‘glab-*’ - functions. - - • If ‘CALLBACK’ and/or ‘ERRORBACK’ is non-nil, then this - function makes one or more asynchronous requests and calls - ‘CALLBACK’ or ‘ERRORBACK’ when finished. If an error - occurred, then it calls ‘ERRORBACK’, or if that is ‘nil’, then - ‘CALLBACK’. When no error occurred then it calls ‘CALLBACK’. - When making asynchronous requests, then no errors are - signaled, regardless of the value of ‘NOERROR’. - - Both callbacks are called with four arguments. - - • For ‘CALLBACK’, the combined value of the retrieved - pages. For ‘ERRORBACK’, the error that occured when - retrieving the last page. - - • The headers of the last page as an alist. - - • Status information provided by ‘url-retrieve’. Its - ‘:error’ property holds the same information as the first - argument to ‘ERRORBACK’. - - • A ‘ghub--req’ struct, which can be passed to - ‘ghub-continue’ (which see) to retrieve the next page, if - any. - - -- Function: ghub-continue args - - If there is a next page, then this function retrieves that. - - This function is only intended to be called from callbacks. If - there is a next page, then that is retrieve and the buffer that the - result will be loaded into is returned, or t if the process has - 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 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. - - As an example, using ‘ghub-continue’ in a callback like so: - - (ghub-get "/users/tarsius/repos" nil - :callback (lambda (value _headers _status req) - (unless (ghub-continue req) - (setq my-value value)))) - - is equivalent to: - - (ghub-get "/users/tarsius/repos" nil - :unpaginate t - :callback (lambda (value _headers _status _req) - (setq my-value value))) - - To demonstrate how to pass information from one callback to the - next, here we record when we start fetching each page: - - (ghub-get "/users/tarsius/repos" nil - :extra (list (current-time)) - :callback (lambda (value _headers _status req) - (push (current-time) (ghub-req-extra req)) - (unless (ghub-continue req) - (setq my-times (ghub-req-extra req)) - (setq my-value value)))) - - -- Variable: ghub-response-headers - - A select few Github API resources respond by transmitting data in - the response header instead of in the response body. Because there - are so few of these inconsistencies, ‘ghub-request’ always returns - the response body. - - To access the response headers use this variable after - ‘ghub-request’ has returned. - - -- 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 - value returned by ‘system-name’ for the purpose of identifying the - local machine, which is necessary because Ghub uses separate tokens - for each machine. Also see *note Configuration Variables::. - - -- Variable: ghub-github-token-scopes - -- Variable: PACKAGE-github-token-scopes - - Such a variable defines the token scopes requested by the - respective package ‘PACKAGE’ given by the first word in the - variable name. ‘ghub’ itself is treated like any other package. - Also see *note Using Ghub in a Package::. - - -- Function: ghub-head resource &optional params &key query payload - headers unpaginate noerror reader username auth host callback - errorback - -- Function: ghub-get resource &optional params &key query payload - headers unpaginate noerror reader username auth host callback - errorback - - These functions are simple wrappers around ‘ghub-request’. Their - signature is identical to that of the latter, except that they do - not have an argument named ‘METHOD’. The HTTP method is instead - given by the second word in the function name. - - As described in the documentation for ‘ghub-request’, it depends on - the used method whether the value of the ‘PARAMS’ argument is used - as the query or the payload. For the "HEAD" and "GET" methods it - is used as the query. - - -- Function: ghub-put resource &optional params &key query payload - headers unpaginate noerror reader username auth host callback - errorback - -- Function: ghub-post resource &optional params &key query payload - headers unpaginate noerror reader username auth host callback - errorback - -- Function: ghub-patch resource &optional params &key query payload - headers unpaginate noerror reader username auth host callback - errorback - -- Function: ghub-delete resource &optional params &key query payload - headers unpaginate noerror reader username auth host callback - errorback - - These functions are simple wrappers around ‘ghub-request’. Their - signature is identical to that of the latter, except that they do - not have an argument named ‘METHOD’. The HTTP method is instead - given by the second word in the function name. - - As described in the documentation for ‘ghub-request’, it depends on - the used method whether the value of the ‘PARAMS’ argument is used - as the query or the payload. For the "PUT", "POST", "PATCH" and - "DELETE" methods it is used as the payload. - - -- Function: ghub-wait resource &optional duration &key username auth - host - - Some API requests result in an immediate successful response even - when the requested action has not actually been carried out yet. - An example is the request for the creation of a new repository, - which doesn’t cause the repository to immediately become available. - The Github API documentation usually mentions this when describing - an affected resource. - - If you want to do something with some resource right after making a - request for its creation, then you might have to wait for it to - actually be created. This function can be used to do so. It - repeatedly tries to access the resource until it becomes available - or until the timeout exceeds. In the latter case it signals - ‘ghub-error’. - - ‘RESOURCE’ specifies the resource that this function waits for. - - ‘DURATION’ specifies the maximum number of seconds to wait for, - defaulting to 64 seconds. Emacs will block during that time, but - the user can abort using ‘C-g’. - - The first attempt is made immediately and will often succeed. If - not, then another attempt is made after two seconds, and each - subsequent attempt is made after waiting as long as we already - waited between all preceding attempts combined. - - See ‘ghub-request’’s documentation above for information about the - other arguments. - - -- Function: ghub-graphql graphql &optional variables &key username - auth host callback - - 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. - - -File: ghub.info, Node: Authentication, Next: Configuration Variables, Prev: Making Requests, Up: API - -5.2 Authentication -================== - - -- Command: ghub-create-token - - This command creates a new token using the values it reads from the - user and then stores it according to the variable ‘auth-sources’. - It can also be called non-interactively, but you shouldn’t do that - yourself. - - This is useful if you want to fully setup things before attempting - to make the initial request, if you want to provide fewer than the - requested scopes or customize ‘auth-sources’ first, or if something - has gone wrong when using the wizard that is used when making a - request without doing this first. (Note that instead of using this - command you can also just repeat the initial request after making - the desired adjustments — that is easier.) - - This command reads, in order, the ‘HOST’ (Github instance), the - ‘USERNAME’, the ‘PACKAGE’, and the ‘SCOPES’ in the minibuffer, - providing reasonable default choices. ‘SCOPES’ defaults to the - scopes that ‘PACKAGE’ requests using the variable - ‘PACKAGE-github-token-scopes’. - - -- Command: ghub-token-scopes - - Users are free to give a token access to fewer scopes than what the - respective package requested. That can, of course, lead to issues, - and package maintainers have to be able to quickly determine if - such a (mis-)configuration is the root cause when users report - issues. - - This command reads the required values in the minibuffer and then - shows a message containing these values along with the scopes of - the respective token. It also returns the scopes (only) when - called non-interactively. Also see *note Using Ghub in a - Package::. - - -File: ghub.info, Node: Configuration Variables, Prev: Authentication, Up: API - -5.3 Configuration Variables -=========================== - -The username and, unless you only use Github.com itself, the Github -Enterprise instance have to be configured using Git variables. In rare -cases it might also be necessary to specify the identity of the local -machine, which is done using a lisp variable. - - -- Variable: github.user - - The Github.com username. This should be set globally and if you - have multiple Github.com user accounts, then you should set this - locally only for those repositories that you want to access using - the secondary identity. - - -- Variable: github.HOST.user - - This variable serves the same purpose as ‘github.user’ but for the - Github Enterprise instance identified by ‘HOST’. - - The reason why separate variables are used is that this makes it - possible to set both values globally instead of having to set one - of the values locally in each and every repository that is - connected to the Github Enterprise instance, not Github.com. - - -- Variable: github.host - - This variable should only be set locally for a repository and - specifies the Github Enterprise edition that that repository is - connected to. You should not set this globally because then each - and every repository becomes connected to the specified Github - Enterprise instance, including those that should actually be - connected to Github.com. - - When this is undefined, then "api.github.com" is used (defined in - the constant ‘ghub-default-host’, which you should never attempt to - change.) - - -- Variable: ghub-override-system-name - - Ghub uses a different token for each quadruple ‘(USERNAME PACKAGE - HOST LOCAL-MACHINE)’. Theoretically it could reuse tokens to some - extent but that would be more difficult to implement, less - flexible, and less secure (though slightly more convenient). - - A token is identified on the respective Github instance (Github.com - or a Github Enterprise instance) using the pair ‘(PACKAGE . - LOCAL-MACHINE)’, or more precisely the string "Emacs package - PACKAGE @ LOCAL-MACHINE". ‘USERNAME’ and ‘HOST’ do not have to be - encoded because the token is stored for ‘USERNAME’ on ‘HOST’ and - cannot be used by another user and/or on another instance. - - There is one potential problem though; for any given ‘(PACKAGE . - LOCAL-MACHINE)’ there can only be one token identified by "Emacs - package PACKAGE @ LOCAL-MACHINE"; Github does not allow multiple - tokens with the same description because it uses the description as - the identifier (it could use some hash instead, but alas it does - not). - - If you have multiple machines and some of them have the same name, - then you should probably change that as this is not how things - ought to be. However if you dual-boot, then it might make sense to - give that machine the same name regardless of what operating system - you have booted into. - - You could use the same token on both operating systems, but setting - that up might be somewhat difficult because it is not possible to - download an existing token from Github. You could, of course, - locally copy the token, but that is inconvenient and would make it - harder to only revoke the token used on your infected Windows - installation without also revoking it for your totally safe *BSD - installation. - - Alternatively you can set this variable to a unique value, that - will then be used to identify the local machine instead of the - value returned by ‘system-name’. - - -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 <https://github.com> 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 <https://gitlab.com> 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 <https://bitbucket.org> 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: <https://gitlab.com/profile/personal_access_tokens> - - • Bitbucket: - <https://bitbucket.org/account/user/tarsius/app-passwords> - - • Gitea: <https://localhost:3000/user/settings/applications> - - • Gogs: <https://localhost:3000/user/settings/applications> - - Also see *note Manually Creating and Storing a Token:: and *note - How Ghub uses Auth-Source::. - - • As mentioned in the previous node, the variables ‘gitea.host’ and - ‘gogs.host’ are not taken into account. - - • Gitea and Gogs do not support limiting a token to certain scopes. - - • 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. - - • 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. - - • 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") - - - -Tag Table: -Node: Top763 -Node: Introduction3279 -Node: Getting Started6321 -Node: Setting the Username9481 -Node: Interactively Creating and Storing a Token10906 -Node: Manually Creating and Storing a Token16546 -Node: How Ghub uses Auth-Source17769 -Node: Using Ghub in Personal Scripts19702 -Node: Using Ghub in a Package21158 -Node: API23776 -Node: Making Requests24573 -Node: Authentication38612 -Node: Configuration Variables40457 -Node: GraphQL Support44177 -Node: Support for Other Forges50842 -Node: Forge Functions and Variables51059 -Node: Forge Limitations and Notes55578 - -End Tag Table - - -Local Variables: -coding: utf-8 -End: diff --git a/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/glab.el b/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/glab.el deleted file mode 100644 index fa35b351d2f1..000000000000 --- a/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/glab.el +++ /dev/null @@ -1,153 +0,0 @@ -;;; glab.el --- minuscule client library for the Gitlab API -*- lexical-binding: t -*- - -;; Copyright (C) 2016-2018 Jonas Bernoulli - -;; Author: Jonas Bernoulli <jonas@bernoul.li> -;; 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: - -;; Glab is a library that provides basic support for using the Gitlab 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, Glab does -;; not support the guided creation of tokens because Gitlab lacks the -;; features that would be necessary to implement that. Users have to -;; create tokens through the web interface. - -;;; Code: - -(require 'ghub) - -(defconst glab-default-host "gitlab.com/api/v4" - "The default host that is used if `glab.host' is not set.") - -(cl-defun glab-head (resource &optional params - &key query payload headers - silent unpaginate noerror reader - username auth host - callback errorback extra) - "Make a `HEAD' request for RESOURCE, with optional query PARAMS. -Like calling `ghub-request' (which see) with \"HEAD\" as METHOD -and `gitlab' as FORGE." - (ghub-request "HEAD" resource params :forge 'gitlab - :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 glab-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 `gitlab' as FORGE." - (ghub-request "GET" resource params :forge 'gitlab - :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 glab-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 `gitlab' as FORGE." - (ghub-request "PUT" resource params :forge 'gitlab - :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 glab-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 `gitlab' as FORGE." - (ghub-request "POST" resource params :forge 'gitlab - :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 glab-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 `gitlab' as FORGE." - (ghub-request "PATCH" resource params :forge 'gitlab - :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 glab-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 `gitlab' as FORGE." - (ghub-request "DELETE" resource params :forge 'gitlab - :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 glab-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 `gitlab' as FORGE." - (ghub-request method resource params :forge 'gitlab - :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 glab-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 (glab-get (format "/projects/%s%%2F%s" owner name) - nil :username username :auth auth :host host))))) - -;;; _ -(provide 'glab) -;;; glab.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/glab.elc b/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/glab.elc deleted file mode 100644 index e8a1cee34af2..000000000000 --- a/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/glab.elc +++ /dev/null Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/gogs.el b/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/gogs.el deleted file mode 100644 index 0fbac46ee913..000000000000 --- a/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/gogs.el +++ /dev/null @@ -1,140 +0,0 @@ -;;; gogs.el --- minuscule client library for the Gogs API -*- lexical-binding: t -*- - -;; Copyright (C) 2016-2018 Jonas Bernoulli - -;; Author: Jonas Bernoulli <jonas@bernoul.li> -;; 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/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/gogs.elc b/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/gogs.elc deleted file mode 100644 index 1621489eb528..000000000000 --- a/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/gogs.elc +++ /dev/null Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/gtea.el b/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/gtea.el deleted file mode 100644 index 07ca2909f1ee..000000000000 --- a/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/gtea.el +++ /dev/null @@ -1,140 +0,0 @@ -;;; gtea.el --- minuscule client library for the Gitea API -*- lexical-binding: t -*- - -;; Copyright (C) 2016-2018 Jonas Bernoulli - -;; Author: Jonas Bernoulli <jonas@bernoul.li> -;; 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 diff --git a/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/gtea.elc b/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/gtea.elc deleted file mode 100644 index 9a5c99fd2625..000000000000 --- a/configs/shared/emacs/.emacs.d/elpa/ghub-20180911.1858/gtea.elc +++ /dev/null Binary files differ |