diff --git a/Makefile b/Makefile index 97c15d7..60c774f 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,9 @@ PKG = ghub ELS = $(PKG).el ELS += $(PKG)-graphql.el ELS += glab.el +ELS += gtea.el +ELS += gogs.el +ELS += buck.el ELCS = $(ELS:.el=.elc) DEPS = diff --git a/README.md b/README.md index fafd48e..f1c0129 100644 --- a/README.md +++ b/README.md @@ -1,38 +1,27 @@ -Ghub.el — Minuscule client library for the Github API -===================================================== +Ghub — Minuscule client libraries for the APIs of various Git forges +==================================================================== -Ghub is a library that provides basic support for using the Github -REST (v3) and GraphQL (v4) APIs from Emacs packages. It abstracts -access to API resources using only a handful of functions that are -not resource-specific. +Ghub provides basic support for using the APIs of various Git forges +from Emacs packages. Originally it only supported the Github REST +API, but now it also supports the Github GraphQL API as well as the +REST APIs of Gitlab, Gitea, Gogs and Bitbucket. -Ghub handles the creation, storage and use of access tokens using a -setup wizard to make it easier for users to get started and to reduce -the support burden imposed on package maintainers. It also comes with -a comprehensive manual to address the cases when things don't just -work as expected or in case you don't want to use the wizard. +Ghub abstracts access to API resources using only a handful of basic +functions such as `ghub-get`. These are convenience wrappers around +`ghub-request`. Additional forge-specific wrappers like `glab-put`, +`gtea-put`, `gogs-post` and `buck-delete` are also available. Ghub +does not provide any resource-specific functions, with the exception +of `FORGE-repository-id`. + +When accessing Github, then Ghub handles the creation and storage of +access tokens using a setup wizard to make it easier for users to get +started. The tokens for other forges have to be created manually. Ghub is intentionally limited to only provide these two essential features — basic request functions and guided setup — to avoid being too opinionated, which would hinder wide adoption. It is assumed that wide adoption would make life easier for users and maintainers alike, -because then all packages that talk to the Github API could be -configured the same way. +because then all packages that talk to forge APIs could be configured +the same way. Please consult the [manual][manual-ghub] for more information. - -Glab.el — Minuscule client library for the Gitlab API -===================================================== - -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. Instructions can be found -[here][manual-glab]. - -[manual-ghub]: https://magit.vc/manual/ghub -[manual-glab]: https://magit.vc/manual/ghub/Gitlab-Support.html diff --git a/buck.el b/buck.el new file mode 100644 index 0000000..141ea90 --- /dev/null +++ b/buck.el @@ -0,0 +1,128 @@ +;;; buck.el --- minuscule client library for the Bitbucket API -*- lexical-binding: t -*- + +;; Copyright (C) 2016-2018 Jonas Bernoulli + +;; Author: Jonas Bernoulli +;; Homepage: https://github.com/magit/ghub +;; Keywords: tools + +;; This file is not part of GNU Emacs. + +;; This file is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; This file is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; For a copy of the GPL see https://www.gnu.org/licenses/gpl.txt. + +;;; Commentary: + +;; Buck is a library that provides basic support for using the Bitbucket API +;; from Emacs packages. It abstracts access to API resources using only +;; a handful of functions that are not resource-specific. + +;; This library is implemented on top of Ghub. Unlike Ghub, Buck does +;; not support the guided creation of tokens because Bitbucket lacks the +;; features that would be necessary to implement that. Users have to +;; create tokens through the web interface. + +;;; Code: + +(require 'ghub) + +(defconst buck-default-host "api.bitbucket.org/2.0" + "The default host that is used if `buck.host' is not set.") + +;; HEAD and PATCH are not supported according to +;; https://developer.atlassian.com/bitbucket/api/2/reference/meta/uri-uuid + +(cl-defun buck-get (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `GET' request for RESOURCE, with optional query PARAMS. +Like calling `ghub-request' (which see) with \"GET\" as METHOD +and `bitbucket' as FORGE." + (ghub-request "GET" resource params :forge 'bitbucket + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun buck-put (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `PUT' request for RESOURCE, with optional payload PARAMS. +Like calling `ghub-request' (which see) with \"PUT\" as METHOD +and `bitbucket' as FORGE." + (ghub-request "PUT" resource params :forge 'bitbucket + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun buck-post (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `POST' request for RESOURCE, with optional payload PARAMS. +Like calling `ghub-request' (which see) with \"POST\" as METHOD +and `bitbucket' as FORGE." + (ghub-request "POST" resource params :forge 'bitbucket + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun buck-delete (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `DELETE' request for RESOURCE, with optional payload PARAMS. +Like calling `ghub-request' (which see) with \"DELETE\" as METHOD +and `bitbucket' as FORGE." + (ghub-request "DELETE" resource params :forge 'bitbucket + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun buck-request (method resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a request for RESOURCE and return the response body. +Like calling `ghub-request' (which see) with `bitbucket' as FORGE." + (ghub-request method resource params :forge 'bitbucket + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun buck-repository-id (owner name &key username auth host) + "Return the id of the repository specified by OWNER, NAME and HOST." + (substring (cdr (assq 'uuid + (buck-get (format "/repositories/%s/%s" owner name) + nil + :username username :auth auth :host host))) + 1 -1)) + +;;; _ +(provide 'buck) +;;; buck.el ends here diff --git a/ghub.el b/ghub.el index 038dcdc..177e1bf 100644 --- a/ghub.el +++ b/ghub.el @@ -1,4 +1,4 @@ -;;; ghub.el --- minuscule client library for the Github API -*- lexical-binding: t -*- +;;; ghub.el --- minuscule client libraries for Git forge APIs -*- lexical-binding: t -*- ;; Copyright (C) 2016-2018 Jonas Bernoulli @@ -23,22 +23,30 @@ ;;; Commentary: -;; Ghub is a library that provides basic support for using the Github API -;; from Emacs packages. It abstracts access to API resources using only -;; a handful of functions that are not resource-specific. +;; Ghub provides basic support for using the APIs of various Git forges +;; from Emacs packages. Originally it only supported the Github REST +;; API, but now it also supports the Github GraphQL API as well as the +;; REST APIs of Gitlab, Gitea, Gogs and Bitbucket. -;; Ghub handles the creation, storage and use of access tokens using a -;; setup wizard to make it easier for users to get started and to reduce -;; the support burden imposed on package maintainers. It also comes with -;; a comprehensive manual to address the cases when things don't just -;; work as expected or in case you don't want to use the wizard. +;; Ghub abstracts access to API resources using only a handful of basic +;; functions such as `ghub-get'. These are convenience wrappers around +;; `ghub-request'. Additional forge-specific wrappers like `glab-put', +;; `gtea-put', `gogs-post' and `buck-delete' are also available. Ghub +;; does not provide any resource-specific functions, with the exception +;; of `FORGE-repository-id'. + +;; When accessing Github, then Ghub handles the creation and storage of +;; access tokens using a setup wizard to make it easier for users to get +;; started. The tokens for other forges have to be created manually. ;; Ghub is intentionally limited to only provide these two essential ;; features — basic request functions and guided setup — to avoid being ;; too opinionated, which would hinder wide adoption. It is assumed that ;; wide adoption would make life easier for users and maintainers alike, -;; because then all packages that talk to the Github API could be -;; configured the same way. +;; because then all packages that talk to forge APIs could be configured +;; the same way. + +;; Please consult the manual (info "ghub") for more information. ;;; Code: @@ -94,6 +102,7 @@ used instead.") (:constructor ghub--make-req) (:copier nil)) (url nil :read-only nil) + (forge nil :read-only t) (silent nil :read-only t) (method nil :read-only t) (headers nil :read-only t) @@ -327,6 +336,7 @@ Both callbacks are called with four arguments. :url (url-generic-parse-url (concat "https://" host resource (and query (concat "?" (ghub--url-encode-params query))))) + :forge forge :silent silent ;; Encode in case caller used (symbol-name 'GET). #35 :method (encode-coding-string method 'utf-8) @@ -350,11 +360,11 @@ already completed. If there is no next page, then return nil. Callbacks are called with four arguments (see `ghub-request'). The forth argument is a `ghub--req' struct, intended to be passed -to this function. A callbacks may use the struct's `extra' slot +to this function. A callback may use the struct's `extra' slot to pass additional information to the callback that will be called after the next request has finished. Use the function `ghub-req-extra' to get and set the value of this slot." - (and (assq 'next (ghub-response-link-relations)) + (and (assq 'next (ghub-response-link-relations req)) (or (ghub--retrieve nil req) t))) (cl-defun ghub-wait (resource &optional duration &key username auth host) @@ -385,16 +395,35 @@ See `ghub-request' for information about the other arguments." (cl-incf total wait)) (sit-for (setq total 2)))))))) -(defun ghub-response-link-relations (&optional headers) +(defun ghub-response-link-relations (req &optional headers payload) "Return an alist of link relations in HEADERS. -If optional HEADERS is nil, then return those -in `ghub-response-headers'." - (let ((rels (cdr (assoc "Link" (or headers ghub-response-headers))))) - (and rels (mapcar (lambda (elt) - (pcase-let ((`(,url ,rel) (split-string elt "; "))) - (cons (intern (substring rel 5 -1)) - (substring url 1 -1)))) - (split-string rels ", "))))) +If optional HEADERS is nil, then return those that were +previously stored in the variable `ghub-response-headers'. + +When accessing a Bitbucket instance then the link relations +are in PAYLOAD instead of HEADERS, making their API merely +RESTish and forcing this function to append those relations +to the value of `ghub-response-headers', for later use when +this function is called with nil for PAYLOAD." + (if (eq (ghub--req-forge req) 'bitbucket) + (if payload + (let* ((page (cl-mapcan (lambda (key) + (when-let ((elt (assq key payload))) + (list elt))) + '(size page pagelen next previous))) + (headers (cons (cons 'link-alist page) headers))) + (if (and req (or (ghub--req-callback req) + (ghub--req-errorback req))) + (setq-local ghub-response-headers headers) + (setq-default ghub-response-headers headers)) + page) + (cdr (assq 'link-alist ghub-response-headers))) + (when-let ((rels (cdr (assoc "Link" (or headers ghub-response-headers))))) + (mapcar (lambda (elt) + (pcase-let ((`(,url ,rel) (split-string elt "; "))) + (cons (intern (substring rel 5 -1)) + (substring url 1 -1)))) + (split-string rels ", "))))) ;;;; Internal @@ -433,14 +462,13 @@ in `ghub-response-headers'." (headers (ghub--handle-response-headers status req)) (payload (ghub--handle-response-payload req)) (payload (ghub--handle-response-error status payload req)) - (value (nconc (ghub--req-value req) payload)) + (value (ghub--handle-response-value payload req)) (next (cdr (assq 'next (ghub-response-link-relations - headers))))) + req headers payload))))) (when (numberp unpaginate) (cl-decf unpaginate)) (setf (ghub--req-url req) (url-generic-parse-url next)) - (setf (ghub--req-value req) value) (setf (ghub--req-unpaginate req) unpaginate) (or (and next unpaginate @@ -501,6 +529,14 @@ in `ghub-response-headers'." (signal 'ghub-error data)) (signal symb data)))) +(defun ghub--handle-response-value (payload req) + (setf (ghub--req-value req) + (nconc (ghub--req-value req) + (if-let ((nested (and (eq (ghub--req-forge req) 'bitbucket) + (assq 'values payload)))) + (cdr nested) + payload)))) + (defun ghub--handle-response-payload (req) (funcall (or (ghub--req-reader req) 'ghub--read-json-payload) @@ -642,12 +678,16 @@ and call `auth-source-forget+'." (unless username (setq username (ghub--username host))) (if (eq auth 'basic) - (if (eq forge 'gitlab) - (error "Gitlab does not support basic authentication") - (cons "Authorization" (ghub--basic-auth host username))) - (cons (if (eq forge 'gitlab) - "Private-Token" - "Authorization") + (cl-ecase forge + ((nil github gitea gogs bitbucket) + (cons "Authorization" (ghub--basic-auth host username))) + (gitlab + (error "Gitlab does not support basic authentication"))) + (cons (cl-ecase forge + ((nil github gitea gogs bitbucket) + "Authorization") + (gitlab + "Private-Token")) (concat (and (not (eq forge 'gitlab)) "token ") (encode-coding-string @@ -700,27 +740,46 @@ and call `auth-source-forget+'." ;; end for Emacs releases before 26.1. See #24, #64. (auth-source-forget (list :host host :user user :max 1)) (and (not nocreate) - (if (eq forge 'gitlab) - (error - (concat - "Required Gitlab token does not exist. See " - "https://magit.vc/manual/ghub/Gitlab-Support.html " - "for instructions.")) - (ghub--confirm-create-token host username package))))))) + (cl-ecase forge + ((nil github) + (ghub--confirm-create-token host username package)) + ((gitlab gitea gogs bitbucket) + (error "Required %s token (%S for %S) does not exist. +See https://magit.vc/manual/ghub/Support-for-Other-Forges.html for instructions." + (capitalize (symbol-name forge)) + user host)))))))) (if (functionp token) (funcall token) token))) (defun ghub--host (&optional forge) - (if (eq forge 'gitlab) - (or (ignore-errors (car (process-lines "git" "config" "gitlab.host"))) - (bound-and-true-p glab-default-host)) - (or (ignore-errors (car (process-lines "git" "config" "github.host"))) - ghub-default-host))) + (cl-ecase forge + ((nil github) + (or (ignore-errors (car (process-lines "git" "config" "github.host"))) + ghub-default-host)) + (gitlab + (or (ignore-errors (car (process-lines "git" "config" "gitlab.host"))) + (bound-and-true-p glab-default-host))) + (gitea + (or (ignore-errors (car (process-lines "git" "config" "gitea.host"))) + (bound-and-true-p gtea-default-host))) + (gogs + (or (ignore-errors (car (process-lines "git" "config" "gogs.host"))) + (bound-and-true-p gogs-default-host))) + (bitbucket + (or (ignore-errors (car (process-lines "git" "config" "bitbucket.host"))) + (bound-and-true-p buck-default-host))))) (defun ghub--username (host &optional forge) - (let ((var (cond ((string-prefix-p "api.github.com" host) "github.user") - ((string-prefix-p "gitlab.com/api" host) "gitlab.user") - ((eq forge 'gitlab) (format "gitlab.%s.user" host)) - (t (format "github.%s.user" host))))) + (let ((var (cond ((equal host ghub-default-host) + "github.user") + ((equal host (bound-and-true-p glab-default-host)) + "gitlab.user") + ((equal host (bound-and-true-p buck-default-host)) + "bitbucket.user") + ((eq forge 'github) (format "github.%s.user" host)) + ((eq forge 'gitlab) (format "gitlab.%s.user" host)) + ((eq forge 'bitbucket) (format "bitbucket.%s.user" host)) + ((eq forge 'gitea) (format "gitea.%s.user" host)) + ((eq forge 'gogs) (format "gogs.%s.user" host))))) (condition-case nil (car (process-lines "git" "config" var)) (error diff --git a/ghub.org b/ghub.org index b6edaae..fe11146 100644 --- a/ghub.org +++ b/ghub.org @@ -8,31 +8,37 @@ #+TEXINFO_DIR_CATEGORY: Emacs #+TEXINFO_DIR_TITLE: Ghub: (ghub). #+TEXINFO_DIR_DESC: Minuscule client library for the Github API. -#+SUBTITLE: for version 2.0.1 (v2.0.1-10-g85b5ae3+1) -#+BIND: ox-texinfo+-before-export-hook ox-texinfo+-update-version-strings +#+SUBTITLE: for version 2.0.1 (v2.0.1-39-g52e5352+1) #+TEXINFO_DEFFN: t #+OPTIONS: H:4 num:4 toc:2 +#+BIND: ox-texinfo+-before-export-hook ox-texinfo+-update-version-strings + +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 is a library that provides basic support for using the Github API -from Emacs packages. It abstracts access to API resources using only -a handful of functions that are not resource-specific. +Ghub abstracts access to API resources using only a handful of basic +functions such as `ghub-get`. These are convenience wrappers around +`ghub-request`. Additional forge-specific wrappers like `glab-put`, +`gtea-put`, `gogs-post` and `buck-delete` are also available. Ghub +does not provide any resource-specific functions, with the exception +of `FORGE-repository-id`. -Ghub handles the creation, storage and use of access tokens using a -setup wizard to make it easier for users to get started and to reduce -the support burden imposed on package maintainers. It also comes with -a comprehensive manual to address the cases when things don't just -work as expected or in case you don't want to use the wizard. +When accessing Github, then Ghub handles the creation and storage of +access tokens using a setup wizard to make it easier for users to get +started. The tokens for other forges have to be created manually. Ghub is intentionally limited to only provide these two essential features — basic request functions and guided setup — to avoid being too opinionated, which would hinder wide adoption. It is assumed that wide adoption would make life easier for users and maintainers alike, -because then all packages that talk to the Github API could be -configured the same way. +because then all packages that talk to forge APIs could be configured +the same way. #+TEXINFO: @noindent -This manual is for Ghub version 2.0.1 (v2.0.1-10-g85b5ae3+1). +This manual is for Ghub version 2.0.1 (v2.0.1-39-g52e5352+1). #+BEGIN_QUOTE Copyright (C) 2017-2018 Jonas Bernoulli @@ -50,22 +56,28 @@ General Public License for more details. :END: * Introduction -Ghub is a library that provides basic support for using the Github API -from Emacs packages. It abstracts access to API resources using only -a handful of functions that are not resource-specific. +Ghub provides basic support for using the APIs of various Git forges +from Emacs packages. Originally it only supported the Github REST +API, but now it also supports the Github GraphQL API as well as the +REST APIs of Gitlab, Gitea, Gogs and Bitbucket. -Ghub handles the creation, storage and use of access tokens using a -setup wizard to make it easier for users to get started and to reduce -the support burden imposed on package maintainers. It also comes with -a comprehensive manual to address the cases when things don't just -work as expected or in case you don't want to use the wizard. +Ghub abstracts access to API resources using only a handful of basic +functions such as `ghub-get`. These are convenience wrappers around +`ghub-request`. Additional forge-specific wrappers like `glab-put`, +`gtea-put`, `gogs-post` and `buck-delete` are also available. Ghub +does not provide any resource-specific functions, with the exception +of `FORGE-repository-id`. + +When accessing Github, then Ghub handles the creation and storage of +access tokens using a setup wizard to make it easier for users to get +started. The tokens for other forges have to be created manually. Ghub is intentionally limited to only provide these two essential features — basic request functions and guided setup — to avoid being too opinionated, which would hinder wide adoption. It is assumed that wide adoption would make life easier for users and maintainers alike, -because then all packages that talk to the Github API could be -configured the same way. +because then all packages that talk to forge APIs could be configured +the same way. Fancier interfaces can be implemented on top of Ghub, and one such wrapper — named simply Ghub+ — has already been implemented. The @@ -103,11 +115,11 @@ Each package that uses Ghub uses its own token. Despite that, chances are good that after successfully configuring one package you can just start using another package pretty much instantly. -If the necessary token is not available when a package makes an API -request, then a setup wizard pops up, and after answering a few -questions you are good to go. Even the request that caused the wizard -to be summoned should succeed and for most users this should be true -even when configuring the very first token. +If the necessary token to access a Github instance is not available +when a package makes an API request, then a setup wizard pops up, and +after answering a few questions you are good to go. Even the request +that caused the wizard to be summoned should succeed and for most +users this should be true even when configuring the very first token. However, in some situations some manual configuration is necessary *before* using the wizard, or the wizard cannot be used at all: @@ -116,9 +128,10 @@ However, in some situations some manual configuration is necessary create tokens manually as described in [[*Manually Creating and Storing a Token]]. -- If you want to access Gitlab.com or another Gitlab instance, then - you have to create the token manually as describe in [[*Manually - Creating and Storing a Token]]. Also see [[*Gitlab Support]]. +- Unfortunately only Github supports the creation of tokens by using + the API. If you want to access another forge, then you have to + create the token manually as describe in [[*Manually Creating and + Storing a Token]]. Also see [[*Support for Other Forges]]. - If you want to access a Github Enterprise instance, then you have to tell Ghub about that before the wizard makes its appearance by @@ -130,7 +143,7 @@ However, in some situations some manual configuration is necessary instance) is unset when the wizard is first summoned, then you are asked to provide your username. That value is then stored *globally* to avoid having to ask you that question once per repository. If - you have multiple accounts on Github.com (or an Enterprise + you have multiple accounts on Github.com (or a Github Enterprise instance), then you have to explicitly tell Ghub about that. This can be done by setting the repository-local values of the appropriate variable *before* the wizard is invoked. @@ -268,7 +281,7 @@ of the doubts that you might have: #+BEGIN_EXAMPLE WARNING: The token will be stored unencrypted in "~/.authinfo". If you don't want that, you have to abort and customize - the `auth-sources' option.\n\n" (car auth-sources)) + the `auth-sources' option. #+END_EXAMPLE Whether that is something that needs fixing, is up to you. If your @@ -471,9 +484,16 @@ behalf of which package a request is being made by passing the symbol * API This section describes the Ghub API. In other words it describes the -public functions and variables provided by the Ghub library and not -the Github API that can be accessed by using those functions. The -latter is documented at https://developer.github.com/v3. +public functions and variables provided by the Ghub package and not +the APIs of the supported forges, which can be accessed by using those +functions. The forge APIs are documented at: + +- Github: https://developer.github.com/v3 +- Gitlab: https://docs.gitlab.com/ee/api/README.html +- Gitea: https://docs.gitea.io/en-us/api-usage and + https://try.gitea.io/api/swagger +- Gogs: https://github.com/gogs/go-gogs-client/wiki +- Bitbucket: https://developer.atlassian.com/bitbucket/api/2/reference ** Making Requests @@ -596,7 +616,7 @@ latter is documented at https://developer.github.com/v3. Callbacks are called with four arguments (see ~ghub-request~). The forth argument is a ~ghub--req~ struct, intended to be passed - to this function. A callbacks may use the struct's ~extra~ slot + to this function. A callback may use the struct's ~extra~ slot to pass additional information to the callback that will be called after the next request. Use the function ~ghub-req-extra~ to get and set the value of that slot. @@ -642,11 +662,17 @@ latter is documented at https://developer.github.com/v3. To access the response headers use this variable after ~ghub-request~ has returned. -- Function: ghub-response-link-relations headers +- Function: ghub-response-link-relations req headers payload This function returns an alist of the link relations in ~HEADERS~, or if optional ~HEADERS~ is nil, then those in ~ghub-response-headers~. + When accessing a Bitbucket instance then the link relations are in + ~PAYLOAD~ instead of ~HEADERS~, making their API merely RESTish and + forcing this function to append those relations to the value of + ~ghub-response-headers~, for later use when this function is called + with ~nil~ for ~PAYLOAD~. + - Variable: ghub-override-system-name If non-nil, the value of this variable is used to override the value @@ -842,39 +868,133 @@ local machine, which is done using a lisp variable. then be used to identify the local machine instead of the value returned by ~system-name~. -* Gitlab Support +* Support for Other Forges +** Forge Functions and Variables + +Originally Ghub supported only Github but now it also supports Gitlab, +Gitea, Gogs and Bitbucket. The function ~ghub-request~ and all the +~ghub-METHOD~ convenience wrappers default to acting on a Github forge +but can be told to act on another forge using their FORGE argument. + +The FORGE argument only specifies what kind of forge to act on, not +which instance. The HOST argument can be used to select the instance. +For some forges a default instance is defined: + +- Forge ~github~ defaults to host ~api.github.com~. +- Forge ~gitlab~ defaults to host ~gitlab.com/api/v4~. +- Forge ~bitbucket~ defaults to host ~api.bitbucket.org/2.0~. +- No canonical host exists for the ~gitea~ and ~gogs~ forges and + ~localhost:3000/api/v1~ is used as the default host in both cases. + +Together the FORGE and HOST arguments specify the forge type and +instance. In addition to that, it is also necessary to specify on +whose behalf the request is being made, which can be done using the +USERNAME and AUTH arguments. + +Having to specify these arguments for every request is inconvenient. +Additional variables and convenience functions can be used to make +that unnecessary in most cases. + +These variables can be set globally and/or for a specific repository +as explained in [[*Configuration Variables]] with a focus on Github +instances. To summarize: + +- For https://github.com the Git variable ~github.user~ specifies the + user. +- For another ~github~ instance the Git variable ~github.HOST.user~ + specifies the user. The HOST in that variable name is the same + as the value of the HOST argument of the called function. +- Instead of specifying the HOST in every function call, the Git + variable ~github.host~ can be used. This should only be set locally. -Support for Gitlab.com and other Gitlab instances is implemented in -the library ~glab.el~. This library is build on top of ~ghub.el~ and is -maintained in the same repository and because it has no additional -dependencies it is distributed as part of the Ghub package. +#+TEXINFO: @noindent +For ~gitlab~ and ~bitbucket~ forges similar variables are available: + +- ~gitlab.user~ specifies the https://gitlab.com user. +- ~gitlab.HOST.user~ specifies the user for the HOST ~gitlab~ instance. +- ~gitlab.host~ specifies the ~gitlab~ host, unless the HOST argument + is non-nil +- ~bitbucket.user~ specifies the https://bitbucket.org user. +- ~bitbucket.HOST.user~ specifies the user for the HOST ~bitbucket~ + instance. +- ~bitbucket.host~ specifies the ~bitbucket~ host, unless the HOST + argument is non-nil. + +For ~gitea~ and ~gogs~ forges some similar variables are available, +however for some of the ~ghub.*~ variables no equivalent variable +exist for these two forges: + +- ~gitea.user~ is *not* used because no canonical ~gitea~ instance exists. +- ~gitea.HOST.user~ specifies the user for the HOST ~gitea~ instance. +- ~gitea.host~ specifies the ~gitea~ host, unless the HOST argument is + non-nil +- ~gogs.user~ is *not* used because no canonical ~gitea~ instance exists. +- ~gogs.HOST.user~ specifies the user for the HOST ~gogs~ instance. +- ~gogs.host~ specifies the ~gogs~ host, unless the HOST argument is + non-nil + +~ghub-request~ and ~ghub-METHOD~ can be used to make a request for any +of the supported forge types, but except when making a request for +a ~github~ instance, then that requires the use of the FORGE argument. + +To avoid that, functions named ~FORGE-request~ and ~FORGE-METHOD~ are also +available. The following forms are equivalent, for example: -When accessing Gitlab.com or another Gitlab instance, use ~glab-request~ -instead of ~ghub-request~, ~glab-get~ instead of ~ghub-get~, etc. Likewise -use the Git variables in the ~gitlab~ group instead of those in the -~github~ group, i.e. ~gitlab.user~, ~gitlab.HOST.user~ and ~gitlab.host~. +#+BEGIN_SRC emacs-lisp + (ghub-get ... :auth 'PACKAGE :forge 'gitlab) + (glab-get ... :auth 'PACKAGE) +#+END_SRC -The Gitlab API cannot be used to create tokens, so Glab cannot provide -a setup wizard like Ghub does. As a consequence, if the user makes a -request and the necessary token cannot be found, then that results in -an error. +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 [[*Using Ghub in a Package]]). If you +do omit AUTH, then the request is made on behalf of the ~ghub~ package, +*regardless* of the symbol prefix of the function you use to do so. -You have to manually create and store the necessary tokens. Tokens -can be created at https://gitlab.com/profile/personal_access_tokens, -or the equivalent URL for another Gitlab instance. To store the token -locally, follow the instructions in [[*Manually Creating and Storing a -Token]] and [[*How Ghub uses Auth-Source]]. +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. -Packages that use Glab can define ~PACKAGE-gitlab-token-scopes~ for -documentation purposes. But unlike ~PACKAGE-github-token-scopes~, -which is used by the setup wizard, this is optional. +** Forge Limitations and Notes -And a random hint: where you would use ~user/repo~ when accessing Github, -you have to use ~user%2Frepo~ when accessing Gitlab, e.g.: +- The token creation wizard is only available for ~github~ forges, + because all other forges do not support using the API to create an + API token. As a consequence, if the user makes a request and the + necessary token cannot be found, then that results in an error. + Tokens can be created at: -#+BEGIN_SRC emacs-lisp - (glab-get "/projects/python-mode-devs%2Fpython-mode") -#+END_SRC + - Gitlab: https://gitlab.com/profile/personal_access_tokens + - Bitbucket: https://bitbucket.org/account/user/tarsius/app-passwords + - Gitea: https://localhost:3000/user/settings/applications + - Gogs: https://localhost:3000/user/settings/applications + + Also see [[*Manually Creating and Storing a Token]] and [[*How Ghub uses + Auth-Source]]. + +- As mentioned in the previous node, the variables ~gitea.host~ and + ~gogs.host~ are not taken into account. + +- Gitea and Gogs do not support limiting a token to certain scopes. + +- The Bitbucket API is fairly broken. Some resources only work if a + slash is appended while others only work if no slash is appended. I + am unable to access any private repositories and some resources + don't work for me at all. Also the API is only RESTish; pagination + information is part of the response body instead of the header. Due + to such issues it is possible that I will eventually have to remove + support for Bitbucket altogether. + +- The Gitlab API documentation is not always accurate, though I don't + have an example at hand. It also isn't structured well, making it + occationally difficult to find the information one is looking for. + +- Where one would use ~user/repo~ when accessing another forge, one has + to use ~user%2Frepo~ when accessing Gitlab, e.g.: + + #+BEGIN_SRC emacs-lisp + (glab-get "/projects/python-mode-devs%2Fpython-mode") + #+END_SRC * _ Copying :PROPERTIES: diff --git a/ghub.texi b/ghub.texi index b7ad584..5108732 100644 --- a/ghub.texi +++ b/ghub.texi @@ -30,7 +30,7 @@ General Public License for more details. @finalout @titlepage @title Ghub User and Developer Manual -@subtitle for version 2.0.1 (v2.0.1-10-g85b5ae3+1) +@subtitle for version 2.0.1 (v2.0.1-39-g52e5352+1) @author Jonas Bernoulli @page @vskip 0pt plus 1filll @@ -43,25 +43,31 @@ General Public License for more details. @node Top @top Ghub User and Developer Manual -Ghub is a library that provides basic support for using the Github API -from Emacs packages. It abstracts access to API resources using only -a handful of functions that are not resource-specific. +Ghub provides basic support for using the APIs of various Git forges +from Emacs packages. Originally it only supported the Github REST +API, but now it also supports the Github GraphQL API as well as the +REST APIs of Gitlab, Gitea, Gogs and Bitbucket. -Ghub handles the creation, storage and use of access tokens using a -setup wizard to make it easier for users to get started and to reduce -the support burden imposed on package maintainers. It also comes with -a comprehensive manual to address the cases when things don't just -work as expected or in case you don't want to use the wizard. +Ghub abstracts access to API resources using only a handful of basic +functions such as `ghub-get`. These are convenience wrappers around +`ghub-request`. Additional forge-specific wrappers like `glab-put`, +`gtea-put`, `gogs-post` and `buck-delete` are also available. Ghub +does not provide any resource-specific functions, with the exception +of `FORGE-repository-id`. + +When accessing Github, then Ghub handles the creation and storage of +access tokens using a setup wizard to make it easier for users to get +started. The tokens for other forges have to be created manually. Ghub is intentionally limited to only provide these two essential features — basic request functions and guided setup — to avoid being too opinionated, which would hinder wide adoption. It is assumed that wide adoption would make life easier for users and maintainers alike, -because then all packages that talk to the Github API could be -configured the same way. +because then all packages that talk to forge APIs could be configured +the same way. @noindent -This manual is for Ghub version 2.0.1 (v2.0.1-10-g85b5ae3+1). +This manual is for Ghub version 2.0.1 (v2.0.1-39-g52e5352+1). @quotation Copyright (C) 2017-2018 Jonas Bernoulli @@ -84,7 +90,7 @@ General Public License for more details. * Using Ghub in Personal Scripts:: * Using Ghub in a Package:: * API:: -* Gitlab Support:: +* Support for Other Forges:: @detailmenu --- The Detailed Node Listing --- @@ -102,28 +108,39 @@ API * Authentication:: * Configuration Variables:: +Support for Other Forges + +* Forge Functions and Variables:: +* Forge Limitations and Notes:: + @end detailmenu @end menu @node Introduction @chapter Introduction -Ghub is a library that provides basic support for using the Github API -from Emacs packages. It abstracts access to API resources using only -a handful of functions that are not resource-specific. +Ghub provides basic support for using the APIs of various Git forges +from Emacs packages. Originally it only supported the Github REST +API, but now it also supports the Github GraphQL API as well as the +REST APIs of Gitlab, Gitea, Gogs and Bitbucket. + +Ghub abstracts access to API resources using only a handful of basic +functions such as `ghub-get`. These are convenience wrappers around +`ghub-request`. Additional forge-specific wrappers like `glab-put`, +`gtea-put`, `gogs-post` and `buck-delete` are also available. Ghub +does not provide any resource-specific functions, with the exception +of `FORGE-repository-id`. -Ghub handles the creation, storage and use of access tokens using a -setup wizard to make it easier for users to get started and to reduce -the support burden imposed on package maintainers. It also comes with -a comprehensive manual to address the cases when things don't just -work as expected or in case you don't want to use the wizard. +When accessing Github, then Ghub handles the creation and storage of +access tokens using a setup wizard to make it easier for users to get +started. The tokens for other forges have to be created manually. Ghub is intentionally limited to only provide these two essential features — basic request functions and guided setup — to avoid being too opinionated, which would hinder wide adoption. It is assumed that wide adoption would make life easier for users and maintainers alike, -because then all packages that talk to the Github API could be -configured the same way. +because then all packages that talk to forge APIs could be configured +the same way. Fancier interfaces can be implemented on top of Ghub, and one such wrapper — named simply Ghub+ — has already been implemented. The @@ -162,11 +179,11 @@ Each package that uses Ghub uses its own token. Despite that, chances are good that after successfully configuring one package you can just start using another package pretty much instantly. -If the necessary token is not available when a package makes an API -request, then a setup wizard pops up, and after answering a few -questions you are good to go. Even the request that caused the wizard -to be summoned should succeed and for most users this should be true -even when configuring the very first token. +If the necessary token to access a Github instance is not available +when a package makes an API request, then a setup wizard pops up, and +after answering a few questions you are good to go. Even the request +that caused the wizard to be summoned should succeed and for most +users this should be true even when configuring the very first token. However, in some situations some manual configuration is necessary @strong{before} using the wizard, or the wizard cannot be used at all: @@ -178,8 +195,9 @@ create tokens manually as described in @ref{Manually Creating and Storing a Toke @item -If you want to access Gitlab.com or another Gitlab instance, then -you have to create the token manually as describe in @ref{Manually Creating and Storing a Token}. Also see @ref{Gitlab Support}. +Unfortunately only Github supports the creation of tokens by using +the API@. If you want to access another forge, then you have to +create the token manually as describe in @ref{Manually Creating and Storing a Token}. Also see @ref{Support for Other Forges}. @item @@ -195,7 +213,7 @@ If the variable @code{github.user} (or @code{github.HOST.user} for an Enterprise instance) is unset when the wizard is first summoned, then you are asked to provide your username. That value is then stored @strong{globally} to avoid having to ask you that question once per repository. If -you have multiple accounts on Github.com (or an Enterprise +you have multiple accounts on Github.com (or a Github Enterprise instance), then you have to explicitly tell Ghub about that. This can be done by setting the repository-local values of the appropriate variable @strong{before} the wizard is invoked. @@ -357,7 +375,7 @@ unexpected, Ghub additionally displays a warning when appropriate. @example WARNING: The token will be stored unencrypted in "~/.authinfo". If you don't want that, you have to abort and customize - the `auth-sources' option.\n\n" (car auth-sources)) + the `auth-sources' option. @end example Whether that is something that needs fixing, is up to you. If your @@ -570,9 +588,27 @@ Scopes for USERNAME^PACKAGE@@HOST: (SCOPE...) @chapter API This section describes the Ghub API@. In other words it describes the -public functions and variables provided by the Ghub library and not -the Github API that can be accessed by using those functions. The -latter is documented at @uref{https://developer.github.com/v3}. +public functions and variables provided by the Ghub package and not +the APIs of the supported forges, which can be accessed by using those +functions. The forge APIs are documented at: + +@itemize +@item +Github: @uref{https://developer.github.com/v3} + +@item +Gitlab: @uref{https://docs.gitlab.com/ee/api/README.html} + +@item +Gitea: @uref{https://docs.gitea.io/en-us/api-usage} and +@uref{https://try.gitea.io/api/swagger} + +@item +Gogs: @uref{https://github.com/gogs/go-gogs-client/wiki} + +@item +Bitbucket: @uref{https://developer.atlassian.com/bitbucket/api/2/reference} +@end itemize @menu * Making Requests:: @@ -746,7 +782,7 @@ has already completed. If there is no next page, then return nil. Callbacks are called with four arguments (see @code{ghub-request}). The forth argument is a @code{ghub--req} struct, intended to be passed -to this function. A callbacks may use the struct's @code{extra} slot +to this function. A callback may use the struct's @code{extra} slot to pass additional information to the callback that will be called after the next request. Use the function @code{ghub-req-extra} to get and set the value of that slot. @@ -794,10 +830,16 @@ To access the response headers use this variable after @code{ghub-request} has returned. @end defvar -@defun ghub-response-link-relations headers +@defun ghub-response-link-relations req headers payload This function returns an alist of the link relations in @code{HEADERS}, or if optional @code{HEADERS} is nil, then those in @code{ghub-response-headers}. + +When accessing a Bitbucket instance then the link relations are in +@code{PAYLOAD} instead of @code{HEADERS}, making their API merely RESTish and +forcing this function to append those relations to the value of +@code{ghub-response-headers}, for later use when this function is called +with @code{nil} for @code{PAYLOAD}. @end defun @defvar ghub-override-system-name @@ -1015,38 +1057,204 @@ then be used to identify the local machine instead of the value returned by @code{system-name}. @end defvar -@node Gitlab Support -@chapter Gitlab Support +@node Support for Other Forges +@chapter Support for Other Forges -Support for Gitlab.com and other Gitlab instances is implemented in -the library @code{glab.el}. This library is build on top of @code{ghub.el} and is -maintained in the same repository, but it is distributed as a separate -package. +@menu +* Forge Functions and Variables:: +* Forge Limitations and Notes:: +@end menu + +@node Forge Functions and Variables +@section Forge Functions and Variables + +Originally Ghub supported only Github but now it also supports Gitlab, +Gitea, Gogs and Bitbucket. The function @code{ghub-request} and all the +@code{ghub-METHOD} convenience wrappers default to acting on a Github forge +but can be told to act on another forge using their FORGE argument. + +The FORGE argument only specifies what kind of forge to act on, not +which instance. The HOST argument can be used to select the instance. +For some forges a default instance is defined: + +@itemize +@item +Forge @code{github} defaults to host @code{api.github.com}. + +@item +Forge @code{gitlab} defaults to host @code{gitlab.com/api/v4}. + +@item +Forge @code{bitbucket} defaults to host @code{api.bitbucket.org/2.0}. + +@item +No canonical host exists for the @code{gitea} and @code{gogs} forges and +@code{localhost:3000/api/v1} is used as the default host in both cases. +@end itemize + +Together the FORGE and HOST arguments specify the forge type and +instance. In addition to that, it is also necessary to specify on +whose behalf the request is being made, which can be done using the +USERNAME and AUTH arguments. + +Having to specify these arguments for every request is inconvenient. +Additional variables and convenience functions can be used to make +that unnecessary in most cases. + +These variables can be set globally and/or for a specific repository +as explained in @ref{Configuration Variables} with a focus on Github +instances. To summarize: + +@itemize +@item +For @uref{https://github.com} the Git variable @code{github.user} specifies the +user. + +@item +For another @code{github} instance the Git variable @code{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. + +@item +Instead of specifying the HOST in every function call, the Git +variable @code{github.host} can be used. This should only be set locally. +@end itemize + +@noindent +For @code{gitlab} and @code{bitbucket} forges similar variables are available: + +@itemize +@item +@code{gitlab.user} specifies the @uref{https://gitlab.com} user. + +@item +@code{gitlab.HOST.user} specifies the user for the HOST @code{gitlab} instance. + +@item +@code{gitlab.host} specifies the @code{gitlab} host, unless the HOST argument +is non-nil + +@item +@code{bitbucket.user} specifies the @uref{https://bitbucket.org} user. + +@item +@code{bitbucket.HOST.user} specifies the user for the HOST @code{bitbucket} +instance. + +@item +@code{bitbucket.host} specifies the @code{bitbucket} host, unless the HOST +argument is non-nil. +@end itemize + +For @code{gitea} and @code{gogs} forges some similar variables are available, +however for some of the @code{ghub.*} variables no equivalent variable +exist for these two forges: + +@itemize +@item +@code{gitea.user} is @strong{not} used because no canonical @code{gitea} instance exists. + +@item +@code{gitea.HOST.user} specifies the user for the HOST @code{gitea} instance. + +@item +@code{gitea.host} specifies the @code{gitea} host, unless the HOST argument is +non-nil + +@item +@code{gogs.user} is @strong{not} used because no canonical @code{gitea} instance exists. + +@item +@code{gogs.HOST.user} specifies the user for the HOST @code{gogs} instance. + +@item +@code{gogs.host} specifies the @code{gogs} host, unless the HOST argument is +non-nil +@end itemize + +@code{ghub-request} and @code{ghub-METHOD} can be used to make a request for any +of the supported forge types, but except when making a request for +a @code{github} instance, then that requires the use of the FORGE argument. + +To avoid that, functions named @code{FORGE-request} and @code{FORGE-METHOD} are also +available. The following forms are equivalent, for example: + +@lisp +(ghub-get ... :auth 'PACKAGE :forge 'gitlab) +(glab-get ... :auth 'PACKAGE) +@end lisp + +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 @ref{Using Ghub in a Package}). If you +do omit AUTH, then the request is made on behalf of the @code{ghub} package, +@strong{regardless} of the symbol prefix of the function you use to do so. -When accessing Gitlab.com or another Gitlab instance, use @code{glab-request} -instead of @code{ghub-request}, @code{glab-get} instead of @code{ghub-get}, etc. Likewise -use the Git variables in the @code{gitlab} group instead of those in the -@code{github} group, i.e. @code{gitlab.user}, @code{gitlab.HOST.user} and @code{gitlab.host}. +All @code{FORGE-request} and @code{FORGE-METHOD} functions, including but not +limited to @code{ghub-METHOD}, are very simple wrappers around @code{ghub-request}. +They take fewer arguments than @code{ghub-request} and instead pass constant +values for the arguments METHOD and/or FORGE@. -The Gitlab API cannot be used to create tokens, so Glab cannot provide -a setup wizard like Ghub does. As a consequence, if the user makes a -request and the necessary token cannot be found, then that results in -an error. +@node Forge Limitations and Notes +@section Forge Limitations and Notes -You have to manually create and store the necessary tokens. Tokens -can be created at @uref{https://gitlab.com/profile/personal_access_tokens}, -or the equivalent URL for another Gitlab instance. To store the token -locally, follow the instructions in @ref{Manually Creating and Storing a Token} and @ref{How Ghub uses Auth-Source}. +@itemize +@item +The token creation wizard is only available for @code{github} forges, +because all other forges do not support using the API to create an +API token. As a consequence, if the user makes a request and the +necessary token cannot be found, then that results in an error. +Tokens can be created at: + +@itemize +@item +Gitlab: @uref{https://gitlab.com/profile/personal_access_tokens} + +@item +Bitbucket: @uref{https://bitbucket.org/account/user/tarsius/app-passwords} -Packages that use Glab can define @code{PACKAGE-gitlab-token-scopes} for -documentation purposes. But unlike @code{PACKAGE-github-token-scopes}, -which is used by the setup wizard, this is optional. +@item +Gitea: @uref{https://localhost:3000/user/settings/applications} + +@item +Gogs: @uref{https://localhost:3000/user/settings/applications} +@end itemize -And a random hint: where you would use @code{user/repo} when accessing Github, -you have to use @code{user%2Frepo} when accessing Gitlab, e.g.: +Also see @ref{Manually Creating and Storing a Token} and @ref{How Ghub uses Auth-Source}. + + +@item +As mentioned in the previous node, the variables @code{gitea.host} and +@code{gogs.host} are not taken into account. + + +@item +Gitea and Gogs do not support limiting a token to certain scopes. + + +@item +The Bitbucket API is fairly broken. Some resources only work if a +slash is appended while others only work if no slash is appended. I +am unable to access any private repositories and some resources +don't work for me at all. Also the API is only RESTish; pagination +information is part of the response body instead of the header. Due +to such issues it is possible that I will eventually have to remove +support for Bitbucket altogether. + + +@item +The Gitlab API documentation is not always accurate, though I don't +have an example at hand. It also isn't structured well, making it +occationally difficult to find the information one is looking for. + + +@item +Where one would use @code{user/repo} when accessing another forge, one has +to use @code{user%2Frepo} when accessing Gitlab, e.g.: @lisp (glab-get "/projects/python-mode-devs%2Fpython-mode") @end lisp +@end itemize @bye diff --git a/gogs.el b/gogs.el new file mode 100644 index 0000000..0fbac46 --- /dev/null +++ b/gogs.el @@ -0,0 +1,140 @@ +;;; gogs.el --- minuscule client library for the Gogs API -*- lexical-binding: t -*- + +;; Copyright (C) 2016-2018 Jonas Bernoulli + +;; Author: Jonas Bernoulli +;; Homepage: https://github.com/magit/ghub +;; Keywords: tools + +;; This file is not part of GNU Emacs. + +;; This file is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; This file is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; For a copy of the GPL see https://www.gnu.org/licenses/gpl.txt. + +;;; Commentary: + +;; Gogs is a library that provides basic support for using the Gogs API +;; from Emacs packages. It abstracts access to API resources using only +;; a handful of functions that are not resource-specific. + +;; This library is implemented on top of Ghub. Unlike Ghub, Gogs does +;; not support the guided creation of tokens because Gogs lacks the +;; features that would be necessary to implement that. Users have to +;; create tokens through the web interface. + +;;; Code: + +(require 'ghub) + +(defconst gogs-default-host "localhost:3000/api/v1" + "The default host that is used if `gogs.host' is not set.") + +;; HEAD does not appear to be supported. + +(cl-defun gogs-get (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `GET' request for RESOURCE, with optional query PARAMS. +Like calling `ghub-request' (which see) with \"GET\" as METHOD +and `gogs' as FORGE." + (ghub-request "GET" resource params :forge 'gogs + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun gogs-put (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `PUT' request for RESOURCE, with optional payload PARAMS. +Like calling `ghub-request' (which see) with \"PUT\" as METHOD +and `gogs' as FORGE." + (ghub-request "PUT" resource params :forge 'gogs + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun gogs-post (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `POST' request for RESOURCE, with optional payload PARAMS. +Like calling `ghub-request' (which see) with \"POST\" as METHOD +and `gogs' as FORGE." + (ghub-request "POST" resource params :forge 'gogs + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun gogs-patch (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `PATCH' request for RESOURCE, with optional payload PARAMS. +Like calling `ghub-request' (which see) with \"PATCH\" as METHOD +and `gogs' as FORGE." + (ghub-request "PATCH" resource params :forge 'gogs + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun gogs-delete (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `DELETE' request for RESOURCE, with optional payload PARAMS. +Like calling `ghub-request' (which see) with \"DELETE\" as METHOD +and `gogs' as FORGE." + (ghub-request "DELETE" resource params :forge 'gogs + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun gogs-request (method resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a request for RESOURCE and return the response body. +Like calling `ghub-request' (which see) with `gogs' as FORGE." + (ghub-request method resource params :forge 'gogs + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun gogs-repository-id (owner name &key username auth host) + "Return the id of the repository specified by OWNER, NAME and HOST." + (number-to-string + (cdr (assq 'id (gogs-get (format "/repos/%s/%s" owner name) + nil :username username :auth auth :host host))))) + +;;; _ +(provide 'gogs) +;;; gogs.el ends here diff --git a/gtea.el b/gtea.el new file mode 100644 index 0000000..07ca290 --- /dev/null +++ b/gtea.el @@ -0,0 +1,140 @@ +;;; gtea.el --- minuscule client library for the Gitea API -*- lexical-binding: t -*- + +;; Copyright (C) 2016-2018 Jonas Bernoulli + +;; Author: Jonas Bernoulli +;; Homepage: https://github.com/magit/ghub +;; Keywords: tools + +;; This file is not part of GNU Emacs. + +;; This file is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; This file is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; For a copy of the GPL see https://www.gnu.org/licenses/gpl.txt. + +;;; Commentary: + +;; Gtea is a library that provides basic support for using the Gitea API +;; from Emacs packages. It abstracts access to API resources using only +;; a handful of functions that are not resource-specific. + +;; This library is implemented on top of Ghub. Unlike Ghub, Gtea does +;; not support the guided creation of tokens because Gitea lacks the +;; features that would be necessary to implement that. Users have to +;; create tokens through the web interface. + +;;; Code: + +(require 'ghub) + +(defconst gtea-default-host "localhost:3000/api/v1" + "The default host that is used if `gtea.host' is not set.") + +;; HEAD does not appear to be supported. + +(cl-defun gtea-get (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `GET' request for RESOURCE, with optional query PARAMS. +Like calling `ghub-request' (which see) with \"GET\" as METHOD +and `gitea' as FORGE." + (ghub-request "GET" resource params :forge 'gitea + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun gtea-put (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `PUT' request for RESOURCE, with optional payload PARAMS. +Like calling `ghub-request' (which see) with \"PUT\" as METHOD +and `gitea' as FORGE." + (ghub-request "PUT" resource params :forge 'gitea + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun gtea-post (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `POST' request for RESOURCE, with optional payload PARAMS. +Like calling `ghub-request' (which see) with \"POST\" as METHOD +and `gitea' as FORGE." + (ghub-request "POST" resource params :forge 'gitea + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun gtea-patch (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `PATCH' request for RESOURCE, with optional payload PARAMS. +Like calling `ghub-request' (which see) with \"PATCH\" as METHOD +and `gitea' as FORGE." + (ghub-request "PATCH" resource params :forge 'gitea + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun gtea-delete (resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a `DELETE' request for RESOURCE, with optional payload PARAMS. +Like calling `ghub-request' (which see) with \"DELETE\" as METHOD +and `gitea' as FORGE." + (ghub-request "DELETE" resource params :forge 'gitea + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun gtea-request (method resource &optional params + &key query payload headers + silent unpaginate noerror reader + username auth host + callback errorback extra) + "Make a request for RESOURCE and return the response body. +Like calling `ghub-request' (which see) with `gitea' as FORGE." + (ghub-request method resource params :forge 'gitea + :query query :payload payload :headers headers + :silent silent :unpaginate unpaginate + :noerror noerror :reader reader + :username username :auth auth :host host + :callback callback :errorback errorback :extra extra)) + +(cl-defun gtea-repository-id (owner name &key username auth host) + "Return the id of the repository specified by OWNER, NAME and HOST." + (number-to-string + (cdr (assq 'id (gtea-get (format "/repos/%s/%s" owner name) + nil :username username :auth auth :host host))))) + +;;; _ +(provide 'gtea) +;;; gtea.el ends here