about summary refs log tree commit diff
path: root/users/aspen/emacs.d/github-org.el
diff options
context:
space:
mode:
Diffstat (limited to 'users/aspen/emacs.d/github-org.el')
-rw-r--r--users/aspen/emacs.d/github-org.el99
1 files changed, 99 insertions, 0 deletions
diff --git a/users/aspen/emacs.d/github-org.el b/users/aspen/emacs.d/github-org.el
new file mode 100644
index 0000000000..f4f9d2e370
--- /dev/null
+++ b/users/aspen/emacs.d/github-org.el
@@ -0,0 +1,99 @@
+;;; -*- lexical-binding: t; -*-
+
+(require 'ghub)
+
+(defun grfn/alist->plist (alist)
+  (->> alist
+       (-mapcat (lambda (pair)
+                  (list (intern (concat ":" (symbol-name (car pair))))
+                        (cdr pair))))))
+
+;;;
+
+(cl-defstruct pull-request url number title author repository)
+
+(defun grfn/query-pulls (query)
+  (let ((resp (ghub-graphql "query reviewRequests($query: String!) {
+    reviewRequests: search(
+      type:ISSUE,
+      query: $query,
+      first: 100
+    ) {
+      issueCount
+      nodes {
+        ... on PullRequest {
+          url
+          number
+          title
+          author {
+            login
+            ... on User { name }
+          }
+          repository {
+            name
+            owner { login }
+          }
+        }
+      }
+    }
+  }" `((query . ,query)))))
+    (->> resp
+         (alist-get 'data)
+         (alist-get 'reviewRequests)
+         (alist-get 'nodes)
+         (-map
+          (lambda (pr)
+            (apply
+             #'make-pull-request
+             (grfn/alist->plist pr)))))))
+
+(defun grfn/requested-changes ())
+
+(defun grfn/pull-request->org-headline (format-string level pr)
+  (check-type format-string string)
+  (check-type level integer)
+  (check-type pr pull-request)
+  (s-format (concat (make-string level ?*) " " format-string)
+            'aget
+            `((author . ,(or (->> pr (pull-request-author) (alist-get 'name))
+                             "no author"))
+              (owner . ,(->> pr (pull-request-repository)
+                             (alist-get 'owner)
+                             (alist-get 'login)))
+              (repo . ,(->> pr (pull-request-repository) (alist-get 'name)))
+              (pr-link . ,(org-make-link-string
+                           (pull-request-url pr)
+                           (pull-request-title pr)))
+              (today . ,(format-time-string "%Y-%m-%d %a")))))
+
+(defun grfn/org-headlines-from-review-requests (level)
+  "Create org-mode headlines at LEVEL from all review-requested PRs on Github"
+  (interactive "*nLevel: ")
+  (let* ((prs (grfn/query-pulls
+               "is:open is:pr review-requested:glittershark archived:false"))
+         (text (mapconcat
+                (apply-partially
+                 #'grfn/pull-request->org-headline
+                 "TODO Review ${author}'s PR on ${owner}/${repo}: ${pr-link} :pr:
+SCHEDULED: <${today}>"
+                 level) prs "\n")))
+    (save-mark-and-excursion
+      (insert text))
+    (org-align-tags 't)))
+
+(defun grfn/org-headlines-from-requested-changes (level)
+  "Create org-mode headlines at LEVEL from all PRs with changes requested
+ on Github"
+  (interactive "*nLevel: ")
+  (let* ((prs (grfn/query-pulls
+               (concat "is:pr is:open author:glittershark archived:false "
+                       "sort:updated-desc review:changes-requested")))
+         (text (mapconcat
+                (apply-partially
+                 #'grfn/pull-request->org-headline
+                 "TODO Address review comments on ${pr-link} :pr:
+SCHEDULED: <${today}>"
+                 level) prs "\n")))
+    (save-mark-and-excursion
+      (insert text))
+    (org-align-tags 't)))