From cfde555bfde177f70fe11504138e55c143817f96 Mon Sep 17 00:00:00 2001 From: Wanderson Ferreira Date: Sun, 3 Oct 2021 13:52:26 -0300 Subject: [PATCH 01/11] respond to inline comments --- README.md | 6 +++ github-review.el | 90 ++++++++++++++++++++++++++++++++++---- test/github-review-test.el | 27 ++++++++---- 3 files changed, 106 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 26446ab..2ce2872 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,12 @@ configure the endpoint of your GitHub Enterprise installation, this should look `github-review-view-comments-in-code-lines-outdated` to `t`, however we cannot guarantee correct placement of these comments in the review buffer. + You can also enable replies to inline comments by setting + `github-review-reply-inline-comments` to `t`, this feature only works if + `github-review-view-comments-in-code-lines` is also set to `t`. This way, if + you include a comment right after a previous received comment in the diff + buffer, your new comment will be sent as a reply. + ## Notice *I am providing code in the repository to you under an open source license. Because this is my personal repository, the license you receive to my diff --git a/github-review.el b/github-review.el index 5a9c9e3..60a2475 100644 --- a/github-review.el +++ b/github-review.el @@ -68,6 +68,11 @@ "Flag to enable displaying outdated comments in code lines." :group 'github-review) +(defcustom github-review-reply-inline-comments nil + "Flag to enable replies to inline comments. + +This flag will only be valid if `github-review-view-comments-in-code-lines' is set to `t`.") + (defconst github-review-diffheader '(("Accept" . "application/vnd.github.v3.diff")) "Header for requesting diffs from GitHub.") @@ -140,7 +145,7 @@ return a deferred object" reviews(first: 50) { nodes { author { login } bodyText state comments(first: 50) - { nodes { bodyText originalPosition position outdated path} }} + { nodes { bodyText originalPosition position outdated path databaseId} }} } } } }" .repo .owner .num))) @@ -175,6 +180,31 @@ CALLBACK will be called back when done" :errorback #'github-review-errback :callback callback))) +(defun github-review-post-review-replies (pr-alist replies callback) + "Submit replies to review comments inline." + (let-alist pr-alist + (-map + (lambda (comment) + (let* ((path (a-get comment 'path)) + (position (a-get comment 'position)) + (comment-id (alist-get (s-concat path + ":" + (number-to-string position)) + github-review-pos->databaseid + nil nil 'equal)) + (body (a-get comment 'body))) + (ghub-post (format "/repos/%s/%s/pulls/%s/comments/%s/replies" + .owner .repo .num comment-id) + nil + :payload (a-alist 'body body) + :headers github-review-diffheader + :auth 'github-review + :host (github-review-api-host pr-alist) + :callback (lambda (&rest _)) + :errorback #'github-review-errback))) + replies) + (funcall callback))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Code review file parsing ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -195,7 +225,7 @@ CALLBACK will be called back when done" (defun github-review-previous-comment? (l) "Return t if L, a string, is a comment from previous review." - (string-prefix-p "~ " l)) + (string-prefix-p "~" l)) (defun github-review-is-start-of-file-hunk? (l) "Return t if L, a string that start with 'diff' marking the start of a file hunk." @@ -248,8 +278,11 @@ ACC is an alist accumulating parsing state." (let* ((top-level? (equal nil .pos)) (in-file? (not top-level?))) (cond - ;; Previous comments are ignored and don't affect the parsing - ((github-review-previous-comment? l) acc) + ;; Previous comments are marked if not top level and will be used to distinguish replies from new code comments + ((github-review-previous-comment? l) + (if .pos + (a-assoc acc 'previous-comment? t) + acc)) ;; First cgithub-review-hunk ((and top-level? (github-review-hunk? l)) @@ -274,14 +307,18 @@ ACC is an alist accumulating parsing state." ;; For such comments we report it on on the first line (a-alist 'position (max .pos 1) 'path .path - 'body (github-review-comment-text l)) + 'body (github-review-comment-text l) + 'reply? .previous-comment?) .comments))) ;; Header before the filenames, restart the position ((github-review-is-start-of-file-hunk? l) (a-assoc acc 'pos nil)) ;; Any other line in a file - (in-file? (a-assoc acc 'pos (+ 1 .pos))) + (in-file? + (a-assoc acc + 'pos (+ 1 .pos) + 'previous-comment? nil)) (t acc))))) @@ -290,7 +327,8 @@ ACC is an alist accumulating parsing state." (let* ((acc (a-alist 'path nil 'pos nil 'body "" - 'comments ())) + 'comments () + 'previous-comment? nil)) (parsed-data (-reduce-from #'github-review-parse-line acc lines)) (parsed-comments (a-get parsed-data 'comments)) (parsed-body (s-trim-right (a-get parsed-data 'body))) @@ -347,8 +385,31 @@ This function infers the PR name based on the current filename" (message "Submitting review, this may take a while ...") (let* ((pr-alist (github-review-pr-from-fname (buffer-file-name))) (parsed-review (github-review-parsed-review-from-current-buffer)) + (comments (a-get parsed-review 'comments)) + (regular-comments (->> comments + (-filter + (lambda (c) + (not (a-get c 'reply?)))) + (-map + (lambda (c) + (a-dissoc c 'reply?))))) + (reply-comments (-filter + (lambda (c) + (a-get c 'reply?)) + comments)) (head-sha (a-get pr-alist 'sha)) - (review (a-assoc parsed-review 'commit_id head-sha 'event kind))) + (review (a-assoc parsed-review + 'commit_id head-sha + 'event kind + 'comments regular-comments))) + + (when github-review-reply-inline-comments + (github-review-post-review-replies + pr-alist + reply-comments + (lambda (&rest _) + (message "Done submitting review replies")))) + (github-review-post-review pr-alist review (lambda (&rest _) @@ -378,6 +439,9 @@ Github API provides only the originalPosition in the query.") (defun github-review--get-how-many-comments-written (path) (or (a-get github-review-comment-pos path) 0)) +(defvar github-review-pos->databaseid () + "Hold databaseID to each path and comment combination") + (defun github-review-place-review-comments (gitdiff review) (if (not (a-get-in review (list 'comments 'nodes))) gitdiff @@ -416,6 +480,15 @@ Github API provides only the originalPosition in the query.") 0 (length body-lines)))) + ;; save databaseID to each path and comment combination + (setf (alist-get (s-concat + path ":" + (number-to-string + (or position original-pos))) + github-review-pos->databaseid + nil nil 'equal) + (a-get comment 'databaseId)) + ;; include comments on buffer for this path (let* ((result (-concat @@ -470,6 +543,7 @@ Github API provides only the originalPosition in the query.") (if github-review-view-comments-in-code-lines (progn (setq github-review-comment-pos ()) + (setq github-review-pos->databaseid ()) (-reduce-from (lambda (acc-gitdiff node) (github-review-place-review-comments acc-gitdiff node)) diff --git a/test/github-review-test.el b/test/github-review-test.el index 78ed55f..21f99a6 100644 --- a/test/github-review-test.el +++ b/test/github-review-test.el @@ -84,7 +84,8 @@ index 8ad537d..0000000 (comments ((position . 5) (body . "Comment test") - (path . "bar"))))) + (path . "bar") + (reply? . nil))))) (defconst example-review-deleted-comment-haskell "# comment test ~ remove bad @@ -165,10 +166,12 @@ index 9eced0230..4512bb335 100644 (comments ((position . 5) (body . "Comment test") - (path . "bar")) + (path . "bar") + (reply? . nil)) ((position . 6) (body . "here too") - (path . "hledger-lib/Hledger/Reports/MultiBalanceReport.hs"))))) + (path . "hledger-lib/Hledger/Reports/MultiBalanceReport.hs") + (reply? . nil))))) (defconst examplediff "# This is a global comment at the top of the file # with multiple @@ -243,23 +246,28 @@ index 58baa4b..eae7707 100644 (comments ((position . 1) (body . "comment on zeroth line\ncomment on first line") - (path . "content/reference/google-closure-library.adoc")) + (path . "content/reference/google-closure-library.adoc") + (reply? . nil)) ((position . 5) (body . "And a comment inline about\na specific line\n```with some\ncode```") - (path . "content/reference/google-closure-library.adoc")) + (path . "content/reference/google-closure-library.adoc") + (reply? . nil)) ((position . 6) (body . "Some other comment inline") - (path . "content/reference/google-closure-library.adoc"))))) + (path . "content/reference/google-closure-library.adoc") + (reply? . nil))))) (defconst complex-review-expected-no-comment-on-zeroth-and-first-line '((body . "This is a global comment at the top of the file\nwith multiple\nlines") (comments ((position . 5) (body . "And a comment inline about\na specific line\n```with some\ncode```") - (path . "content/reference/google-closure-library.adoc")) + (path . "content/reference/google-closure-library.adoc") + (reply? . t)) ((position . 6) (body . "Some other comment inline") - (path . "content/reference/google-closure-library.adoc"))))) + (path . "content/reference/google-closure-library.adoc") + (reply? . nil))))) (describe "github-review-parse-review-lines" @@ -352,7 +360,8 @@ index 58baa4b..eae7707 100644 (before-all (setq github-review-comment-pos ()) (setq github-review-view-comments-in-code-lines nil) - (setq github-review-view-comments-in-code-lines-outdated nil)) + (setq github-review-view-comments-in-code-lines-outdated nil) + (setq github-review-reply-inline-comments nil)) (it "can include PR comments made in code lines" (expect (github-review-place-review-comments example-diff-before-comments-in-code-line review-with-comments) :to-equal From fdee424a71962fa2bed2c9b64f3d7629d2037a68 Mon Sep 17 00:00:00 2001 From: Wanderson Ferreira Date: Sat, 9 Oct 2021 12:59:49 -0300 Subject: [PATCH 02/11] fix bug with reviews without comments --- github-review.el | 60 +++++++++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/github-review.el b/github-review.el index 60a2475..c7177d5 100644 --- a/github-review.el +++ b/github-review.el @@ -333,10 +333,9 @@ ACC is an alist accumulating parsing state." (parsed-comments (a-get parsed-data 'comments)) (parsed-body (s-trim-right (a-get parsed-data 'body))) (merged-comments (when parsed-comments (github-review-merge-comments (reverse parsed-comments))))) - (if (equal nil merged-comments) - `((body . ,parsed-body)) - `((body . ,parsed-body) - (comments . ,(reverse merged-comments)))))) + `((body . ,parsed-body) + (comments . ,(reverse merged-comments))))) + ;;;;;;;;;;;;;;;;;;;;;;;;; ;; Buffer interactions ;; ;;;;;;;;;;;;;;;;;;;;;;;;; @@ -379,31 +378,43 @@ ACC is an alist accumulating parsing state." ;; Helpers ;; ;;;;;;;;;;;;; +(defun github-review--split-comments-by-type (comments) + "Return A-LIST with regular-comments and reply-comments." + (if (equal nil comments) + `((regular-comments . ,nil) + (reply-comments . ,nil)) + (let* ((regular-comments (->> comments + (-filter (lambda (c) + (not (a-get c 'reply?)))) + (-map (lambda (c) + (a-dissoc c 'reply?))))) + (reply-comments (-filter (lambda (c) + (a-get c 'reply?)) + comments))) + `((regular-comments . ,regular-comments) + (reply-comments . ,reply-comments))))) + (defun github-review-submit-review (kind) "Submit a code review of KIND. This function infers the PR name based on the current filename" (message "Submitting review, this may take a while ...") (let* ((pr-alist (github-review-pr-from-fname (buffer-file-name))) (parsed-review (github-review-parsed-review-from-current-buffer)) - (comments (a-get parsed-review 'comments)) - (regular-comments (->> comments - (-filter - (lambda (c) - (not (a-get c 'reply?)))) - (-map - (lambda (c) - (a-dissoc c 'reply?))))) - (reply-comments (-filter - (lambda (c) - (a-get c 'reply?)) - comments)) + (comments (github-review--split-comments-by-type + (a-get parsed-review 'comments))) + (regular-comments (a-get comments 'regular-comments)) + (reply-comments (a-get comments 'reply-comments)) (head-sha (a-get pr-alist 'sha)) - (review (a-assoc parsed-review - 'commit_id head-sha - 'event kind - 'comments regular-comments))) - - (when github-review-reply-inline-comments + (partial-review (a-assoc parsed-review + 'commit_id head-sha + 'event kind)) + (review (if (equal nil regular-comments) + (a-assoc partial-review + 'comments regular-comments) + partial-review))) + + (when (and github-review-reply-inline-comments + reply-comments) (github-review-post-review-replies pr-alist reply-comments @@ -412,8 +423,9 @@ This function infers the PR name based on the current filename" (github-review-post-review pr-alist - review (lambda (&rest _) - (message "Done submitting review"))))) + review + (lambda (&rest _) + (message "Done submitting review"))))) (defun github-review-to-comments (text) "Convert TEXT, a string to a string where each line is prefixed by ~." From 1a105be05f0dfbf4085cf03854dd241a90f5d490 Mon Sep 17 00:00:00 2001 From: Wanderson Ferreira Date: Sun, 10 Oct 2021 00:31:38 -0300 Subject: [PATCH 03/11] fix if correct order --- github-review.el | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/github-review.el b/github-review.el index c7177d5..a00b082 100644 --- a/github-review.el +++ b/github-review.el @@ -409,9 +409,9 @@ This function infers the PR name based on the current filename" 'commit_id head-sha 'event kind)) (review (if (equal nil regular-comments) - (a-assoc partial-review - 'comments regular-comments) - partial-review))) + partial-review + (a-assoc partial-review + 'comments regular-comments)))) (when (and github-review-reply-inline-comments reply-comments) From 2c7232eb05dc5e80f563dc4bd61e4d607dfde3d0 Mon Sep 17 00:00:00 2001 From: Wanderson Ferreira Date: Sun, 10 Oct 2021 00:44:27 -0300 Subject: [PATCH 04/11] fix wording --- github-review.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/github-review.el b/github-review.el index a00b082..02c7a26 100644 --- a/github-review.el +++ b/github-review.el @@ -71,7 +71,7 @@ (defcustom github-review-reply-inline-comments nil "Flag to enable replies to inline comments. -This flag will only be valid if `github-review-view-comments-in-code-lines' is set to `t`.") +This flag will only be considered if `github-review-view-comments-in-code-lines' is set to `t`.") (defconst github-review-diffheader '(("Accept" . "application/vnd.github.v3.diff")) "Header for requesting diffs from GitHub.") From 9510d9053e58e51a7c36bd31e193a1f2c8bb4c29 Mon Sep 17 00:00:00 2001 From: Wanderson Ferreira Date: Sun, 10 Oct 2021 00:45:16 -0300 Subject: [PATCH 05/11] revert "~" to "~ " --- github-review.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/github-review.el b/github-review.el index 02c7a26..92a2874 100644 --- a/github-review.el +++ b/github-review.el @@ -225,7 +225,7 @@ CALLBACK will be called back when done" (defun github-review-previous-comment? (l) "Return t if L, a string, is a comment from previous review." - (string-prefix-p "~" l)) + (string-prefix-p "~ " l)) (defun github-review-is-start-of-file-hunk? (l) "Return t if L, a string that start with 'diff' marking the start of a file hunk." From 04c1d45df74c3c0f032f31cb206544973d946617 Mon Sep 17 00:00:00 2001 From: Wanderson Ferreira Date: Sun, 10 Oct 2021 00:54:04 -0300 Subject: [PATCH 06/11] improve code clarity --- github-review.el | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/github-review.el b/github-review.el index 92a2874..6528290 100644 --- a/github-review.el +++ b/github-review.el @@ -378,21 +378,28 @@ ACC is an alist accumulating parsing state." ;; Helpers ;; ;;;;;;;;;;;;; +(defun github-review--filter-reply-comments (comments) + "If comments exist, return only reply comments." + (when comments + (-filter (lambda (c) (a-get c 'reply?)) comments))) + +(defun github-review--filter-code-comments (comments) + "If comments exist, return only code comments." + (when comments + (let ((filter-code-comments (lambda (c) (not (a-get c 'reply?)))) + (clean-reply-placeholders (lambda (c) (a-dissoc c 'reply?)))) + (->> comments + (-filter filter-code-comments) + (-map clean-reply-placeholders))))) + (defun github-review--split-comments-by-type (comments) "Return A-LIST with regular-comments and reply-comments." - (if (equal nil comments) - `((regular-comments . ,nil) - (reply-comments . ,nil)) - (let* ((regular-comments (->> comments - (-filter (lambda (c) - (not (a-get c 'reply?)))) - (-map (lambda (c) - (a-dissoc c 'reply?))))) - (reply-comments (-filter (lambda (c) - (a-get c 'reply?)) - comments))) - `((regular-comments . ,regular-comments) - (reply-comments . ,reply-comments))))) + (let ((regular-comments + (github-review--filter-code-comments comments)) + (reply-comments + (github-review--filter-reply-comments comments))) + `((regular-comments . ,regular-comments) + (reply-comments . ,reply-comments)))) (defun github-review-submit-review (kind) "Submit a code review of KIND. From 3d09efc451f1d5aaad5157618571fbbfadfe0941 Mon Sep 17 00:00:00 2001 From: Wanderson Ferreira Date: Sun, 10 Oct 2021 01:36:49 -0300 Subject: [PATCH 07/11] using deferred to run github reply call --- github-review.el | 52 ++++++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/github-review.el b/github-review.el index 6528290..3a6fbf6 100644 --- a/github-review.el +++ b/github-review.el @@ -182,28 +182,36 @@ CALLBACK will be called back when done" (defun github-review-post-review-replies (pr-alist replies callback) "Submit replies to review comments inline." - (let-alist pr-alist - (-map - (lambda (comment) - (let* ((path (a-get comment 'path)) - (position (a-get comment 'position)) - (comment-id (alist-get (s-concat path - ":" - (number-to-string position)) - github-review-pos->databaseid - nil nil 'equal)) - (body (a-get comment 'body))) - (ghub-post (format "/repos/%s/%s/pulls/%s/comments/%s/replies" - .owner .repo .num comment-id) - nil - :payload (a-alist 'body body) - :headers github-review-diffheader - :auth 'github-review - :host (github-review-api-host pr-alist) - :callback (lambda (&rest _)) - :errorback #'github-review-errback))) - replies) - (funcall callback))) + (deferred:$ + (deferred:loop + replies + (lambda (comment) + (let-alist pr-alist + (let* ((path (a-get comment 'path)) + (position (a-get comment 'position)) + (comment-id (alist-get (s-concat path + ":" + (number-to-string position)) + github-review-pos->databaseid + nil nil 'equal)) + (body (a-get comment 'body))) + (ghub-post (format "/repos/%s/%s/pulls/%s/comments/%s/replies" + .owner .repo .num comment-id) + nil + :payload (a-alist 'body body) + :headers github-review-diffheader + :auth 'github-review + :host (github-review-api-host pr-alist) + :callback (lambda (&rest _)) + :errorback #'github-review-errback))))) + + (deferred:nextc it + (lambda (x) + (funcall callback))) + + (deferred:error it + (lambda (err) + (message "Got an error from the Github Reply API %S!" err))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Code review file parsing ;; From a0157b81b05968906c76d98e7ee74e3b3b2c3a34 Mon Sep 17 00:00:00 2001 From: Wanderson Ferreira Date: Sun, 10 Oct 2021 01:37:04 -0300 Subject: [PATCH 08/11] remove 'comments from review if empty --- github-review.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/github-review.el b/github-review.el index 3a6fbf6..f4f7204 100644 --- a/github-review.el +++ b/github-review.el @@ -424,7 +424,7 @@ This function infers the PR name based on the current filename" 'commit_id head-sha 'event kind)) (review (if (equal nil regular-comments) - partial-review + (a-dissoc partial-review 'comments) (a-assoc partial-review 'comments regular-comments)))) From 9d1761307e09d01a53be1e13ec7a22a961ad7ab4 Mon Sep 17 00:00:00 2001 From: Wanderson Ferreira Date: Sun, 10 Oct 2021 01:37:26 -0300 Subject: [PATCH 09/11] sometimes we dont have top level comments --- github-review.el | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/github-review.el b/github-review.el index f4f7204..7b41445 100644 --- a/github-review.el +++ b/github-review.el @@ -436,11 +436,13 @@ This function infers the PR name based on the current filename" (lambda (&rest _) (message "Done submitting review replies")))) - (github-review-post-review - pr-alist - review - (lambda (&rest _) - (message "Done submitting review"))))) + (when (or regular-comments + (not (string-empty-p (a-get review 'body)))) + (github-review-post-review + pr-alist + review + (lambda (&rest _) + (message "Done submitting review")))))) (defun github-review-to-comments (text) "Convert TEXT, a string to a string where each line is prefixed by ~." From 37ad44ae5e397e8446a39e3137e50377ba171aff Mon Sep 17 00:00:00 2001 From: Wanderson Ferreira Date: Sun, 10 Oct 2021 20:51:44 -0300 Subject: [PATCH 10/11] fix broken test --- github-review.el | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/github-review.el b/github-review.el index d40b90d..1ec3063 100644 --- a/github-review.el +++ b/github-review.el @@ -341,8 +341,10 @@ ACC is an alist accumulating parsing state." (parsed-comments (a-get parsed-data 'comments)) (parsed-body (s-trim-right (a-get parsed-data 'body))) (merged-comments (when parsed-comments (github-review-merge-comments (reverse parsed-comments))))) - `((body . ,parsed-body) - (comments . ,(reverse merged-comments))))) + (if (equal nil merged-comments) + `((body . ,parsed-body)) + `((body . ,parsed-body) + (comments . ,(reverse merged-comments)))))) ;;;;;;;;;;;;;;;;;;;;;;;;; ;; Buffer interactions ;; @@ -614,12 +616,12 @@ Github API provides only the originalPosition in the query.") (if (not (forge-pullreq-p pullreq)) (message "We can only review PRs at the moment. You tried on something else.") - (progn - (setq forge-current-dir default-directory) - (github-review-start-internal (a-alist 'owner (oref repo owner) - 'repo (oref repo name) - 'apihost (oref repo apihost) - 'num (oref pullreq number))))))) + (progn + (setq forge-current-dir default-directory) + (github-review-start-internal (a-alist 'owner (oref repo owner) + 'repo (oref repo name) + 'apihost (oref repo apihost) + 'num (oref pullreq number))))))) ;;;###autoload (defun github-review-start (url) From e4e85ab74dd2ac47cd50fef17464e8e7f5c09d9c Mon Sep 17 00:00:00 2001 From: Wanderson Ferreira Date: Mon, 11 Oct 2021 16:22:27 -0300 Subject: [PATCH 11/11] add changelog and change :loop to :parallel --- CHANGELOG.md | 1 + github-review.el | 43 ++++++++++++++++++++++--------------------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index abf1d89..adc1d78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,4 +2,5 @@ # Unreleased +- [#81](https://github.com/charignon/github-review/pull/81): Allow reply to code comments. Enable via `github-review-reply-inline-comments`. See README. - [#87](https://github.com/charignon/github-review/pull/87): Enable `outline-mode` by default to allow hide/show hunks. See `outline-*` commands. diff --git a/github-review.el b/github-review.el index eafcad4..bd5ae3f 100644 --- a/github-review.el +++ b/github-review.el @@ -183,27 +183,28 @@ CALLBACK will be called back when done" (defun github-review-post-review-replies (pr-alist replies callback) "Submit replies to review comments inline." (deferred:$ - (deferred:loop - replies - (lambda (comment) - (let-alist pr-alist - (let* ((path (a-get comment 'path)) - (position (a-get comment 'position)) - (comment-id (alist-get (s-concat path - ":" - (number-to-string position)) - github-review-pos->databaseid - nil nil 'equal)) - (body (a-get comment 'body))) - (ghub-post (format "/repos/%s/%s/pulls/%s/comments/%s/replies" - .owner .repo .num comment-id) - nil - :payload (a-alist 'body body) - :headers github-review-diffheader - :auth 'github-review - :host (github-review-api-host pr-alist) - :callback (lambda (&rest _)) - :errorback #'github-review-errback))))) + (deferred:parallel + (-map (lambda (comment) + (lambda () + (let-alist pr-alist + (let* ((path (a-get comment 'path)) + (position (a-get comment 'position)) + (comment-id (alist-get (s-concat path + ":" + (number-to-string position)) + github-review-pos->databaseid + nil nil 'equal)) + (body (a-get comment 'body))) + (ghub-post (format "/repos/%s/%s/pulls/%s/comments/%s/replies" + .owner .repo .num comment-id) + nil + :payload (a-alist 'body body) + :headers github-review-diffheader + :auth 'github-review + :host (github-review-api-host pr-alist) + :callback (lambda (&rest _)) + :errorback #'github-review-errback))))) + replies)) (deferred:nextc it (lambda (x)