225 lines
9.6 KiB
EmacsLisp
225 lines
9.6 KiB
EmacsLisp
![]() |
;;; org-jira-sdk.el -- SDK Layer for entities
|
||
|
|
||
|
;; Copyright (C) 2018 Matthew Carter <m@ahungry.com>
|
||
|
;;
|
||
|
;; Authors:
|
||
|
;; Matthew Carter <m@ahungry.com>
|
||
|
;;
|
||
|
;; Maintainer: Matthew Carter <m@ahungry.com>
|
||
|
;; URL: https://github.com/ahungry/org-jira
|
||
|
;; Version: 3.1.1
|
||
|
;; Keywords: ahungry jira org bug tracker
|
||
|
;; Package-Requires: ((emacs "24.5") (cl-lib "0.5") (request "0.2.0") (s "0.0.0"))
|
||
|
|
||
|
;; This file is not part of GNU Emacs.
|
||
|
|
||
|
;; This program 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 program 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 program. If not, see
|
||
|
;; <http://www.gnu.org/licenses/> or write to the Free Software
|
||
|
;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||
|
;; 02110-1301, USA.
|
||
|
|
||
|
;;; Commentary:
|
||
|
|
||
|
;; This provides an SDK wrapper for more strictly defining the entities we interact with.
|
||
|
|
||
|
;;; Code:
|
||
|
|
||
|
(require 'jiralib)
|
||
|
(require 'cl-lib)
|
||
|
(require 'eieio)
|
||
|
(require 'dash)
|
||
|
(require 'cl-generic)
|
||
|
|
||
|
(defclass org-jira-sdk-record ()
|
||
|
((id :initarg :id :type string :required t)
|
||
|
(data :initarg :data :documentation "The area to hold a big alist of data.")
|
||
|
(hydrate-fn :initform (lambda (id) (message "Not implemented."))))
|
||
|
"The ID of the record.")
|
||
|
|
||
|
(defun org-jira-sdk-string-but-first (s) (cl-subseq s 1))
|
||
|
|
||
|
(defun org-jira-sdk-to-string (s) (format "%s" s))
|
||
|
|
||
|
(defun org-jira-sdk-to-prefixed-string (s) (format "org-jira-sdk-%s" s))
|
||
|
|
||
|
(defun org-jira-sdk-record-type-to-symbol (record-type)
|
||
|
(-> record-type symbol-name org-jira-sdk-string-but-first org-jira-sdk-to-prefixed-string intern))
|
||
|
|
||
|
(defun org-jira-sdk-create-from-id (record-type id &optional parent-id callback)
|
||
|
(let ((rec (funcall (org-jira-sdk-record-type-to-symbol record-type)
|
||
|
:id (format "%s" id)
|
||
|
:parent-id parent-id)))
|
||
|
(with-slots (data) rec
|
||
|
(setf data (org-jira-sdk-hydrate rec callback))
|
||
|
(org-jira-sdk-from-data rec))))
|
||
|
|
||
|
(defun org-jira-sdk-create-from-data (record-type data)
|
||
|
(let ((rec (funcall (org-jira-sdk-record-type-to-symbol record-type) :data data)))
|
||
|
(org-jira-sdk-from-data rec)))
|
||
|
|
||
|
(cl-defmethod org-jira-sdk-hydrate ((rec org-jira-sdk-record) &optional callback)
|
||
|
"Populate the record with data from the remote endpoint."
|
||
|
(with-slots (id hydrate-fn) rec
|
||
|
(funcall hydrate-fn id callback)))
|
||
|
|
||
|
(cl-defgeneric org-jira-sdk-from-data ((rec org-jira-sdk-record)))
|
||
|
|
||
|
(cl-defmethod org-jira-sdk-dump ((rec org-jira-sdk-record))
|
||
|
"A decent pretty print/object dump for working with the class items."
|
||
|
(let ((slots (mapcar (lambda (slot) (aref slot 1)) (eieio-class-slots (eieio-object-class rec)))))
|
||
|
(setq slots (cl-remove-if (lambda (s) (not (slot-boundp rec s))) slots))
|
||
|
(apply #'concat
|
||
|
(mapcar (lambda (slot)
|
||
|
(let ((slot (intern (org-jira-sdk-to-string slot))))
|
||
|
(format "\n%+16s: %s" slot (slot-value rec (intern (org-jira-sdk-to-string slot)))))
|
||
|
)
|
||
|
slots))))
|
||
|
|
||
|
(defun org-jira-sdk-path (alist key-chain)
|
||
|
"Query a nested path in some type of ALIST by traversing down the keys of KEY-CHAIN."
|
||
|
(cl-reduce (lambda (a k) (alist-get k a)) key-chain :initial-value alist))
|
||
|
|
||
|
(defclass org-jira-sdk-issue (org-jira-sdk-record)
|
||
|
((assignee :type (or null string) :initarg :assignee)
|
||
|
(components :type string :initarg :components)
|
||
|
(labels :type string :initarg :labels)
|
||
|
(created :type string :initarg :created)
|
||
|
(description :type (or null string) :initarg :description)
|
||
|
(duedate :type (or null string) :initarg :duedate)
|
||
|
(headline :type string :initarg :headline)
|
||
|
(id :type string :initarg :id) ; TODO: Probably remove me
|
||
|
(issue-id :type string :initarg :issue-id :documentation "The common ID/key, such as EX-1.")
|
||
|
(issue-id-int :type string :initarg :issue-id-int :documentation "The internal Jira ID, such as 12345.")
|
||
|
(filename :type (or null string) :initarg :filename :documentation "The filename to write issue to.")
|
||
|
(priority :type (or null string) :initarg :priority)
|
||
|
(proj-key :type string :initarg :proj-key)
|
||
|
(reporter :type (or null string) :initarg :reporter)
|
||
|
(resolution :type (or null string) :initarg :resolution)
|
||
|
(start-date :type (or null string) :initarg :start-date)
|
||
|
(status :type string :initarg :status)
|
||
|
(summary :type string :initarg :summary)
|
||
|
(type :type string :initarg :type)
|
||
|
(updated :type string :initarg :updated)
|
||
|
(data :initarg :data :documentation "The remote Jira data object (alist).")
|
||
|
(hydrate-fn :initform #'jiralib-get-issue :initarg :hydrate-fn))
|
||
|
"An issue on the end. ID of the form EX-1, or a numeric such as 10000.")
|
||
|
|
||
|
(defclass org-jira-sdk-comment (org-jira-sdk-record)
|
||
|
((author :type string :initarg :author)
|
||
|
(body :type string :initarg :body)
|
||
|
(comment-id :type string :initarg :comment-id :documentation "The comment ID, such as 12345.")
|
||
|
(created :type string :initarg :created)
|
||
|
(headline :type string :initarg :headline)
|
||
|
(parent-id :type string :initarg :parent-id :documentation "The parent issue-id such as EX-1.")
|
||
|
(updated :type string :initarg :updated)
|
||
|
(data :initarg :data :documentation "The reomte Jira data object (alist).")
|
||
|
(hydrate-fn :initform #'jiralib-get-comment :initarg :hydrate-fn)))
|
||
|
|
||
|
(defclass org-jira-sdk-board (org-jira-sdk-record)
|
||
|
((name :type string :initarg :name :required t)
|
||
|
(url :type string :initarg :url :required t)
|
||
|
(board-type :type string :initarg :board-type)
|
||
|
(jql :type string :initarg :jql)
|
||
|
(limit :type integer :initarg :limit)
|
||
|
;; unused
|
||
|
(parent-id :type string :initarg :parent-id)
|
||
|
(hydrate-fn :initform #'jiralib-get-board :initarg :hydrate-fn)))
|
||
|
|
||
|
(cl-defmethod org-jira-sdk-hydrate ((rec org-jira-sdk-comment) &optional callback)
|
||
|
"Populate the record with data from the remote endpoint."
|
||
|
(with-slots (id proj-key hydrate-fn) rec
|
||
|
(funcall hydrate-fn proj-key id callback)))
|
||
|
|
||
|
(cl-defmethod org-jira-sdk-from-data ((rec org-jira-sdk-issue))
|
||
|
(cl-flet ((path (keys) (org-jira-sdk-path (oref rec data) keys)))
|
||
|
(org-jira-sdk-issue
|
||
|
:assignee (path '(fields assignee name))
|
||
|
:components (mapconcat (lambda (c) (org-jira-sdk-path c '(name))) (path '(fields components)) ", ")
|
||
|
:labels (mapconcat (lambda (c) (format "%s" c)) (map 'list #'identity (path '(fields labels))) ", ")
|
||
|
:created (path '(fields created)) ; confirm
|
||
|
:description (or (path '(fields description)) "")
|
||
|
:duedate (path '(fields duedate)) ; confirm
|
||
|
:filename (path '(fields project key))
|
||
|
:headline (path '(fields summary)) ; Duplicate of summary, maybe different.
|
||
|
:id (path '(key))
|
||
|
:issue-id (path '(key))
|
||
|
:issue-id-int (path '(id))
|
||
|
:priority (path '(fields priority name))
|
||
|
:proj-key (path '(fields project key))
|
||
|
:reporter (path '(fields reporter name)) ; reporter could be an object of its own slot values
|
||
|
:resolution (path '(fields resolution name)) ; confirm
|
||
|
:start-date (path '(fields start-date)) ; confirm
|
||
|
:status (org-jira-decode (path '(fields status name)))
|
||
|
:summary (path '(fields summary))
|
||
|
:type (path '(fields issuetype name))
|
||
|
:updated (path '(fields updated)) ; confirm
|
||
|
;; TODO: Remove this
|
||
|
;; :data (oref rec data)
|
||
|
)))
|
||
|
|
||
|
(cl-defmethod org-jira-sdk-from-data ((rec org-jira-sdk-comment))
|
||
|
(cl-flet ((path (keys) (org-jira-sdk-path (oref rec data) keys)))
|
||
|
(org-jira-sdk-comment
|
||
|
:author (path '(author displayName))
|
||
|
:body (path '(body))
|
||
|
:comment-id (path '(id))
|
||
|
:created (path '(created))
|
||
|
:headline (format "Comment: %s" (path '(author displayName)))
|
||
|
:parent-id (if (slot-boundp rec 'parent-id) (oref rec parent-id) "")
|
||
|
:updated (path '(updated))
|
||
|
;; TODO: Remove this
|
||
|
;; :data (oref rec data)
|
||
|
)))
|
||
|
|
||
|
(cl-defmethod org-jira-sdk-from-data ((rec org-jira-sdk-board))
|
||
|
(with-slots (data) rec
|
||
|
(org-jira-sdk-board
|
||
|
:id (int-to-string (alist-get 'id data))
|
||
|
:name (alist-get 'name data)
|
||
|
:url (alist-get 'self data)
|
||
|
;; TODO: remove it? used by org-jira-sdk-create-from-id
|
||
|
:parent-id ""
|
||
|
:board-type (alist-get 'type data))))
|
||
|
|
||
|
;; Issue
|
||
|
(defun org-jira-sdk-create-issue-from-data (d) (org-jira-sdk-create-from-data :issue d))
|
||
|
(defun org-jira-sdk-create-issues-from-data-list (ds) (mapcar #'org-jira-sdk-create-issue-from-data ds))
|
||
|
|
||
|
;; Issue with custom filename setting
|
||
|
(defun org-jira-sdk-create-issue-from-data-with-filename (filename)
|
||
|
(lambda (d)
|
||
|
(let ((Issue (org-jira-sdk-create-from-data :issue d)))
|
||
|
(setf (oref Issue filename) filename)
|
||
|
Issue)))
|
||
|
|
||
|
(defun org-jira-sdk-create-issues-from-data-list-with-filename (filename ds)
|
||
|
(let ((fn (org-jira-sdk-create-issue-from-data-with-filename filename)))
|
||
|
(mapcar fn ds)))
|
||
|
|
||
|
;; Comment
|
||
|
(defun org-jira-sdk-create-comment-from-data (d) (org-jira-sdk-create-from-data :comment d))
|
||
|
(defun org-jira-sdk-create-comments-from-data-list (ds) (mapcar #'org-jira-sdk-create-comment-from-data ds))
|
||
|
|
||
|
(defun org-jira-sdk-isa-record? (i) (typep i 'org-jira-sdk-record))
|
||
|
(defun org-jira-sdk-isa-issue? (i) (typep i 'org-jira-sdk-issue))
|
||
|
(defun org-jira-sdk-isa-comment? (i) (typep i 'org-jira-sdk-comment))
|
||
|
|
||
|
;; Board
|
||
|
(defun org-jira-sdk-create-board-from-data (d) (org-jira-sdk-create-from-data :board d))
|
||
|
(defun org-jira-sdk-create-boards-from-data-list (ds) (mapcar #'org-jira-sdk-create-board-from-data ds))
|
||
|
|
||
|
(provide 'org-jira-sdk)
|
||
|
|
||
|
;;; org-jira-sdk.el ends here
|