jira-ruby-dmg 0.1.10 → 0.1.20

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c07448f99963fb48aa853b5306c3b282c7d07ee1
4
- data.tar.gz: c8ddbf9b54cf03c5cf523104c60a6f67054a8f7b
3
+ metadata.gz: 5091836e1cd94b8d437b8b90ffd30f240cd9075a
4
+ data.tar.gz: c2335e7bdc26a6aecdad5494a87587fbf54c1089
5
5
  SHA512:
6
- metadata.gz: 3c8b513fc02ee7eafa30543e9222f5fff2698886e197e069aadb978d888d79da127a219d74b79eba5db2e5d5cecbdbbb646a7aab3479f051257e559be4cc114f
7
- data.tar.gz: 51fc2db5eca63cc660a731f4f0006ffe2267e321db94fa9d58b068f1877b858a5c7119508a2d02fa9c895b6dcf2997eeae2a01c0fc9f73e96ff157567892fad2
6
+ metadata.gz: 1b4188f3c85f548a907dfd59e01c282f681ea6fba9d0a0dafbd5776e0afa3de63d1289d711c122ae2fc874a2d411678d0263c246550cc7024a72ac8622e25c33
7
+ data.tar.gz: cb4b9f8dea064c7a36abadc57a5477ebdd76fe77618d15b7cddabfb0972f926627ae02445719b527b8f55465818549e26bec4a2648113ee9648ba16099620f88
data/.gitignore CHANGED
@@ -8,3 +8,4 @@ pkg/*
8
8
  *.pem
9
9
  .DS_STORE
10
10
  doc
11
+ lib/debugClient.rb
data/Gemfile CHANGED
@@ -2,3 +2,7 @@ source "http://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in jira-api-dmg.gemspec
4
4
  gemspec
5
+
6
+ group :development do
7
+ gem 'pry-debugger'
8
+ end
data/lib/jira/base.rb CHANGED
@@ -98,9 +98,8 @@ module JIRA
98
98
  if collection_attributes_are_nested
99
99
  json = json[endpoint_name.pluralize]
100
100
  end
101
- json.map do |attrs|
102
- self.new(client, {:attrs => attrs}.merge(options))
103
- end
101
+
102
+ self.populate(client, options, json)
104
103
  end
105
104
 
106
105
  # Finds and retrieves a resource with the given ID.
@@ -153,6 +152,12 @@ module JIRA
153
152
  :id
154
153
  end
155
154
 
155
+ def self.populate(client, options, json)
156
+ json.map do |attrs|
157
+ self.new(client, {:attrs => attrs}.merge(options))
158
+ end
159
+ end
160
+
156
161
  def self.parse_json(string) # :nodoc:
157
162
  JSON.parse(string)
158
163
  end
data/lib/jira/client.rb CHANGED
@@ -125,6 +125,18 @@ module JIRA
125
125
  JIRA::Resource::FieldFactory.new(self)
126
126
  end
127
127
 
128
+ def Sprint # :nodoc:
129
+ JIRA::Resource::SprintFactory.new(self)
130
+ end
131
+
132
+ def Agileboard # :nodoc:
133
+ JIRA::Resource::AgileboardFactory.new(self)
134
+ end
135
+
136
+ def Velocity # :nodoc:
137
+ JIRA::Resource::VelocityFactory.new(self)
138
+ end
139
+
128
140
  # HTTP methods without a body
129
141
  def delete(path, headers = {})
130
142
  request(:delete, path, nil, merge_default_headers(headers))
@@ -0,0 +1,74 @@
1
+ module JIRA
2
+ module Resource
3
+
4
+ class AgileboardFactory < JIRA::BaseFactory # :nodoc:
5
+ end
6
+
7
+ class Agileboard < JIRA::Base
8
+ has_one :filter
9
+ has_one :boardAdmin, :class => JIRA::Resource::User
10
+
11
+ # override population for different responses from jira
12
+ def self.populate(client, options, json)
13
+ if json['views']
14
+ json = json['views']
15
+ end
16
+
17
+ super
18
+ end
19
+
20
+ # override collection path for different API endpoint
21
+ def self.collection_path(client, prefix = '/')
22
+ '/rest/greenhopper/1.0/rapidviews/list'
23
+ end
24
+
25
+ # get all issues of agile board
26
+ def issues
27
+ search_url = client.options[:site] +
28
+ '/rest/greenhopper/1.0/xboard/work/allData/?rapidViewId=' + attrs['id'].to_s
29
+
30
+ response = client.get(search_url)
31
+ json = self.class.parse_json(response.body)
32
+ json['issues'].map do |issue|
33
+ client.Issue.build(issue)
34
+ end
35
+ end
36
+
37
+ # get all sprints of agile board
38
+ def sprints
39
+ search_url = client.options[:site] + '/rest/greenhopper/1.0/sprintquery/' + attrs['id'].to_s
40
+ response = client.get(search_url)
41
+ json = self.class.parse_json(response.body)
42
+
43
+ vels = velocities
44
+ json['sprints'].map do |sprint|
45
+ velocity = vels.select { |vel| vel.sprint_id.to_s == sprint["id"].to_s }.first
46
+ sprint["velocity"] = velocity
47
+ client.Sprint.build(sprint)
48
+ end
49
+ end
50
+
51
+ # get velocities of agile board
52
+ def velocities
53
+ search_url = client.options[:site] +
54
+ '/rest/greenhopper/1.0/rapid/charts/velocity.json?rapidViewId=' + id.to_s
55
+
56
+ begin
57
+ response = client.get(search_url)
58
+ rescue
59
+ return []
60
+ end
61
+
62
+ json = self.class.parse_json(response.body)
63
+ json['velocityStatEntries'].map do |velocity|
64
+ client.Velocity.build({
65
+ "sprint_id" => velocity[0],
66
+ "estimated" => velocity[1]['estimated']['value'],
67
+ "completed" => velocity[1]['completed']['value']
68
+ })
69
+ end
70
+ end
71
+
72
+ end
73
+ end
74
+ end
@@ -26,6 +26,20 @@ module JIRA
26
26
  client.Issue.build(issue)
27
27
  end
28
28
  end
29
+
30
+ # Returns all sprints for this project
31
+ def sprints
32
+ search_url = client.options[:site] +
33
+ '/rest/greenhopper/1.0/integration/teamcalendars/sprint/list?jql=project=' + key
34
+
35
+ response = client.get(search_url)
36
+ json = self.class.parse_json(response.body)
37
+
38
+ json["sprints"].map do |sprint|
39
+ client.Sprint.build(sprint)
40
+ end
41
+ end
42
+
29
43
  end
30
44
  end
31
45
  end
@@ -0,0 +1,81 @@
1
+ module JIRA
2
+ module Resource
3
+
4
+ class SprintFactory < JIRA::BaseFactory # :nodoc:
5
+ end
6
+
7
+ class Sprint < JIRA::Base
8
+
9
+ # get all issues of sprint
10
+ def issues
11
+ jql = "sprint = " + id
12
+ Issue.jql(client, jql)
13
+ end
14
+
15
+ # get rapid view id
16
+ def agileboard_id
17
+ search_url = client.options[:site] + "/secure/GHGoToBoard.jspa?sprintId=" + id.to_s
18
+
19
+ begin
20
+ response = client.get(search_url)
21
+ rescue JIRA::HTTPError => error
22
+ unless error.response.instance_of? Net::HTTPFound
23
+ return
24
+ end
25
+
26
+ rapid_view_match = /rapidView=(\d+)&/.match(error.response['location'])
27
+ if rapid_view_match != nil
28
+ return rapid_view_match[1]
29
+ end
30
+ end
31
+ end
32
+
33
+ def velocity=(velocity)
34
+ @attrs["velocity"] = velocity
35
+ end
36
+
37
+ def velocity
38
+ unless attrs.keys.include? "velocity"
39
+ @attrs["velocity"] = get_velocity
40
+ end
41
+
42
+ @attrs["velocity"]
43
+ end
44
+
45
+ private
46
+ def get_velocity
47
+ search_url = client.options[:site] +
48
+ '/rest/greenhopper/1.0/rapid/charts/velocity.json?rapidViewId=' + agileboard_id.to_s
49
+ begin
50
+ response = client.get(search_url).body
51
+ rescue
52
+ return empty_velocity
53
+ end
54
+
55
+ json = self.class.parse_json(response)
56
+ resultVelocity = json['velocityStatEntries'].select do |sprint_id|
57
+ sprint_id.to_i == id.to_i
58
+ end
59
+
60
+ if resultVelocity.length == 0
61
+ return empty_velocity
62
+ end
63
+
64
+ client.Velocity.build({
65
+ "sprint_id" => id,
66
+ "estimated" => resultVelocity[id.to_s]['estimated']['value'],
67
+ "completed" => resultVelocity[id.to_s]['completed']['value']
68
+ })
69
+ end
70
+
71
+ def empty_velocity
72
+ client.Velocity.build({
73
+ "sprint_id" => id,
74
+ "estimated" => 0,
75
+ "completed" => 0
76
+ })
77
+ end
78
+
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,11 @@
1
+ module JIRA
2
+ module Resource
3
+
4
+ class VelocityFactory < JIRA::BaseFactory # :nodoc:
5
+ end
6
+
7
+ class Velocity < JIRA::Base
8
+ end
9
+
10
+ end
11
+ end
data/lib/jira/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module JIRA
2
- VERSION = "0.1.10"
2
+ VERSION = "0.1.20"
3
3
  end
data/lib/jira.rb CHANGED
@@ -17,13 +17,16 @@ require 'jira/resource/issuetype'
17
17
  require 'jira/resource/version'
18
18
  require 'jira/resource/status'
19
19
  require 'jira/resource/transition'
20
+ require 'jira/resource/filter'
21
+ require 'jira/resource/velocity'
22
+ require 'jira/resource/sprint'
20
23
  require 'jira/resource/project'
21
24
  require 'jira/resource/priority'
22
25
  require 'jira/resource/comment'
23
26
  require 'jira/resource/worklog'
24
27
  require 'jira/resource/issue'
25
- require 'jira/resource/filter'
26
28
  require 'jira/resource/field'
29
+ require 'jira/resource/agileboard'
27
30
 
28
31
  require 'jira/request_client'
29
32
  require 'jira/oauth_client'
@@ -3,7 +3,8 @@ require 'spec_helper'
3
3
  describe JIRA::Resource::Project do
4
4
 
5
5
  let(:client) { double("client", :options => {
6
- :rest_base_path => '/jira/rest/api/2'
6
+ :rest_base_path => '/jira/rest/api/2',
7
+ :site => 'https://example.com'
7
8
  })
8
9
  }
9
10
 
@@ -67,4 +68,27 @@ describe JIRA::Resource::Project do
67
68
  end
68
69
  end
69
70
  end
71
+
72
+ describe "sprints" do
73
+ subject {
74
+ JIRA::Resource::Project.new(client, :attrs => {
75
+ 'key' => 'test'
76
+ })
77
+ }
78
+
79
+ it "returns sprints" do
80
+ response_body = '{"expand":"schema,names","startAt":0,"maxResults":1,"total":1,"sprints":[{"expand":"editmeta,renderedFields,transitions,changelog,operations","id":"53062","self":"/rest/api/2/issue/53062","key":"test key","fields":{"summary":"test summary"}}]}'
81
+ response = double("response",
82
+ :body => response_body)
83
+ sprint_factory = double("sprint factory")
84
+
85
+ client.should_receive(:get)
86
+ .with('https://example.com/rest/greenhopper/1.0/integration/teamcalendars/sprint/list?jql=project=test')
87
+ .and_return(response)
88
+ client.should_receive(:Sprint).and_return(sprint_factory)
89
+ sprint_factory.should_receive(:build)
90
+ .with(JSON.parse(response_body)["sprints"][0])
91
+ subject.sprints
92
+ end
93
+ end
70
94
  end
@@ -0,0 +1,63 @@
1
+ require 'spec_helper'
2
+
3
+ describe JIRA::Resource::Sprint do
4
+
5
+ let(:client) { double("client", :options => {
6
+ :rest_base_path => '/jira/rest/api/2',
7
+ :site => 'https://example.com'
8
+ })
9
+ }
10
+
11
+ describe "relationships" do
12
+ subject {
13
+ JIRA::Resource::Sprint.new(client, :attrs => {
14
+ 'filter' => {'foo' => 'bar'},
15
+ 'boardAdmin' => {'foo' =>'bar'}
16
+ })
17
+ }
18
+
19
+ it "has the correct relationships" do
20
+ subject.should have_one(:filter, JIRA::Resource::Filter)
21
+ subject.filter.foo.should == 'bar'
22
+
23
+ subject.should have_one(:boardAdmin, JIRA::Resource::User)
24
+ subject.boardAdmin.foo.should == "bar"
25
+ end
26
+ end
27
+
28
+
29
+ describe "collection_path" do
30
+ subject {
31
+ JIRA::Resource::Sprint
32
+ }
33
+
34
+ it "should have the correct collection path" do
35
+ collection_path = JIRA::Resource::Sprint.collection_path(client)
36
+ collection_path.should == '/rest/greenhopper/1.0/rapidviews/list'
37
+ end
38
+ end
39
+
40
+ describe "issues" do
41
+ subject {
42
+ JIRA::Resource::Sprint.new(client, :attrs => {
43
+ 'id' => '42'
44
+ })
45
+ }
46
+
47
+ it "returns issues" do
48
+ response_body = '{"expand":"names,schema","startAt":0,"maxResults":1,"total":299,"issues":[{"expand":"editmeta,renderedFields,transitions,changelog,operations","id":"865585","self":"https://thisisdmg.atlassian.net/rest/api/2/issue/865585","key":"GHPOO-2728","fields":{"summary":"Touch | Produktberater | Beim ersten Mal Verändern des Jahrgangssliders wird die Ergbnissemenge nicht korrekt gesetzt.","progress":{"progress":300,"total":300,"percent":100},"issuetype":{"self":"https://thisisdmg.atlassian.net/rest/api/2/issuetype/1","id":"1","description":"A problem which impairs or prevents the functions of the product.","iconUrl":"https://thisisdmg.atlassian.net/images/icons/issuetypes/bug.png","name":"Bug","subtask":false},"timespent":300,"reporter":{"self":"https://thisisdmg.atlassian.net/rest/api/2/user?username=heinemann_c.gewalt","name":"heinemann_c.gewalt","emailAddress":"c.gewalt@nextpilgrims.com","avatarUrls":{"16x16":"https://thisisdmg.atlassian.net/secure/useravatar?size=xsmall&avatarId=10122","24x24":"https://thisisdmg.atlassian.net/secure/useravatar?size=small&avatarId=10122","32x32":"https://thisisdmg.atlassian.net/secure/useravatar?size=medium&avatarId=10122","48x48":"https://thisisdmg.atlassian.net/secure/useravatar?avatarId=10122"},"displayName":"Christian Gewalt","active":true},"created":"2014-04-02T14:02:43.000+0200","updated":"2014-04-14T16:00:37.000+0200","description":"Beim ersten Mal Verändern des Jahrgangssliders wird die Ergbnissemenge nicht korrekt gesetzt. Danach funktioniert es dann. ","priority":{"self":"https://thisisdmg.atlassian.net/rest/api/2/priority/3","iconUrl":"https://thisisdmg.atlassian.net/images/icons/priorities/major.png","name":"Major","id":"3"},"customfield_10001":"2014-04-14 16:00:37.849","customfield_10002":null,"customfield_10003":null,"issuelinks":[],"customfield_10000":"1_*:*_1_*:*_596873640_*|*_5_*:*_1_*:*_0","subtasks":[],"customfield_10008":null,"customfield_10007":null,"status":{"self":"https://thisisdmg.atlassian.net/rest/api/2/status/6","description":"The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.","iconUrl":"https://thisisdmg.atlassian.net/images/icons/statuses/closed.png","name":"Closed","id":"6","statusCategory":{"self":"https://thisisdmg.atlassian.net/rest/api/2/statuscategory/3","id":3,"key":"done","colorName":"green","name":"Complete"}},"customfield_10006":"349","labels":["Kundenfeedback","TouchScreen"],"workratio":-1,"project":{"self":"https://thisisdmg.atlassian.net/rest/api/2/project/13600","id":"13600","key":"GHPOO","name":"Gebrüder Heinemann - DIA","avatarUrls":{"16x16":"https://thisisdmg.atlassian.net/secure/projectavatar?size=xsmall&pid=13600&avatarId=10011","24x24":"https://thisisdmg.atlassian.net/secure/projectavatar?size=small&pid=13600&avatarId=10011","32x32":"https://thisisdmg.atlassian.net/secure/projectavatar?size=medium&pid=13600&avatarId=10011","48x48":"https://thisisdmg.atlassian.net/secure/projectavatar?pid=13600&avatarId=10011"},"projectCategory":{"self":"https://thisisdmg.atlassian.net/rest/api/2/projectCategory/10100","id":"10100","description":"Hier finden sich alle Kundenprojekte","name":"Kunden Projekte"}},"environment":null,"lastViewed":null,"aggregateprogress":{"progress":300,"total":300,"percent":100},"customfield_10012":["com.atlassian.greenhopper.service.sprint.Sprint@1829488[rapidViewId=142,state=CLOSED,name=07.04 - 24.04,startDate=2014-04-07T13:55:52.263+02:00,endDate=2014-04-24T15:00:00.000+02:00,completeDate=2014-04-22T17:30:25.628+02:00,id=642]"],"components":[{"self":"https://thisisdmg.atlassian.net/rest/api/2/component/13904","id":"13904","name":"Technik"}],"customfield_10011":null,"timeoriginalestimate":null,"votes":{"self":"https://thisisdmg.atlassian.net/rest/api/2/issue/GHPOO-2728/votes","votes":0,"hasVoted":false},"resolution":{"self":"https://thisisdmg.atlassian.net/rest/api/2/resolution/5","id":"5","description":"All attempts at reproducing this issue failed, or not enough information was available to reproduce the issue. Reading the code produces no clues as to why this behavior would occur. If more information appears later, please reopen the issue.","name":"Cannot Reproduce"},"fixVersions":[{"self":"https://thisisdmg.atlassian.net/rest/api/2/version/15700","id":"15700","description":"Prototyp","name":"Prototyp","archived":false,"released":false}],"resolutiondate":"2014-04-09T11:50:37.000+0200","creator":{"self":"https://thisisdmg.atlassian.net/rest/api/2/user?username=heinemann_c.gewalt","name":"heinemann_c.gewalt","emailAddress":"c.gewalt@nextpilgrims.com","avatarUrls":{"16x16":"https://thisisdmg.atlassian.net/secure/useravatar?size=xsmall&avatarId=10122","24x24":"https://thisisdmg.atlassian.net/secure/useravatar?size=small&avatarId=10122","32x32":"https://thisisdmg.atlassian.net/secure/useravatar?size=medium&avatarId=10122","48x48":"https://thisisdmg.atlassian.net/secure/useravatar?avatarId=10122"},"displayName":"Christian Gewalt","active":true},"aggregatetimeoriginalestimate":null,"duedate":null,"customfield_10104":null,"customfield_10105":null,"watches":{"self":"https://thisisdmg.atlassian.net/rest/api/2/issue/GHPOO-2728/watchers","watchCount":2,"isWatching":false},"customfield_10103":null,"customfield_10102":null,"customfield_10600":"GHPOO-113","customfield_10101":null,"customfield_10100":null,"assignee":{"self":"https://thisisdmg.atlassian.net/rest/api/2/user?username=l.soeder","name":"l.soeder","emailAddress":"l.soeder@thisisdmg.com","avatarUrls":{"16x16":"https://thisisdmg.atlassian.net/secure/useravatar?size=xsmall&ownerId=l.soeder&avatarId=11302","24x24":"https://thisisdmg.atlassian.net/secure/useravatar?size=small&ownerId=l.soeder&avatarId=11302","32x32":"https://thisisdmg.atlassian.net/secure/useravatar?size=medium&ownerId=l.soeder&avatarId=11302","48x48":"https://thisisdmg.atlassian.net/secure/useravatar?ownerId=l.soeder&avatarId=11302"},"displayName":"Lars Söder","active":true},"aggregatetimeestimate":0,"versions":[{"self":"https://thisisdmg.atlassian.net/rest/api/2/version/15700","id":"15700","description":"Prototyp","name":"Prototyp","archived":false,"released":false},{"self":"https://thisisdmg.atlassian.net/rest/api/2/version/17100","id":"17100","description":"Labshop installation vom 21. März","name":"Prototyp 3. Abnahme","archived":false,"released":true,"releaseDate":"2014-03-21"}],"customfield_10700":null,"customfield_10400":null,"timeestimate":0,"customfield_10300":"Not Started","aggregatetimespent":300}}]}'
49
+ response = double("response",
50
+ :body => response_body)
51
+ issue_factory = double("issue factory")
52
+
53
+ client.should_receive(:get)
54
+ .with('https://example.com/rest/greenhopper/1.0/xboard/work/allData/?rapidViewId=42')
55
+ .and_return(response)
56
+ client.should_receive(:Issue).and_return(issue_factory)
57
+ issue_factory.should_receive(:build)
58
+ .with(JSON.parse(response_body)["issues"][0])
59
+ subject.issues
60
+ end
61
+ end
62
+
63
+ end
data/spec/spec_helper.rb CHANGED
@@ -2,6 +2,7 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
2
  require 'rubygems'
3
3
  require 'bundler/setup'
4
4
  require 'webmock/rspec'
5
+ require 'pry-debugger'
5
6
  Dir["./spec/support/**/*.rb"].each {|f| require f}
