pivotal-tracker-api 0.2.3 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +8 -2
- data/Gemfile.lock +65 -47
- data/README.md +7 -7
- data/VERSION +1 -1
- data/lib/pivotal-tracker-api.rb +10 -2
- data/lib/pivotal-tracker-api/activity.rb +52 -18
- data/lib/pivotal-tracker-api/analytics.rb +23 -0
- data/lib/pivotal-tracker-api/base.rb +14 -2
- data/lib/pivotal-tracker-api/client.rb +43 -21
- data/lib/pivotal-tracker-api/comment.rb +76 -27
- data/lib/pivotal-tracker-api/core_ext/string.rb +3 -0
- data/lib/pivotal-tracker-api/cycle_time_details.rb +43 -0
- data/lib/pivotal-tracker-api/file_attachment.rb +56 -0
- data/lib/pivotal-tracker-api/iteration.rb +73 -11
- data/lib/pivotal-tracker-api/label.rb +32 -0
- data/lib/pivotal-tracker-api/me.rb +16 -0
- data/lib/pivotal-tracker-api/person.rb +13 -9
- data/lib/pivotal-tracker-api/project.rb +76 -23
- data/lib/pivotal-tracker-api/service.rb +202 -0
- data/lib/pivotal-tracker-api/story.rb +173 -132
- data/lib/pivotal-tracker-api/story_transition.rb +81 -0
- data/lib/pivotal-tracker-api/string_extensions.rb +61 -0
- data/lib/pivotal-tracker-api/task.rb +56 -12
- data/pivotal-tracker-api.gemspec +28 -15
- data/test/helper.rb +1 -0
- data/test/test_activity.rb +79 -0
- data/test/test_analytics.rb +38 -0
- data/test/test_cycle_time_details.rb +69 -0
- data/test/test_iteration.rb +182 -0
- data/test/test_label.rb +29 -0
- data/test/test_me.rb +52 -0
- data/test/test_service.rb +67 -0
- data/test/test_story.rb +557 -0
- data/test/test_story_transition.rb +80 -0
- data/test/test_string_extensions.rb +37 -0
- metadata +29 -27
- data/lib/pivotal-tracker-api/attachment.rb +0 -28
- data/lib/pivotal-tracker-api/pivotal_service.rb +0 -141
- data/test/test_pivotal-tracker-api.rb +0 -7
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestStoryTransition < Test::Unit::TestCase
|
4
|
+
should "parse a valid json object into an instance of StoryTransition" do
|
5
|
+
transition = PivotalAPI::StoryTransition.from_json({
|
6
|
+
state: "started",
|
7
|
+
story_id: 1,
|
8
|
+
project_id: 2,
|
9
|
+
project_version: 3,
|
10
|
+
occurred_at: "2016-08-09T18:55:58Z",
|
11
|
+
performed_by_id: 4,
|
12
|
+
kind: "some-kind"
|
13
|
+
})
|
14
|
+
|
15
|
+
assert_equal(1, transition.story_id)
|
16
|
+
assert_equal(2, transition.project_id)
|
17
|
+
assert_equal(3, transition.project_version)
|
18
|
+
assert_equal(4, transition.performed_by_id)
|
19
|
+
assert_equal("started", transition.state)
|
20
|
+
assert_equal(DateTime.parse("2016-08-09T18:55:58Z"), transition.occurred_at)
|
21
|
+
assert_equal("some-kind", transition.kind)
|
22
|
+
end
|
23
|
+
|
24
|
+
should "parse a valid json array into an arrary of StoryTransition instances" do
|
25
|
+
transitions = PivotalAPI::StoryTransition.from_json([{
|
26
|
+
state: "started",
|
27
|
+
story_id: 1,
|
28
|
+
project_id: 2,
|
29
|
+
project_version: 3,
|
30
|
+
occurred_at: "2016-08-09T18:55:58Z",
|
31
|
+
performed_by_id: 4,
|
32
|
+
kind: "some-kind"
|
33
|
+
},
|
34
|
+
{
|
35
|
+
state: "finished",
|
36
|
+
story_id: 5,
|
37
|
+
project_id: 6,
|
38
|
+
project_version: 7,
|
39
|
+
occurred_at: "2016-08-09T18:55:58Z",
|
40
|
+
performed_by_id: 8,
|
41
|
+
kind: "some-kind"
|
42
|
+
},
|
43
|
+
{
|
44
|
+
state: "accepted",
|
45
|
+
story_id: 9,
|
46
|
+
project_id: 10,
|
47
|
+
project_version: 11,
|
48
|
+
occurred_at: "2016-08-09T18:55:58Z",
|
49
|
+
performed_by_id: 12,
|
50
|
+
kind: "some-kind"
|
51
|
+
}
|
52
|
+
])
|
53
|
+
|
54
|
+
assert_equal(3, transitions.count)
|
55
|
+
|
56
|
+
assert_equal(1, transitions[0].story_id)
|
57
|
+
assert_equal(2, transitions[0].project_id)
|
58
|
+
assert_equal(3, transitions[0].project_version)
|
59
|
+
assert_equal(4, transitions[0].performed_by_id)
|
60
|
+
assert_equal("started", transitions[0].state)
|
61
|
+
assert_equal(DateTime.parse("2016-08-09T18:55:58Z"), transitions[0].occurred_at)
|
62
|
+
assert_equal("some-kind", transitions[0].kind)
|
63
|
+
|
64
|
+
assert_equal(5, transitions[1].story_id)
|
65
|
+
assert_equal(6, transitions[1].project_id)
|
66
|
+
assert_equal(7, transitions[1].project_version)
|
67
|
+
assert_equal(8, transitions[1].performed_by_id)
|
68
|
+
assert_equal("finished", transitions[1].state)
|
69
|
+
assert_equal(DateTime.parse("2016-08-09T18:55:58Z"), transitions[1].occurred_at)
|
70
|
+
assert_equal("some-kind", transitions[1].kind)
|
71
|
+
|
72
|
+
assert_equal(9, transitions[2].story_id)
|
73
|
+
assert_equal(10, transitions[2].project_id)
|
74
|
+
assert_equal(11, transitions[2].project_version)
|
75
|
+
assert_equal(12, transitions[2].performed_by_id)
|
76
|
+
assert_equal("accepted", transitions[2].state)
|
77
|
+
assert_equal(DateTime.parse("2016-08-09T18:55:58Z"), transitions[2].occurred_at)
|
78
|
+
assert_equal("some-kind", transitions[2].kind)
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestActivity < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "Appending query params" do
|
6
|
+
|
7
|
+
should "should append limit, offset, and fields as expected" do
|
8
|
+
url = "/projects/12345/stories"
|
9
|
+
query_params = {
|
10
|
+
limit: 1,
|
11
|
+
offset: 2,
|
12
|
+
fields: PivotalAPI::Comment.fields
|
13
|
+
}
|
14
|
+
url.append_pivotal_params(query_params)
|
15
|
+
expected_url = "/projects/12345/stories?limit=1&offset=2"
|
16
|
+
expected_url += "&fields=person(name,id,initials,email,username,kind),text,updated_at,id," \
|
17
|
+
"created_at,story_id,file_attachments,google_attachment_ids,commit_identifier,commit_type,kind"
|
18
|
+
assert_equal(expected_url, url)
|
19
|
+
end
|
20
|
+
|
21
|
+
should "should append filters" do
|
22
|
+
url = "/projects/12345/stories"
|
23
|
+
query_params = {
|
24
|
+
limit: 1,
|
25
|
+
offset: 2,
|
26
|
+
filter: {
|
27
|
+
includedone: true,
|
28
|
+
id: [1,2,3,4,5]
|
29
|
+
}
|
30
|
+
}
|
31
|
+
url.append_pivotal_params(query_params)
|
32
|
+
expected_url = "/projects/12345/stories?limit=1&offset=2&filter=includedone%3Atrue%20id%3A1,2,3,4,5"
|
33
|
+
assert_equal(expected_url, url)
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pivotal-tracker-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- jfox
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-08-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rest-client
|
@@ -25,19 +25,19 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.7'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: business_time
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
34
|
-
type: :
|
33
|
+
version: 0.7.6
|
34
|
+
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 0.7.6
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rdoc
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -72,28 +72,14 @@ dependencies:
|
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: 1
|
75
|
+
version: '2.1'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: 1
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: simplecov
|
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'
|
82
|
+
version: '2.1'
|
97
83
|
description: A ruby gem to communicate with the Picotal Tracker API v5
|
98
84
|
email: atljeremy@me.com
|
99
85
|
executables: []
|
@@ -119,19 +105,35 @@ files:
|
|
119
105
|
- VERSION
|
120
106
|
- lib/pivotal-tracker-api.rb
|
121
107
|
- lib/pivotal-tracker-api/activity.rb
|
122
|
-
- lib/pivotal-tracker-api/
|
108
|
+
- lib/pivotal-tracker-api/analytics.rb
|
123
109
|
- lib/pivotal-tracker-api/base.rb
|
124
110
|
- lib/pivotal-tracker-api/client.rb
|
125
111
|
- lib/pivotal-tracker-api/comment.rb
|
112
|
+
- lib/pivotal-tracker-api/core_ext/string.rb
|
113
|
+
- lib/pivotal-tracker-api/cycle_time_details.rb
|
114
|
+
- lib/pivotal-tracker-api/file_attachment.rb
|
126
115
|
- lib/pivotal-tracker-api/iteration.rb
|
116
|
+
- lib/pivotal-tracker-api/label.rb
|
117
|
+
- lib/pivotal-tracker-api/me.rb
|
127
118
|
- lib/pivotal-tracker-api/person.rb
|
128
|
-
- lib/pivotal-tracker-api/pivotal_service.rb
|
129
119
|
- lib/pivotal-tracker-api/project.rb
|
120
|
+
- lib/pivotal-tracker-api/service.rb
|
130
121
|
- lib/pivotal-tracker-api/story.rb
|
122
|
+
- lib/pivotal-tracker-api/story_transition.rb
|
123
|
+
- lib/pivotal-tracker-api/string_extensions.rb
|
131
124
|
- lib/pivotal-tracker-api/task.rb
|
132
125
|
- pivotal-tracker-api.gemspec
|
133
126
|
- test/helper.rb
|
134
|
-
- test/
|
127
|
+
- test/test_activity.rb
|
128
|
+
- test/test_analytics.rb
|
129
|
+
- test/test_cycle_time_details.rb
|
130
|
+
- test/test_iteration.rb
|
131
|
+
- test/test_label.rb
|
132
|
+
- test/test_me.rb
|
133
|
+
- test/test_service.rb
|
134
|
+
- test/test_story.rb
|
135
|
+
- test/test_story_transition.rb
|
136
|
+
- test/test_string_extensions.rb
|
135
137
|
homepage: http://github.com/atljeremy/pivotal-tracker-api
|
136
138
|
licenses:
|
137
139
|
- MIT
|
@@ -1,28 +0,0 @@
|
|
1
|
-
module Scorer
|
2
|
-
class Attachment < Base
|
3
|
-
|
4
|
-
attr_accessor :filename, :id, :created_at, :uploaded_by, :big_url,
|
5
|
-
:width, :height, :download_url, :thumbnail_url, :size, :content_type
|
6
|
-
|
7
|
-
def self.parse_attachments(attachments)
|
8
|
-
parsed_attachments = []
|
9
|
-
attachments.each do |file|
|
10
|
-
parsed_attachments << new({
|
11
|
-
id: file[:id].to_i,
|
12
|
-
filename: file[:filename],
|
13
|
-
created_at: file[:created_at],
|
14
|
-
uploaded_by: file[:uploaded_by],
|
15
|
-
big_url: file[:big_url],
|
16
|
-
width: file[:width],
|
17
|
-
height: file[:height],
|
18
|
-
download_url: file[:download_url],
|
19
|
-
thumbnail_url: file[:thumbnail_url],
|
20
|
-
size: file[:size],
|
21
|
-
content_type: file[:content_type]
|
22
|
-
})
|
23
|
-
end if attachments
|
24
|
-
parsed_attachments
|
25
|
-
end
|
26
|
-
|
27
|
-
end
|
28
|
-
end
|
@@ -1,141 +0,0 @@
|
|
1
|
-
require 'json'
|
2
|
-
|
3
|
-
class PivotalService
|
4
|
-
|
5
|
-
class << self
|
6
|
-
|
7
|
-
def set_token(token)
|
8
|
-
Scorer::Client.token = token
|
9
|
-
end
|
10
|
-
|
11
|
-
def all_projects(fields=[])
|
12
|
-
api_url = append_fields('/projects', fields)
|
13
|
-
response = Scorer::Client.get(api_url)
|
14
|
-
json_projects = JSON.parse(response, {:symbolize_names => true})
|
15
|
-
Scorer::Project.parse_json_projects(json_projects)
|
16
|
-
end
|
17
|
-
|
18
|
-
def one_project(id, fields=[])
|
19
|
-
return @project if !@project.nil? && @project.id == id
|
20
|
-
|
21
|
-
api_url = append_fields('/projects' + "/#{id}", fields)
|
22
|
-
response = Scorer::Client.get(api_url)
|
23
|
-
json_project = JSON.parse(response, {:symbolize_names => true})
|
24
|
-
@project = Scorer::Project.parse_json_project(json_project)
|
25
|
-
end
|
26
|
-
|
27
|
-
def activity(project_id, story_id=0, limit=20)
|
28
|
-
api_url = "/projects/#{project_id}/"
|
29
|
-
api_url = api_url + "stories/#{story_id}/" if story_id > 0
|
30
|
-
api_url = api_url + "activity?limit=#{limit}"
|
31
|
-
response = Scorer::Client.get(api_url)
|
32
|
-
json_activity = JSON.parse(response, {:symbolize_names => true})
|
33
|
-
Scorer::Activity.parse_json_activity(json_activity, project_id)
|
34
|
-
end
|
35
|
-
|
36
|
-
def iterations(project_id, scope, fields=[], limit=1, offset=1)
|
37
|
-
return @iterations if !@iterations.nil? && @iterations.last.project_id == project_id
|
38
|
-
|
39
|
-
api_url = "/projects/#{project_id}/iterations?"
|
40
|
-
|
41
|
-
if scope == 'current'
|
42
|
-
api_url = append_scope(api_url, scope)
|
43
|
-
elsif scope == 'done' || scope == 'backlog' || scope == 'current_backlog'
|
44
|
-
api_url = append_limit_offset(api_url, limit, offset)
|
45
|
-
api_url = append_scope(api_url, scope)
|
46
|
-
else
|
47
|
-
api_url = append_limit_offset(api_url, limit, offset)
|
48
|
-
end
|
49
|
-
|
50
|
-
api_url = append_fields(api_url, fields)
|
51
|
-
response = Scorer::Client.get_with_caching(api_url)
|
52
|
-
json_iterations = JSON.parse(response, {:symbolize_names => true})
|
53
|
-
@iterations = []
|
54
|
-
json_iterations.each do |iteration|
|
55
|
-
@iterations << Scorer::Iteration.parse_json_iteration(iteration, (scope == 'done'))
|
56
|
-
end
|
57
|
-
@iterations
|
58
|
-
end
|
59
|
-
|
60
|
-
def all_stories(project_label, project, fields=[])
|
61
|
-
api_url = append_fields('/projects' + "/#{project.id}/stories", fields)
|
62
|
-
api_url = api_url + "&with_label=#{project_label}&with_state=unstarted&limit=100"
|
63
|
-
response = Scorer::Client.get(api_url)
|
64
|
-
json_stories = JSON.parse(response, {:symbolize_names => true})
|
65
|
-
Scorer::Story.parse_json_stories(json_stories, project.id)
|
66
|
-
end
|
67
|
-
|
68
|
-
def one_story(project_label, project, fields=[])
|
69
|
-
api_url = append_fields('/projects' + "/#{project.id}/stories", fields)
|
70
|
-
api_url = api_url + "&with_label=#{project_label}&with_state=unstarted&limit=100"
|
71
|
-
response = Scorer::Client.get(api_url)
|
72
|
-
json_story = JSON.parse(response, {:symbolize_names => true})
|
73
|
-
Scorer::Story.parse_json_story(json_story, project.id)
|
74
|
-
end
|
75
|
-
|
76
|
-
def stories(project, should_cache, ids=[], fields=[], include_done=false)
|
77
|
-
@stories = Array.new
|
78
|
-
api_url = append_fields('/projects' + "/#{project.id}/stories", fields)
|
79
|
-
if api_url.rindex('?fields=')
|
80
|
-
api_url = "#{api_url}&filter=includedone%3A#{include_done}%20id%3A"
|
81
|
-
else
|
82
|
-
api_url = "#{api_url}?filter=includedone%3A#{include_done}%20id%3A"
|
83
|
-
end
|
84
|
-
if ids.size == 1
|
85
|
-
api_url = api_url + ids[0].to_s
|
86
|
-
if should_cache
|
87
|
-
response = Scorer::Client.get_with_caching(api_url)
|
88
|
-
else
|
89
|
-
response = Scorer::Client.get(api_url)
|
90
|
-
end
|
91
|
-
json_story = JSON.parse(response, {:symbolize_names => true})
|
92
|
-
@stories << Scorer::Story.parse_json_story(json_story[0], project.id)
|
93
|
-
else
|
94
|
-
story_ids = ''
|
95
|
-
ids.each do |id|
|
96
|
-
story_ids = "#{story_ids}#{id}%2C"
|
97
|
-
end
|
98
|
-
api_url = api_url + story_ids
|
99
|
-
if should_cache
|
100
|
-
response = Scorer::Client.get_with_caching(api_url)
|
101
|
-
else
|
102
|
-
response = Scorer::Client.get(api_url)
|
103
|
-
end
|
104
|
-
json_stories = JSON.parse(response, {:symbolize_names => true})
|
105
|
-
@stories = Scorer::Story.parse_json_stories(json_stories, project.id)
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
def update_story(story_id, project_id, updates={})
|
110
|
-
project = one_project(project_id, Scorer::Project.fields)
|
111
|
-
api_url = '/projects' + "/#{project.id}/stories/#{story_id}"
|
112
|
-
Scorer::Client.put(api_url, updates)
|
113
|
-
end
|
114
|
-
|
115
|
-
def comments(project_id, story, fields)
|
116
|
-
api_url = append_fields('/projects' + "/#{project_id}/stories/#{story.id}/comments", fields)
|
117
|
-
response = Scorer::Client.get_with_caching(api_url)
|
118
|
-
json_comments = JSON.parse(response, {:symbolize_names => true})
|
119
|
-
Scorer::Comment.parse_json_comments(json_comments, story)
|
120
|
-
end
|
121
|
-
|
122
|
-
private
|
123
|
-
|
124
|
-
def append_fields(api_url, fields)
|
125
|
-
url = api_url
|
126
|
-
fields.each do |field|
|
127
|
-
url = url.rindex('?fields=') ? url + ",#{field}" : url + "?fields=#{field}"
|
128
|
-
end
|
129
|
-
url
|
130
|
-
end
|
131
|
-
|
132
|
-
def append_scope(api_url, scope)
|
133
|
-
api_url + "&scope=#{scope}"
|
134
|
-
end
|
135
|
-
|
136
|
-
def append_limit_offset(api_url, limit, offset)
|
137
|
-
api_url + "&limit=#{limit}&offset=#{offset}"
|
138
|
-
end
|
139
|
-
|
140
|
-
end
|
141
|
-
end
|