forked from arbox/org-sync
-
Notifications
You must be signed in to change notification settings - Fork 0
/
org-sync-gitlab.el
207 lines (188 loc) · 7.23 KB
/
org-sync-gitlab.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
;;; org-sync-gitlab --- Gitlab backend for org-sync
;;
;; Copyright (C) 2017 Yisrael Dov Lebow
;;
;; Author: Yisrael Dov Lebow <lebow at lebowtech dot com>
;; Keywords: org, gitlab, synchronization
;; Homepage: https://github.com/arbox/org-sync
;;
;; 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.
;;
;; This file is not part of GNU Emacs.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;
;;; Commentary:
;;
;; This package implements a gitlab backend for org-sync to synchronize issues
;; from a Gitlab repo with an org-mode buffer. Read Org-sync documentation for
;; more information about it.
;;
;; This backend only supports basic synchronization for now. Components,
;; versions, tags and milestones are ignored.
;;
;; You must set the org-sync-gitlab-auth-token before you can sync.
;;
;; Specify the URL to your project, for example: https://gitlab.com/group/project
;; Do not include any ending like /issues or similar.
;;
;; The org-sync backend list (org-sync-backend-alist) is setup per default to
;; associate any URL containing 'gitlab' with the gitlab backend, matching both
;; the public gitlab.com but also a private gitlab instance as long as 'gitlab'
;; is in the URL. If you are using a private GitLab instance that does not
;; include 'gitlab' in the URL, you can add an entry to org-sync-backend-alist
;; to forcibly associate the FQDN of your instance with the gitlab backend:
;;
;; (add-to-list 'org-sync-backend-alist (cons "private-instance.example.com" 'org-sync-gitlab-backend))
;;
;;; Code:
(eval-when-compile (require 'cl))
(require 'org-sync)
(require 'url)
(require 'url-parse)
(require 'json)
(defvar org-sync-gitlab-backend
'((base-url . org-sync-gitlab-base-url)
(fetch-buglist . org-sync-gitlab-fetch-buglist)
(send-buglist . org-sync-gitlab-send-buglist))
"Gitlab backend.")
(defun org-sync-gitlab-base-url (url)
"Return base URL."
;; if no url type, try https
(when (not (string-match "^https?://" url))
(setq url (concat "https://" url)))
url)
(defun org-sync-fqdn-from-url (url)
"Return FQDN part from a URL, effectively stripping leading https:// and the path of the URL"
(string-match "/\\([^/]+\\)/?" url)
(match-string 1 url))
(defun org-sync-gitlab-api-url ()
"Gets the api url from the base-url."
(let* ((url (url-generic-parse-url org-sync-base-url ))
(fqdn (url-host url))
(path (split-string (substring (url-filename url) 1) "/"))
(project (first (last path)))
(groups (butlast path)))
(format "https://%s/api/v4/projects/%s%s%s/"
fqdn
(mapconcat 'identity groups "%2F")
"%2F"
project)))
;; override
(defun org-sync-gitlab-fetch-buglist (last-update)
"Return the buglist at org-sync-base-url."
;;TODO implement SINCE
;;TODO get name for task list from url
`(:title "Tasks"
:url ,org-sync-base-url
:bugs ,(org-sync-gitlab-fetch-bugs last-update)
))
(defun org-sync-gitlab-fetch-bugs (last-update)
"Return the json bugs."
;;TODO impliment LAST-UPDATE
(let
((jsonBugs (org-sync-gitlab-request
"GET"
(concat (org-sync-gitlab-api-url) "issues?per_page=100"))))
(mapcar 'org-sync-gitlab-json-to-bug jsonBugs)
)
)
;; override
(defun org-sync-gitlab-send-buglist (buglist)
"Send a BUGLIST to gitlab and return updated BUGLIST."
(dolist (b (org-sync-get-prop :bugs buglist))
(let*
(
(id (org-sync-get-prop :id b))
(issuePath (concat "issues/" (if id (number-to-string id ))))
(state_event (if (string= (org-sync-get-prop :status b) 'open) "reopen" "close"))
(issueDataJson (json-encode `((title . ,(org-sync-get-prop :title b))
(description . ,(org-sync-get-prop :desc b))
(state_event . ,state_event)
)))
)
(cond
;; new bug (no id)
((null id)
(org-sync-gitlab-request
"POST"
(concat (org-sync-gitlab-api-url)
issuePath)
issueDataJson
'(("Content-Type" . "application/json"))))
;; delete bug
((org-sync-get-prop :delete b)
(org-sync-gitlab-request
"DELETE"
(concat (org-sync-gitlab-api-url)
issuePath
)))
;; else, modified bug
(t
(org-sync-gitlab-request
"PUT"
(concat (org-sync-gitlab-api-url)
issuePath)
issueDataJson
'(("Content-Type" . "application/json")))))
)
)
;;brute force update bugs
;;TODO be smarter and only show updated bugs
`(:bugs ,(org-sync-gitlab-fetch-bugs (org-sync-get-prop :since
buglist)))
)
(defun org-sync-gitlab-json-to-bug (data)
"Convert the provided Json DATA into a bug."
`(
:id ,(assoc-default `iid data) ;; iid is the internal issue id, used for updating
:title ,(assoc-default `title data)
:status, (if (string= (assoc-default `state data) "opened") 'open 'closed)
:date-creation ,(org-sync-parse-date (assoc-default 'created_at data))
:date-modification ,(org-sync-parse-date (assoc-default 'updated_at data))
:web-url ,(assoc-default 'web_url data)
:weight ,(assoc-default 'weight data)
:desc, (assoc-default `description data)))
(defun org-sync-gitlab-request (method url &optional data extra-headers)
"Sends HTTP request at URL using METHOD with DATA
Return a JSON response"
(let* ((url-request-method method)
(url-request-data data)
(url-request-extra-headers (append `(("Private-Token" . ,(org-sync-gitlab-get-auth-token)))
extra-headers))
)
(message "%s %s %s" method url (prin1-to-string data))
;; first line is like 'HTTP/1.1 200 OK' so we move forward to capture the
;; status code and make sure it is 200
(with-current-buffer (url-retrieve-synchronously url)
(beginning-of-buffer)
(search-forward " ")
(setq http-code (thing-at-point 'word 'no-properties))
(if (not (string-equal http-code "200"))
(error "Didn't get 200 OK for HTTP request"))
(goto-char url-http-end-of-headers)
(prog1
(if
(not (string-equal method "DELETE" ))
(json-read)
)
(kill-buffer)
))))
(defun org-sync-gitlab-get-auth-token ()
"Gets the private-token."
;;TODO: prompt the user for auth token
(unless org-sync-gitlab-auth-token
(error "Please set org-sync-gitlab-auth-token"))
org-sync-gitlab-auth-token
)
(provide 'org-sync-gitlab)
;;; org-sync-gitlab ends here