From: Andreas Gerler Date: Sun, 26 Nov 2023 15:56:43 +0000 (+0100) Subject: update ghub X-Git-Url: http://git.bundesbrandschatzamt.de/?a=commitdiff_plain;h=88629f6d7b69b50d6f21a1aebb2dd4baf4db1534;p=emacsconfig.git update ghub Signed-off-by: Andreas Gerler --- diff --git a/elpa/ghub-20230301.1402/buck.el b/elpa/ghub-20230301.1402/buck.el deleted file mode 100644 index b7a5cba9..00000000 --- a/elpa/ghub-20230301.1402/buck.el +++ /dev/null @@ -1,129 +0,0 @@ -;;; buck.el --- Client library for the Bitbucket API -*- lexical-binding:t -*- - -;; Copyright (C) 2016-2023 Jonas Bernoulli - -;; Author: Jonas Bernoulli -;; Homepage: https://github.com/magit/ghub -;; Keywords: tools - -;; SPDX-License-Identifier: GPL-3.0-or-later - -;; 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 of the License, -;; or (at your option) any later version. -;; -;; This file is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with this file. If not, see . - -;;; Commentary: - -;; Buck is a library that provides basic support for using the Bitbucket API -;; from Emacs packages. It abstracts access to API resources using only -;; a handful of functions that are not resource-specific. - -;; This library is implemented on top of Ghub. Unlike Ghub, Buck does -;; not support the guided creation of tokens because Bitbucket lacks the -;; features that would be necessary to implement that. Users have to -;; create tokens through the web interface. - -;;; Code: - -(require 'ghub) - -(defconst buck-default-host "api.bitbucket.org/2.0" - "The default host that is used if `buck.host' is not set.") - -;; HEAD and PATCH are not supported according to -;; https://developer.atlassian.com/bitbucket/api/2/reference/meta/uri-uuid - -(cl-defun buck-get (resource &optional params - &key query payload headers - silent unpaginate noerror reader - username auth host - callback errorback extra) - "Make a `GET' request for RESOURCE, with optional query PARAMS. -Like calling `ghub-request' (which see) with \"GET\" as METHOD -and `bitbucket' as FORGE." - (ghub-request "GET" resource params :forge 'bitbucket - :query query :payload payload :headers headers - :silent silent :unpaginate unpaginate - :noerror noerror :reader reader - :username username :auth auth :host host - :callback callback :errorback errorback :extra extra)) - -(cl-defun buck-put (resource &optional params - &key query payload headers - silent unpaginate noerror reader - username auth host - callback errorback extra) - "Make a `PUT' request for RESOURCE, with optional payload PARAMS. -Like calling `ghub-request' (which see) with \"PUT\" as METHOD -and `bitbucket' as FORGE." - (ghub-request "PUT" resource params :forge 'bitbucket - :query query :payload payload :headers headers - :silent silent :unpaginate unpaginate - :noerror noerror :reader reader - :username username :auth auth :host host - :callback callback :errorback errorback :extra extra)) - -(cl-defun buck-post (resource &optional params - &key query payload headers - silent unpaginate noerror reader - username auth host - callback errorback extra) - "Make a `POST' request for RESOURCE, with optional payload PARAMS. -Like calling `ghub-request' (which see) with \"POST\" as METHOD -and `bitbucket' as FORGE." - (ghub-request "POST" resource params :forge 'bitbucket - :query query :payload payload :headers headers - :silent silent :unpaginate unpaginate - :noerror noerror :reader reader - :username username :auth auth :host host - :callback callback :errorback errorback :extra extra)) - -(cl-defun buck-delete (resource &optional params - &key query payload headers - silent unpaginate noerror reader - username auth host - callback errorback extra) - "Make a `DELETE' request for RESOURCE, with optional payload PARAMS. -Like calling `ghub-request' (which see) with \"DELETE\" as METHOD -and `bitbucket' as FORGE." - (ghub-request "DELETE" resource params :forge 'bitbucket - :query query :payload payload :headers headers - :silent silent :unpaginate unpaginate - :noerror noerror :reader reader - :username username :auth auth :host host - :callback callback :errorback errorback :extra extra)) - -(cl-defun buck-request (method resource &optional params - &key query payload headers - silent unpaginate noerror reader - username auth host - callback errorback extra) - "Make a request for RESOURCE and return the response body. -Like calling `ghub-request' (which see) with `bitbucket' as FORGE." - (ghub-request method resource params :forge 'bitbucket - :query query :payload payload :headers headers - :silent silent :unpaginate unpaginate - :noerror noerror :reader reader - :username username :auth auth :host host - :callback callback :errorback errorback :extra extra)) - -(cl-defun buck-repository-id (owner name &key username auth host) - "Return the id of the repository specified by OWNER, NAME and HOST." - (substring (cdr (assq 'uuid - (buck-get (format "/repositories/%s/%s" owner name) - nil - :username username :auth auth :host host))) - 1 -1)) - -;;; _ -(provide 'buck) -;;; buck.el ends here diff --git a/elpa/ghub-20230301.1402/dir b/elpa/ghub-20230301.1402/dir deleted file mode 100644 index b703bcac..00000000 --- a/elpa/ghub-20230301.1402/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" 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). Client library for the Github API. diff --git a/elpa/ghub-20230301.1402/ghub-autoloads.el b/elpa/ghub-20230301.1402/ghub-autoloads.el deleted file mode 100644 index 8ddfa370..00000000 --- a/elpa/ghub-20230301.1402/ghub-autoloads.el +++ /dev/null @@ -1,78 +0,0 @@ -;;; ghub-autoloads.el --- automatically extracted autoloads -*- lexical-binding: t -*- -;; -;;; Code: - -(add-to-list 'load-path (directory-file-name - (or (file-name-directory #$) (car load-path)))) - - -;;;### (autoloads nil "buck" "buck.el" (0 0 0 0)) -;;; Generated autoloads from buck.el - -(register-definition-prefixes "buck" '("buck-default-host")) - -;;;*** - -;;;### (autoloads nil "ghub" "ghub.el" (0 0 0 0)) -;;; Generated autoloads from ghub.el - -(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+'." t nil) - -(register-definition-prefixes "ghub" '("ghub-")) - -;;;*** - -;;;### (autoloads nil "ghub-graphql" "ghub-graphql.el" (0 0 0 0)) -;;; Generated autoloads from ghub-graphql.el - -(register-definition-prefixes "ghub-graphql" '("ghub-")) - -;;;*** - -;;;### (autoloads nil "glab" "glab.el" (0 0 0 0)) -;;; Generated autoloads from glab.el - -(register-definition-prefixes "glab" '("glab-default-host")) - -;;;*** - -;;;### (autoloads nil "gogs" "gogs.el" (0 0 0 0)) -;;; Generated autoloads from gogs.el - -(register-definition-prefixes "gogs" '("gogs-default-host")) - -;;;*** - -;;;### (autoloads nil "gsexp" "gsexp.el" (0 0 0 0)) -;;; Generated autoloads from gsexp.el - -(register-definition-prefixes "gsexp" '("gsexp-")) - -;;;*** - -;;;### (autoloads nil "gtea" "gtea.el" (0 0 0 0)) -;;; Generated autoloads from gtea.el - -(register-definition-prefixes "gtea" '("gtea-default-host")) - -;;;*** - -;;;### (autoloads nil nil ("ghub-pkg.el") (0 0 0 0)) - -;;;*** - -;; Local Variables: -;; version-control: never -;; no-byte-compile: t -;; no-update-autoloads: t -;; coding: utf-8 -;; End: -;;; ghub-autoloads.el ends here diff --git a/elpa/ghub-20230301.1402/ghub-graphql.el b/elpa/ghub-20230301.1402/ghub-graphql.el deleted file mode 100644 index 1e40c5c6..00000000 --- a/elpa/ghub-20230301.1402/ghub-graphql.el +++ /dev/null @@ -1,564 +0,0 @@ -;;; ghub-graphql.el --- Access Github API using GrapthQL -*- lexical-binding:t -*- - -;; Copyright (C) 2016-2023 Jonas Bernoulli - -;; Author: Jonas Bernoulli -;; Homepage: https://github.com/magit/ghub -;; Keywords: tools - -;; SPDX-License-Identifier: GPL-3.0-or-later - -;; 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 of the License, -;; or (at your option) any later version. -;; -;; This file is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with this file. If not, see . - -;;; Code: - -(require 'ghub) -(require 'gsexp) -(require 'treepy) - -;; Needed for Emacs < 27. -(eval-when-compile (require 'json)) -(declare-function json-read-from-string "json" (string)) -(declare-function json-encode "json" (object)) - -(eval-when-compile (require 'pp)) ; Needed for Emacs < 29. -(eval-when-compile (require 'subr-x)) - -;;; Api - -(defvar ghub-graphql-items-per-request 100 - "Number of GraphQL items to query for entities that return a collection. - -Adjust this value if you're hitting query timeouts against larger -repositories.") - -(cl-defun ghub-graphql (graphql &optional variables - &key username auth host forge - headers 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 (not (stringp variables))) - (cl-assert (or (stringp graphql) - (memq (car-safe graphql) '(query mutation)))) - (unless (stringp graphql) - (setq graphql (gsexp-encode (ghub--graphql-prepare-query graphql)))) - (ghub-request "POST" - (if (eq forge 'gitlab) "/api/graphql" "/graphql") - nil - :payload `((query . ,graphql) - ,@(and variables `((variables ,@variables)))) - :headers headers :silent silent - :username username :auth auth :host host :forge forge - :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 (repository [(owner $owner String!) - (name $name String!)] - id)) - `((owner . ,owner) - (name . ,name)) - :username username :auth auth :host host) - .data.repository.id)) - -;;; Api (drafts) - -(defconst ghub-fetch-repository-sparse - '(query - (repository - [(owner $owner String!) - (name $name String!)] - name - id - createdAt - updatedAt - nameWithOwner - (parent nameWithOwner) - description - homepageUrl - (defaultBranchRef name) - isArchived - isFork - isLocked - isMirror - isPrivate - hasIssuesEnabled - hasWikiEnabled - (licenseInfo name) - (stargazers totalCount) - (watchers totalCount)))) - -(defconst ghub-fetch-repository - `(query - (repository - ,@(cdr (cadr ghub-fetch-repository-sparse)) - (assignableUsers [(:edges t)] - id - login - name) - (issues [(:edges t) - (:singular issue number) - (orderBy ((field UPDATED_AT) (direction DESC)))] - number - id - state - (author login) - title - createdAt - updatedAt - closedAt - locked - (milestone id) - body - (assignees [(:edges t)] - id) - (comments [(:edges t)] - databaseId - (author login) - createdAt - updatedAt - body) - (labels [(:edges t)] - id)) - (labels [(:edges t) - (:singular label id)] - id - name - color - description) - (milestones [(:edges t) - (:singular milestone id)] - id - number - title - createdAt - updatedAt - dueOn - closedAt - description) - (pullRequests [(:edges t) - (:singular pullRequest number) - (orderBy ((field UPDATED_AT) (direction DESC)))] - number - id - state - (author login) - title - createdAt - updatedAt - closedAt - mergedAt - isDraft - locked - maintainerCanModify - isCrossRepository - (milestone id) - body - (baseRef name - (repository nameWithOwner)) - baseRefOid - (headRef name - (repository (owner login) - nameWithOwner)) - headRefOid - (assignees [(:edges t)] - id) - (reviewRequests [(:edges t)] - (requestedReviewer "... on User { id }\n")) - (comments [(:edges t)] - databaseId - (author login) - createdAt - updatedAt - body) - (labels [(:edges t)] - id))))) - -(defconst ghub-fetch-repository-review-threads - '(query - (repository - [(owner $owner String!) - (name $name String!)] - (pullRequests [(:edges t) - (:singular pullRequest number) - (orderBy ((field UPDATED_AT) (direction DESC)))] - number - baseRefOid - headRefOid - (reviewThreads [(:edges t)] - id - line - originalLine - diffSide - (resolvedBy login) - (comments [(:edges t)] - id - databaseId - (author login) - createdAt - updatedAt - body - (replyTo databaseId) - (originalCommit oid) - path)))))) - -(cl-defun ghub-fetch-repository (owner name callback - &optional until - &key username auth host forge - headers errorback sparse) - "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 (if sparse - ghub-fetch-repository-sparse - ghub-fetch-repository) - `((owner . ,owner) - (name . ,name)) - callback until - :narrow '(repository) - :username username - :auth auth - :host host - :forge forge - :headers headers - :errorback errorback)) - -(cl-defun ghub-fetch-issue (owner name number callback - &optional until - &key username auth host forge - headers errorback) - "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 - :headers headers - :errorback errorback)) - -(cl-defun ghub-fetch-pullreq (owner name number callback - &optional until - &key username auth host forge - headers errorback) - "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 - :headers headers - :errorback errorback)) - -(cl-defun ghub-fetch-review-threads (owner name number callback - &optional until - &key username auth host forge - headers errorback) - "Asynchronously fetch forge data about the review threads from a 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-review-threads - `(repository pullRequests (pullRequest . ,number))) - `((owner . ,owner) - (name . ,name)) - callback until - :narrow '(repository pullRequest) - :username username - :auth auth - :host host - :forge forge - :headers headers - :errorback errorback)) - -;;; Internal - -(cl-defstruct (ghub--graphql-req - (:include ghub--req) - (:constructor ghub--make-graphql-req) - (:copier nil)) - (query nil :read-only t) - (query-str nil :read-only nil) - (variables nil :read-only t) - (until nil :read-only t) - (buffer 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 - headers errorback) - "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 - (format "https://%s/graphql" - (if (string-suffix-p "/v3" host) - (substring host 0 -3) - host))) - :method "POST" - :headers (ghub--headers headers host auth username forge) - :handler #'ghub--graphql-handle-response - :query query - :variables variables - :until until - :buffer (current-buffer) - :callback (and (not (eq callback 'synchronous)) - (let ((buf (current-buffer))) - (if narrow - (lambda (data) - (let ((path narrow) key) - (while (setq key (pop path)) - (setq data (cdr (assq key data))))) - (ghub--graphql-set-mode-line buf nil) - (funcall (or callback #'ghub--graphql-pp-response) - data)) - (lambda (data) - (ghub--graphql-set-mode-line buf nil) - (funcall (or callback #'ghub--graphql-pp-response) - data))))) - :errorback (and (not (eq callback 'synchronous)) - errorback)))) - -(cl-defun ghub--graphql-retrieve (req &optional lineage cursor) - (let ((p (cl-incf (ghub--graphql-req-pages req)))) - (when (> p 1) - (ghub--graphql-set-mode-line req "Fetching page %s" p))) - (setf (ghub--graphql-req-query-str req) - (gsexp-encode - (ghub--graphql-prepare-query - (ghub--graphql-req-query req) - lineage cursor))) - (ghub--retrieve - (let ((json-false nil)) - (ghub--encode-payload - `((query . ,(ghub--graphql-req-query-str req)) - (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 (and (vectorp node) - (listp (aref node 0))) - (let ((alist (cl-coerce node 'list)) - vars) - (when (cadr (assq :edges alist)) - (push (list 'first ghub-graphql-items-per-request) 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 (vconcat (nreverse vars))))))) - (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)))) - (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 req (assq 'data payload))))) - (when (buffer-live-p buffer) - (kill-buffer buffer))))) - -(defun ghub--graphql-walk-response (req data) - (let* ((loc (ghub--req-value req)) - (loc (if (not 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")))) - (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 - (seq-take-while - (lambda (node) - (or (string> (cdr (assq 'updatedAt node)) - 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)))))))) - (cond ((not (treepy-end-p loc)) - (setq loc (treepy-next loc))) - ((ghub--req-callback req) - (funcall (ghub--req-callback req) - (treepy-root loc)) - (cl-return)) - ((cl-return (treepy-root loc)))))))) - -(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)) - ;; Alias - (cl-find-if (lambda (c) - (eq (car-safe (car-safe c)) - (car lineage))) - query) - ;; Edges - (cl-find-if (lambda (c) - (and (listp c) - (vectorp (cadr c)) - (eq (cadr (assq :singular - (cl-coerce (cadr c) - 'list))) - (car lineage)))) - (cdr query)) - (error "BUG: Failed to narrow 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--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))) - -(defun ghub--graphql-set-mode-line (buf string &rest args) - (when (ghub--graphql-req-p buf) - (setq buf (ghub--graphql-req-buffer buf))) - (when (buffer-live-p buf) - (with-current-buffer buf - (setq mode-line-process - (and string (concat " " (apply #'format string args)))) - (force-mode-line-update t)))) - -(defun ghub--graphql-pp-response (data) - (require 'pp) ; needed for Emacs < 29. - (pp-display-expression data "*Pp Eval Output*")) - -;;; _ -(provide 'ghub-graphql) -;;; ghub-graphql.el ends here diff --git a/elpa/ghub-20230301.1402/ghub-pkg.el b/elpa/ghub-20230301.1402/ghub-pkg.el deleted file mode 100644 index e5e45783..00000000 --- a/elpa/ghub-20230301.1402/ghub-pkg.el +++ /dev/null @@ -1,15 +0,0 @@ -(define-package "ghub" "20230301.1402" "Client libraries for Git forge APIs." - '((emacs "25.1") - (compat "29.1.3.4") - (let-alist "1.0.6") - (treepy "0.1.1")) - :commit "6a5de97649ff3eca9aa20b79f3526b4b3ab86b13" :authors - '(("Jonas Bernoulli" . "jonas@bernoul.li")) - :maintainer - '("Jonas Bernoulli" . "jonas@bernoul.li") - :keywords - '("tools") - :url "https://github.com/magit/ghub") -;; Local Variables: -;; no-byte-compile: t -;; End: diff --git a/elpa/ghub-20230301.1402/ghub.el b/elpa/ghub-20230301.1402/ghub.el deleted file mode 100644 index f169ad01..00000000 --- a/elpa/ghub-20230301.1402/ghub.el +++ /dev/null @@ -1,1013 +0,0 @@ -;;; ghub.el --- Client libraries for Git forge APIs -*- lexical-binding:t -*- - -;; Copyright (C) 2016-2023 Jonas Bernoulli - -;; Author: Jonas Bernoulli -;; Homepage: https://github.com/magit/ghub -;; Keywords: tools - -;; SPDX-License-Identifier: GPL-3.0-or-later - -;; 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 of the License, -;; or (at your option) any later version. -;; -;; This file is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with this file. If not, see . - -;;; 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 'compat) -(require 'gnutls) -(require 'let-alist) -(require 'url) -(require 'url-auth) -(require 'url-http) - -(eval-when-compile (require 'subr-x)) - -;; Needed for Emacs < 27. -(eval-when-compile (require 'json)) -(declare-function json-read-from-string "json" (string)) -(declare-function json-encode "json" (object)) - -(declare-function glab-repository-id "glab" (owner name &key username auth host)) -(declare-function gtea-repository-id "gtea" (owner name &key username auth host)) -(declare-function gogs-repository-id "gogs" (owner name &key username auth host)) -(declare-function buck-repository-id "buck" (owner name &key username auth host)) - -(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. - -You have to manually create or update the token at -https://github.com/settings/tokens. This variable -only serves as documentation.") - -(defvar ghub-insecure-hosts nil - "List of hosts that use http instead of https.") - -(defvar ghub-json-use-jansson nil - "Whether to use the Jansson library, if available. -This is experimental. Only let-bind this but do not enable it -globally because doing that is likely to break other packages -that use `ghub'. As a user also do not enable this yet. -See https://github.com/magit/ghub/pull/149.") - -(defvar ghub-json-object-type 'alist - "The object type that is used for json payload decoding.") - -(defvar ghub-json-array-type 'list - "The array type that is used for json payload decoding.") - -;;; 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 headers 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 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 no error occurred, then call CALLBACK, unless - that is nil. - - If an error occurred, then call ERRORBACK, or if that is nil, - then CALLBACK. ERRORBACK can also be t, in which case an error - is signaled instead. NOERROR is ignored for all asynchronous - requests. - -Both callbacks are called with four arguments. - 1. For CALLBACK, the combined value of the retrieved pages. - For ERRORBACK, the error that occurred 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 (if (member host ghub-insecure-hosts) "http://" "https://") - (cond ((and (equal resource "/graphql") - (string-suffix-p "/v3" host)) - ;; Needed for some Github Enterprise instances. - (substring host 0 -3)) - ((and (equal resource "/api/graphql") - (string-suffix-p "/api/v4" host)) - ;; Needed for all Gitlab instances. - (substring host 0 -7)) - (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 forge) - "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-request "GET" resource nil - :noerror t - :username username - :auth auth - :host host - :forge forge)) - (message "Waited (%3ss of %ss) for %s..." total duration resource) - (if (= total duration) - (error "%s is taking too long to create %s" - (if forge (capitalize (symbol-name forge)) "Github") - 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) - (and-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))) - (and-let* ((rels (cdr (assoc "Link" (or headers ghub-response-headers))))) - (mapcar (lambda (elt) - (pcase-let ((`(,url ,rel) (split-string elt "; "))) - (cons (intern (substring rel 5 -1)) - (substring url 1 -1)))) - (split-string rels ", "))))) - -(cl-defun ghub-repository-id (owner name &key username auth host forge noerror) - "Return the id of the specified repository. -Signal an error if the id cannot be determined." - (let ((fn (cl-case forge - ((nil ghub github) #'ghub--repository-id) - (gitlab #'glab-repository-id) - (gitea #'gtea-repository-id) - (gogs #'gogs-repository-id) - (bitbucket #'buck-repository-id) - (t (intern (format "%s-repository-id" forge)))))) - (unless (fboundp fn) - (error "ghub-repository-id: Forge type/abbreviation `%s' is unknown" - forge)) - (or (funcall fn owner name :username username :auth auth :host host) - (and (not noerror) - (error "Repository %S does not exist on %S.\n%s%S?" - (concat owner "/" name) - (or host (ghub--host forge)) - "Maybe it was renamed and you have to update " - "remote..url"))))) - -;;;; Internal - -(defvar ghub-use-workaround-for-emacs-bug t - "Whether to work around Emacs bug debbugs#34341. - -First see https://github.com/magit/ghub/wiki/Known-Issues, -for information about this bug and another related bug. - -Because our under of these bugs evolved over time, the possible -values of this variable are a bit odd: If t, enable workaround if -necessary (i.e., if Emacs < 26.3 and GnuTLS >= 3.6.3 are used). -If `force', enable workaround even if that is believed to be -unnecessary. If nil, do not enable the workaround. The default -is t.") - -(defvar ghub-use-workaround-for-emacs-bug-54989 t - "Whether to work around Emacs bug debbugs#54989. - -First see https://github.com/magit/ghub/wiki/Known-Issues, -for information about this bug and another related bug. - -If t, work around the bug if necessary (i.e., if not using Emacs' -\"master\" branch). If nil, then don't work around the bug. The -default is t. Setting this variable only has an effect if it is -done before `ghub' is loaded.") - -(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)) - (gnutls-algorithm-priority - (if (and ghub-use-workaround-for-emacs-bug - (or (eq ghub-use-workaround-for-emacs-bug 'force) - (and (not gnutls-algorithm-priority) - (>= libgnutls-version 30603) - (version< emacs-version "26.3") - ;; (memq (ghub--req-forge req) '(github nil)) - ))) - "NORMAL:-VERS-TLS1.3" - gnutls-algorithm-priority))) - (if (or (ghub--req-callback req) - (ghub--req-errorback req)) - (url-retrieve url handler (list req) silent) - (with-current-buffer - (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)) - (prev (ghub--req-url 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) - (setf (ghub--req-url req) prev) - (funcall (if (eq errorback t) - 'ghub--errorback - 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) - (when (memq url-http-end-of-headers '(nil 0)) - (setq url-debug t) - (error "BUG: missing headers; but there's a patch for that \ -see https://github.com/magit/ghub/wiki/Known-Issues")) - (while (re-search-forward "^\\([^:]*\\): \\(.+\\)" - url-http-end-of-headers t) - (push (cons (match-string 1) - (match-string 2)) - headers)) - (setq headers (nreverse headers)) - (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 req)) - payload))) - -(defun ghub--signal-error (err &optional payload req) - (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)) - (and req (url-filename (ghub--req-url req))) - payload))) - (signal 'ghub-error data)) - (signal symb data)))) - -(defun ghub--errorback (err _headers _status req) - (ghub--signal-error err (nth 3 err) req)) - -(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 - (if (and ghub-json-use-jansson - (fboundp 'json-parse-string)) - (json-parse-string - raw - :object-type ghub-json-object-type - :array-type ghub-json-array-type - :false-object nil - :null-object nil) - (require 'json) - (let ((json-object-type ghub-json-object-type) - (json-array-type ghub-json-array-type) - (json-false nil) - (json-null nil)) - (json-read-from-string raw))) - ((json-parse-error json-readtable-error) - `((message - . ,(if (looking-at "") - (if (re-search-forward - "

