branch: externals/srht commit 7322b06ffeaa0fcf30f6df9ff9c5a46469e9ebe2 Author: Aleksandr Vityazev <avitya...@posteo.org> Commit: Aleksandr Vityazev <avitya...@posteo.org>
srht-git: use graphql api in commands. --- lisp/srht-git.el | 332 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 204 insertions(+), 128 deletions(-) diff --git a/lisp/srht-git.el b/lisp/srht-git.el index 50bbb33bf4..b9d6e248e9 100644 --- a/lisp/srht-git.el +++ b/lisp/srht-git.el @@ -27,6 +27,7 @@ (require 'srht) (require 'srht-gql) +(require 'transient) (defvar srht-git-repositories nil "Authenticated user repos plist of the form (:instance repos ...).") @@ -48,7 +49,7 @@ subsequent request, you'll get the next page.") (defun srht-git--gql-next-query (cursor) "Created next query from CURSOR." - (pcase-let* ((plist (copy-sequence srht-git-gql-base-query)) + (pcase-let* ((plist (seq-copy srht-git-gql-base-query)) ((map (:fields (seq n lst))) plist)) (plist-put plist @@ -77,6 +78,208 @@ Or CALLBACK may be `sync' to make a synchronous request." pointer (append results ac))) ac))) +(defun srht-git--candidates (instance) + "Return completion candidates for INSTANCE." + (seq-map (pcase-lambda ((map (:created c) + (:visibility v) + (:name n))) + (list n c v)) + (plist-get + (or srht-git-repositories + (srht-put srht-git-repositories + instance (srht-git-repos instance))) + (intern instance)))) + +(defun srht-git--annot (instance str) + "Function to add annotations in the completions buffer for STR and INSTANCE." + (pcase-let (((seq _n created visibility) + (assoc str (srht-git--candidates instance)))) + (srht-annotation str visibility created))) + +(defun srht-git--select-repo (instance) + "Read a repository name in the minibuffer, with completion. +INSTANCE is the instance name of the Sourcehut instance." + (srht-read-with-annotaion "Select repository: " + (srht-git--candidates instance) + (lambda (str) (srht-git--annot instance str)) + 'sourcehut-git-repository)) + +(defun srht-git--message (instance &rest args) + "Display a message at the bottom of the screen. +Update repositories from INSTANCE." + (declare (indent 1)) + (apply #'message args) + (srht-put srht-git-repositories + instance (srht-git-repos instance))) + +(defvar srht-git-repo-name-history nil + "History variable.") + +(defun srht-git--read-non-empty (prompt initial-input history) + "Read non-empty string from the minibuffer, prompting with string PROMPT. +INITIAL-INPUT, HISTORY (see `read-from-minibuffer')." + (save-match-data + (cl-block nil + (while t + (let ((str (read-from-minibuffer prompt initial-input nil nil history))) + (unless (string-empty-p str) + (cl-return str))) + (message "Please enter non-empty!") + (sit-for 1))))) + +;;;###autoload (autoload 'srht-git-repo-create "srht-git" nil t) +(transient-define-prefix srht-git-repo-create () + "Prefix that just shows off many typical infix types." + ["Repo input" + ("i" "instance" "instance=" + :always-read t + :init-value (lambda (obj) (oset obj value (seq-first srht-instances)))) + ("n" "name" "name=" + :always-read t + :prompt "Git repository name: " + :reader srht-git--read-non-empty) + ("v" "visibility" "visibility=" + :choices (public unlisted private) + :always-read t + :allow-empty nil) + ("d" "description" "description=" + :always-read t + :prompt "Repository description (markdown): ") + ("u" "clone URL" "cloneUrl=" + :always-read t + :prompt "Repository will be cloned from the given URL: " + ;; TODO: add custom reader + )] + ["New repository" + ("c" "create repository" srht-git-repo-create0)]) + +(defun srht-git--transient-value (arg) + "Return the value of ARG." + (transient-arg-value arg (transient-args 'srht-git-repo-create))) + +(transient-define-suffix srht-git-repo-create0 () + "Create the NAME repository on an instance with the instance name INSTANCE. +Set VISIBILITY and DESCRIPTION." + (interactive) + (let ((instance (srht-git--transient-value "instance=")) + (name (let ((val (srht-git--transient-value "name="))) + (if (or (null val) (string-empty-p val)) + (error "Repository name required") + val))) + (visibility (let ((val (srht-git--transient-value "visibility="))) + (if (or (null val) (string-empty-p val)) + (error "Visibility required") + (intern (upcase val))))) + (description (srht-git--transient-value "description=")) + (cloneurl (srht-git--transient-value "cloneUrl="))) + (srht--gql-api-request + :instance instance + :service 'git + :token-host "git.sr.ht" + :query (srht-gql-mutation + `(:query createRepository + :arguments (:name ,name + :visibility ,visibility + :description ,description + :cloneurl ,cloneurl) + :fields (id))) + :then (lambda (_r) + (let* ((username (string-trim-left srht-username "~")) + (url (srht--make-uri + instance 'git + (format "/~%s/%s" username name) nil))) + (srht-copy-url url) + (srht-browse-url url) + (srht-put srht-git-repositories + instance (srht-git-repos instance))) + (srht-git--message instance + "Sourcehut %s git repository created" name))))) + +(defun srht-git--find-repo (instance repo-name) + "Find repository information by REPO-NAME from the INSTANCE instance." + (seq-find + (lambda (repo) + (equal (plist-get repo :name) repo-name)) + (plist-get srht-git-repositories (intern instance)))) + +(defun srht-git--repoinput (repo-name new-name visibility description) + "Create a list from REPO-NAME, NEW-NAME, VISIBILITY, DESCRIPTION. +It will contains the data that is passed as the value of +the :input argument when making changes to the repository." + (declare (indent defun)) + (let ((name-plist (unless (and (string-empty-p new-name) + (equal repo-name new-name)) + (list :name new-name)))) + `(:visibility ,(intern (upcase visibility)) + :description ,description + ,@name-plist))) + +;;;###autoload +(defun srht-git-repo-update (instance repo-name new-name visibility description) + "Update the REPO-NAME repository from the INSTANCE instance. +Set VISIBILITY, NEW-NAME and DESCRIPTION." + (interactive + (let* ((inst (srht-read-instance "Instance: ")) + (name (srht-git--select-repo inst))) + (list inst + name + (read-string "Repository new name: " nil + 'srht-git-repo-name-history) + (srht-read-visibility "Visibility: ") + (read-string "Repository description (markdown): ")))) + (when (yes-or-no-p (format "Update %s repository?" repo-name)) + (let* ((repo (srht-git--find-repo instance repo-name)) + (id (plist-get repo :id)) + (repoinput (srht-git--repoinput + repo-name new-name visibility description))) + (srht--gql-api-request + :instance instance + :service 'git + :token-host "git.sr.ht" + :query (srht-gql-mutation + `(:query updateRepository + :arguments (:id ,id :input ,repoinput) + :fields (id))) + :then (lambda (_r) + (srht-git--message instance + "Sourcehut %s git repository updated!" new-name)))))) + +;;;###autoload +(defun srht-git-repo-delete (instance repo-name) + "Delete the REPO-NAME repository from the INSTANCE instance." + (interactive + (let ((instance (srht-read-instance "Instance: "))) + (list instance (srht-git--select-repo instance)))) + (when (yes-or-no-p + (format "This action cannot be undone.\n Delete %s repository?" + repo-name)) + (let ((id (plist-get + (srht-git--find-repo instance repo-name) :id))) + (srht--gql-api-request + :instance instance + :service 'git + :token-host "git.sr.ht" + :query (srht-gql-mutation + `(:query deleteRepository + :arguments (:id ,id) + :fields (id))) + :then (lambda (_r) + (srht-git--message instance + "Sourcehut %s git repository deleted!" repo-name)))))) + +;;;###autoload +(defun srht-git-repos-list (instance) + "Display a list of Sourcehut INSTANCE git repositories." + (interactive + (list (srht-read-instance "Instance: "))) + (unless (fboundp 'make-vtable) + (error "Vtable required")) + (srht--view instance srht-git-repositories + `("d" (lambda (obj) + (srht-git-repo-delete ,instance (plist-get obj :name)))))) + +;;;;;;;;;;;;;;;;;;;LEGACY API;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + (defun srht-git--make-crud (instance path &optional query body form) "Make a crud for the git service for the INSTANCE of the Sourcehut instance. PATH is the path for the URI. BODY is the body sent to the URI. @@ -209,132 +412,5 @@ NAME is a repository name. If USERNAME is nil the authenticated user is assumed." (srht-git--endpoint instance "tree" name username)) -(defun srht-git--candidates (instance) - "Return completion candidates for INSTANCE." - (seq-map (pcase-lambda ((map (:created c) - (:visibility v) - (:name n))) - (list n c v)) - (plist-get - (or srht-git-repositories - (srht-put srht-git-repositories - instance (srht-git-repos instance))) - (intern instance)))) - -(defun srht-git--annot (instance str) - "Function to add annotations in the completions buffer for STR and INSTANCE." - (pcase-let (((seq _n created visibility) - (assoc str (srht-git--candidates instance)))) - (srht-annotation str visibility created))) - -(defun srht-git--repo-name-read (instance) - "Read a repository name in the minibuffer, with completion. -INSTANCE is the instance name of the Sourcehut instance." - (srht-read-with-annotaion "Select repository: " - (srht-git--candidates instance) - (lambda (str) (srht-git--annot instance str)) - 'sourcehut-git-repository)) - -(defvar srht-git-repo-name-history nil - "History variable.") - -;;;###autoload -(defun srht-git-repo-create (instance visibility name description) - "Create the NAME repository on an instance with the instance name INSTANCE. -Set VISIBILITY and DESCRIPTION." - (interactive - (list (srht-read-instance "Instance: ") - (srht-read-visibility "Visibility: ") - (read-string "New git repository name: " nil - 'srht-git-repo-name-history) - (read-string "Repository description (markdown): "))) - (srht-create (srht-git-repo instance nil nil - :visibility visibility - :name name - :description description) - :then (lambda (results) - (pcase-let* (((map (:name repo-name) - (:owner (map (:canonical_name username)))) - results) - (url (srht--make-uri - instance 'git - (format "/%s/%s" username repo-name) nil))) - (srht-copy-url url) - (srht-browse-url url) - (srht-put srht-git-repositories - instance (srht-git-repos instance)) - )))) - -(defun srht-git--find-info (instance repo-name) - "Find repository information by REPO-NAME from the INSTANCE instance." - (catch 'found - (seq-doseq (repo (plist-get srht-git-repositories instance)) - (when (equal (cl-getf repo :name) repo-name) - (throw 'found repo))))) - -;;;###autoload -(defun srht-git-repo-update (instance repo-name visibility new-name description) - "Update the REPO-NAME repository from the INSTANCE instance. -Set VISIBILITY, NEW-NAME and DESCRIPTION." - (interactive - (pcase-let* ((instance (srht-read-instance "Instance: ")) - (name (srht-git--repo-name-read instance)) - ((map (:visibility v) - (:description d)) - (srht-git--find-info instance name))) - (list instance - name - (srht-read-visibility "Visibility: " v) - (read-string "Repository name: " nil - 'srht-git-repo-name-history) - (read-string "Repository description (markdown): " d)))) - (when (yes-or-no-p (format "Update %s repository?" repo-name)) - (srht-update (srht-git-repo instance repo-name nil - :visibility visibility - :name new-name - :description description) - :then (lambda (_resp) - ;; NOTE: resp examle - ;; (:id 110277 - ;; :created 2022-04-29T14:05:29.662497Z - ;; :updated 2022-04-29T14:43:53.155504Z - ;; :name test-from-srht-6.el - ;; :owner (:canonical_name ~akagi :name akagi) - ;; :description nil - ;; :visibility unlisted) - (message "Updated!") - (srht-put srht-git-repositories - instance (srht-git-repos instance)) - )))) - -;;;###autoload -(defun srht-git-repo-delete (instance repo-name) - "Delete the REPO-NAME repository from the INSTANCE instance." - (interactive - (let ((instance (srht-read-instance "Instance: "))) - (list instance (srht-git--repo-name-read instance)))) - (when (yes-or-no-p - (format "This action cannot be undone.\n Delete %s repository?" repo-name)) - (srht-delete - (srht-git-repo instance repo-name) - :as 'string - :then (lambda (_r) - (message - (format "Sourcehut %s git repository deleted!" repo-name)) - (srht-put srht-git-repositories - instance (srht-git-repos instance)) - )))) - -;;;###autoload -(defun srht-git-repos-list (instance) - "Display a list of Sourcehut INSTANCE git repositories." - (interactive - (list (srht-read-instance "Instance: "))) - (unless (fboundp 'make-vtable) - (error "Vtable required")) - (srht--view instance srht-git-repositories - `("d" (lambda (obj) - (srht-git-repo-delete ,instance (plist-get obj :name)))))) - (provide 'srht-git) ;;; srht-git.el ends here