lita-rally 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 69fbe9f6b8d8878c919cfe737a9aa5424c8cfeaf
4
+ data.tar.gz: 5b5a75657b23de9bdaf7ca122057e500538d9b52
5
+ SHA512:
6
+ metadata.gz: e60d126c94f11b2993501ca3997e1d885fa5ddc6d725edbf454ece01429a03085aec9fb04b4cb413afd18c12492aa1fdc9378ae551c26d92c972f397fdc65a5a
7
+ data.tar.gz: a38d3ccbeab0af552bd044bdf54c5539498487dad7bc74faa9c11d6139fd5aa0a20dd2da9ed44fe6aa01a8fd75633050fc6faafb420252f50a744a3be718d008
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2015 Richard Li
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,48 @@
1
+ # lita-rally
2
+
3
+ A port of
4
+ [Hubot-Rally](https://github.com/github/hubot-scripts/blob/master/src/scripts/rally.coffee)
5
+ with some enhancements.
6
+
7
+ ## Installation
8
+
9
+ Add lita-rally to your Lita instance's Gemfile:
10
+
11
+ ``` ruby
12
+ gem "lita-rally"
13
+ ```
14
+
15
+
16
+ ## Configuration
17
+
18
+ **Required:**
19
+
20
+ ```config.handlers.rally.username``` - Rally username
21
+
22
+ ```config.handlers.rally.password``` - Rally password
23
+
24
+ **Optional:**
25
+
26
+ ```config.handlers.rally.api_version``` - API version, default 'v2.0'
27
+
28
+
29
+ ## Usage
30
+
31
+ ```
32
+ lita rally me <FormattedID>
33
+ ```
34
+ Show information about Rally object identified by FormattedID.
35
+
36
+ ```
37
+ lita rally me release stats for <release_name>
38
+ ```
39
+ Show defect and user story count for the release <release_name>
40
+
41
+ ```
42
+ lita rally me release info for <release_name>
43
+ ```
44
+ Show object IDs (defects, user story, etc.) for release <release_name>.
45
+
46
+ ## License
47
+
48
+ [MIT](http://opensource.org/licenses/MIT)
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
@@ -0,0 +1,259 @@
1
+ require 'rest-client'
2
+ require 'json'
3
+
4
+ module Lita
5
+ module Handlers
6
+ class Rally < Handler
7
+ @@key_map = {
8
+ 'de' => {
9
+ name: 'defect',
10
+ extra_output: [
11
+ 'State',
12
+ 'ScheduleState',
13
+ 'Severity',
14
+ ['Release', '_refObjectName'],
15
+ ],
16
+ },
17
+ 'ds' => {
18
+ name: 'defectsuite',
19
+ extra_output: [
20
+ 'ScheduleState',
21
+ ]
22
+ },
23
+ 'f' => {
24
+ name: 'feature',
25
+ query_path: 'portfolioitem/feature',
26
+ extra_output: [
27
+ ['State', '_refObjectName'],
28
+ ['Parent', '_refObjectName'],
29
+ ]
30
+ },
31
+ 'i' => {
32
+ name: 'initiative',
33
+ query_path: 'portfolioitem/initiative',
34
+ extra_output: [
35
+ ['State', '_refObjectName'],
36
+ ['Parent', '_refObjectName'],
37
+ ]
38
+ },
39
+ 't' => {
40
+ name: 'theme',
41
+ query_path: 'portfolioitem/theme',
42
+ extra_output: [
43
+ ['State', '_refObjectName'],
44
+ ['Parent', '_refObjectName'],
45
+ ]
46
+ },
47
+ 'ta' => {
48
+ name: 'task',
49
+ extra_output: [
50
+ 'State',
51
+ ['WorkProduct', '_refObjectName'],
52
+ ]
53
+ },
54
+ 'tc' => {
55
+ name: 'testcase',
56
+ extra_output: [
57
+ ['WorkProduct', '_refObjectName'],
58
+ 'Type',
59
+ ]
60
+ },
61
+ 'us' => {
62
+ name: 'story',
63
+ query_path: 'hierarchicalrequirement',
64
+ link_path: 'userstory',
65
+ extra_output: [
66
+ 'ScheduleState',
67
+ ['Parent', '_refObjectName'],
68
+ ['Feature', '_refObjectName'],
69
+ ]
70
+ }
71
+ }
72
+
73
+ config :username
74
+ config :password
75
+ config :api_version
76
+
77
+ route(/^rally me ([[:alpha:]]+)(\d+)/, :rally_show, command: true, help: {
78
+ 'rally me <identifier>' => 'Show me that rally object'
79
+ })
80
+
81
+ route(/^rally me release stats for (.+)/, :rally_release_stats,
82
+ command: true, help: {
83
+ 'rally me release count for <release>' => 'Count US and DE for release'
84
+ })
85
+
86
+ route(/^rally me release info for (.+)/, :rally_release_info,
87
+ command: true, help: {
88
+ 'rally me release info for <release>' => 'Show release info'
89
+ })
90
+
91
+ def rally_show(response)
92
+ if config_validate
93
+ get_rally_object(response)
94
+ else
95
+ response.reply('Configuration failed to validate, '\
96
+ 'check your config')
97
+ end
98
+ end
99
+
100
+ def rally_release_stats(response)
101
+ if config_validate
102
+ get_rally_release_stat(response)
103
+ else
104
+ response.reply('Configuration failed to validate, '\
105
+ 'check your config')
106
+ end
107
+ end
108
+
109
+ def rally_release_info(response)
110
+ if config_validate
111
+ get_rally_release_info(response)
112
+ else
113
+ response.reply('Configuration failed to validate, '\
114
+ 'check your config')
115
+ end
116
+ end
117
+
118
+ private
119
+
120
+ def config_validate
121
+ (config.username && config.password) ? true : false
122
+ end
123
+
124
+ def get_rest
125
+ api_version = config.api_version ? config.api_version : 'v2.0'
126
+ RestClient::Resource.new(
127
+ "https://rally1.rallydev.com/slm/webservice/#{api_version}/",
128
+ user: config.username,
129
+ password: config.password,
130
+ )
131
+ end
132
+
133
+ def validate_release(rest, release)
134
+ query = "(Name = \"#{release}\")"
135
+ JSON.parse(
136
+ rest['release'].get(params: {query: query})
137
+ )['QueryResult']['TotalResultCount'] == 0
138
+ end
139
+
140
+ def get_rally_release_info(response)
141
+ rest = get_rest
142
+ release = response.matches[0][0]
143
+ if validate_release(rest, release)
144
+ response.reply("I can find anything about release: '#{release}'!")
145
+ else
146
+ query = "(Release.Name = \"#{release}\")"
147
+ defects = JSON.parse(
148
+ rest['defect'].get(
149
+ params: {
150
+ query: query,
151
+ fetch: 'true',
152
+ pagesize: '200',
153
+ }
154
+ )
155
+ )['QueryResult']['Results'].map {|r| r['FormattedID']}.join(' ')
156
+
157
+ us = JSON.parse(
158
+ rest['hierarchicalrequirement'].get(
159
+ params: {
160
+ query: query,
161
+ fetch: 'true',
162
+ pagesize: '200',
163
+ }
164
+ )
165
+ )['QueryResult']['Results'].map {|r| r['FormattedID']}.join(' ')
166
+
167
+ output = "Release info for: #{release}\n" \
168
+ "Defects: #{defects}\n" \
169
+ "User Stories: #{us}\n"
170
+ response.reply(output)
171
+ end
172
+ end
173
+
174
+ def get_rally_release_stat(response)
175
+ rest = get_rest
176
+ release = response.matches[0][0]
177
+ if validate_release(rest, release)
178
+ response.reply("I can find anything about release: '#{release}'!")
179
+ else
180
+ query = "(Release.Name = \"#{release}\")"
181
+ de_result = JSON.parse(
182
+ rest['defect'].get(params: {query: query})
183
+ )['QueryResult']
184
+ de_count = de_result['TotalResultCount']
185
+
186
+ us_result = JSON.parse(
187
+ rest['hierarchicalrequirement'].get(params: {query: query})
188
+ )['QueryResult']
189
+ us_count = us_result['TotalResultCount']
190
+
191
+ output = "Release stats for: #{release}\n" \
192
+ "Defects count: #{de_count}\n" \
193
+ "User Story count: #{us_count}\n"
194
+ response.reply(output)
195
+ end
196
+ end
197
+
198
+ def get_rally_object(response)
199
+ rest = get_rest
200
+ type = response.matches[0][0].downcase
201
+ id = response.matches[0][1]
202
+ if @@key_map[type]
203
+ query_path = (@@key_map[type][:query_path] || @@key_map[type][:name])
204
+ link_path = (@@key_map[type][:link_path] || query_path)
205
+ query_result = JSON.parse(
206
+ rest[query_path].get(
207
+ params: {
208
+ query: "(FormattedId = #{id})",
209
+ fetch: 'true'
210
+ }
211
+ )
212
+ )['QueryResult']
213
+ if query_result['TotalResultCount'] == 0
214
+ response.reply("Can't find your so called #{type}#{id} in Rally!")
215
+ else
216
+ result = query_result['Results'][0]
217
+ link = link_to_item(result, link_path)
218
+ output = ''
219
+ output += link + "\n" if link
220
+ output += "#{result['FormattedID']} - #{result['Name']}\n" \
221
+ "Owner: #{result['Owner']['_refObjectName']}\n" \
222
+ "Project: #{result['Project']['_refObjectName']}\n"
223
+ @@key_map[type][:extra_output].each do |field|
224
+ output += "#{field}: #{result[field]}\n" if
225
+ field.is_a?(String) && result[field]
226
+ output += "#{field[0]}: #{result[field[0]][field[1]]}\n" if
227
+ field.is_a?(Array) && result[field[0]]
228
+ end
229
+ output += "Description: #{strip_html(result['Description'])}\n"
230
+ response.reply(output)
231
+ end
232
+ else
233
+ response.reply("I don't know the type #{type}")
234
+ end
235
+ end
236
+
237
+ def link_to_item(result, type)
238
+ return false unless result['Project'] && result['ObjectID']
239
+ project_id = result['Project']['_ref'].split('/')[-1]
240
+ object_id = result['ObjectID']
241
+ "https://rally1.rallydev.com/#/#{project_id}/detail/#{type}/#{object_id}"
242
+ end
243
+
244
+ def strip_html(text)
245
+ text.gsub( '<br />', "\n\n"
246
+ ).gsub('&nbsp;', ' '
247
+ ).gsub('&gt;', '>'
248
+ ).gsub('&lt;', '<'
249
+ ).gsub('<div>', ''
250
+ ).gsub('</div>', "\n"
251
+ ).gsub(/<style.+\/style>/, ''
252
+ )
253
+ end
254
+
255
+ end
256
+
257
+ Lita.register_handler(Rally)
258
+ end
259
+ end
data/lib/lita-rally.rb ADDED
@@ -0,0 +1,7 @@
1
+ require "lita"
2
+
3
+ Lita.load_locales Dir[File.expand_path(
4
+ File.join("..", "..", "locales", "*.yml"), __FILE__
5
+ )]
6
+
7
+ require "lita/handlers/rally"
@@ -0,0 +1,25 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = "lita-rally"
3
+ spec.version = "0.1.0"
4
+ spec.authors = ['Richard Li']
5
+ spec.email = ['evilcat@wisewolfsolutions.com']
6
+ spec.description = %q{lita bot Rally plugin}
7
+ spec.summary = %q{lita bot Rally plugin}
8
+ spec.homepage = "https://github.com/ecwws/lita-rally"
9
+ spec.license = "MIT"
10
+ spec.metadata = { "lita_plugin_type" => "handler" }
11
+
12
+ spec.files = `git ls-files`.split($/)
13
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
14
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
15
+ spec.require_paths = ["lib"]
16
+
17
+ spec.add_runtime_dependency "lita", ">= 4.1"
18
+ spec.add_runtime_dependency "rest-client"
19
+ spec.add_runtime_dependency "json"
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rack-test"
24
+ spec.add_development_dependency "rspec", ">= 3.0.0"
25
+ end
data/locales/en.yml ADDED
@@ -0,0 +1,4 @@
1
+ en:
2
+ lita:
3
+ handlers:
4
+ rally:
@@ -0,0 +1,4 @@
1
+ require "spec_helper"
2
+
3
+ describe Lita::Handlers::Rally, lita_handler: true do
4
+ end
@@ -0,0 +1,6 @@
1
+ require "lita-rally"
2
+ require "lita/rspec"
3
+
4
+ # A compatibility mode is provided for older plugins upgrading from Lita 3. Since this plugin
5
+ # was generated with Lita 4, the compatibility mode should be left disabled.
6
+ Lita.version_3_compatibility_mode = false
metadata ADDED
@@ -0,0 +1,156 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lita-rally
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Richard Li
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-03-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: lita
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '4.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '4.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rest-client
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: json
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.3'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rack-test
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'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 3.0.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: 3.0.0
111
+ description: lita bot Rally plugin
112
+ email:
113
+ - evilcat@wisewolfsolutions.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - ".gitignore"
119
+ - Gemfile
120
+ - LICENSE
121
+ - README.md
122
+ - Rakefile
123
+ - lib/lita-rally.rb
124
+ - lib/lita/handlers/rally.rb
125
+ - lita-rally.gemspec
126
+ - locales/en.yml
127
+ - spec/lita/handlers/rally_spec.rb
128
+ - spec/spec_helper.rb
129
+ homepage: https://github.com/ecwws/lita-rally
130
+ licenses:
131
+ - MIT
132
+ metadata:
133
+ lita_plugin_type: handler
134
+ post_install_message:
135
+ rdoc_options: []
136
+ require_paths:
137
+ - lib
138
+ required_ruby_version: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - ">="
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ required_rubygems_version: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - ">="
146
+ - !ruby/object:Gem::Version
147
+ version: '0'
148
+ requirements: []
149
+ rubyforge_project:
150
+ rubygems_version: 2.2.2
151
+ signing_key:
152
+ specification_version: 4
153
+ summary: lita bot Rally plugin
154
+ test_files:
155
+ - spec/lita/handlers/rally_spec.rb
156
+ - spec/spec_helper.rb