\\(?:\\)?\\([^<]+\\)" 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 - (if (and ghub-json-use-jansson - (fboundp 'json-serialize)) - (json-serialize payload - ;; :object-type and :array-type - ;; are not supported here. - :false-object nil - :null-object :null) - (require 'json) - (let ((json-object-type ghub-json-object-type) - (json-array-type ghub-json-array-type) - (json-false nil) - (json-null :null)) - ;; Unfortunately `json-encode' may modify the input. - ;; See https://debbugs.gnu.org/cgi/bugreport.cgi?bug=40693. - ;; and https://github.com/magit/forge/issues/267 - (json-encode (copy-tree 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)) "=" - (cl-typecase val - (integer (number-to-string val)) - (boolean (if val "true" "false")) - (t (url-hexify-string val)))))) - params "&")) - -;;; Authentication -;;;; API - -;;;###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))))) - -(cl-defgeneric ghub--auth (host auth &optional username forge) - (unless username - (setq username (ghub--username host forge))) - (if (eq auth 'basic) - (cl-ecase forge - ((nil gitea gogs bitbucket) - (cons "Authorization" (ghub--basic-auth host username))) - ((github gitlab) - (error "%s does not support basic authentication" - (capitalize (symbol-name forge))))) - (cons (cl-ecase forge - ((nil github gitea gogs bitbucket) - "Authorization") - (gitlab - "Private-Token")) - (if (eq forge 'bitbucket) - ;; For some undocumented reason Bitbucket supports - ;; values of the form "token " only for GET - ;; requests. For PUT requests we have to use basic - ;; authentication. Note that the secret is a token - ;; (aka "app password"), not the actual password. - ;; The documentation fails to mention this little - ;; detail. See #97. - (concat "Basic " - (base64-encode-string - (concat username ":" - (ghub--token host username auth nil forge)) - t)) - (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 - (if (member host ghub-insecure-hosts) "http://" "https://")))) - (setf (url-user url) username) - (url-basic-auth url t))) - -(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. #24 #64 #72 - (auth-source-forget (list :host host :user user :max 1)) - (and (not nocreate) - (error "\ -Required %s token (\"%s\" for \"%s\") does not exist. -See https://magit.vc/manual/ghub/Getting-Started.html -or (info \"(ghub)Getting Started\") for instructions. -\(The setup wizard no longer exists.)" - (capitalize (symbol-name (or forge 'github))) - user host)))))) - (if (functionp token) (funcall token) token))) - -(cl-defgeneric 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))))) - -(cl-defgeneric ghub--username (host &optional forge) - (let ((var - (cl-ecase forge - ((nil github) - (if (equal host ghub-default-host) - "github.user" - (format "github.%s.user" host))) - (gitlab - (if (equal host "gitlab.com/api/v4") - "gitlab.user" - (format "gitlab.%s.user" host))) - (bitbucket - (if (equal host "api.bitbucket.org/2.0") - "bitbucket.user" - (format "bitbucket.%s.user" host))) - (gitea - (when (zerop (call-process "git" nil nil nil "config" "gitea.host")) - (error "gitea.host is set but always ignored")) - (format "gitea.%s.user" host)) - (gogs - (when (zerop (call-process "git" nil nil nil "config" "gogs.host")) - (error "gogs.host is set but always ignored")) - (format "gogs.%s.user" host))))) - (condition-case nil - (car (process-lines "git" "config" var)) - (error - (let ((user (read-string - (format "Git variable `%s' is unset. Set to: " var)))) - (if (equal user "") - (user-error "The empty string is not a valid username") - (call-process - "git" nil nil nil "config" - (if (eq (read-char-choice - (format "Set %s=%s [g]lobally (recommended) or [l]ocally? " - var user) - (list ?g ?l)) - ?g) - "--global" - "--local") - var user) - user)))))) - -(defun ghub--ident (username package) - (format "%s^%s" username package)) - -(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))) - -(when (version< emacs-version "26.2") - ;; Fixed by Emacs commit 60ff8101449eea3a5ca4961299501efd83d011bd. - (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)))) - -(when (< emacs-major-version 28) - ;; Fixed by Emacs commit 0b98ea5fbe276c67206896dca111c000f984ee0f. - (advice-add 'url-http-handle-authentication :around - 'url-http-handle-authentication@unauthorized-bugfix) - (defun url-http-handle-authentication@unauthorized-bugfix (fn proxy) - "If authorization failed then don't try again but fail properly. -For Emacs 27.1 prevent a useful `http' error from being replaced -by a generic one that omits all useful information. For earlier -releases prevent a new request from being made, which would -either result in an infinite loop or (e.g. in the case of `ghub') -the user being asked for their name." - (if (assoc "Authorization" url-http-extra-headers) - t ; Return "success", here also known as "successfully failed". - (funcall fn proxy)))) - -(when (and (< emacs-major-version 29) - ghub-use-workaround-for-emacs-bug-54989) - ;; Fixed in Emacs commit 0829c6836eff14dda0cf8b3047376967f7b000f4. - ;; Cleanup from 26faa2b943675107e1664b2fea7174137c473475 is not - ;; included in this copy because doing that would require changes - ;; to more functions. This function has seen a few other changes - ;; since Emacs 25.1, the oldest version we still support. Of these - ;; only 4f1df40db36b221e7842bd75d6281922dcb268ee makes a functional - ;; change, fixing debbug#35658. The first release to contain that - ;; commit is 27.1. That commit either fixes a related bug or it - ;; deals with the same bug but only partially fixes it. - (advice-add 'url-http-chunked-encoding-after-change-function :override - 'url-http-chunked-encoding-after-change-function@54989-backport) - (defvar url-http-chunked-last-crlf-missing nil) - (defvar url-http-content-type) - (defvar url-http-chunked-start) - (defvar url-http-chunked-length) - (defvar url-http-chunked-counter) - (defun url-http-chunked-encoding-after-change-function@54989-backport - (st nd length) - "Backport bugfix from https://debbugs.gnu.org/cgi/bugreport.cgi?bug=54989." - (if url-http-chunked-last-crlf-missing - (progn - (goto-char url-http-chunked-last-crlf-missing) - (if (not (looking-at "\r\n")) - (url-http-debug - "Still spinning for the terminator of last chunk...") - (url-http-debug "Saw the last CRLF.") - (delete-region (match-beginning 0) (match-end 0)) - (when (url-http-parse-headers) - (url-http-activate-callback)))) - (save-excursion - (goto-char st) - (let ((read-next-chunk t) - (case-fold-search t) - (regexp nil) - (no-initial-crlf nil)) - ;; We need to loop thru looking for more chunks even within - ;; one after-change-function call. - (while read-next-chunk - (setq no-initial-crlf (= 0 url-http-chunked-counter)) - (with-no-warnings - (if url-http-content-type - (url-display-percentage nil - "Reading [%s]... chunk #%d" - url-http-content-type url-http-chunked-counter) - (url-display-percentage nil - "Reading... chunk #%d" - url-http-chunked-counter))) - (url-http-debug "Reading chunk %d (%d %d %d)" - url-http-chunked-counter st nd length) - (setq regexp (if no-initial-crlf - "\\([0-9a-z]+\\).*\r?\n" - "\r?\n\\([0-9a-z]+\\).*\r?\n")) - - (if url-http-chunked-start - ;; We know how long the chunk is supposed to be, skip over - ;; leading crap if possible. - (if (> nd (+ url-http-chunked-start url-http-chunked-length)) - (progn - (url-http-debug "Got to the end of chunk #%d!" - url-http-chunked-counter) - (goto-char (+ url-http-chunked-start - url-http-chunked-length))) - (url-http-debug "Still need %d bytes to hit end of chunk" - (- (+ url-http-chunked-start - url-http-chunked-length) - nd)) - (setq read-next-chunk nil))) - (if (not read-next-chunk) - (url-http-debug "Still spinning for next chunk...") - (if no-initial-crlf (skip-chars-forward "\r\n")) - (if (not (looking-at regexp)) - (progn - ;; Must not have received the entirety of the chunk header, - ;; need to spin some more. - (url-http-debug "Did not see start of chunk @ %d!" (point)) - (setq read-next-chunk nil)) - ;; The data we got may have started in the middle of the - ;; initial chunk header, so move back to the start of the - ;; line and re-compute. - (when (= url-http-chunked-counter 0) - (beginning-of-line) - (looking-at regexp)) - (add-text-properties (match-beginning 0) (match-end 0) - (list 'chunked-encoding t - 'face 'cursor - 'invisible t)) - (setq url-http-chunked-length - (string-to-number (buffer-substring (match-beginning 1) - (match-end 1)) - 16) - url-http-chunked-counter (1+ url-http-chunked-counter) - url-http-chunked-start (set-marker - (or url-http-chunked-start - (make-marker)) - (match-end 0))) - (delete-region (match-beginning 0) (match-end 0)) - (url-http-debug "Saw start of chunk %d (length=%d, start=%d" - url-http-chunked-counter url-http-chunked-length - (marker-position url-http-chunked-start)) - (if (= 0 url-http-chunked-length) - (progn - ;; Found the end of the document! Wheee! - (url-http-debug "Saw end of stream chunk!") - (setq read-next-chunk nil) - (with-no-warnings - (url-display-percentage nil nil)) - ;; Every chunk, even the last 0-length one, is - ;; terminated by CRLF. Skip it. - (if (not (looking-at "\r?\n")) - (progn - (url-http-debug - "Spinning for the terminator of last chunk...") - (setq-local url-http-chunked-last-crlf-missing - (point))) - (url-http-debug "Removing terminator of last chunk") - (delete-region (match-beginning 0) (match-end 0)) - (when (re-search-forward "^\r?\n" nil t) - (url-http-debug "Saw end of trailers...")) - (when (url-http-parse-headers) - (url-http-activate-callback))))))))))))) - -;;; _ -(provide 'ghub) -(require 'ghub-graphql) -;;; ghub.el ends here diff --git a/elpa/ghub-20230301.1402/ghub.info b/elpa/ghub-20230301.1402/ghub.info deleted file mode 100644 index 56286bfe..00000000 --- a/elpa/ghub-20230301.1402/ghub.info +++ /dev/null @@ -1,1170 +0,0 @@ -This is ghub.info, produced by makeinfo version 6.7 from ghub.texi. - - Copyright (C) 2017-2023 Jonas Bernoulli - - 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). 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 is an Emacs library that is used by various packages to access the -APIs of various instances of various Git forge implementations. - -This manual is for Ghub version 3.5.6.50-git. - - Copyright (C) 2017-2023 Jonas Bernoulli - - 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:: -* API:: -* Notes:: -* Function Index:: -* Variable Index:: - -— The Detailed Node Listing — - -Getting Started - -* Basic Concepts, Arguments and Variables: Basic Concepts Arguments and Variables. -* Setting the Username:: -* Creating and Storing a Token:: -* Github Configuration Variables:: - -Creating and Storing a Token - -* Creating a Token:: -* Storing a Token:: - - -API - -* Their APIs:: -* Making REST Requests:: -* Making GraphQL Requests:: -* Github Convenience Wrappers:: -* Non-Github Convenience Wrappers:: - -Notes - -* Using Ghub in Personal Scripts:: -* Using Ghub in Your Own Package:: -* Forge Limitations and Notes:: - - - -File: ghub.info, Node: Introduction, Next: Getting Started, Prev: Top, Up: Top - -1 Introduction -************** - -Ghub is an Emacs library that is used by various packages to access the -APIs of various instances of various Git forge implementations. - - A forge is a web-based collaborative software platform for developing -and distributing computer applications. Examples include Github and -Gitlab. - - -File: ghub.info, Node: Getting Started, Next: API, Prev: Introduction, Up: Top - -2 Getting Started -***************** - -This manual guides you through the steps that are necessary to use the -Forge package and/or to make a request using just Ghub itself, such as -this: - - (ghub-request "GET" "/user") - - To be able to do that, Ghub needs to know who you want to talk to, -who you are, and how you are going to prove the latter to the former. - - Additionally Ghub wants to know on behalf of which Emacs package it -is making a request. So the question of "who is making the request" has -to be rephrased as "which human (or bot) is using what (Emacs) package -to make the request". If for example, the human known as "tarsius" is -using the ‘forge’ package, then that is represented in some places using -the string "tarsius^forge". - - This package used to attempt to get the answers to these questions -using a setup wizard. Unfortunately that had to be removed because (a) -it only ever supported Github, (b) by now Github has removed support for -that on their end, (c) it did not always work, and (d) when it couldn’t -be used, or failed, then it made things _more_ complicated. - - So now it is necessary for users to read some documentation and -because many things can go wrong, those instructions have to be fairly -detailed. You can of course skip over most of this, but if things go -wrong, then I would like to kindly request that you take another look -before asking me for help. - -* Menu: - -* Basic Concepts, Arguments and Variables: Basic Concepts Arguments and Variables. -* Setting the Username:: -* Creating and Storing a Token:: -* Github Configuration Variables:: - - -File: ghub.info, Node: Basic Concepts Arguments and Variables, Next: Setting the Username, Up: Getting Started - -2.1 Basic Concepts, Arguments and Variables -=========================================== - -Originally Ghub supported only Github but now it also supports Gitlab, -Gitea, Gogs and Bitbucket. For the historic reason just given, the -function ‘ghub-request’ defaults to acting on a ‘github’ forge, but can -be told to act on another forge using the 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. For example: - - (ghub-request "GET" "/user" nil - :forge 'github - :host "api.github.com" - :username "tarsius" - :auth 'forge) - - 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. - - (But for debugging purposes the above explicit form is very useful. -You will obviously have to change the value of USERNAME and you should -use ‘ghub’ as AUTH when first trying this at home.) - - These variables can be set globally and/or for a specific repository. - - • For "api.github.com" (aka the API of ) 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. - - These ‘github’ specific variables are discussed in more detail in -*note Github Configuration Variables::. - -For ‘gitlab’ and ‘bitbucket’ forges similar variables are available: - - • ‘gitlab.user’ specifies the user. - • ‘gitlab.HOST.user’ specifies the user for the HOST ‘gitlab’ - instance. - • ‘gitlab.host’ specifies the ‘gitlab’ host, unless the HOST argument - is non-nil - • ‘bitbucket.user’ specifies the user. - • ‘bitbucket.HOST.user’ specifies the user for the HOST ‘bitbucket’ - instance. - • ‘bitbucket.host’ specifies the ‘bitbucket’ host, unless the HOST - argument is non-nil. - - For the ‘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 ‘gogs’ 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 - - -File: ghub.info, Node: Setting the Username, Next: Creating and Storing a Token, Prev: Basic Concepts Arguments and Variables, Up: Getting Started - -2.2 Setting the Username -======================== - -Ghub needs to know your username that you use on the host that you want -it to connect to. For each host a different Git variable has to be set -to specify the username on that host. More than one variable is needed -because you might use different usernames on different hosts. - -Setting your Github.com Username --------------------------------- - -To inform Ghub about your "github.com" username do this: - - 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: - - cd /path/to/repo - git config --local github.user USERNAME - -Setting your Gitlab.com Username --------------------------------- - -To inform Ghub about your "gitlab.com" username do this: - - git config --global gitlab.user USERNAME - - If you need to identify as another user in a particular repository, -then you have to set that variable locally: - - cd /path/to/repo - git config --local gitlab.user USERNAME - - Make sure you use the correct USERNAME for this forge/host. It might -not be the same as on "github.com"! - -Setting your Github Enterprise Username ---------------------------------------- - -For Github Enterprise instances you have to specify where the API can be -accessed 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: - - git config --global github.example.com/api/v3.user USERNAME - - Make sure you use the correct USERNAME for this instance. It might -not be the same as on "github.com"! - - Doing this only tells Ghub who you are on this host, additionally you -have to tell Ghub which repositories are connected to that forge/host, -like so: - - cd /path/to/repo - git config --local github.host example.com/api/v3 - -Setting your Username for Other Hosts and/or Forges ---------------------------------------------------- - -To inform Ghub about your username on HOST (a FORGE instance) do this: - - git config --global FORGE.HOST.user USERNAME - - FORGE can be one of ‘bitbucket’, ‘gitea’ or ‘gogs’. It can also be -‘github’ or ‘gitlab’; but if that is the case, then you should look at -the preceding sections instead, which discuss these cases specifically. - - HOST identifies the instance. This actually points at the top-level -endpoint of the API and may contain path components, e.g.: -‘example.com/api’. - - If you need to identify as another user in a particular repository, -then you have to set that variable locally: - - cd /path/to/repo - git config --local FORGE.HOST.user USERNAME - - -File: ghub.info, Node: Creating and Storing a Token, Next: Github Configuration Variables, Prev: Setting the Username, Up: Getting Started - -2.3 Creating and Storing a Token -================================ - -* Menu: - -* Creating a Token:: -* Storing a Token:: - - -File: ghub.info, Node: Creating a Token, Next: Storing a Token, Up: Creating and Storing a Token - -2.3.1 Creating a Token ----------------------- - -To create a token, use the web interface of the forge/host you want to -connect to. Here is a list of pages to do this for certain popular -hosts: - - • - • - - For other forges we cannot provide a functioning URL because they -contain unknown values such as your name. Just go to the general -settings page of the respective host and then go from there. - - Except on ‘gitea’ and ‘gogs’ each token can be limited to certain -"scopes", i.e., it is possible to limit for which purposes any given -token can be used. - - Before you create a token to be used for a certain package, you -should consult the documentation of that package, which in turn should -tell you which scopes are needed and why. The Forge package for example -does so in *note (forge)Token Creation::. - - -File: ghub.info, Node: Storing a Token, Prev: Creating a Token, Up: Creating and Storing a Token - -2.3.2 Storing a Token ---------------------- - -Please also see *note (auth)Top:: for all the gory details about -Auth-Source. - - The variable ‘auth-sources’ controls how and where Auth-Source keeps -its secrets. The default value is a list of three files: -‘("~/.authinfo" "~/.authinfo.gpg" "~/.netrc")’, but to avoid confusion -you should make sure that only one of these files exists and then you -should also adjust the value of the variable to only ever use that file, -for example: - - (setq auth-sources '("~/.authinfo")) - - In ‘~/.authinfo’ secrets are stored in plain text. If you don’t want -that, then you should use the encrypted ‘~/.authinfo.gpg’ instead: - - (setq auth-sources '("~/.authinfo.gpg")) - - Auth-Source also supports storing secrets in various external -key-chains. See *note (auth)Top:: for more information. - - The default 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 *Github* username is "ziggy", the package is named -"forge", and you want to access *Github.com* with the *token* -"012345abcdef...", an entry in one of the three mentioned files would -then look like this: - - machine api.github.com login ziggy^forge password 012345abcdef... - - Assuming your *Gitlab* username is "ziggy", the package is named -"forge", and you want to access *Gitlab.com* with the *token* -"012345abcdef...", an entry in one of the three mentioned files would -then look like this: - - machine gitlab.com/api/v4 login ziggy^forge password 012345abcdef... - - -File: ghub.info, Node: Github Configuration Variables, Prev: Creating and Storing a Token, Up: Getting Started - -2.4 Github 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.) - - -File: ghub.info, Node: API, Next: Notes, Prev: Getting Started, Up: Top - -3 API -***** - -* Menu: - -* Their APIs:: -* Making REST Requests:: -* Making GraphQL Requests:: -* Github Convenience Wrappers:: -* Non-Github Convenience Wrappers:: - - -File: ghub.info, Node: Their APIs, Next: Making REST Requests, Up: API - -3.1 Their APIs -============== - -Of course this manual does not cover the APIs of all forges that it -supports, but for your convenience, here are the links to their API -manuals: - - • Github: - • (GraphQl) - • (REST) - • Gitlab: - • - • Gitea: - • - • - • Gogs: - • - • Bitbucket: - • - - -File: ghub.info, Node: Making REST Requests, Next: Making GraphQL Requests, Prev: Their APIs, Up: API - -3.2 Making REST 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 headers are 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 makes 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 package 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 no error - occurred, then it calls ‘CALLBACK’, unless that is ‘nil’. - - If an error occurred, then it calls ‘ERRORBACK’, or if that is - nil, then ‘CALLBACK’. ‘ERRORBACK’ can also be ‘t’, in which - case it signals instead. ‘NOERROR’ is ignored for all - asynchronous requests. - - Both callbacks are called with four arguments. - - 1. For ‘CALLBACK’, the combined value of the retrieved - pages. For ‘ERRORBACK’, the error that occurred 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 the first - argument to ‘ERRORBACK’. - 4. 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 retrieved 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’. - - -File: ghub.info, Node: Making GraphQL Requests, Next: Github Convenience Wrappers, Prev: Making REST Requests, Up: API - -3.3 Making GraphQL Requests -=========================== - - -- 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 ‘GRAPHQL’ 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 have implemented 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 on 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 - bundled ‘gsexp’ library is used to turn that into a GraphQL query - string. 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. If ‘CALLBACK’ is nil, pretty-print the response. - - 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 uses ‘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: Github Convenience Wrappers, Next: Non-Github Convenience Wrappers, Prev: Making GraphQL Requests, Up: API - -3.4 Github Convenience Wrappers -=============================== - - -- 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 a timeout is reached. 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. - - -File: ghub.info, Node: Non-Github Convenience Wrappers, Prev: Github Convenience Wrappers, Up: API - -3.5 Non-Github Convenience Wrappers -=================================== - -‘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 Your Own -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. - - -- Function: buck-request resource &optional params &key query payload - headers unpaginate noerror reader username auth host callback - errorback - -- Function: glab-request resource &optional params &key query payload - headers unpaginate noerror reader username auth host callback - errorback - -- Function: gogs-request resource &optional params &key query payload - headers unpaginate noerror reader username auth host callback - errorback - Wrappers around ‘ghub-request’ which hardcode the FORGE to either - ‘bitbucket’, ‘gitlab’, ‘gogs’ or ‘gitea’. - - -- Function: buck-get resource &optional params &key query payload - headers unpaginate noerror reader username auth host callback - errorback - -- Function: buck-put resource &optional params &key query payload - headers unpaginate noerror reader username auth host callback - errorback - -- Function: buck-post resource &optional params &key query payload - headers unpaginate noerror reader username auth host callback - errorback - -- Function: buck-delete resource &optional params &key query payload - headers unpaginate noerror reader username auth host callback - errorback - -- Function: glab-head resource &optional params &key query payload - headers unpaginate noerror reader username auth host callback - errorback - -- Function: glab-get resource &optional params &key query payload - headers unpaginate noerror reader username auth host callback - errorback - -- Function: glab-put resource &optional params &key query payload - headers unpaginate noerror reader username auth host callback - errorback - -- Function: glab-post resource &optional params &key query payload - headers unpaginate noerror reader username auth host callback - errorback - -- Function: glab-patch resource &optional params &key query payload - headers unpaginate noerror reader username auth host callback - errorback - -- Function: glab-delete resource &optional params &key query payload - headers unpaginate noerror reader username auth host callback - errorback - -- Function: gogs-get resource &optional params &key query payload - headers unpaginate noerror reader username auth host callback - errorback - -- Function: gogs-put resource &optional params &key query payload - headers unpaginate noerror reader username auth host callback - errorback - -- Function: gogs-post resource &optional params &key query payload - headers unpaginate noerror reader username auth host callback - errorback - -- Function: gogs-patch resource &optional params &key query payload - headers unpaginate noerror reader username auth host callback - errorback - -- Function: gogs-delete resource &optional params &key query payload - headers unpaginate noerror reader username auth host callback - errorback - -- Function: gtea-get resource &optional params &key query payload - headers unpaginate noerror reader username auth host callback - errorback - -- Function: gtea-put resource &optional params &key query payload - headers unpaginate noerror reader username auth host callback - errorback - -- Function: gtea-post resource &optional params &key query payload - headers unpaginate noerror reader username auth host callback - errorback - -- Function: gtea-patch resource &optional params &key query payload - headers unpaginate noerror reader username auth host callback - errorback - -- Function: gtea-delete resource &optional params &key query payload - headers unpaginate noerror reader username auth host callback - errorback - Wrappers around ‘FORGE-METHOD’ which hardcode the FORGE to either - ‘bitbucket’, ‘gitlab’, ‘gogs’ or ‘gitea’, and the METHOD to the - implied method. - - Note that ‘buck-head’, ‘buck-patch’, ‘gogs-head’ and ‘gtea-head’ do - not exist because the respective APIs do not appear to support - these methods. - - -File: ghub.info, Node: Notes, Next: Function Index, Prev: API, Up: Top - -4 Notes -******* - -* Menu: - -* Using Ghub in Personal Scripts:: -* Using Ghub in Your Own Package:: -* Forge Limitations and Notes:: - - -File: ghub.info, Node: Using Ghub in Personal Scripts, Next: Using Ghub in Your Own Package, Up: Notes - -4.1 Using Ghub in Personal Scripts -================================== - -You can of course use ‘ghub-request’ and its wrapper functions in your -personal scripts. Unlike when you use Ghub in a package that you -distribute for others to use, you don’t have to explicitly specify a -package in personal scripts. - - ;; This is perfectly acceptable in personal scripts ... - (ghub-get "/user") - - ;; ... and actually equals to - (ghub-get "/user" nil :auth 'ghub) - - ;; In packages you have to specify the package using AUTH. - (ghub-get "/user" nil :auth 'some-package) - - When the ‘AUTH’ argument is not specified, then a request is made on -behalf of the ‘ghub’ package itself. Like for any other package you -have to create a dedicated token of coures. - - -File: ghub.info, Node: Using Ghub in Your Own Package, Next: Forge Limitations and Notes, Prev: Using Ghub in Personal Scripts, Up: Notes - -4.2 Using Ghub in Your Own 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. - - 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) - - Keep in mind that the users of your package will have to manually -create a suitable token. To make that easier, you should not only link -to this manual but also prominently mention the scopes the token needs; -and explain what they are needed for. - - -File: ghub.info, Node: Forge Limitations and Notes, Prev: Using Ghub in Your Own Package, Up: Notes - -4.3 Forge Limitations and Notes -=============================== - - • There are no default Gitea and Gogs instances so 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 and my willingness to deal with - that is extremely limited unless someone pays me vast amounts of - money. - - • 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 - occasionally 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") - - -File: ghub.info, Node: Function Index, Next: Variable Index, Prev: Notes, Up: Top - -Appendix A Function Index -************************* - -[index] -* Menu: - -* buck-delete: Non-Github Convenience Wrappers. - (line 49) -* buck-get: Non-Github Convenience Wrappers. - (line 40) -* buck-post: Non-Github Convenience Wrappers. - (line 46) -* buck-put: Non-Github Convenience Wrappers. - (line 43) -* buck-request: Non-Github Convenience Wrappers. - (line 28) -* ghub--graphql-vacuum: Making GraphQL Requests. - (line 56) -* ghub-continue: Making REST Requests. - (line 125) -* ghub-delete: Github Convenience Wrappers. - (line 31) -* ghub-fetch-issue: Making GraphQL Requests. - (line 105) -* ghub-fetch-pullreq: Making GraphQL Requests. - (line 111) -* ghub-fetch-repository: Making GraphQL Requests. - (line 99) -* ghub-get: Github Convenience Wrappers. - (line 9) -* ghub-graphql: Making GraphQL Requests. - (line 6) -* ghub-head: Github Convenience Wrappers. - (line 6) -* ghub-patch: Github Convenience Wrappers. - (line 28) -* ghub-post: Github Convenience Wrappers. - (line 25) -* ghub-put: Github Convenience Wrappers. - (line 22) -* ghub-request: Making REST Requests. - (line 6) -* ghub-response-link-relations: Making REST Requests. - (line 174) -* ghub-wait: Github Convenience Wrappers. - (line 44) -* glab-delete: Non-Github Convenience Wrappers. - (line 67) -* glab-get: Non-Github Convenience Wrappers. - (line 55) -* glab-head: Non-Github Convenience Wrappers. - (line 52) -* glab-patch: Non-Github Convenience Wrappers. - (line 64) -* glab-post: Non-Github Convenience Wrappers. - (line 61) -* glab-put: Non-Github Convenience Wrappers. - (line 58) -* glab-request: Non-Github Convenience Wrappers. - (line 31) -* gogs-delete: Non-Github Convenience Wrappers. - (line 82) -* gogs-get: Non-Github Convenience Wrappers. - (line 70) -* gogs-patch: Non-Github Convenience Wrappers. - (line 79) -* gogs-post: Non-Github Convenience Wrappers. - (line 76) -* gogs-put: Non-Github Convenience Wrappers. - (line 73) -* gogs-request: Non-Github Convenience Wrappers. - (line 34) -* gtea-delete: Non-Github Convenience Wrappers. - (line 97) -* gtea-get: Non-Github Convenience Wrappers. - (line 85) -* gtea-patch: Non-Github Convenience Wrappers. - (line 94) -* gtea-post: Non-Github Convenience Wrappers. - (line 91) -* gtea-put: Non-Github Convenience Wrappers. - (line 88) - - -File: ghub.info, Node: Variable Index, Prev: Function Index, Up: Top - -Appendix B Variable Index -************************* - -[index] -* Menu: - -* ghub-response-headers: Making REST Requests. - (line 165) -* github.host: Github Configuration Variables. - (line 26) -* github.HOST.user: Github Configuration Variables. - (line 17) -* github.user: Github Configuration Variables. - (line 11) - - - -Tag Table: -Node: Top754 -Node: Introduction2285 -Node: Getting Started2690 -Node: Basic Concepts Arguments and Variables4372 -Node: Setting the Username8226 -Ref: Setting your Githubcom Username8710 -Ref: Setting your Gitlabcom Username9066 -Ref: Setting your Github Enterprise Username9532 -Ref: Setting your Username for Other Hosts and/or Forges10265 -Node: Creating and Storing a Token11071 -Node: Creating a Token11335 -Node: Storing a Token12355 -Node: Github Configuration Variables14200 -Node: API15911 -Node: Their APIs16149 -Node: Making REST Requests16874 -Node: Making GraphQL Requests26287 -Node: Github Convenience Wrappers32970 -Node: Non-Github Convenience Wrappers36674 -Node: Notes42178 -Node: Using Ghub in Personal Scripts42385 -Node: Using Ghub in Your Own Package43276 -Node: Forge Limitations and Notes44211 -Node: Function Index45184 -Node: Variable Index50833 - -End Tag Table - - -Local Variables: -coding: utf-8 -End: diff --git a/elpa/ghub-20230301.1402/glab.el b/elpa/ghub-20230301.1402/glab.el deleted file mode 100644 index 9dd2608a..00000000 --- a/elpa/ghub-20230301.1402/glab.el +++ /dev/null @@ -1,168 +0,0 @@ -;;; glab.el --- Client library for the Gitlab API -*- lexical-binding:t -*- - -;; Copyright (C) 2016-2023 Jonas Bernoulli - -;; Author: Jonas Bernoulli -;; Homepage: https://github.com/magit/ghub -;; Keywords: tools - -;; SPDX-License-Identifier: GPL-3.0-or-later - -;; 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 of the License, -;; or (at your option) any later version. -;; -;; This file is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with this file. If not, see . - -;;; 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-graphql (graphql &optional variables - &key username auth host - headers silent - callback errorback value extra) - "Make a GraphQL request using GRAPHQL and VARIABLES. -Like calling `ghub-graphql' (which see) with `gitlab' as FORGE." - (ghub-graphql graphql variables :forge 'gitlab - :username username :auth auth :host host - :headers headers :silent silent - :callback callback :errorback errorback - :value value :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" - (string-replace "/" "%2F" owner) - name) - nil :username username :auth auth :host host))))) - -;;; _ -(provide 'glab) -;;; glab.el ends here diff --git a/elpa/ghub-20230301.1402/gogs.el b/elpa/ghub-20230301.1402/gogs.el deleted file mode 100644 index f191ea93..00000000 --- a/elpa/ghub-20230301.1402/gogs.el +++ /dev/null @@ -1,141 +0,0 @@ -;;; gogs.el --- Client library for the Gogs API -*- lexical-binding:t -*- - -;; Copyright (C) 2016-2023 Jonas Bernoulli - -;; Author: Jonas Bernoulli -;; Homepage: https://github.com/magit/ghub -;; Keywords: tools - -;; SPDX-License-Identifier: GPL-3.0-or-later - -;; 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 of the License, -;; or (at your option) any later version. -;; -;; This file is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with this file. If not, see . - -;;; 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 Gogs host.") - -;; HEAD does not appear to be supported. - -(cl-defun gogs-get (resource &optional params - &key query payload headers - silent unpaginate noerror reader - username auth host - callback errorback extra) - "Make a `GET' request for RESOURCE, with optional query PARAMS. -Like calling `ghub-request' (which see) with \"GET\" as METHOD -and `gogs' as FORGE." - (ghub-request "GET" resource params :forge 'gogs - :query query :payload payload :headers headers - :silent silent :unpaginate unpaginate - :noerror noerror :reader reader - :username username :auth auth :host host - :callback callback :errorback errorback :extra extra)) - -(cl-defun gogs-put (resource &optional params - &key query payload headers - silent unpaginate noerror reader - username auth host - callback errorback extra) - "Make a `PUT' request for RESOURCE, with optional payload PARAMS. -Like calling `ghub-request' (which see) with \"PUT\" as METHOD -and `gogs' as FORGE." - (ghub-request "PUT" resource params :forge 'gogs - :query query :payload payload :headers headers - :silent silent :unpaginate unpaginate - :noerror noerror :reader reader - :username username :auth auth :host host - :callback callback :errorback errorback :extra extra)) - -(cl-defun gogs-post (resource &optional params - &key query payload headers - silent unpaginate noerror reader - username auth host - callback errorback extra) - "Make a `POST' request for RESOURCE, with optional payload PARAMS. -Like calling `ghub-request' (which see) with \"POST\" as METHOD -and `gogs' as FORGE." - (ghub-request "POST" resource params :forge 'gogs - :query query :payload payload :headers headers - :silent silent :unpaginate unpaginate - :noerror noerror :reader reader - :username username :auth auth :host host - :callback callback :errorback errorback :extra extra)) - -(cl-defun gogs-patch (resource &optional params - &key query payload headers - silent unpaginate noerror reader - username auth host - callback errorback extra) - "Make a `PATCH' request for RESOURCE, with optional payload PARAMS. -Like calling `ghub-request' (which see) with \"PATCH\" as METHOD -and `gogs' as FORGE." - (ghub-request "PATCH" resource params :forge 'gogs - :query query :payload payload :headers headers - :silent silent :unpaginate unpaginate - :noerror noerror :reader reader - :username username :auth auth :host host - :callback callback :errorback errorback :extra extra)) - -(cl-defun gogs-delete (resource &optional params - &key query payload headers - silent unpaginate noerror reader - username auth host - callback errorback extra) - "Make a `DELETE' request for RESOURCE, with optional payload PARAMS. -Like calling `ghub-request' (which see) with \"DELETE\" as METHOD -and `gogs' as FORGE." - (ghub-request "DELETE" resource params :forge 'gogs - :query query :payload payload :headers headers - :silent silent :unpaginate unpaginate - :noerror noerror :reader reader - :username username :auth auth :host host - :callback callback :errorback errorback :extra extra)) - -(cl-defun gogs-request (method resource &optional params - &key query payload headers - silent unpaginate noerror reader - username auth host - callback errorback extra) - "Make a request for RESOURCE and return the response body. -Like calling `ghub-request' (which see) with `gogs' as FORGE." - (ghub-request method resource params :forge 'gogs - :query query :payload payload :headers headers - :silent silent :unpaginate unpaginate - :noerror noerror :reader reader - :username username :auth auth :host host - :callback callback :errorback errorback :extra extra)) - -(cl-defun gogs-repository-id (owner name &key username auth host) - "Return the id of the repository specified by OWNER, NAME and HOST." - (number-to-string - (cdr (assq 'id (gogs-get (format "/repos/%s/%s" owner name) - nil :username username :auth auth :host host))))) - -;;; _ -(provide 'gogs) -;;; gogs.el ends here diff --git a/elpa/ghub-20230301.1402/gsexp.el b/elpa/ghub-20230301.1402/gsexp.el deleted file mode 100644 index 4e578550..00000000 --- a/elpa/ghub-20230301.1402/gsexp.el +++ /dev/null @@ -1,102 +0,0 @@ -;;; gsexp.el --- GraphQl as S-expressions -*- lexical-binding:t -*- - -;; Copyright (C) 2016-2023 Jonas Bernoulli - -;; Author: Jonas Bernoulli -;; Homepage: https://github.com/magit/ghub -;; Keywords: tools - -;; SPDX-License-Identifier: GPL-3.0-or-later - -;; 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 of the License, -;; or (at your option) any later version. -;; -;; This file is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with this file. If not, see . - -;;; Commentary: - -;; This library encodes S-expressions as GraphQl documents. Currently -;; it is rather incomplete and only intended for use by `ghub-graphql' -;; but I might fill the gaps and add documentation eventually. I am -;; not in a hurry though. - -;;; Code: - -(require 'cl-lib) - -(defvar gsexp-one-variable-per-line nil) - -(defun gsexp-encode (document) - (gsexp--pp (gsexp--encode-field document))) - -(defun gsexp--encode-field (field) - (cond - ((stringp field) - field) - ((symbolp field) - (symbol-name field)) - ((listp (car field)) - (concat (format "%s: " (caar field)) - (gsexp--encode-field (cons (car (cdar field)) - (cdr field))))) - ((concat - (pcase (pop field) - (`[] "") - ((and (pred symbolp) op) (symbol-name op)) - (`[,op] (symbol-name op)) - (`[,op ,name] (format "%s %s" op name))) - (and (vectorp (car field)) - (format " (%s%s)" - (if gsexp-one-variable-per-line "\n" "") - (mapconcat #'gsexp--encode-argument - (append (pop field) nil) - (if gsexp-one-variable-per-line ",\n" ",")))) - (and field - (format " {\n%s\n}" - (mapconcat #'gsexp--encode-field field "\n"))))))) - -(cl-defun gsexp--encode-argument ((argument value)) - (format "%s: %s" argument (gsexp--encode-value value))) - -(defun gsexp--encode-value (value) - (cond - ((numberp value) - (number-to-string value)) - ((symbolp value) ; including variables, enums, booleans and null - (symbol-name value)) - ((stringp value) - (prin1-to-string value)) - ((vectorp value) - (format "(%s)" (mapconcat #'gsexp--encode-value value ""))) - ((listp value) - (format "{%s}" (mapconcat - (pcase-lambda (`(,name ,value)) - (format "%s: %s" name (gsexp--encode-value value))) - value ", "))) - ((error "Invalid field value: %S" value)))) - -(defun gsexp--pp (string) - (with-temp-buffer - (save-excursion - (insert string)) - (while (< (point) (point-max)) - (unless (and (bolp) (eolp)) - (save-excursion - (let ((level (car (syntax-ppss (line-beginning-position))))) - (when (looking-at "\\s-*\\s)") - (cl-decf level)) - (indent-line-to (* 2 level))))) - (forward-line 1)) - (buffer-string))) - -;;; _ -(provide 'gsexp) -;;; gsexp.el ends here diff --git a/elpa/ghub-20230301.1402/gtea.el b/elpa/ghub-20230301.1402/gtea.el deleted file mode 100644 index 267a0b46..00000000 --- a/elpa/ghub-20230301.1402/gtea.el +++ /dev/null @@ -1,141 +0,0 @@ -;;; gtea.el --- Client library for the Gitea API -*- lexical-binding:t -*- - -;; Copyright (C) 2016-2023 Jonas Bernoulli - -;; Author: Jonas Bernoulli -;; Homepage: https://github.com/magit/ghub -;; Keywords: tools - -;; SPDX-License-Identifier: GPL-3.0-or-later - -;; 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 of the License, -;; or (at your option) any later version. -;; -;; This file is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with this file. If not, see . - -;;; 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 Gitea host.") - -;; 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/elpa/ghub-20230513.1619/buck.el b/elpa/ghub-20230513.1619/buck.el new file mode 100644 index 00000000..b7a5cba9 --- /dev/null +++ b/elpa/ghub-20230513.1619/buck.el @@ -0,0 +1,129 @@ +;;; buck.el --- Client library for the Bitbucket API -*- lexical-binding:t -*- + +;; Copyright (C) 2016-2023 Jonas Bernoulli + +;; Author: Jonas Bernoulli +;; Homepage: https://github.com/magit/ghub +;; Keywords: tools + +;; SPDX-License-Identifier: GPL-3.0-or-later + +;; 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 of the License, +;; or (at your option) any later version. +;; +;; This file is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this file. If not, see . + +;;; Commentary: + +;; Buck is a library that provides basic support for using the Bitbucket API +;; from Emacs packages. It abstracts access to API resources using only +;; a handful of functions that are not resource-specific. + +;; This library is implemented on top of Ghub. Unlike Ghub, Buck does +;; not support the guided creation of tokens because Bitbucket lacks the +;; features that would be necessary to implement that. Users have to +;; create tokens through the web interface. + +;;; Code: + +(require 'ghub) + +(defconst buck-default-host "api.bitbucket.org/2.0" + "The default host that is used if `buck.host' is not set.") + +;; HEAD and PATCH are not supported according to +;; https://developer.atlassian.com/bitbucket/api/2/reference/meta/uri-uuid + +(cl-defun buck-get (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `GET' request for RESOURCE, with optional query PARAMS. +Like calling `ghub-request' (which see) with \"GET\" as METHOD +and `bitbucket' as FORGE." + (ghub-request "GET" resource params :forge 'bitbucket + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun buck-put (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `PUT' request for RESOURCE, with optional payload PARAMS. +Like calling `ghub-request' (which see) with \"PUT\" as METHOD +and `bitbucket' as FORGE." + (ghub-request "PUT" resource params :forge 'bitbucket + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun buck-post (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `POST' request for RESOURCE, with optional payload PARAMS. +Like calling `ghub-request' (which see) with \"POST\" as METHOD +and `bitbucket' as FORGE." + (ghub-request "POST" resource params :forge 'bitbucket + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun buck-delete (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `DELETE' request for RESOURCE, with optional payload PARAMS. +Like calling `ghub-request' (which see) with \"DELETE\" as METHOD +and `bitbucket' as FORGE." + (ghub-request "DELETE" resource params :forge 'bitbucket + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun buck-request (method resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a request for RESOURCE and return the response body. +Like calling `ghub-request' (which see) with `bitbucket' as FORGE." + (ghub-request method resource params :forge 'bitbucket + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun buck-repository-id (owner name &key username auth host) + "Return the id of the repository specified by OWNER, NAME and HOST." + (substring (cdr (assq 'uuid + (buck-get (format "/repositories/%s/%s" owner name) + nil + :username username :auth auth :host host))) + 1 -1)) + +;;; _ +(provide 'buck) +;;; buck.el ends here diff --git a/elpa/ghub-20230513.1619/dir b/elpa/ghub-20230513.1619/dir new file mode 100644 index 00000000..b703bcac --- /dev/null +++ b/elpa/ghub-20230513.1619/dir @@ -0,0 +1,18 @@ +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" 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). Client library for the Github API. diff --git a/elpa/ghub-20230513.1619/ghub-autoloads.el b/elpa/ghub-20230513.1619/ghub-autoloads.el new file mode 100644 index 00000000..8ddfa370 --- /dev/null +++ b/elpa/ghub-20230513.1619/ghub-autoloads.el @@ -0,0 +1,78 @@ +;;; ghub-autoloads.el --- automatically extracted autoloads -*- lexical-binding: t -*- +;; +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + +;;;### (autoloads nil "buck" "buck.el" (0 0 0 0)) +;;; Generated autoloads from buck.el + +(register-definition-prefixes "buck" '("buck-default-host")) + +;;;*** + +;;;### (autoloads nil "ghub" "ghub.el" (0 0 0 0)) +;;; Generated autoloads from ghub.el + +(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+'." t nil) + +(register-definition-prefixes "ghub" '("ghub-")) + +;;;*** + +;;;### (autoloads nil "ghub-graphql" "ghub-graphql.el" (0 0 0 0)) +;;; Generated autoloads from ghub-graphql.el + +(register-definition-prefixes "ghub-graphql" '("ghub-")) + +;;;*** + +;;;### (autoloads nil "glab" "glab.el" (0 0 0 0)) +;;; Generated autoloads from glab.el + +(register-definition-prefixes "glab" '("glab-default-host")) + +;;;*** + +;;;### (autoloads nil "gogs" "gogs.el" (0 0 0 0)) +;;; Generated autoloads from gogs.el + +(register-definition-prefixes "gogs" '("gogs-default-host")) + +;;;*** + +;;;### (autoloads nil "gsexp" "gsexp.el" (0 0 0 0)) +;;; Generated autoloads from gsexp.el + +(register-definition-prefixes "gsexp" '("gsexp-")) + +;;;*** + +;;;### (autoloads nil "gtea" "gtea.el" (0 0 0 0)) +;;; Generated autoloads from gtea.el + +(register-definition-prefixes "gtea" '("gtea-default-host")) + +;;;*** + +;;;### (autoloads nil nil ("ghub-pkg.el") (0 0 0 0)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8 +;; End: +;;; ghub-autoloads.el ends here diff --git a/elpa/ghub-20230513.1619/ghub-graphql.el b/elpa/ghub-20230513.1619/ghub-graphql.el new file mode 100644 index 00000000..1e40c5c6 --- /dev/null +++ b/elpa/ghub-20230513.1619/ghub-graphql.el @@ -0,0 +1,564 @@ +;;; ghub-graphql.el --- Access Github API using GrapthQL -*- lexical-binding:t -*- + +;; Copyright (C) 2016-2023 Jonas Bernoulli + +;; Author: Jonas Bernoulli +;; Homepage: https://github.com/magit/ghub +;; Keywords: tools + +;; SPDX-License-Identifier: GPL-3.0-or-later + +;; 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 of the License, +;; or (at your option) any later version. +;; +;; This file is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this file. If not, see . + +;;; Code: + +(require 'ghub) +(require 'gsexp) +(require 'treepy) + +;; Needed for Emacs < 27. +(eval-when-compile (require 'json)) +(declare-function json-read-from-string "json" (string)) +(declare-function json-encode "json" (object)) + +(eval-when-compile (require 'pp)) ; Needed for Emacs < 29. +(eval-when-compile (require 'subr-x)) + +;;; Api + +(defvar ghub-graphql-items-per-request 100 + "Number of GraphQL items to query for entities that return a collection. + +Adjust this value if you're hitting query timeouts against larger +repositories.") + +(cl-defun ghub-graphql (graphql &optional variables + &key username auth host forge + headers 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 (not (stringp variables))) + (cl-assert (or (stringp graphql) + (memq (car-safe graphql) '(query mutation)))) + (unless (stringp graphql) + (setq graphql (gsexp-encode (ghub--graphql-prepare-query graphql)))) + (ghub-request "POST" + (if (eq forge 'gitlab) "/api/graphql" "/graphql") + nil + :payload `((query . ,graphql) + ,@(and variables `((variables ,@variables)))) + :headers headers :silent silent + :username username :auth auth :host host :forge forge + :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 (repository [(owner $owner String!) + (name $name String!)] + id)) + `((owner . ,owner) + (name . ,name)) + :username username :auth auth :host host) + .data.repository.id)) + +;;; Api (drafts) + +(defconst ghub-fetch-repository-sparse + '(query + (repository + [(owner $owner String!) + (name $name String!)] + name + id + createdAt + updatedAt + nameWithOwner + (parent nameWithOwner) + description + homepageUrl + (defaultBranchRef name) + isArchived + isFork + isLocked + isMirror + isPrivate + hasIssuesEnabled + hasWikiEnabled + (licenseInfo name) + (stargazers totalCount) + (watchers totalCount)))) + +(defconst ghub-fetch-repository + `(query + (repository + ,@(cdr (cadr ghub-fetch-repository-sparse)) + (assignableUsers [(:edges t)] + id + login + name) + (issues [(:edges t) + (:singular issue number) + (orderBy ((field UPDATED_AT) (direction DESC)))] + number + id + state + (author login) + title + createdAt + updatedAt + closedAt + locked + (milestone id) + body + (assignees [(:edges t)] + id) + (comments [(:edges t)] + databaseId + (author login) + createdAt + updatedAt + body) + (labels [(:edges t)] + id)) + (labels [(:edges t) + (:singular label id)] + id + name + color + description) + (milestones [(:edges t) + (:singular milestone id)] + id + number + title + createdAt + updatedAt + dueOn + closedAt + description) + (pullRequests [(:edges t) + (:singular pullRequest number) + (orderBy ((field UPDATED_AT) (direction DESC)))] + number + id + state + (author login) + title + createdAt + updatedAt + closedAt + mergedAt + isDraft + locked + maintainerCanModify + isCrossRepository + (milestone id) + body + (baseRef name + (repository nameWithOwner)) + baseRefOid + (headRef name + (repository (owner login) + nameWithOwner)) + headRefOid + (assignees [(:edges t)] + id) + (reviewRequests [(:edges t)] + (requestedReviewer "... on User { id }\n")) + (comments [(:edges t)] + databaseId + (author login) + createdAt + updatedAt + body) + (labels [(:edges t)] + id))))) + +(defconst ghub-fetch-repository-review-threads + '(query + (repository + [(owner $owner String!) + (name $name String!)] + (pullRequests [(:edges t) + (:singular pullRequest number) + (orderBy ((field UPDATED_AT) (direction DESC)))] + number + baseRefOid + headRefOid + (reviewThreads [(:edges t)] + id + line + originalLine + diffSide + (resolvedBy login) + (comments [(:edges t)] + id + databaseId + (author login) + createdAt + updatedAt + body + (replyTo databaseId) + (originalCommit oid) + path)))))) + +(cl-defun ghub-fetch-repository (owner name callback + &optional until + &key username auth host forge + headers errorback sparse) + "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 (if sparse + ghub-fetch-repository-sparse + ghub-fetch-repository) + `((owner . ,owner) + (name . ,name)) + callback until + :narrow '(repository) + :username username + :auth auth + :host host + :forge forge + :headers headers + :errorback errorback)) + +(cl-defun ghub-fetch-issue (owner name number callback + &optional until + &key username auth host forge + headers errorback) + "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 + :headers headers + :errorback errorback)) + +(cl-defun ghub-fetch-pullreq (owner name number callback + &optional until + &key username auth host forge + headers errorback) + "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 + :headers headers + :errorback errorback)) + +(cl-defun ghub-fetch-review-threads (owner name number callback + &optional until + &key username auth host forge + headers errorback) + "Asynchronously fetch forge data about the review threads from a 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-review-threads + `(repository pullRequests (pullRequest . ,number))) + `((owner . ,owner) + (name . ,name)) + callback until + :narrow '(repository pullRequest) + :username username + :auth auth + :host host + :forge forge + :headers headers + :errorback errorback)) + +;;; Internal + +(cl-defstruct (ghub--graphql-req + (:include ghub--req) + (:constructor ghub--make-graphql-req) + (:copier nil)) + (query nil :read-only t) + (query-str nil :read-only nil) + (variables nil :read-only t) + (until nil :read-only t) + (buffer 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 + headers errorback) + "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 + (format "https://%s/graphql" + (if (string-suffix-p "/v3" host) + (substring host 0 -3) + host))) + :method "POST" + :headers (ghub--headers headers host auth username forge) + :handler #'ghub--graphql-handle-response + :query query + :variables variables + :until until + :buffer (current-buffer) + :callback (and (not (eq callback 'synchronous)) + (let ((buf (current-buffer))) + (if narrow + (lambda (data) + (let ((path narrow) key) + (while (setq key (pop path)) + (setq data (cdr (assq key data))))) + (ghub--graphql-set-mode-line buf nil) + (funcall (or callback #'ghub--graphql-pp-response) + data)) + (lambda (data) + (ghub--graphql-set-mode-line buf nil) + (funcall (or callback #'ghub--graphql-pp-response) + data))))) + :errorback (and (not (eq callback 'synchronous)) + errorback)))) + +(cl-defun ghub--graphql-retrieve (req &optional lineage cursor) + (let ((p (cl-incf (ghub--graphql-req-pages req)))) + (when (> p 1) + (ghub--graphql-set-mode-line req "Fetching page %s" p))) + (setf (ghub--graphql-req-query-str req) + (gsexp-encode + (ghub--graphql-prepare-query + (ghub--graphql-req-query req) + lineage cursor))) + (ghub--retrieve + (let ((json-false nil)) + (ghub--encode-payload + `((query . ,(ghub--graphql-req-query-str req)) + (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 (and (vectorp node) + (listp (aref node 0))) + (let ((alist (cl-coerce node 'list)) + vars) + (when (cadr (assq :edges alist)) + (push (list 'first ghub-graphql-items-per-request) 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 (vconcat (nreverse vars))))))) + (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)))) + (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 req (assq 'data payload))))) + (when (buffer-live-p buffer) + (kill-buffer buffer))))) + +(defun ghub--graphql-walk-response (req data) + (let* ((loc (ghub--req-value req)) + (loc (if (not 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")))) + (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 + (seq-take-while + (lambda (node) + (or (string> (cdr (assq 'updatedAt node)) + 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)))))))) + (cond ((not (treepy-end-p loc)) + (setq loc (treepy-next loc))) + ((ghub--req-callback req) + (funcall (ghub--req-callback req) + (treepy-root loc)) + (cl-return)) + ((cl-return (treepy-root loc)))))))) + +(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)) + ;; Alias + (cl-find-if (lambda (c) + (eq (car-safe (car-safe c)) + (car lineage))) + query) + ;; Edges + (cl-find-if (lambda (c) + (and (listp c) + (vectorp (cadr c)) + (eq (cadr (assq :singular + (cl-coerce (cadr c) + 'list))) + (car lineage)))) + (cdr query)) + (error "BUG: Failed to narrow 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--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))) + +(defun ghub--graphql-set-mode-line (buf string &rest args) + (when (ghub--graphql-req-p buf) + (setq buf (ghub--graphql-req-buffer buf))) + (when (buffer-live-p buf) + (with-current-buffer buf + (setq mode-line-process + (and string (concat " " (apply #'format string args)))) + (force-mode-line-update t)))) + +(defun ghub--graphql-pp-response (data) + (require 'pp) ; needed for Emacs < 29. + (pp-display-expression data "*Pp Eval Output*")) + +;;; _ +(provide 'ghub-graphql) +;;; ghub-graphql.el ends here diff --git a/elpa/ghub-20230513.1619/ghub-pkg.el b/elpa/ghub-20230513.1619/ghub-pkg.el new file mode 100644 index 00000000..3757703f --- /dev/null +++ b/elpa/ghub-20230513.1619/ghub-pkg.el @@ -0,0 +1,15 @@ +(define-package "ghub" "20230513.1619" "Client libraries for Git forge APIs." + '((emacs "25.1") + (compat "29.1.4.1") + (let-alist "1.0.6") + (treepy "0.1.2")) + :commit "0fd648f0529f34b5da441d54c9dbff7810477d12" :authors + '(("Jonas Bernoulli" . "jonas@bernoul.li")) + :maintainer + '("Jonas Bernoulli" . "jonas@bernoul.li") + :keywords + '("tools") + :url "https://github.com/magit/ghub") +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/elpa/ghub-20230513.1619/ghub.el b/elpa/ghub-20230513.1619/ghub.el new file mode 100644 index 00000000..f169ad01 --- /dev/null +++ b/elpa/ghub-20230513.1619/ghub.el @@ -0,0 +1,1013 @@ +;;; ghub.el --- Client libraries for Git forge APIs -*- lexical-binding:t -*- + +;; Copyright (C) 2016-2023 Jonas Bernoulli + +;; Author: Jonas Bernoulli +;; Homepage: https://github.com/magit/ghub +;; Keywords: tools + +;; SPDX-License-Identifier: GPL-3.0-or-later + +;; 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 of the License, +;; or (at your option) any later version. +;; +;; This file is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this file. If not, see . + +;;; 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 'compat) +(require 'gnutls) +(require 'let-alist) +(require 'url) +(require 'url-auth) +(require 'url-http) + +(eval-when-compile (require 'subr-x)) + +;; Needed for Emacs < 27. +(eval-when-compile (require 'json)) +(declare-function json-read-from-string "json" (string)) +(declare-function json-encode "json" (object)) + +(declare-function glab-repository-id "glab" (owner name &key username auth host)) +(declare-function gtea-repository-id "gtea" (owner name &key username auth host)) +(declare-function gogs-repository-id "gogs" (owner name &key username auth host)) +(declare-function buck-repository-id "buck" (owner name &key username auth host)) + +(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. + +You have to manually create or update the token at +https://github.com/settings/tokens. This variable +only serves as documentation.") + +(defvar ghub-insecure-hosts nil + "List of hosts that use http instead of https.") + +(defvar ghub-json-use-jansson nil + "Whether to use the Jansson library, if available. +This is experimental. Only let-bind this but do not enable it +globally because doing that is likely to break other packages +that use `ghub'. As a user also do not enable this yet. +See https://github.com/magit/ghub/pull/149.") + +(defvar ghub-json-object-type 'alist + "The object type that is used for json payload decoding.") + +(defvar ghub-json-array-type 'list + "The array type that is used for json payload decoding.") + +;;; 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 headers 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 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 no error occurred, then call CALLBACK, unless + that is nil. + + If an error occurred, then call ERRORBACK, or if that is nil, + then CALLBACK. ERRORBACK can also be t, in which case an error + is signaled instead. NOERROR is ignored for all asynchronous + requests. + +Both callbacks are called with four arguments. + 1. For CALLBACK, the combined value of the retrieved pages. + For ERRORBACK, the error that occurred 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 (if (member host ghub-insecure-hosts) "http://" "https://") + (cond ((and (equal resource "/graphql") + (string-suffix-p "/v3" host)) + ;; Needed for some Github Enterprise instances. + (substring host 0 -3)) + ((and (equal resource "/api/graphql") + (string-suffix-p "/api/v4" host)) + ;; Needed for all Gitlab instances. + (substring host 0 -7)) + (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 forge) + "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-request "GET" resource nil + :noerror t + :username username + :auth auth + :host host + :forge forge)) + (message "Waited (%3ss of %ss) for %s..." total duration resource) + (if (= total duration) + (error "%s is taking too long to create %s" + (if forge (capitalize (symbol-name forge)) "Github") + 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) + (and-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))) + (and-let* ((rels (cdr (assoc "Link" (or headers ghub-response-headers))))) + (mapcar (lambda (elt) + (pcase-let ((`(,url ,rel) (split-string elt "; "))) + (cons (intern (substring rel 5 -1)) + (substring url 1 -1)))) + (split-string rels ", "))))) + +(cl-defun ghub-repository-id (owner name &key username auth host forge noerror) + "Return the id of the specified repository. +Signal an error if the id cannot be determined." + (let ((fn (cl-case forge + ((nil ghub github) #'ghub--repository-id) + (gitlab #'glab-repository-id) + (gitea #'gtea-repository-id) + (gogs #'gogs-repository-id) + (bitbucket #'buck-repository-id) + (t (intern (format "%s-repository-id" forge)))))) + (unless (fboundp fn) + (error "ghub-repository-id: Forge type/abbreviation `%s' is unknown" + forge)) + (or (funcall fn owner name :username username :auth auth :host host) + (and (not noerror) + (error "Repository %S does not exist on %S.\n%s%S?" + (concat owner "/" name) + (or host (ghub--host forge)) + "Maybe it was renamed and you have to update " + "remote..url"))))) + +;;;; Internal + +(defvar ghub-use-workaround-for-emacs-bug t + "Whether to work around Emacs bug debbugs#34341. + +First see https://github.com/magit/ghub/wiki/Known-Issues, +for information about this bug and another related bug. + +Because our under of these bugs evolved over time, the possible +values of this variable are a bit odd: If t, enable workaround if +necessary (i.e., if Emacs < 26.3 and GnuTLS >= 3.6.3 are used). +If `force', enable workaround even if that is believed to be +unnecessary. If nil, do not enable the workaround. The default +is t.") + +(defvar ghub-use-workaround-for-emacs-bug-54989 t + "Whether to work around Emacs bug debbugs#54989. + +First see https://github.com/magit/ghub/wiki/Known-Issues, +for information about this bug and another related bug. + +If t, work around the bug if necessary (i.e., if not using Emacs' +\"master\" branch). If nil, then don't work around the bug. The +default is t. Setting this variable only has an effect if it is +done before `ghub' is loaded.") + +(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)) + (gnutls-algorithm-priority + (if (and ghub-use-workaround-for-emacs-bug + (or (eq ghub-use-workaround-for-emacs-bug 'force) + (and (not gnutls-algorithm-priority) + (>= libgnutls-version 30603) + (version< emacs-version "26.3") + ;; (memq (ghub--req-forge req) '(github nil)) + ))) + "NORMAL:-VERS-TLS1.3" + gnutls-algorithm-priority))) + (if (or (ghub--req-callback req) + (ghub--req-errorback req)) + (url-retrieve url handler (list req) silent) + (with-current-buffer + (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)) + (prev (ghub--req-url 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) + (setf (ghub--req-url req) prev) + (funcall (if (eq errorback t) + 'ghub--errorback + 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) + (when (memq url-http-end-of-headers '(nil 0)) + (setq url-debug t) + (error "BUG: missing headers; but there's a patch for that \ +see https://github.com/magit/ghub/wiki/Known-Issues")) + (while (re-search-forward "^\\([^:]*\\): \\(.+\\)" + url-http-end-of-headers t) + (push (cons (match-string 1) + (match-string 2)) + headers)) + (setq headers (nreverse headers)) + (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 req)) + payload))) + +(defun ghub--signal-error (err &optional payload req) + (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)) + (and req (url-filename (ghub--req-url req))) + payload))) + (signal 'ghub-error data)) + (signal symb data)))) + +(defun ghub--errorback (err _headers _status req) + (ghub--signal-error err (nth 3 err) req)) + +(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 + (if (and ghub-json-use-jansson + (fboundp 'json-parse-string)) + (json-parse-string + raw + :object-type ghub-json-object-type + :array-type ghub-json-array-type + :false-object nil + :null-object nil) + (require 'json) + (let ((json-object-type ghub-json-object-type) + (json-array-type ghub-json-array-type) + (json-false nil) + (json-null nil)) + (json-read-from-string raw))) + ((json-parse-error json-readtable-error) + `((message + . ,(if (looking-at "") + (if (re-search-forward + "

