aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-05-28 09:36:06 -0500
committerCraig Jennings <c@cjennings.net>2026-05-28 09:36:06 -0500
commit0975e7de0c7bfdc6f65bb64537d4eff1aeb09a7e (patch)
tree4b872db4e0417e173595409c63c7d1291015adbd /tests
parentfd94237903c15883173e438a5af4ba4e6bfdbd46 (diff)
downloadpearl-0975e7de0c7bfdc6f65bb64537d4eff1aeb09a7e.tar.gz
pearl-0975e7de0c7bfdc6f65bb64537d4eff1aeb09a7e.zip
feat(view-sync): pearl-publish-current-source convenience wrapper
This is Phase 5 of docs/saved-query-sync-spec.org (ยง New: pearl-publish-current-source). When I'm reading a local saved query rendered in pearl and decide it should be a Linear view, I now have a one-chord publish instead of the M-x round-trip through pearl-sync-saved-query-to-linear with the name lookup. The new command reads the active buffer's #+LINEAR-SOURCE header and dispatches to pearl-sync-saved-query-to-linear with the name pre-filled when the source is a :type filter that matches an entry in pearl-saved-queries. Other shapes refuse with a clear message: no source header at all, the source is already a :type view (no publish needed), the type isn't filter, the source has no usable name (transient ad-hoc filter, or whitespace-only name), or the recorded name doesn't match any local saved query. I bound the command under C-; L f P in pearl-fetch-map. The transient gets ("U" "upload current source") in the Fetch group because P is taken in the transient's flat namespace, and the verb-prefix shape revisit task tracks reshaping that. 7 new tests cover each refusal branch and the dispatch path, including a regression for the whitespace-only :name case the pre-commit review surfaced. The prior check used string-empty-p, which let " " fall through to the no-matching-saved-query branch with a visibly-blank name in the error message. string-blank-p routes it to the cleaner no-name branch. The keymap and transient menu tests gained coverage for the new binding. 660 ert tests total green. make compile and make lint clean.
Diffstat (limited to 'tests')
-rw-r--r--tests/test-pearl-keymap.el4
-rw-r--r--tests/test-pearl-menu.el1
-rw-r--r--tests/test-pearl-saved-query-sync.el65
3 files changed, 69 insertions, 1 deletions
diff --git a/tests/test-pearl-keymap.el b/tests/test-pearl-keymap.el
index b1b5e23..1ae0d3d 100644
--- a/tests/test-pearl-keymap.el
+++ b/tests/test-pearl-keymap.el
@@ -74,7 +74,9 @@ The lowercase `c' is no longer a direct command -- it is the create prefix."
(should (eq 'pearl-run-view (lookup-key pearl-prefix-map (kbd "f v"))))
(should (eq 'pearl-run-saved-query (lookup-key pearl-prefix-map (kbd "f q"))))
(should (eq 'pearl-sync-saved-query-to-linear
- (lookup-key pearl-prefix-map (kbd "f S")))))
+ (lookup-key pearl-prefix-map (kbd "f S"))))
+ (should (eq 'pearl-publish-current-source
+ (lookup-key pearl-prefix-map (kbd "f P")))))
(ert-deftest test-pearl-prefix-map-edit-group ()
"The edit group resolves each field-edit command."
diff --git a/tests/test-pearl-menu.el b/tests/test-pearl-menu.el
index c25c9a9..e2ea550 100644
--- a/tests/test-pearl-menu.el
+++ b/tests/test-pearl-menu.el
@@ -63,6 +63,7 @@ menu entry that still points at it fails here."
pearl-run-view
pearl-run-saved-query
pearl-sync-saved-query-to-linear
+ pearl-publish-current-source
pearl-save-issue
pearl-save-all
pearl-edit-state
diff --git a/tests/test-pearl-saved-query-sync.el b/tests/test-pearl-saved-query-sync.el
index 830f738..f9bab00 100644
--- a/tests/test-pearl-saved-query-sync.el
+++ b/tests/test-pearl-saved-query-sync.el
@@ -387,6 +387,71 @@ URL the create path already wrote."
(let ((shared-value (cdr (assoc "shared" captured-input))))
(should (eq :json-false shared-value))))))
+;;; pearl-publish-current-source
+
+(defmacro test-pearl-publish--in-buffer (source-form &rest body)
+ "Run BODY in an org-mode temp buffer carrying SOURCE-FORM as #+LINEAR-SOURCE.
+SOURCE-FORM is the source plist (or nil for no source header)."
+ (declare (indent 1))
+ `(with-temp-buffer
+ (when ,source-form
+ (insert (format "#+title: test\n#+LINEAR-SOURCE: %s\n\n"
+ (prin1-to-string ,source-form))))
+ (org-mode)
+ ,@body))
+
+(ert-deftest test-pearl-publish-current-source-no-source-header-errors ()
+ "A buffer with no #+LINEAR-SOURCE signals a clear user-error."
+ (test-pearl-publish--in-buffer nil
+ (should-error (pearl-publish-current-source) :type 'user-error)))
+
+(ert-deftest test-pearl-publish-current-source-view-source-errors ()
+ "A view source signals user-error -- views are already on Linear."
+ (test-pearl-publish--in-buffer '(:type view :name "Eng dashboard" :id "v1")
+ (should-error (pearl-publish-current-source) :type 'user-error)))
+
+(ert-deftest test-pearl-publish-current-source-transient-filter-no-name-errors ()
+ "A :type filter with no :name (transient ad-hoc) signals user-error."
+ (test-pearl-publish--in-buffer '(:type filter :filter (:open t))
+ (should-error (pearl-publish-current-source) :type 'user-error)))
+
+(ert-deftest test-pearl-publish-current-source-no-matching-saved-query-errors ()
+ "A :type filter source whose name doesn't match any pearl-saved-queries entry errors."
+ (let ((pearl-saved-queries '(("Other" :filter (:open t)))))
+ (test-pearl-publish--in-buffer
+ '(:type filter :name "Gone" :filter (:open t))
+ (should-error (pearl-publish-current-source) :type 'user-error))))
+
+(ert-deftest test-pearl-publish-current-source-dispatches-to-sync-with-name ()
+ "A :type filter source whose name matches dispatches to pearl-sync-saved-query-to-linear."
+ (let ((pearl-saved-queries '(("Mine" :filter (:open t))))
+ (sync-called-with nil))
+ (cl-letf (((symbol-function 'pearl-sync-saved-query-to-linear)
+ (lambda (n) (setq sync-called-with n))))
+ (test-pearl-publish--in-buffer
+ '(:type filter :name "Mine" :filter (:open t))
+ (pearl-publish-current-source))
+ (should (equal "Mine" sync-called-with)))))
+
+(ert-deftest test-pearl-publish-current-source-empty-name-errors ()
+ "A :type filter source with an empty-string :name (degenerate) errors cleanly."
+ (test-pearl-publish--in-buffer
+ '(:type filter :name "" :filter (:open t))
+ (should-error (pearl-publish-current-source) :type 'user-error)))
+
+(ert-deftest test-pearl-publish-current-source-whitespace-name-errors ()
+ "A :type filter source with a whitespace-only :name takes the no-name branch
+rather than falling through to the no-matching-saved-query branch with a
+visibly-blank name in the error message."
+ (let ((pearl-saved-queries '()))
+ (test-pearl-publish--in-buffer
+ '(:type filter :name " " :filter (:open t))
+ (let ((err (should-error (pearl-publish-current-source)
+ :type 'user-error)))
+ ;; The message should name the source-has-no-name reason, not the
+ ;; no-matching-query reason.
+ (should (string-match-p "no name" (error-message-string err)))))))
+
;;; Cache-shape parity โ€” pearl-get-teams-async and pearl--all-teams must agree
(ert-deftest test-pearl-get-teams-async-query-fetches-key ()