6
7
 
7
8
  require 'jira'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jira-ruby-dmg
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.10
4
+ version: 0.1.20
5
5
  platform: ruby
6
6
  authors:
7
7
  - ThisIs! DMG
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-05-24 00:00:00.000000000 Z
11
+ date: 2014-05-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -119,6 +119,7 @@ files:
119
119
  - lib/jira/oauth_client.rb
120
120
  - lib/jira/railtie.rb
121
121
  - lib/jira/request_client.rb
122
+ - lib/jira/resource/agileboard.rb
122
123
  - lib/jira/resource/attachment.rb
123
124
  - lib/jira/resource/comment.rb
124
125
  - lib/jira/resource/component.rb
@@ -128,9 +129,11 @@ files:
128
129
  - lib/jira/resource/issuetype.rb
129
130
  - lib/jira/resource/priority.rb
130
131
  - lib/jira/resource/project.rb
132
+ - lib/jira/resource/sprint.rb
131
133
  - lib/jira/resource/status.rb
132
134
  - lib/jira/resource/transition.rb
133
135
  - lib/jira/resource/user.rb
136
+ - lib/jira/resource/velocity.rb
134
137
  - lib/jira/resource/version.rb
135
138
  - lib/jira/resource/worklog.rb
136
139
  - lib/jira/tasks.rb
@@ -162,6 +165,7 @@ files:
162
165
  - spec/jira/resource/issue_spec.rb
163
166
  - spec/jira/resource/project_factory_spec.rb
164
167
  - spec/jira/resource/project_spec.rb
168
+ - spec/jira/resource/sprint_spec.rb
165
169
  - spec/jira/resource/worklog_spec.rb
166
170
  - spec/mock_responses/attachment/10000.json
167
171
  - spec/mock_responses/component.post.json
@@ -256,6 +260,7 @@ test_files:
256
260
  - spec/jira/resource/issue_spec.rb
257
261
  - spec/jira/resource/project_factory_spec.rb
258
262
  - spec/jira/resource/project_spec.rb
263
+ - spec/jira/resource/sprint_spec.rb
259
264
  - spec/jira/resource/worklog_spec.rb
260
265
  - spec/mock_responses/attachment/10000.json
261
266
  - spec/mock_responses/component.post.json