\\(?:\\)?\\([^<]+\\)" 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 + (if (and ghub-json-use-jansson + (fboundp 'json-serialize)) + (json-serialize payload + ;; :object-type and :array-type + ;; are not supported here. + :false-object nil + :null-object :null) + (require 'json) + (let ((json-object-type ghub-json-object-type) + (json-array-type ghub-json-array-type) + (json-false nil) + (json-null :null)) + ;; Unfortunately `json-encode' may modify the input. + ;; See https://debbugs.gnu.org/cgi/bugreport.cgi?bug=40693. + ;; and https://github.com/magit/forge/issues/267 + (json-encode (copy-tree 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)) "=" + (cl-typecase val + (integer (number-to-string val)) + (boolean (if val "true" "false")) + (t (url-hexify-string val)))))) + params "&")) + +;;; Authentication +;;;; API + +;;;###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))))) + +(cl-defgeneric ghub--auth (host auth &optional username forge) + (unless username + (setq username (ghub--username host forge))) + (if (eq auth 'basic) + (cl-ecase forge + ((nil gitea gogs bitbucket) + (cons "Authorization" (ghub--basic-auth host username))) + ((github gitlab) + (error "%s does not support basic authentication" + (capitalize (symbol-name forge))))) + (cons (cl-ecase forge + ((nil github gitea gogs bitbucket) + "Authorization") + (gitlab + "Private-Token")) + (if (eq forge 'bitbucket) + ;; For some undocumented reason Bitbucket supports + ;; values of the form "token " only for GET + ;; requests. For PUT requests we have to use basic + ;; authentication. Note that the secret is a token + ;; (aka "app password"), not the actual password. + ;; The documentation fails to mention this little + ;; detail. See #97. + (concat "Basic " + (base64-encode-string + (concat username ":" + (ghub--token host username auth nil forge)) + t)) + (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 + (if (member host ghub-insecure-hosts) "http://" "https://")))) + (setf (url-user url) username) + (url-basic-auth url t))) + +(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. #24 #64 #72 + (auth-source-forget (list :host host :user user :max 1)) + (and (not nocreate) + (error "\ +Required %s token (\"%s\" for \"%s\") does not exist. +See https://magit.vc/manual/ghub/Getting-Started.html +or (info \"(ghub)Getting Started\") for instructions. +\(The setup wizard no longer exists.)" + (capitalize (symbol-name (or forge 'github))) + user host)))))) + (if (functionp token) (funcall token) token))) + +(cl-defgeneric 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))))) + +(cl-defgeneric ghub--username (host &optional forge) + (let ((var + (cl-ecase forge + ((nil github) + (if (equal host ghub-default-host) + "github.user" + (format "github.%s.user" host))) + (gitlab + (if (equal host "gitlab.com/api/v4") + "gitlab.user" + (format "gitlab.%s.user" host))) + (bitbucket + (if (equal host "api.bitbucket.org/2.0") + "bitbucket.user" + (format "bitbucket.%s.user" host))) + (gitea + (when (zerop (call-process "git" nil nil nil "config" "gitea.host")) + (error "gitea.host is set but always ignored")) + (format "gitea.%s.user" host)) + (gogs + (when (zerop (call-process "git" nil nil nil "config" "gogs.host")) + (error "gogs.host is set but always ignored")) + (format "gogs.%s.user" host))))) + (condition-case nil + (car (process-lines "git" "config" var)) + (error + (let ((user (read-string + (format "Git variable `%s' is unset. Set to: " var)))) + (if (equal user "") + (user-error "The empty string is not a valid username") + (call-process + "git" nil nil nil "config" + (if (eq (read-char-choice + (format "Set %s=%s [g]lobally (recommended) or [l]ocally? " + var user) + (list ?g ?l)) + ?g) + "--global" + "--local") + var user) + user)))))) + +(defun ghub--ident (username package) + (format "%s^%s" username package)) + +(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))) + +(when (version< emacs-version "26.2") + ;; Fixed by Emacs commit 60ff8101449eea3a5ca4961299501efd83d011bd. + (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)))) + +(when (< emacs-major-version 28) + ;; Fixed by Emacs commit 0b98ea5fbe276c67206896dca111c000f984ee0f. + (advice-add 'url-http-handle-authentication :around + 'url-http-handle-authentication@unauthorized-bugfix) + (defun url-http-handle-authentication@unauthorized-bugfix (fn proxy) + "If authorization failed then don't try again but fail properly. +For Emacs 27.1 prevent a useful `http' error from being replaced +by a generic one that omits all useful information. For earlier +releases prevent a new request from being made, which would +either result in an infinite loop or (e.g. in the case of `ghub') +the user being asked for their name." + (if (assoc "Authorization" url-http-extra-headers) + t ; Return "success", here also known as "successfully failed". + (funcall fn proxy)))) + +(when (and (< emacs-major-version 29) + ghub-use-workaround-for-emacs-bug-54989) + ;; Fixed in Emacs commit 0829c6836eff14dda0cf8b3047376967f7b000f4. + ;; Cleanup from 26faa2b943675107e1664b2fea7174137c473475 is not + ;; included in this copy because doing that would require changes + ;; to more functions. This function has seen a few other changes + ;; since Emacs 25.1, the oldest version we still support. Of these + ;; only 4f1df40db36b221e7842bd75d6281922dcb268ee makes a functional + ;; change, fixing debbug#35658. The first release to contain that + ;; commit is 27.1. That commit either fixes a related bug or it + ;; deals with the same bug but only partially fixes it. + (advice-add 'url-http-chunked-encoding-after-change-function :override + 'url-http-chunked-encoding-after-change-function@54989-backport) + (defvar url-http-chunked-last-crlf-missing nil) + (defvar url-http-content-type) + (defvar url-http-chunked-start) + (defvar url-http-chunked-length) + (defvar url-http-chunked-counter) + (defun url-http-chunked-encoding-after-change-function@54989-backport + (st nd length) + "Backport bugfix from https://debbugs.gnu.org/cgi/bugreport.cgi?bug=54989." + (if url-http-chunked-last-crlf-missing + (progn + (goto-char url-http-chunked-last-crlf-missing) + (if (not (looking-at "\r\n")) + (url-http-debug + "Still spinning for the terminator of last chunk...") + (url-http-debug "Saw the last CRLF.") + (delete-region (match-beginning 0) (match-end 0)) + (when (url-http-parse-headers) + (url-http-activate-callback)))) + (save-excursion + (goto-char st) + (let ((read-next-chunk t) + (case-fold-search t) + (regexp nil) + (no-initial-crlf nil)) + ;; We need to loop thru looking for more chunks even within + ;; one after-change-function call. + (while read-next-chunk + (setq no-initial-crlf (= 0 url-http-chunked-counter)) + (with-no-warnings + (if url-http-content-type + (url-display-percentage nil + "Reading [%s]... chunk #%d" + url-http-content-type url-http-chunked-counter) + (url-display-percentage nil + "Reading... chunk #%d" + url-http-chunked-counter))) + (url-http-debug "Reading chunk %d (%d %d %d)" + url-http-chunked-counter st nd length) + (setq regexp (if no-initial-crlf + "\\([0-9a-z]+\\).*\r?\n" + "\r?\n\\([0-9a-z]+\\).*\r?\n")) + + (if url-http-chunked-start + ;; We know how long the chunk is supposed to be, skip over + ;; leading crap if possible. + (if (> nd (+ url-http-chunked-start url-http-chunked-length)) + (progn + (url-http-debug "Got to the end of chunk #%d!" + url-http-chunked-counter) + (goto-char (+ url-http-chunked-start + url-http-chunked-length))) + (url-http-debug "Still need %d bytes to hit end of chunk" + (- (+ url-http-chunked-start + url-http-chunked-length) + nd)) + (setq read-next-chunk nil))) + (if (not read-next-chunk) + (url-http-debug "Still spinning for next chunk...") + (if no-initial-crlf (skip-chars-forward "\r\n")) + (if (not (looking-at regexp)) + (progn + ;; Must not have received the entirety of the chunk header, + ;; need to spin some more. + (url-http-debug "Did not see start of chunk @ %d!" (point)) + (setq read-next-chunk nil)) + ;; The data we got may have started in the middle of the + ;; initial chunk header, so move back to the start of the + ;; line and re-compute. + (when (= url-http-chunked-counter 0) + (beginning-of-line) + (looking-at regexp)) + (add-text-properties (match-beginning 0) (match-end 0) + (list 'chunked-encoding t + 'face 'cursor + 'invisible t)) + (setq url-http-chunked-length + (string-to-number (buffer-substring (match-beginning 1) + (match-end 1)) + 16) + url-http-chunked-counter (1+ url-http-chunked-counter) + url-http-chunked-start (set-marker + (or url-http-chunked-start + (make-marker)) + (match-end 0))) + (delete-region (match-beginning 0) (match-end 0)) + (url-http-debug "Saw start of chunk %d (length=%d, start=%d" + url-http-chunked-counter url-http-chunked-length + (marker-position url-http-chunked-start)) + (if (= 0 url-http-chunked-length) + (progn + ;; Found the end of the document! Wheee! + (url-http-debug "Saw end of stream chunk!") + (setq read-next-chunk nil) + (with-no-warnings + (url-display-percentage nil nil)) + ;; Every chunk, even the last 0-length one, is + ;; terminated by CRLF. Skip it. + (if (not (looking-at "\r?\n")) + (progn + (url-http-debug + "Spinning for the terminator of last chunk...") + (setq-local url-http-chunked-last-crlf-missing + (point))) + (url-http-debug "Removing terminator of last chunk") + (delete-region (match-beginning 0) (match-end 0)) + (when (re-search-forward "^\r?\n" nil t) + (url-http-debug "Saw end of trailers...")) + (when (url-http-parse-headers) + (url-http-activate-callback))))))))))))) + +;;; _ +(provide 'ghub) +(require 'ghub-graphql) +;;; ghub.el ends here diff --git a/elpa/ghub-20230513.1619/ghub.info b/elpa/ghub-20230513.1619/ghub.info new file mode 100644 index 00000000..8de5b13c --- /dev/null +++ b/elpa/ghub-20230513.1619/ghub.info @@ -0,0 +1,1170 @@ +This is ghub.info, produced by makeinfo version 6.7 from ghub.texi. + + Copyright (C) 2017-2023 Jonas Bernoulli + + 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). 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 is an Emacs library that is used by various packages to access the +APIs of various instances of various Git forge implementations. + +This manual is for Ghub version 3.6.0. + + Copyright (C) 2017-2023 Jonas Bernoulli + + 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:: +* API:: +* Notes:: +* Function Index:: +* Variable Index:: + +— The Detailed Node Listing — + +Getting Started + +* Basic Concepts, Arguments and Variables: Basic Concepts Arguments and Variables. +* Setting the Username:: +* Creating and Storing a Token:: +* Github Configuration Variables:: + +Creating and Storing a Token + +* Creating a Token:: +* Storing a Token:: + + +API + +* Their APIs:: +* Making REST Requests:: +* Making GraphQL Requests:: +* Github Convenience Wrappers:: +* Non-Github Convenience Wrappers:: + +Notes + +* Using Ghub in Personal Scripts:: +* Using Ghub in Your Own Package:: +* Forge Limitations and Notes:: + + + +File: ghub.info, Node: Introduction, Next: Getting Started, Prev: Top, Up: Top + +1 Introduction +************** + +Ghub is an Emacs library that is used by various packages to access the +APIs of various instances of various Git forge implementations. + + A forge is a web-based collaborative software platform for developing +and distributing computer applications. Examples include Github and +Gitlab. + + +File: ghub.info, Node: Getting Started, Next: API, Prev: Introduction, Up: Top + +2 Getting Started +***************** + +This manual guides you through the steps that are necessary to use the +Forge package and/or to make a request using just Ghub itself, such as +this: + + (ghub-request "GET" "/user") + + To be able to do that, Ghub needs to know who you want to talk to, +who you are, and how you are going to prove the latter to the former. + + Additionally Ghub wants to know on behalf of which Emacs package it +is making a request. So the question of "who is making the request" has +to be rephrased as "which human (or bot) is using what (Emacs) package +to make the request". If for example, the human known as "tarsius" is +using the ‘forge’ package, then that is represented in some places using +the string "tarsius^forge". + + This package used to attempt to get the answers to these questions +using a setup wizard. Unfortunately that had to be removed because (a) +it only ever supported Github, (b) by now Github has removed support for +that on their end, (c) it did not always work, and (d) when it couldn’t +be used, or failed, then it made things _more_ complicated. + + So now it is necessary for users to read some documentation and +because many things can go wrong, those instructions have to be fairly +detailed. You can of course skip over most of this, but if things go +wrong, then I would like to kindly request that you take another look +before asking me for help. + +* Menu: + +* Basic Concepts, Arguments and Variables: Basic Concepts Arguments and Variables. +* Setting the Username:: +* Creating and Storing a Token:: +* Github Configuration Variables:: + + +File: ghub.info, Node: Basic Concepts Arguments and Variables, Next: Setting the Username, Up: Getting Started + +2.1 Basic Concepts, Arguments and Variables +=========================================== + +Originally Ghub supported only Github but now it also supports Gitlab, +Gitea, Gogs and Bitbucket. For the historic reason just given, the +function ‘ghub-request’ defaults to acting on a ‘github’ forge, but can +be told to act on another forge using the 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. For example: + + (ghub-request "GET" "/user" nil + :forge 'github + :host "api.github.com" + :username "tarsius" + :auth 'forge) + + 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. + + (But for debugging purposes the above explicit form is very useful. +You will obviously have to change the value of USERNAME and you should +use ‘ghub’ as AUTH when first trying this at home.) + + These variables can be set globally and/or for a specific repository. + + • For "api.github.com" (aka the API of ) 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. + + These ‘github’ specific variables are discussed in more detail in +*note Github Configuration Variables::. + +For ‘gitlab’ and ‘bitbucket’ forges similar variables are available: + + • ‘gitlab.user’ specifies the user. + • ‘gitlab.HOST.user’ specifies the user for the HOST ‘gitlab’ + instance. + • ‘gitlab.host’ specifies the ‘gitlab’ host, unless the HOST argument + is non-nil + • ‘bitbucket.user’ specifies the user. + • ‘bitbucket.HOST.user’ specifies the user for the HOST ‘bitbucket’ + instance. + • ‘bitbucket.host’ specifies the ‘bitbucket’ host, unless the HOST + argument is non-nil. + + For the ‘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 ‘gogs’ 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 + + +File: ghub.info, Node: Setting the Username, Next: Creating and Storing a Token, Prev: Basic Concepts Arguments and Variables, Up: Getting Started + +2.2 Setting the Username +======================== + +Ghub needs to know your username that you use on the host that you want +it to connect to. For each host a different Git variable has to be set +to specify the username on that host. More than one variable is needed +because you might use different usernames on different hosts. + +Setting your Github.com Username +-------------------------------- + +To inform Ghub about your "github.com" username do this: + + 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: + + cd /path/to/repo + git config --local github.user USERNAME + +Setting your Gitlab.com Username +-------------------------------- + +To inform Ghub about your "gitlab.com" username do this: + + git config --global gitlab.user USERNAME + + If you need to identify as another user in a particular repository, +then you have to set that variable locally: + + cd /path/to/repo + git config --local gitlab.user USERNAME + + Make sure you use the correct USERNAME for this forge/host. It might +not be the same as on "github.com"! + +Setting your Github Enterprise Username +--------------------------------------- + +For Github Enterprise instances you have to specify where the API can be +accessed 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: + + git config --global github.example.com/api/v3.user USERNAME + + Make sure you use the correct USERNAME for this instance. It might +not be the same as on "github.com"! + + Doing this only tells Ghub who you are on this host, additionally you +have to tell Ghub which repositories are connected to that forge/host, +like so: + + cd /path/to/repo + git config --local github.host example.com/api/v3 + +Setting your Username for Other Hosts and/or Forges +--------------------------------------------------- + +To inform Ghub about your username on HOST (a FORGE instance) do this: + + git config --global FORGE.HOST.user USERNAME + + FORGE can be one of ‘bitbucket’, ‘gitea’ or ‘gogs’. It can also be +‘github’ or ‘gitlab’; but if that is the case, then you should look at +the preceding sections instead, which discuss these cases specifically. + + HOST identifies the instance. This actually points at the top-level +endpoint of the API and may contain path components, e.g.: +‘example.com/api’. + + If you need to identify as another user in a particular repository, +then you have to set that variable locally: + + cd /path/to/repo + git config --local FORGE.HOST.user USERNAME + + +File: ghub.info, Node: Creating and Storing a Token, Next: Github Configuration Variables, Prev: Setting the Username, Up: Getting Started + +2.3 Creating and Storing a Token +================================ + +* Menu: + +* Creating a Token:: +* Storing a Token:: + + +File: ghub.info, Node: Creating a Token, Next: Storing a Token, Up: Creating and Storing a Token + +2.3.1 Creating a Token +---------------------- + +To create a token, use the web interface of the forge/host you want to +connect to. Here is a list of pages to do this for certain popular +hosts: + + • + • + + For other forges we cannot provide a functioning URL because they +contain unknown values such as your name. Just go to the general +settings page of the respective host and then go from there. + + Except on ‘gitea’ and ‘gogs’ each token can be limited to certain +"scopes", i.e., it is possible to limit for which purposes any given +token can be used. + + Before you create a token to be used for a certain package, you +should consult the documentation of that package, which in turn should +tell you which scopes are needed and why. The Forge package for example +does so in *note (forge)Token Creation::. + + +File: ghub.info, Node: Storing a Token, Prev: Creating a Token, Up: Creating and Storing a Token + +2.3.2 Storing a Token +--------------------- + +Please also see *note (auth)Top:: for all the gory details about +Auth-Source. + + The variable ‘auth-sources’ controls how and where Auth-Source keeps +its secrets. The default value is a list of three files: +‘("~/.authinfo" "~/.authinfo.gpg" "~/.netrc")’, but to avoid confusion +you should make sure that only one of these files exists and then you +should also adjust the value of the variable to only ever use that file, +for example: + + (setq auth-sources '("~/.authinfo")) + + In ‘~/.authinfo’ secrets are stored in plain text. If you don’t want +that, then you should use the encrypted ‘~/.authinfo.gpg’ instead: + + (setq auth-sources '("~/.authinfo.gpg")) + + Auth-Source also supports storing secrets in various external +key-chains. See *note (auth)Top:: for more information. + + The default 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 *Github* username is "ziggy", the package is named +"forge", and you want to access *Github.com* with the *token* +"012345abcdef...", an entry in one of the three mentioned files would +then look like this: + + machine api.github.com login ziggy^forge password 012345abcdef... + + Assuming your *Gitlab* username is "ziggy", the package is named +"forge", and you want to access *Gitlab.com* with the *token* +"012345abcdef...", an entry in one of the three mentioned files would +then look like this: + + machine gitlab.com/api/v4 login ziggy^forge password 012345abcdef... + + +File: ghub.info, Node: Github Configuration Variables, Prev: Creating and Storing a Token, Up: Getting Started + +2.4 Github 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.) + + +File: ghub.info, Node: API, Next: Notes, Prev: Getting Started, Up: Top + +3 API +***** + +* Menu: + +* Their APIs:: +* Making REST Requests:: +* Making GraphQL Requests:: +* Github Convenience Wrappers:: +* Non-Github Convenience Wrappers:: + + +File: ghub.info, Node: Their APIs, Next: Making REST Requests, Up: API + +3.1 Their APIs +============== + +Of course this manual does not cover the APIs of all forges that it +supports, but for your convenience, here are the links to their API +manuals: + + • Github: + • (GraphQl) + • (REST) + • Gitlab: + • + • Gitea: + • + • + • Gogs: + • + • Bitbucket: + • + + +File: ghub.info, Node: Making REST Requests, Next: Making GraphQL Requests, Prev: Their APIs, Up: API + +3.2 Making REST 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 headers are 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 makes 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 package 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 no error + occurred, then it calls ‘CALLBACK’, unless that is ‘nil’. + + If an error occurred, then it calls ‘ERRORBACK’, or if that is + nil, then ‘CALLBACK’. ‘ERRORBACK’ can also be ‘t’, in which + case it signals instead. ‘NOERROR’ is ignored for all + asynchronous requests. + + Both callbacks are called with four arguments. + + 1. For ‘CALLBACK’, the combined value of the retrieved + pages. For ‘ERRORBACK’, the error that occurred 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 the first + argument to ‘ERRORBACK’. + 4. 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 retrieved 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’. + + +File: ghub.info, Node: Making GraphQL Requests, Next: Github Convenience Wrappers, Prev: Making REST Requests, Up: API + +3.3 Making GraphQL Requests +=========================== + + -- 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 ‘GRAPHQL’ 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 have implemented 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 on 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 + bundled ‘gsexp’ library is used to turn that into a GraphQL query + string. 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. If ‘CALLBACK’ is nil, pretty-print the response. + + 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 uses ‘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: Github Convenience Wrappers, Next: Non-Github Convenience Wrappers, Prev: Making GraphQL Requests, Up: API + +3.4 Github Convenience Wrappers +=============================== + + -- 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 a timeout is reached. 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. + + +File: ghub.info, Node: Non-Github Convenience Wrappers, Prev: Github Convenience Wrappers, Up: API + +3.5 Non-Github Convenience Wrappers +=================================== + +‘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 Your Own +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. + + -- Function: buck-request resource &optional params &key query payload + headers unpaginate noerror reader username auth host callback + errorback + -- Function: glab-request resource &optional params &key query payload + headers unpaginate noerror reader username auth host callback + errorback + -- Function: gogs-request resource &optional params &key query payload + headers unpaginate noerror reader username auth host callback + errorback + Wrappers around ‘ghub-request’ which hardcode the FORGE to either + ‘bitbucket’, ‘gitlab’, ‘gogs’ or ‘gitea’. + + -- Function: buck-get resource &optional params &key query payload + headers unpaginate noerror reader username auth host callback + errorback + -- Function: buck-put resource &optional params &key query payload + headers unpaginate noerror reader username auth host callback + errorback + -- Function: buck-post resource &optional params &key query payload + headers unpaginate noerror reader username auth host callback + errorback + -- Function: buck-delete resource &optional params &key query payload + headers unpaginate noerror reader username auth host callback + errorback + -- Function: glab-head resource &optional params &key query payload + headers unpaginate noerror reader username auth host callback + errorback + -- Function: glab-get resource &optional params &key query payload + headers unpaginate noerror reader username auth host callback + errorback + -- Function: glab-put resource &optional params &key query payload + headers unpaginate noerror reader username auth host callback + errorback + -- Function: glab-post resource &optional params &key query payload + headers unpaginate noerror reader username auth host callback + errorback + -- Function: glab-patch resource &optional params &key query payload + headers unpaginate noerror reader username auth host callback + errorback + -- Function: glab-delete resource &optional params &key query payload + headers unpaginate noerror reader username auth host callback + errorback + -- Function: gogs-get resource &optional params &key query payload + headers unpaginate noerror reader username auth host callback + errorback + -- Function: gogs-put resource &optional params &key query payload + headers unpaginate noerror reader username auth host callback + errorback + -- Function: gogs-post resource &optional params &key query payload + headers unpaginate noerror reader username auth host callback + errorback + -- Function: gogs-patch resource &optional params &key query payload + headers unpaginate noerror reader username auth host callback + errorback + -- Function: gogs-delete resource &optional params &key query payload + headers unpaginate noerror reader username auth host callback + errorback + -- Function: gtea-get resource &optional params &key query payload + headers unpaginate noerror reader username auth host callback + errorback + -- Function: gtea-put resource &optional params &key query payload + headers unpaginate noerror reader username auth host callback + errorback + -- Function: gtea-post resource &optional params &key query payload + headers unpaginate noerror reader username auth host callback + errorback + -- Function: gtea-patch resource &optional params &key query payload + headers unpaginate noerror reader username auth host callback + errorback + -- Function: gtea-delete resource &optional params &key query payload + headers unpaginate noerror reader username auth host callback + errorback + Wrappers around ‘FORGE-METHOD’ which hardcode the FORGE to either + ‘bitbucket’, ‘gitlab’, ‘gogs’ or ‘gitea’, and the METHOD to the + implied method. + + Note that ‘buck-head’, ‘buck-patch’, ‘gogs-head’ and ‘gtea-head’ do + not exist because the respective APIs do not appear to support + these methods. + + +File: ghub.info, Node: Notes, Next: Function Index, Prev: API, Up: Top + +4 Notes +******* + +* Menu: + +* Using Ghub in Personal Scripts:: +* Using Ghub in Your Own Package:: +* Forge Limitations and Notes:: + + +File: ghub.info, Node: Using Ghub in Personal Scripts, Next: Using Ghub in Your Own Package, Up: Notes + +4.1 Using Ghub in Personal Scripts +================================== + +You can of course use ‘ghub-request’ and its wrapper functions in your +personal scripts. Unlike when you use Ghub in a package that you +distribute for others to use, you don’t have to explicitly specify a +package in personal scripts. + + ;; This is perfectly acceptable in personal scripts ... + (ghub-get "/user") + + ;; ... and actually equals to + (ghub-get "/user" nil :auth 'ghub) + + ;; In packages you have to specify the package using AUTH. + (ghub-get "/user" nil :auth 'some-package) + + When the ‘AUTH’ argument is not specified, then a request is made on +behalf of the ‘ghub’ package itself. Like for any other package you +have to create a dedicated token of coures. + + +File: ghub.info, Node: Using Ghub in Your Own Package, Next: Forge Limitations and Notes, Prev: Using Ghub in Personal Scripts, Up: Notes + +4.2 Using Ghub in Your Own 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. + + 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) + + Keep in mind that the users of your package will have to manually +create a suitable token. To make that easier, you should not only link +to this manual but also prominently mention the scopes the token needs; +and explain what they are needed for. + + +File: ghub.info, Node: Forge Limitations and Notes, Prev: Using Ghub in Your Own Package, Up: Notes + +4.3 Forge Limitations and Notes +=============================== + + • There are no default Gitea and Gogs instances so 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 and my willingness to deal with + that is extremely limited unless someone pays me vast amounts of + money. + + • 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 + occasionally 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") + + +File: ghub.info, Node: Function Index, Next: Variable Index, Prev: Notes, Up: Top + +Appendix A Function Index +************************* + +[index] +* Menu: + +* buck-delete: Non-Github Convenience Wrappers. + (line 49) +* buck-get: Non-Github Convenience Wrappers. + (line 40) +* buck-post: Non-Github Convenience Wrappers. + (line 46) +* buck-put: Non-Github Convenience Wrappers. + (line 43) +* buck-request: Non-Github Convenience Wrappers. + (line 28) +* ghub--graphql-vacuum: Making GraphQL Requests. + (line 56) +* ghub-continue: Making REST Requests. + (line 125) +* ghub-delete: Github Convenience Wrappers. + (line 31) +* ghub-fetch-issue: Making GraphQL Requests. + (line 105) +* ghub-fetch-pullreq: Making GraphQL Requests. + (line 111) +* ghub-fetch-repository: Making GraphQL Requests. + (line 99) +* ghub-get: Github Convenience Wrappers. + (line 9) +* ghub-graphql: Making GraphQL Requests. + (line 6) +* ghub-head: Github Convenience Wrappers. + (line 6) +* ghub-patch: Github Convenience Wrappers. + (line 28) +* ghub-post: Github Convenience Wrappers. + (line 25) +* ghub-put: Github Convenience Wrappers. + (line 22) +* ghub-request: Making REST Requests. + (line 6) +* ghub-response-link-relations: Making REST Requests. + (line 174) +* ghub-wait: Github Convenience Wrappers. + (line 44) +* glab-delete: Non-Github Convenience Wrappers. + (line 67) +* glab-get: Non-Github Convenience Wrappers. + (line 55) +* glab-head: Non-Github Convenience Wrappers. + (line 52) +* glab-patch: Non-Github Convenience Wrappers. + (line 64) +* glab-post: Non-Github Convenience Wrappers. + (line 61) +* glab-put: Non-Github Convenience Wrappers. + (line 58) +* glab-request: Non-Github Convenience Wrappers. + (line 31) +* gogs-delete: Non-Github Convenience Wrappers. + (line 82) +* gogs-get: Non-Github Convenience Wrappers. + (line 70) +* gogs-patch: Non-Github Convenience Wrappers. + (line 79) +* gogs-post: Non-Github Convenience Wrappers. + (line 76) +* gogs-put: Non-Github Convenience Wrappers. + (line 73) +* gogs-request: Non-Github Convenience Wrappers. + (line 34) +* gtea-delete: Non-Github Convenience Wrappers. + (line 97) +* gtea-get: Non-Github Convenience Wrappers. + (line 85) +* gtea-patch: Non-Github Convenience Wrappers. + (line 94) +* gtea-post: Non-Github Convenience Wrappers. + (line 91) +* gtea-put: Non-Github Convenience Wrappers. + (line 88) + + +File: ghub.info, Node: Variable Index, Prev: Function Index, Up: Top + +Appendix B Variable Index +************************* + +[index] +* Menu: + +* ghub-response-headers: Making REST Requests. + (line 165) +* github.host: Github Configuration Variables. + (line 26) +* github.HOST.user: Github Configuration Variables. + (line 17) +* github.user: Github Configuration Variables. + (line 11) + + + +Tag Table: +Node: Top754 +Node: Introduction2278 +Node: Getting Started2683 +Node: Basic Concepts Arguments and Variables4365 +Node: Setting the Username8219 +Ref: Setting your Githubcom Username8703 +Ref: Setting your Gitlabcom Username9059 +Ref: Setting your Github Enterprise Username9525 +Ref: Setting your Username for Other Hosts and/or Forges10258 +Node: Creating and Storing a Token11064 +Node: Creating a Token11328 +Node: Storing a Token12348 +Node: Github Configuration Variables14193 +Node: API15904 +Node: Their APIs16142 +Node: Making REST Requests16867 +Node: Making GraphQL Requests26280 +Node: Github Convenience Wrappers32963 +Node: Non-Github Convenience Wrappers36667 +Node: Notes42171 +Node: Using Ghub in Personal Scripts42378 +Node: Using Ghub in Your Own Package43269 +Node: Forge Limitations and Notes44204 +Node: Function Index45177 +Node: Variable Index50826 + +End Tag Table + + +Local Variables: +coding: utf-8 +End: diff --git a/elpa/ghub-20230513.1619/glab.el b/elpa/ghub-20230513.1619/glab.el new file mode 100644 index 00000000..9dd2608a --- /dev/null +++ b/elpa/ghub-20230513.1619/glab.el @@ -0,0 +1,168 @@ +;;; glab.el --- Client library for the Gitlab API -*- lexical-binding:t -*- + +;; Copyright (C) 2016-2023 Jonas Bernoulli + +;; Author: Jonas Bernoulli +;; Homepage: https://github.com/magit/ghub +;; Keywords: tools + +;; SPDX-License-Identifier: GPL-3.0-or-later + +;; 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 of the License, +;; or (at your option) any later version. +;; +;; This file is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this file. If not, see . + +;;; 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-graphql (graphql &optional variables + &key username auth host + headers silent + callback errorback value extra) + "Make a GraphQL request using GRAPHQL and VARIABLES. +Like calling `ghub-graphql' (which see) with `gitlab' as FORGE." + (ghub-graphql graphql variables :forge 'gitlab + :username username :auth auth :host host + :headers headers :silent silent + :callback callback :errorback errorback + :value value :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" + (string-replace "/" "%2F" owner) + name) + nil :username username :auth auth :host host))))) + +;;; _ +(provide 'glab) +;;; glab.el ends here diff --git a/elpa/ghub-20230513.1619/gogs.el b/elpa/ghub-20230513.1619/gogs.el new file mode 100644 index 00000000..f191ea93 --- /dev/null +++ b/elpa/ghub-20230513.1619/gogs.el @@ -0,0 +1,141 @@ +;;; gogs.el --- Client library for the Gogs API -*- lexical-binding:t -*- + +;; Copyright (C) 2016-2023 Jonas Bernoulli + +;; Author: Jonas Bernoulli +;; Homepage: https://github.com/magit/ghub +;; Keywords: tools + +;; SPDX-License-Identifier: GPL-3.0-or-later + +;; 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 of the License, +;; or (at your option) any later version. +;; +;; This file is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this file. If not, see . + +;;; 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 Gogs host.") + +;; HEAD does not appear to be supported. + +(cl-defun gogs-get (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `GET' request for RESOURCE, with optional query PARAMS. +Like calling `ghub-request' (which see) with \"GET\" as METHOD +and `gogs' as FORGE." + (ghub-request "GET" resource params :forge 'gogs + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun gogs-put (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `PUT' request for RESOURCE, with optional payload PARAMS. +Like calling `ghub-request' (which see) with \"PUT\" as METHOD +and `gogs' as FORGE." + (ghub-request "PUT" resource params :forge 'gogs + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun gogs-post (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `POST' request for RESOURCE, with optional payload PARAMS. +Like calling `ghub-request' (which see) with \"POST\" as METHOD +and `gogs' as FORGE." + (ghub-request "POST" resource params :forge 'gogs + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun gogs-patch (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `PATCH' request for RESOURCE, with optional payload PARAMS. +Like calling `ghub-request' (which see) with \"PATCH\" as METHOD +and `gogs' as FORGE." + (ghub-request "PATCH" resource params :forge 'gogs + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun gogs-delete (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `DELETE' request for RESOURCE, with optional payload PARAMS. +Like calling `ghub-request' (which see) with \"DELETE\" as METHOD +and `gogs' as FORGE." + (ghub-request "DELETE" resource params :forge 'gogs + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun gogs-request (method resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a request for RESOURCE and return the response body. +Like calling `ghub-request' (which see) with `gogs' as FORGE." + (ghub-request method resource params :forge 'gogs + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun gogs-repository-id (owner name &key username auth host) + "Return the id of the repository specified by OWNER, NAME and HOST." + (number-to-string + (cdr (assq 'id (gogs-get (format "/repos/%s/%s" owner name) + nil :username username :auth auth :host host))))) + +;;; _ +(provide 'gogs) +;;; gogs.el ends here diff --git a/elpa/ghub-20230513.1619/gsexp.el b/elpa/ghub-20230513.1619/gsexp.el new file mode 100644 index 00000000..4e578550 --- /dev/null +++ b/elpa/ghub-20230513.1619/gsexp.el @@ -0,0 +1,102 @@ +;;; gsexp.el --- GraphQl as S-expressions -*- lexical-binding:t -*- + +;; Copyright (C) 2016-2023 Jonas Bernoulli + +;; Author: Jonas Bernoulli +;; Homepage: https://github.com/magit/ghub +;; Keywords: tools + +;; SPDX-License-Identifier: GPL-3.0-or-later + +;; 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 of the License, +;; or (at your option) any later version. +;; +;; This file is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this file. If not, see . + +;;; Commentary: + +;; This library encodes S-expressions as GraphQl documents. Currently +;; it is rather incomplete and only intended for use by `ghub-graphql' +;; but I might fill the gaps and add documentation eventually. I am +;; not in a hurry though. + +;;; Code: + +(require 'cl-lib) + +(defvar gsexp-one-variable-per-line nil) + +(defun gsexp-encode (document) + (gsexp--pp (gsexp--encode-field document))) + +(defun gsexp--encode-field (field) + (cond + ((stringp field) + field) + ((symbolp field) + (symbol-name field)) + ((listp (car field)) + (concat (format "%s: " (caar field)) + (gsexp--encode-field (cons (car (cdar field)) + (cdr field))))) + ((concat + (pcase (pop field) + (`[] "") + ((and (pred symbolp) op) (symbol-name op)) + (`[,op] (symbol-name op)) + (`[,op ,name] (format "%s %s" op name))) + (and (vectorp (car field)) + (format " (%s%s)" + (if gsexp-one-variable-per-line "\n" "") + (mapconcat #'gsexp--encode-argument + (append (pop field) nil) + (if gsexp-one-variable-per-line ",\n" ",")))) + (and field + (format " {\n%s\n}" + (mapconcat #'gsexp--encode-field field "\n"))))))) + +(cl-defun gsexp--encode-argument ((argument value)) + (format "%s: %s" argument (gsexp--encode-value value))) + +(defun gsexp--encode-value (value) + (cond + ((numberp value) + (number-to-string value)) + ((symbolp value) ; including variables, enums, booleans and null + (symbol-name value)) + ((stringp value) + (prin1-to-string value)) + ((vectorp value) + (format "(%s)" (mapconcat #'gsexp--encode-value value ""))) + ((listp value) + (format "{%s}" (mapconcat + (pcase-lambda (`(,name ,value)) + (format "%s: %s" name (gsexp--encode-value value))) + value ", "))) + ((error "Invalid field value: %S" value)))) + +(defun gsexp--pp (string) + (with-temp-buffer + (save-excursion + (insert string)) + (while (< (point) (point-max)) + (unless (and (bolp) (eolp)) + (save-excursion + (let ((level (car (syntax-ppss (line-beginning-position))))) + (when (looking-at "\\s-*\\s)") + (cl-decf level)) + (indent-line-to (* 2 level))))) + (forward-line 1)) + (buffer-string))) + +;;; _ +(provide 'gsexp) +;;; gsexp.el ends here diff --git a/elpa/ghub-20230513.1619/gtea.el b/elpa/ghub-20230513.1619/gtea.el new file mode 100644 index 00000000..267a0b46 --- /dev/null +++ b/elpa/ghub-20230513.1619/gtea.el @@ -0,0 +1,141 @@ +;;; gtea.el --- Client library for the Gitea API -*- lexical-binding:t -*- + +;; Copyright (C) 2016-2023 Jonas Bernoulli + +;; Author: Jonas Bernoulli +;; Homepage: https://github.com/magit/ghub +;; Keywords: tools + +;; SPDX-License-Identifier: GPL-3.0-or-later + +;; 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 of the License, +;; or (at your option) any later version. +;; +;; This file is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this file. If not, see . + +;;; 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 Gitea host.") + +;; 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