ruboty-redmine 0.1.7 → 1.0.0
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.
- checksums.yaml +4 -4
- data/README.md +15 -52
- data/lib/ruboty/handlers/redmine.rb +145 -229
- data/lib/ruboty/redmine/client.rb +30 -0
- data/lib/ruboty/redmine/version.rb +1 -1
- data/ruboty-redmine.gemspec +2 -0
- metadata +30 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d200e7bc660e4bcab752cb57f74289d882679bbd
|
4
|
+
data.tar.gz: 63326c9214311143f44365859121ed79ea245869
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce30f6536f2e2d126180252b101371456cdd181ba65863f4ebfe4f26850fea54a7e4c54dc084b22a09fb4c1ca02b70453b2c00b632b8e355270a6c04a4bf0ab0
|
7
|
+
data.tar.gz: c4e8e22e7f4af6193391bcab9a0a011eed9e3d444583d2eef269028710f7d4f48a6df01f59fbc3a30a1c82be447aa91833b4713751f639797927694c4a277079
|
data/README.md
CHANGED
@@ -2,64 +2,27 @@
|
|
2
2
|
|
3
3
|
Redmine plugin for Ruboty
|
4
4
|
|
5
|
-
This plugin
|
5
|
+
**This plugin currently supports only Slack**
|
6
6
|
|
7
7
|
## Available commands
|
8
8
|
|
9
|
-
### create issue
|
10
|
-
|
11
|
-
```
|
12
|
-
> ruboty create issue "subject" "Mobile" project "Feature" tracker
|
13
|
-
```
|
14
|
-
|
15
|
-
### watch issues
|
16
|
-
|
17
|
-
```
|
18
|
-
> ruboty watch redmine issues in "Feature" tracker of "Mobile" project
|
19
|
-
```
|
20
|
-
|
21
|
-
You will get notifications:
|
22
|
-
|
23
9
|
```
|
24
|
-
|
25
|
-
|
26
|
-
|
10
|
+
# Creating an issue
|
11
|
+
ruboty create redmine YOURTRACKER issue in YOURPROJECT subject of your issue
|
12
|
+
# Automatic assign
|
13
|
+
ruboty assign YOURTRACKER issues in YOURPROJECT to @MENTION_NAME_OF_ASSIGNEE REDMINE_USER_ID_OF_ASSIGNEE and notify to #CHANNEL_TO_BE_NOTIFIED
|
14
|
+
# List assignees
|
15
|
+
ruboty list redmine assignees
|
16
|
+
# Remove assignee
|
17
|
+
ruboty remove redmine assignee ID_GOT_FROM_LIST_COMMAND
|
18
|
+
# Pause assigning temporalily
|
19
|
+
ruboty pause assigning redmine issues to @MENTION_NAME_OF_ASSIGNEE for 1w1d1h1m1s
|
20
|
+
# Unpause assigning
|
21
|
+
ruboty unpause assigning redmien issues to @MENTION_NAME_OF_ASSIGNEE
|
22
|
+
# List paused assignees
|
23
|
+
ruboty list paused assignees
|
27
24
|
```
|
28
25
|
|
29
|
-
You can list and stop watching issues:
|
30
|
-
|
31
|
-
```
|
32
|
-
> ruboty list watching redmine issues
|
33
|
-
#1 Feature tracker in Mobile project and assign to [] (your_chat_room)
|
34
|
-
> ruboty stop watching redmine issues 1
|
35
|
-
```
|
36
|
-
|
37
|
-
### watch and assign issues
|
38
|
-
|
39
|
-
First, associate Redmine user ID with your name in chat:
|
40
|
-
|
41
|
-
```
|
42
|
-
> ruboty redmine user #123 is @bob
|
43
|
-
> ruboty redmine user #456 is @alice
|
44
|
-
```
|
45
|
-
|
46
|
-
Register tracker:
|
47
|
-
|
48
|
-
```
|
49
|
-
> ruboty watch redmine issues in "Feature" tracker of "Mobile" project and assign to 123,456
|
50
|
-
```
|
51
|
-
|
52
|
-
You will get notifications and the issue is assigned automatically:
|
53
|
-
|
54
|
-
```
|
55
|
-
New Issue of Feature in Mobile project
|
56
|
-
-> Awesome search feature
|
57
|
-
-> Assigned to @bob
|
58
|
-
-> https://redmine.example.com/issues/123
|
59
|
-
```
|
60
|
-
|
61
|
-
The assignee will be elected by round-robin.
|
62
|
-
|
63
26
|
## Installation
|
64
27
|
|
65
28
|
Add this line to your application's Gemfile:
|
@@ -1,7 +1,9 @@
|
|
1
|
+
require 'slack-notifier'
|
2
|
+
|
1
3
|
module Ruboty
|
2
4
|
module Handlers
|
3
5
|
class Redmine < Base
|
4
|
-
NAMESPACE = '
|
6
|
+
NAMESPACE = 'redmine_v1'
|
5
7
|
|
6
8
|
env :REDMINE_URL, 'Redmine url (e.g. http://your-redmine)', optional: false
|
7
9
|
env :REDMINE_API_KEY, 'Redmine REST API key', optional: false
|
@@ -9,217 +11,223 @@ module Ruboty
|
|
9
11
|
env :REDMINE_BASIC_AUTH_PASSWORD, 'Basic Auth Password', optional: true
|
10
12
|
env :REDMINE_CHECK_INTERVAL, 'Interval to check new issues', optional: true
|
11
13
|
env :REDMINE_HTTP_PROXY, 'HTTP proxy', optional: true
|
14
|
+
env :SLACK_WEBHOOK_URL, 'Slack webhook URL', optional: false
|
12
15
|
|
13
16
|
on(
|
14
|
-
/create issue (?<
|
17
|
+
/create redmine (?<tracker>[^ ]+) issue in (?<project>[^ ]+) (?<subject>.+)/,
|
15
18
|
name: 'create_issue',
|
16
|
-
description: 'Create a new issue'
|
19
|
+
description: 'Create a new Redmine issue'
|
17
20
|
)
|
18
21
|
|
19
22
|
on(
|
20
|
-
/
|
21
|
-
name: '
|
22
|
-
description: '
|
23
|
+
/assign redmine (?<tracker>[^ ]+) issues in (?<project>[^ ]+) to (?<mention_name>[^ ]+) (?<redmine_user_id>\d+) and notify to (?<channel>[^ ]+)/,
|
24
|
+
name: 'assign_issues',
|
25
|
+
description: 'Assign Redmine issues when created'
|
23
26
|
)
|
24
27
|
|
25
28
|
on(
|
26
|
-
/list
|
27
|
-
name: '
|
28
|
-
description: 'List
|
29
|
+
/list redmine assignees/,
|
30
|
+
name: 'list_assignees',
|
31
|
+
description: 'List rules to assign Redmine issues',
|
29
32
|
)
|
30
33
|
|
31
34
|
on(
|
32
|
-
/
|
33
|
-
name: '
|
34
|
-
description: 'Stop
|
35
|
+
/remove redmine assignee (?<id>\d+)/,
|
36
|
+
name: 'remove_redmine_assignee',
|
37
|
+
description: 'Stop assigning Redmine issues'
|
35
38
|
)
|
36
39
|
|
37
40
|
on(
|
38
|
-
/redmine
|
39
|
-
name: '
|
40
|
-
description: '
|
41
|
+
/pause assigning redmine issues to (?<mention_name>[^ ]+) for (?<duration>[^ ]+)/,
|
42
|
+
name: 'pause_assigning',
|
43
|
+
description: 'Pause assigning Redmine issues',
|
41
44
|
)
|
42
45
|
|
43
46
|
on(
|
44
|
-
/redmine
|
45
|
-
name: '
|
46
|
-
description: '
|
47
|
+
/unpause assigning redmine issues to (?<mention_name>[^ ]+)/,
|
48
|
+
name: 'unpause_assigning',
|
49
|
+
description: 'Unpause assigning Redmine issues',
|
47
50
|
)
|
48
51
|
|
49
52
|
on(
|
50
|
-
/
|
51
|
-
name: '
|
52
|
-
description: '
|
53
|
-
)
|
54
|
-
|
55
|
-
on(
|
56
|
-
/redmine list absent users/,
|
57
|
-
name: 'list_absent_users',
|
58
|
-
description: 'List absent users',
|
53
|
+
/list paused assignees/,
|
54
|
+
name: 'list_paused_assignees',
|
55
|
+
description: 'List paused Redmine assignees',
|
59
56
|
)
|
60
57
|
|
61
58
|
def initialize(*args)
|
62
59
|
super
|
63
|
-
|
64
|
-
start_to_watch_issues
|
65
60
|
end
|
66
61
|
|
67
62
|
def create_issue(message)
|
68
63
|
from_name = message.original[:from_name]
|
69
64
|
|
70
|
-
words = parse_arg(message[:rest])
|
71
65
|
req = {}
|
72
|
-
req[:subject] = "#{
|
73
|
-
|
74
|
-
words.each_with_index do |word, i|
|
75
|
-
next if i == 0
|
76
|
-
|
77
|
-
arg = words[i - 1]
|
78
|
-
|
79
|
-
case word
|
80
|
-
when 'project'
|
81
|
-
project = redmine.find_project(arg)
|
82
|
-
|
83
|
-
unless project
|
84
|
-
message.reply("Project '#{arg}' is not found.")
|
85
|
-
return
|
86
|
-
end
|
87
|
-
|
88
|
-
req[:project] = project
|
89
|
-
when 'tracker'
|
90
|
-
tracker = redmine.find_tracker(arg)
|
66
|
+
req[:subject] = "#{message[:subject]} (from #{from_name})"
|
91
67
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
req[:tracker] = tracker
|
98
|
-
end
|
68
|
+
project = redmine.find_project(message[:project])
|
69
|
+
unless project
|
70
|
+
message.reply("Project '#{message[:project]}' is not found.")
|
71
|
+
return
|
99
72
|
end
|
73
|
+
req[:project] = project
|
100
74
|
|
101
|
-
|
102
|
-
|
75
|
+
tracker = redmine.find_tracker(message[:tracker])
|
76
|
+
unless tracker
|
77
|
+
message.reply("Tracker '#{message[:tracker]}' is not found.")
|
103
78
|
return
|
104
79
|
end
|
80
|
+
req[:tracker] = tracker
|
105
81
|
|
106
82
|
issue = redmine.create_issue(req)
|
83
|
+
Ruboty.logger.debug("Created new issue: #{issue.inspect}")
|
107
84
|
message.reply("Issue created: #{redmine.url_for_issue(issue)}")
|
108
|
-
end
|
109
85
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
86
|
+
rules = assignees.select do |r|
|
87
|
+
paused = active_paused_assignees.find do |a|
|
88
|
+
a[:mention_name] == r[:mention_name]
|
89
|
+
end
|
90
|
+
next false if paused
|
91
|
+
|
92
|
+
r[:project] == issue.project['name'] &&
|
93
|
+
r[:tracker] == issue.tracker['name']
|
115
94
|
end
|
95
|
+
rule = rules[issue.id % rules.size]
|
96
|
+
redmine.update_issue(issue, assigned_to_id: rule[:redmine_user_id])
|
116
97
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
98
|
+
notify_slack(rule[:notify_to], <<-EOTEXT)
|
99
|
+
New Issue of #{issue.tracker['name']} in #{issue.project['name']} project
|
100
|
+
-> #{issue.subject}
|
101
|
+
-> Assigned to @#{rule[:mention_name]}
|
102
|
+
-> #{redmine.url_for_issue(issue)}
|
103
|
+
EOTEXT
|
104
|
+
end
|
122
105
|
|
123
|
-
|
124
|
-
|
125
|
-
|
106
|
+
def assignees
|
107
|
+
robot.brain.data["#{NAMESPACE}_assigns"] ||= []
|
108
|
+
end
|
126
109
|
|
127
|
-
|
110
|
+
def paused_assignees
|
111
|
+
robot.brain.data["#{NAMESPACE}_paused_assignees"] ||= []
|
128
112
|
end
|
129
113
|
|
130
|
-
def
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
114
|
+
def active_paused_assignees
|
115
|
+
paused_assignees.select do |a|
|
116
|
+
Time.now < Time.at(a[:expire_at])
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def assign_issues(message)
|
121
|
+
rule = {
|
122
|
+
tracker: message[:tracker],
|
123
|
+
project: message[:project],
|
124
|
+
mention_name: message[:mention_name].gsub(/\A@/, ''),
|
125
|
+
redmine_user_id: message[:redmine_user_id].gsub(/\A#/, '').to_i,
|
126
|
+
notify_to: message[:channel].gsub(/\A#/, ''),
|
127
|
+
}
|
128
|
+
|
129
|
+
assignees << rule
|
130
|
+
|
131
|
+
message.reply("Registered: #{rule}")
|
132
|
+
end
|
136
133
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
watch['from_name']
|
142
|
-
else
|
143
|
-
"unknown"
|
144
|
-
end
|
134
|
+
def list_assignees(message)
|
135
|
+
if assignees.empty?
|
136
|
+
message.reply("No rule is found")
|
137
|
+
end
|
145
138
|
|
146
|
-
|
139
|
+
reply = assignees.map do |rule|
|
140
|
+
"#{rule.object_id} #{rule}"
|
147
141
|
end.join("\n")
|
148
142
|
|
149
143
|
message.reply(reply)
|
150
144
|
end
|
151
145
|
|
152
|
-
def
|
146
|
+
def remove_redmine_assignee(message)
|
153
147
|
id = message[:id].to_i
|
154
|
-
|
155
|
-
|
148
|
+
rule = assignees.find {|r| r.object_id == id }
|
149
|
+
if rule
|
150
|
+
assignees.delete(rule)
|
151
|
+
message.reply("Rule #{id} is removed")
|
152
|
+
else
|
153
|
+
message.reply("The rule is not found")
|
156
154
|
end
|
157
|
-
|
158
|
-
message.reply("Stopped.")
|
159
155
|
end
|
160
156
|
|
161
|
-
def
|
162
|
-
|
157
|
+
def pause_assigning(message)
|
158
|
+
mention_name = message[:mention_name]
|
159
|
+
duration = message[:duration]
|
160
|
+
|
161
|
+
expire_at = Time.now + parse_duration_to_sec(duration)
|
163
162
|
|
164
|
-
|
163
|
+
pause = {
|
164
|
+
mention_name: mention_name.gsub(/\A@/, ''),
|
165
|
+
expire_at: expire_at.to_i
|
166
|
+
}
|
167
|
+
paused_assignees << pause
|
168
|
+
|
169
|
+
message.reply("Paused: #{pause}")
|
165
170
|
end
|
166
171
|
|
167
|
-
def
|
168
|
-
|
169
|
-
unless u
|
170
|
-
message.reply("#{message[:user]} is not found")
|
171
|
-
return
|
172
|
-
end
|
172
|
+
def unpause_assigning(message)
|
173
|
+
mention_name = message[:mention_name].gsub(/\A@/, '')
|
173
174
|
|
174
|
-
|
175
|
-
|
176
|
-
|
175
|
+
prev_size = paused_assignees.size
|
176
|
+
paused_assignees.reject! do |a|
|
177
|
+
a[:mention_name] == mention_name
|
177
178
|
end
|
178
179
|
|
179
|
-
|
180
|
-
|
180
|
+
if parsed_assignees.size == prev_size
|
181
|
+
message.reply("No paused assignee is found")
|
182
|
+
else
|
183
|
+
message.reply("Unpaused")
|
184
|
+
end
|
181
185
|
end
|
182
186
|
|
183
|
-
def
|
184
|
-
|
185
|
-
|
186
|
-
message.reply("#{message[:user]} is not found")
|
187
|
+
def list_paused_assignees(message)
|
188
|
+
if paused_assignees.empty?
|
189
|
+
message.reply("No paused assingee is found.")
|
187
190
|
return
|
188
191
|
end
|
189
192
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
end
|
193
|
+
reply = active_paused_assignees.map do |a|
|
194
|
+
"#{a[:mention_name]} (until #{Time.at(a[:expire_at])})"
|
195
|
+
end.join("\n")
|
194
196
|
|
195
|
-
|
196
|
-
message.reply("Start assigning issues to #{u}")
|
197
|
+
message.reply(reply)
|
197
198
|
end
|
198
199
|
|
199
|
-
def
|
200
|
-
|
200
|
+
def parse_duration_to_sec(d)
|
201
|
+
sum = 0
|
202
|
+
d.scan(/(\d+)([smhdw])/) do |n, u|
|
203
|
+
scale = case u
|
204
|
+
when 's'
|
205
|
+
1
|
206
|
+
when 'm'
|
207
|
+
60
|
208
|
+
when 'h'
|
209
|
+
60*60
|
210
|
+
when 'd'
|
211
|
+
24*60*60
|
212
|
+
when 'w'
|
213
|
+
7*24*60*60
|
214
|
+
end
|
215
|
+
sum += n.to_i + scale
|
216
|
+
end
|
217
|
+
sum
|
201
218
|
end
|
202
219
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
u = users.find do |u|
|
211
|
-
u['chat_name'] == username
|
212
|
-
end
|
213
|
-
|
214
|
-
u && u['redmine_id'].to_i
|
215
|
-
end
|
220
|
+
def notify_slack(channel, message)
|
221
|
+
slack_notifier.ping(
|
222
|
+
text: message,
|
223
|
+
channel: channel,
|
224
|
+
username: 'ruboty',
|
225
|
+
link_names: '1',
|
226
|
+
)
|
216
227
|
end
|
217
228
|
|
218
|
-
def
|
219
|
-
|
220
|
-
u['redmine_id'] == redmine_id.to_i
|
221
|
-
end
|
222
|
-
u && u['chat_name']
|
229
|
+
def slack_notifier
|
230
|
+
@slack_notifier ||= Slack::Notifier.new(ENV['SLACK_WEBHOOK_URL'])
|
223
231
|
end
|
224
232
|
|
225
233
|
def redmine
|
@@ -231,98 +239,6 @@ module Ruboty
|
|
231
239
|
http_proxy: ENV['REDMINE_HTTP_PROXY'],
|
232
240
|
)
|
233
241
|
end
|
234
|
-
|
235
|
-
def watches
|
236
|
-
robot.brain.data["#{NAMESPACE}_watches"] ||= []
|
237
|
-
end
|
238
|
-
|
239
|
-
def users
|
240
|
-
robot.brain.data["#{NAMESPACE}_users"] ||= []
|
241
|
-
end
|
242
|
-
|
243
|
-
def absent_users
|
244
|
-
robot.brain.data["#{NAMESPACE}_absent_users"] ||= []
|
245
|
-
end
|
246
|
-
|
247
|
-
def find_user_by_id(id)
|
248
|
-
users.find {|user| user['redmine_id'] == id }
|
249
|
-
end
|
250
|
-
|
251
|
-
def parse_arg(text)
|
252
|
-
text.scan(/("([^"]+)"|'([^']+)'|([^ ]+))/).map do |v|
|
253
|
-
v.shift
|
254
|
-
v.find {|itself| itself }
|
255
|
-
end
|
256
|
-
end
|
257
|
-
|
258
|
-
def start_to_watch_issues
|
259
|
-
thread = Thread.start do
|
260
|
-
last_issues_for_watch = {}
|
261
|
-
|
262
|
-
while true
|
263
|
-
sleep (ENV['REDMINE_CHECK_INTERVAL'] || 30).to_i
|
264
|
-
watches.each do |watch|
|
265
|
-
project = redmine.find_project(watch['project'])
|
266
|
-
tracker = redmine.find_tracker(watch['tracker'])
|
267
|
-
|
268
|
-
issues = redmine.issues(project: project, tracker: tracker, sort: 'id:desc')
|
269
|
-
if last_issues = last_issues_for_watch[watch]
|
270
|
-
new_issues = []
|
271
|
-
issues.each do |issue|
|
272
|
-
found = last_issues.find do |last_issue|
|
273
|
-
last_issue.id == issue.id
|
274
|
-
end
|
275
|
-
|
276
|
-
if found
|
277
|
-
break
|
278
|
-
else
|
279
|
-
new_issues << issue
|
280
|
-
end
|
281
|
-
end
|
282
|
-
|
283
|
-
new_issues.each do |new_issue|
|
284
|
-
assignees = watch['assignees']
|
285
|
-
assignee = nil
|
286
|
-
if !assignees.empty? && !new_issue.assigned_to
|
287
|
-
assignees -= absent_users
|
288
|
-
assignee = assignees[watch['assignee_index'] % assignees.size]
|
289
|
-
watch['assignee_index'] += 1
|
290
|
-
|
291
|
-
assignee = find_user_by_id(assignee)
|
292
|
-
end
|
293
|
-
|
294
|
-
if assignee
|
295
|
-
redmine.update_issue(new_issue, assigned_to_id: assignee['redmine_id'])
|
296
|
-
end
|
297
|
-
|
298
|
-
msg = <<-EOC
|
299
|
-
New Issue of #{tracker.name} in #{project.name} project
|
300
|
-
-> #{new_issue.subject}
|
301
|
-
EOC
|
302
|
-
|
303
|
-
if assignee
|
304
|
-
msg += <<-EOC
|
305
|
-
-> Assigned to @#{assignee['chat_name']}
|
306
|
-
EOC
|
307
|
-
end
|
308
|
-
|
309
|
-
msg += <<-EOC
|
310
|
-
-> #{redmine.url_for_issue(new_issue)}
|
311
|
-
EOC
|
312
|
-
|
313
|
-
Message.new(
|
314
|
-
watch.symbolize_keys.merge(robot: robot)
|
315
|
-
).reply(msg)
|
316
|
-
end
|
317
|
-
end
|
318
|
-
|
319
|
-
last_issues_for_watch[watch] = issues
|
320
|
-
end
|
321
|
-
end
|
322
|
-
end
|
323
|
-
|
324
|
-
thread.abort_on_exception = true
|
325
|
-
end
|
326
242
|
end
|
327
243
|
end
|
328
244
|
end
|
@@ -68,6 +68,36 @@ module Ruboty
|
|
68
68
|
OpenStruct.new(
|
69
69
|
JSON.parse(post('/issues.json', req).body)['issue']
|
70
70
|
)
|
71
|
+
# {
|
72
|
+
# "issue": {
|
73
|
+
# "id": 1,
|
74
|
+
# "project": {
|
75
|
+
# "id": 1,
|
76
|
+
# "name": "..."
|
77
|
+
# },
|
78
|
+
# "tracker": {
|
79
|
+
# "id": 1,
|
80
|
+
# "name": "..."
|
81
|
+
# },
|
82
|
+
# "status": {
|
83
|
+
# "id": 1,
|
84
|
+
# "name": "new"
|
85
|
+
# },
|
86
|
+
# "priority": {
|
87
|
+
# "id": 4,
|
88
|
+
# "name": "通常"
|
89
|
+
# },
|
90
|
+
# "author": {
|
91
|
+
# "id": 1,
|
92
|
+
# "name": "Arai Ryota"
|
93
|
+
# },
|
94
|
+
# "subject": "This is test",
|
95
|
+
# "start_date": "2017-02-01",
|
96
|
+
# "done_ratio": 0,
|
97
|
+
# "created_on": "2017-02-01T11:10:35Z",
|
98
|
+
# "updated_on": "2017-02-01T11:10:35Z"
|
99
|
+
# }
|
100
|
+
# }
|
71
101
|
end
|
72
102
|
|
73
103
|
def update_issue(issue, opts)
|
data/ruboty-redmine.gemspec
CHANGED
@@ -20,8 +20,10 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.add_dependency "ruboty"
|
21
21
|
spec.add_dependency "faraday"
|
22
22
|
spec.add_dependency "activesupport"
|
23
|
+
spec.add_dependency "slack-notifier"
|
23
24
|
|
24
25
|
spec.add_development_dependency "pry-byebug"
|
26
|
+
spec.add_development_dependency "ruboty-slack_rtm"
|
25
27
|
spec.add_development_dependency "bundler", "~> 1.7"
|
26
28
|
spec.add_development_dependency "rake", "~> 10.0"
|
27
29
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruboty-redmine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryota Arai
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-02-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ruboty
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: slack-notifier
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: pry-byebug
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,6 +80,20 @@ dependencies:
|
|
66
80
|
- - ">="
|
67
81
|
- !ruby/object:Gem::Version
|
68
82
|
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: ruboty-slack_rtm
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
69
97
|
- !ruby/object:Gem::Dependency
|
70
98
|
name: bundler
|
71
99
|
requirement: !ruby/object:Gem::Requirement
|