From a5e547712914d35e9e18c5f8af53cc8717debc2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Erlwein?= Date: Sat, 31 Oct 2020 12:00:26 +0100 Subject: [PATCH 1/4] Calculate the timezone offset with (current-time-zone) --- ejira-hourmarking.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ejira-hourmarking.el b/ejira-hourmarking.el index a83c71c..93fcb9d 100644 --- a/ejira-hourmarking.el +++ b/ejira-hourmarking.el @@ -113,7 +113,8 @@ (defun ejira-hourmarking-round (time round-by) "Round TIME to nearest ROUND-BY." ;; Account for stupid time zone issues. - (let* ((hours (- (string-to-number (format-time-string "%H" time)) 2)) + (let* ((offset (/ (car (current-time-zone)) 3600)) + (hours (- (string-to-number (format-time-string "%H" time)) offset)) (minutes (string-to-number (format-time-string "%M" time))) (total (+ (* 60 hours) minutes)) (rounded (round total round-by)) From f2863c63a45a1c6b0d1fe4b786648b9291322523 Mon Sep 17 00:00:00 2001 From: Logan Barnett Date: Mon, 2 Nov 2020 18:06:13 -0800 Subject: [PATCH 2/4] provide overrides for JQL to sync tickets This provides the ability to override the JQL used in ejira-update-jql. From #20 there is a need to synchronize only the user's involved tickets. The original behavior should be unchanged. @osktyn has generously provided a JQL statement to use. This is provided as `ejira-jql-my-unresolved-fn`, which can be set via the variable `ejira-update-jql-unresolved-fn`. An additional `ejira-update-jql-resolved-fn` is also provided but doesn't need to be overridden for the purposes of #20 - it just seemed appropriate given this change. Any stylistic changes are unintentional. Please nitpick away :) Thanks for making an awesome project! Closes #20 --- README.org | 14 ++++++++++++++ ejira.el | 36 +++++++++++++++++++++++++++++++++--- 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/README.org b/README.org index 3e8b20c..497df0b 100644 --- a/README.org +++ b/README.org @@ -134,3 +134,17 @@ Commands available in =ejira-agenda=: By default the items are rounded to 15 minutes. If exact times are desired, set =ejira-hourmaking-round-by= to 1. Syncing worklogs from JIRA to org is not currently implemented, as I personally don't have a use case for it. +*** Syncing only your tickets + +By default =ejira= synchronizes all tickets across a project. If you want to +restrict synchronization to only your tickets (assigned or reported), use the +following override: + +#+begin_example emacs-lisp +(setq ejira-update-jql-unresolved-fn #'ejira-jql-my-unresolved-project-tickets) +#+end_example + +*** Syncing tickets using custom JQL + +=ejira-update-jql-unresolved-fn= can be set to any function that accepts a +string representing the project ID, and returns a JQL statement as a string. diff --git a/ejira.el b/ejira.el index 06e55ca..cf17501 100644 --- a/ejira.el +++ b/ejira.el @@ -34,6 +34,16 @@ (defvar ejira-push-deadline-changes t "Sync deadlines to server when updated with `ejira-set-deadline'.") +(defvar ejira-update-jql-resolved-fn #'ejira-jql-all-resolved-project-tickets + "Generates JQL used in `ejira-update-project' to find server-resolved items. +Must take a project-id as a string, a list of keys, and return JQL as a string." + ) + +(defvar ejira-update-jql-unresolved-fn + #'ejira-jql-all-unresolved-project-tickets + "Generates JQL used in `ejira-update-project' to find unresolved items. +Must take a project-id as a string and return JQL as a string.") + (defun ejira-add-comment (to-clocked) "Capture new comment to issue under point. With prefix-argument TO-CLOCKED add comment to currently clocked issue." @@ -50,6 +60,27 @@ With prefix-argument TO-CLOCKED add comment to currently clocked issue." (when (y-or-n-p (format "Delete comment %s? " (cdr id))) (ejira--delete-comment (car id) (cdr id))))) +(defun ejira-jql-all-resolved-project-tickets (project-id keys) + "Builds JQL for server-resolved project tickets in PROJECT-ID from local KEYS. +This is the function used in `ejira-update-project'. Override with +`ejira-update-jql-resolved-fn'." + (format "project = '%s' and key in (%s) and resolution = done" + project-id (s-join ", " keys))) + +(defun ejira-jql-all-unresolved-project-tickets (project-id) + "Builds JQL to find unresolved project tickets assigned to PROJECT-ID. +This is the default function used in `ejira-update-project'. Override with +`ejira-update-jql-unresolved-fn'." + (format "project = '%s' and resolution = unresolved" project-id)) + +(defun ejira-jql-my-unresolved-project-tickets (project-id) + "Builds JQL to find your unresolved project tickets assigned to PROJECT-ID. +This is a convenience function used in `ejira-update-project'. Override with +`ejira-update-jql-unresolved-fn'." + (format "project = '%s' and \ +resolution = unresolved and \ +(assignee = currentUser() or reporter = currentUser())" project-id)) + (defun ejira-pull-item-under-point () "Update the issue, project or comment under point." (interactive) @@ -154,7 +185,7 @@ comments. With SHALLOW, only update todo status and assignee." (ejira--alist-get i 'fields 'assignee 'displayName)) (ejira--update-task (ejira--parse-item i)))) (apply #'jiralib2-jql-search - (format "project = '%s' and resolution = unresolved" id) + (funcall ejira-update-jql-unresolved-fn id) (ejira--get-fields-to-sync shallow))) ;; Then, sync any items that are still marked as unresolved in our local sync, @@ -177,8 +208,7 @@ comments. With SHALLOW, only update todo status and assignee." (ejira--alist-get i 'fields 'assignee 'displayName)) (ejira--update-task (ejira--parse-item i)))) (apply #'jiralib2-jql-search - (format "project = '%s' and key in (%s) and resolution = done" - id (s-join ", " keys)) + (funcall ejira-update-jql-resolved-fn id keys) (ejira--get-fields-to-sync shallow))))) ;; TODO: Handle issue being deleted from server: From 23c408f30b91d4f8a32b5e71c3aa20b437eb1d00 Mon Sep 17 00:00:00 2001 From: Logan Barnett Date: Tue, 3 Nov 2020 18:08:03 -0800 Subject: [PATCH 3/4] support top-level org headers in the document Prior to this change, having org headers (such as `title`) would trip up the creation of a new ticket, and that new ticket would override the project heading. This meant the project couldn't be found in later calls and would eventually lead to a "Target not found", with the document left slightly corrupted. The fix here is to attempt to hang new headings from `ejira--new-heading` off of a parent heading by jumping to that parent heading, and then doing `forward-line` as we normally would. In the case that a parent isn't provided, the project is used. My organization's jira structure is relatively flat. I have tested these changes both with and without top level headings and the problem is resolved. I suggest testing against your own structure to ensure I didn't break anything - though I have no reason to believe it will be broken. --- ejira-core.el | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/ejira-core.el b/ejira-core.el index 8cb9650..79ac075 100644 --- a/ejira-core.el +++ b/ejira-core.el @@ -242,7 +242,7 @@ The default value is applicable for: (find-file project-file-name)))) (unless existing-heading - (ejira--new-heading project-buffer key)) + (ejira--new-heading project-buffer nil key)) (ejira--set-summary key (ejira-project-name project)) (ejira--set-property key "TYPE" "ejira-project")))))) @@ -310,7 +310,9 @@ If the issue heading does not exist, fallback to full update." ;; Create a new heading if needed (unless (ejira--find-heading key) (when (fboundp 'helm-ejira-invalidate-cache) (helm-ejira-invalidate-cache)) - (ejira--new-heading (marker-buffer (ejira--find-heading project)) key)) + (ejira--new-heading (marker-buffer (ejira--find-heading project)) + (or parent project) + key)) (ejira--set-todo-state key (alist-get status ejira-todo-states-alist 1 nil #'equal)) @@ -565,15 +567,19 @@ If LEVEL is given, shift all heading by it." (error nil)))) -(defun ejira--new-heading (buffer id) - "Create a header with id ID into BUFFER and return a marker to it. -If TITLE is given, use it as header title." +(defun ejira--new-heading (buffer parent id) + "Create a header with ID under PARENT into BUFFER and return a marker to it. +If TITLE is given, use it as header title. If PARENT is nil assume the beginning +of the document." (save-window-excursion (with-current-buffer buffer (org-with-wide-buffer (ejira--with-expand-all (goto-char (point-min)) + ;; `forward-line' won't work as intended if the org document contains + ;; headers. We should jump to the parent. + (when parent (goto-char (ejira--find-heading parent))) ;; insert-heading-respect-content does not respect content if we are ;; before first heading in the file. Thus, we want to move to a safe ;; location. In an empty buffer, the first line has the visibility From 7d7782ceecfd4fe8e3e93ee37f7925a401baa643 Mon Sep 17 00:00:00 2001 From: Henrik Nyman Date: Sun, 22 Nov 2020 20:16:22 +0200 Subject: [PATCH 4/4] Use setf + alist-get instead of map-put to handle agenda cache --- ejira-agenda.el | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ejira-agenda.el b/ejira-agenda.el index 8942cac..fb6ef95 100644 --- a/ejira-agenda.el +++ b/ejira-agenda.el @@ -123,12 +123,11 @@ Prefix argument causes discarding the cached issue key list." (mapc #'ejira--update-task (mapcar #'ejira--parse-item (apply #'jiralib2-jql-search jql (ejira--get-fields-to-sync))))) - (when (or current-prefix-arg (not (assoc jql ejira-agenda--jql-cache))) - (map-put ejira-agenda--jql-cache jql (mapcar - (-partial #'alist-get 'key) - (jiralib2-jql-search jql "key")))) + (when (or current-prefix-arg (not (alist-get jql ejira-agenda--jql-cache nil nil #'equal))) + (setf (alist-get jql ejira-agenda--jql-cache nil nil 'equal) + (mapcar (-partial #'alist-get 'key) (jiralib2-jql-search jql "key")))) - (ejira-agenda-view (cdr (assoc jql ejira-agenda--jql-cache)))) + (ejira-agenda-view (alist-get jql ejira-agenda--jql-cache nil nil #'equal))) (defun ejira-agenda--cmd (fun &rest args) "Call function FUN from agenda.