rct_jira 0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. data/bin/jira +39 -0
  2. data/lib/rct_jira.rb +376 -0
  3. metadata +70 -0
data/bin/jira ADDED
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #
4
+ # Copyright 2014-2015 Jyri J. Virkki <jyri@virkki.com>
5
+ #
6
+ # This file is part of rct_jira.
7
+ #
8
+ # rct_jira is free software: you can redistribute it and/or modify it
9
+ # under the terms of the GNU General Public License as published by
10
+ # the Free Software Foundation, either version 3 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # rct_jira is distributed in the hope that it will be useful, but
14
+ # WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
+ # General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU General Public License
19
+ # along with rct_jira. If not, see <http://www.gnu.org/licenses/>.
20
+ #
21
+
22
+
23
+ #
24
+ # Convenience script for running jira CLI directly.
25
+ #
26
+ # Run:
27
+ #
28
+ # jira OPERATION PARAMS
29
+ #
30
+ # This is equivalent to running rct directly as follows:
31
+ #
32
+ # rct --req rct_jira Jira.OPERATION PARAMS
33
+ #
34
+
35
+ require 'rct_jira'
36
+
37
+ $RCT_CLI_APP_CLASS = "Jira"
38
+
39
+ require 'rct_cli_app'
data/lib/rct_jira.rb ADDED
@@ -0,0 +1,376 @@
1
+ #
2
+ # Copyright 2013-2015 Jyri J. Virkki <jyri@virkki.com>
3
+ #
4
+ # This file is part of rct_jira.
5
+ #
6
+ # rct_jira is free software: you can redistribute it and/or modify it
7
+ # under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # rct_jira is distributed in the hope that it will be useful, but
12
+ # WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
+ # General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with rct_jira. If not, see <http://www.gnu.org/licenses/>.
18
+ #
19
+
20
+
21
+ #
22
+ # Implements an rct client for JIRA APIs.
23
+ #
24
+ # Only a tiny subset supported. Expand as needed.
25
+ #
26
+ # https://developer.atlassian.com/display/JIRADEV/JIRA+REST+API+Tutorials
27
+ # https://docs.atlassian.com/jira/REST/latest/
28
+ #
29
+
30
+
31
+ require 'rct_client'
32
+
33
+ class Jira < RCTClient
34
+
35
+ BASE_PATH = '/rest/api/2'
36
+
37
+
38
+ #----------------------------------------------------------------------------
39
+ # Class description, for automated help.
40
+ #
41
+ def description
42
+ "The RCT Jira class implements access to some of the common Jira\n" +
43
+ "(http://en.wikipedia.org/wiki/JIRA) APIs."
44
+ end
45
+
46
+
47
+ #----------------------------------------------------------------------------
48
+ # CLI definition. Used by the rct framework to determine what CLI
49
+ # commands are available here. This maps the operation name to a
50
+ # Hash of info about that operation.
51
+ #
52
+ # Note that this needs to list only those operations which can be
53
+ # invoked in CLI mode. Not all operations supported by an rct client
54
+ # module are necessarily CLI-compatible so this may be a subset of
55
+ # the operations available here.
56
+ #
57
+ def cli
58
+ return {
59
+ 'server_info' => ServerInfo,
60
+ 'not_watching' => NotWatching,
61
+ 'add_my_watch' => AddMyWatch,
62
+ 'watch_category' => WatchCategory,
63
+ 'mine' => Mine
64
+ }
65
+ end
66
+
67
+
68
+ #----------------------------------------------------------------------------
69
+ # Retrieve server info (really only useful to test API/connection).
70
+ # No authentication required.
71
+ #
72
+ # https://docs.atlassian.com/jira/REST/latest/#idp1713744
73
+ #
74
+ # Required: none
75
+ # Optional: none
76
+ # Saves to state: nothing
77
+ #
78
+ ServerInfo = {
79
+ 'description' => "Retrieve server info (mainly for testing connection)",
80
+ 'required' => { },
81
+ 'optional' => { }
82
+ }
83
+
84
+ def server_info
85
+ ssettmp(SERVER_PROTOCOL, 'https')
86
+ ssettmp(REQ_METHOD, 'GET')
87
+ ssettmp(REQ_PATH, "#{BASE_PATH}/serverInfo")
88
+ yield
89
+ end
90
+
91
+
92
+ #----------------------------------------------------------------------------
93
+ # Retrieve a list of issues which I (user authenticating) am not watching.
94
+ #
95
+ # Note this may not be a full list of unwatched issues if the list is larger
96
+ # than the limit, which defaults to 100. The server may also impose a limit
97
+ # which might be smaller than the requested limit.
98
+ #
99
+ # Required:
100
+ # username : Authenticate as this user.
101
+ # password : Password of username.
102
+ # project : JIRA project name to search.
103
+ # Optional:
104
+ # limit : Return up to this many results (default: 100)
105
+ # Saves to state:
106
+ # not_watching_result : Hash of key => description of all issues found
107
+ #
108
+ NotWatching = {
109
+ 'description' => "Retrieve list of issues I am not watching",
110
+ 'required' => {
111
+ 'username' => [ '-u', '--user', 'User name' ],
112
+ 'password' => [ '-P', '--password', 'Password' ],
113
+ 'project' => [ '-c' , '--project', 'Project name (category)' ],
114
+ },
115
+ 'optional' => {
116
+ 'limit' => [ '-l', '--limit', 'Limit result set size to this number'],
117
+ }
118
+ }
119
+
120
+ def not_watching
121
+ user = sget('username')
122
+ password = sget('password')
123
+ project = sget('project')
124
+
125
+ limit = sget('limit')
126
+ limit = '100' if (limit == nil)
127
+
128
+ ssettmp(SERVER_PROTOCOL, 'https')
129
+ ssettmp(REQ_METHOD, 'GET')
130
+ ssettmp(REQ_AUTH_TYPE, REQ_AUTH_TYPE_BASIC)
131
+ ssettmp(REQ_AUTH_NAME, user)
132
+ ssettmp(REQ_AUTH_PWD, password)
133
+ ssettmp(REQ_PATH, "#{BASE_PATH}/search")
134
+
135
+ params = add_param(nil, 'maxResults', limit)
136
+ params = add_param(params, 'fields', 'summary')
137
+ params = add_param(params, 'jql',
138
+ "project=#{project} and watcher != currentUser()")
139
+ ssettmp(REQ_PARAMS, params)
140
+
141
+ result = yield
142
+
143
+ if (result.ok)
144
+ # On success, create a simple key->description hash with the results
145
+ if (is_cli) then cli_output = "\n" end
146
+ unwatched = Hash.new()
147
+ json = JSON.parse(result.body)
148
+
149
+ issues = json['issues']
150
+ if (issues != nil)
151
+ issues.each { |h|
152
+ key = h['key']
153
+ summary = h['fields']['summary']
154
+ unwatched[key] = summary
155
+ if (is_cli) then cli_output += "#{key} : #{summary}\n" end
156
+ }
157
+ end
158
+
159
+ sset('not_watching_result', unwatched)
160
+ if (is_cli)
161
+ sset(CLI_OUTPUT, cli_output)
162
+ end
163
+ end
164
+
165
+ return result
166
+ end
167
+
168
+
169
+ #----------------------------------------------------------------------------
170
+ # Retrieve a list of issues which I (user authenticating) own.
171
+ #
172
+ # Note this may not be a full list of if the list is larger than the
173
+ # limit, which defaults to 100. The server may also impose a limit
174
+ # which might be smaller than the requested limit.
175
+ #
176
+ # Required:
177
+ # username : Authenticate as this user.
178
+ # password : Password of username.
179
+ # Optional:
180
+ # limit : Return up to this many results (default: 100)
181
+ # project : Limit results to this project.
182
+ # Saves to state:
183
+ # my_bugs : Hash of key => description of all issues found
184
+ #
185
+ Mine = {
186
+ 'description' => "Retrieve list of issues I own",
187
+ 'required' => {
188
+ 'username' => [ '-u', '--user', 'User name' ],
189
+ 'password' => [ '-P', '--password', 'Password' ],
190
+ },
191
+ 'optional' => {
192
+ 'limit' => [ '-l', '--limit', 'Limit result set size to this number'],
193
+ 'project' => [ '-c' , '--project', 'Project name (category)' ],
194
+ }
195
+ }
196
+
197
+ def mine
198
+ user = sget('username')
199
+ password = sget('password')
200
+ project = sget('project')
201
+
202
+ limit = sget('limit')
203
+ limit = '100' if (limit == nil)
204
+
205
+ ssettmp(SERVER_PROTOCOL, 'https')
206
+ ssettmp(REQ_METHOD, 'GET')
207
+ ssettmp(REQ_AUTH_TYPE, REQ_AUTH_TYPE_BASIC)
208
+ ssettmp(REQ_AUTH_NAME, user)
209
+ ssettmp(REQ_AUTH_PWD, password)
210
+ ssettmp(REQ_PATH, "#{BASE_PATH}/search")
211
+
212
+ params = add_param(nil, 'maxResults', limit)
213
+ params = add_param(params, 'fields', 'summary')
214
+
215
+ jql = ""
216
+ if (project != nil)
217
+ jql = "project=#{project} AND "
218
+ end
219
+ jql = "#{jql}assignee = currentUser() AND (status=\"Open\" OR status=\"In Progress\")"
220
+
221
+ params = add_param(params, 'jql', jql)
222
+ ssettmp(REQ_PARAMS, params)
223
+
224
+ result = yield
225
+
226
+ if (result.ok)
227
+ # On success, create a simple key->description hash with the results
228
+ if (is_cli) then cli_output = "\n" end
229
+ list = Hash.new()
230
+ json = JSON.parse(result.body)
231
+ issues = json['issues']
232
+ issues.each { |h|
233
+ key = h['key']
234
+ summary = h['fields']['summary']
235
+ list[key] = summary
236
+ if (is_cli) then cli_output += "#{key} : #{summary}\n" end
237
+ }
238
+ sset('my_bugs', list)
239
+ if (is_cli)
240
+ sset(CLI_OUTPUT, cli_output)
241
+ end
242
+ end
243
+
244
+ return result
245
+ end
246
+
247
+
248
+ #----------------------------------------------------------------------------
249
+ # Add myself as a watcher to one issue.
250
+ #
251
+ # https://docs.atlassian.com/jira/REST/latest/#idp1831280
252
+ #
253
+ # Required:
254
+ # username : Authenticate as this user.
255
+ # password : Password of username.
256
+ # project : JIRA project name to search.
257
+ # key : JIRA issue key to update.
258
+ # Optional:
259
+ # none
260
+ # Saves to state:
261
+ # nothing
262
+ #
263
+ AddMyWatch = {
264
+ 'description' => "Add myself as a watcher to one issue",
265
+ 'required' => {
266
+ 'username' => [ '-u', '--user', 'User name' ],
267
+ 'password' => [ '-P', '--password', 'Password' ],
268
+ 'project' => [ '-c' , '--project', 'Project name (category)' ],
269
+ 'key' => [ '-k', '--issuekey', 'Issue to add myself as watcher'],
270
+ },
271
+ 'optional' => { }
272
+ }
273
+
274
+ def add_my_watch
275
+ user = sget('username')
276
+ password = sget('password')
277
+ project = sget('project')
278
+ key = sget('key')
279
+
280
+ ssettmp(SERVER_PROTOCOL, 'https')
281
+ ssettmp(REQ_METHOD, 'POST')
282
+ ssettmp(REQ_AUTH_TYPE, REQ_AUTH_TYPE_BASIC)
283
+ ssettmp(REQ_AUTH_NAME, user)
284
+ ssettmp(REQ_AUTH_PWD, password)
285
+ ssettmp(REQ_PATH, "#{BASE_PATH}/issue/#{key}/watchers")
286
+ ssettmp(REQ_BODY, "\"#{user}\"")
287
+
288
+ headers = Hash.new()
289
+ headers['Content-type'] = 'application/json'
290
+ ssettmp(REQ_HEADERS, headers)
291
+
292
+ result = yield
293
+
294
+ if (result.status == 204)
295
+ if (is_cli)
296
+ sset(CLI_OUTPUT, "Added #{user} as a watcher to #{key}")
297
+ end
298
+ else
299
+ result.add_error("Unable to add #{user} to #{key}")
300
+ end
301
+
302
+ return result
303
+ end
304
+
305
+
306
+ #----------------------------------------------------------------------------
307
+ # Add myself as a watcher to all unwatched issues in a given category.
308
+ #
309
+ # This is a wrapper function which combines NotWatching and AddMyWatch
310
+ # for convenience.
311
+ #
312
+ # Note this may not be able to add me to all unwatched issues if there
313
+ # are more than the server list limit. In that case one may need to run
314
+ # this multiple times.
315
+ #
316
+ # Required:
317
+ # username : Authenticate as this user.
318
+ # password : Password of username.
319
+ # project : JIRA project name to watch.
320
+ # Optional:
321
+ # none
322
+ # Saves to state:
323
+ # nothing
324
+ #
325
+ WatchCategory = {
326
+ 'description' => "Add myself as a watcher to all issues in category",
327
+ 'required' => {
328
+ 'username' => [ '-u', '--user', 'User name' ],
329
+ 'password' => [ '-P', '--password', 'Password' ],
330
+ 'project' => [ '-c' , '--project', 'Project name (category)' ],
331
+ },
332
+ 'optional' => { }
333
+ }
334
+
335
+ def watch_category
336
+
337
+ project = sget('project')
338
+
339
+ # Pretend we're not in CLI mode even if we are to avoid duplicate output
340
+ # from the functions we're wrapping.
341
+
342
+ mode = RCT.sget(RCT_MODE)
343
+ RCT.sdelete(RCT_MODE)
344
+
345
+ result = not_watching { $HTTP.handle_request() }
346
+ if (!result.ok)
347
+ result.add_error("Unable to get list of unwatched issues")
348
+ RCT.sset(RCT_MODE, mode)
349
+ return result
350
+ end
351
+
352
+ issues = RCT.sget('not_watching_result')
353
+ count = 0
354
+
355
+ issues.each { |key, desc|
356
+ RCT.log(RESULT, "#{key}: #{desc}")
357
+ RCT.sset('key', key)
358
+ result = add_my_watch { $HTTP.handle_request() }
359
+ if (!result.ok)
360
+ result.add_error("Unable to add watcher to #{key}")
361
+ RCT.sset(RCT_MODE, mode)
362
+ return result
363
+ end
364
+ count = count + 1
365
+ }
366
+
367
+ RCT.sset(RCT_MODE, mode)
368
+ if (is_cli)
369
+ sset(CLI_OUTPUT, "Added #{count} bugs to watch in #{project}")
370
+ end
371
+
372
+ return result
373
+ end
374
+
375
+
376
+ end
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rct_jira
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.3'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jyri J. Virkki
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2015-02-12 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rct
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0.7'
22
+ - - <
23
+ - !ruby/object:Gem::Version
24
+ version: '1.0'
25
+ type: :runtime
26
+ prerelease: false
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0.7'
33
+ - - <
34
+ - !ruby/object:Gem::Version
35
+ version: '1.0'
36
+ description: wip
37
+ email: jyri@virkki.com
38
+ executables:
39
+ - jira
40
+ extensions: []
41
+ extra_rdoc_files: []
42
+ files:
43
+ - lib/rct_jira.rb
44
+ - bin/jira
45
+ homepage: https://github.com/jvirkki/rct_jira
46
+ licenses:
47
+ - GPLv3
48
+ post_install_message:
49
+ rdoc_options: []
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ! '>='
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ! '>='
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ requirements: []
65
+ rubyforge_project: nowarning
66
+ rubygems_version: 1.8.23
67
+ signing_key:
68
+ specification_version: 3
69
+ summary: rct client support for jira
70
+ test_files: []