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,81 @@
|
|
1
|
+
# state enumerated string
|
2
|
+
# — State the story transitioned to. This field is read only.
|
3
|
+
# Valid enumeration values: accepted, delivered, finished, started, rejected, planned, unstarted, unscheduled
|
4
|
+
#
|
5
|
+
# story_id int
|
6
|
+
# — ID of the story. This field is read only.
|
7
|
+
#
|
8
|
+
# project_id int
|
9
|
+
# — ID of the project. This field is read only.
|
10
|
+
#
|
11
|
+
# project_version int
|
12
|
+
# — The activity version of the story transition. This field is read only.
|
13
|
+
#
|
14
|
+
# occurred_at datetime
|
15
|
+
# — Time of the transition. This field is read only.
|
16
|
+
#
|
17
|
+
# performed_by_id int
|
18
|
+
# — ID of the person who performed the story transition. This field is read only.
|
19
|
+
#
|
20
|
+
# kind string
|
21
|
+
# — The type of this object: story_transition. This field is read only.
|
22
|
+
|
23
|
+
module PivotalAPI
|
24
|
+
class StoryTransition < Base
|
25
|
+
|
26
|
+
attr_accessor :state, :story_id, :project_id, :project_version, :occurred_at, :performed_by_id, :kind
|
27
|
+
|
28
|
+
class << self
|
29
|
+
|
30
|
+
def from_json(json)
|
31
|
+
return nil unless json
|
32
|
+
if json.is_a?(Array)
|
33
|
+
parse_json_story_transitions(json)
|
34
|
+
else
|
35
|
+
parse_json_story_transition(json)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def parse_json_story_transitions(json_story_transitions)
|
40
|
+
transitions = []
|
41
|
+
json_story_transitions.each do |transition|
|
42
|
+
transitions << parse_json_story_transition(transition)
|
43
|
+
end
|
44
|
+
transitions
|
45
|
+
end
|
46
|
+
|
47
|
+
def parse_json_story_transition(json_story_transition)
|
48
|
+
new({
|
49
|
+
state: json_story_transition[:state],
|
50
|
+
story_id: json_story_transition[:story_id].to_i,
|
51
|
+
project_id: json_story_transition[:project_id].to_i,
|
52
|
+
project_version: json_story_transition[:project_version].to_i,
|
53
|
+
occurred_at: (DateTime.parse(json_story_transition[:occurred_at]) if json_story_transition[:occurred_at]),
|
54
|
+
performed_by_id: json_story_transition[:performed_by_id].to_i,
|
55
|
+
kind: json_story_transition[:kind]
|
56
|
+
})
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
class StoryTransitions < StoryTransition
|
64
|
+
|
65
|
+
class << self
|
66
|
+
|
67
|
+
def from_json(json)
|
68
|
+
return nil unless json
|
69
|
+
parse_json_story_transitions(json)
|
70
|
+
end
|
71
|
+
|
72
|
+
def parse_json_story_transitions(story_transitions)
|
73
|
+
transitions = []
|
74
|
+
story_transitions.each { |transition| transitions << parse_json_story_transition(transition) }
|
75
|
+
transitions
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
3
|
+
module PivotalAPI
|
4
|
+
module Extensions
|
5
|
+
module String
|
6
|
+
module QueryParams
|
7
|
+
|
8
|
+
def append_pivotal_params(params, replace=true)
|
9
|
+
return self if params.nil?
|
10
|
+
|
11
|
+
resulting_url = if replace then self else "" end
|
12
|
+
|
13
|
+
if self.rindex("?").nil?
|
14
|
+
resulting_url += "?"
|
15
|
+
replace(resulting_url)
|
16
|
+
end
|
17
|
+
|
18
|
+
case params
|
19
|
+
when Array
|
20
|
+
resulting_url += params_from_array(params)
|
21
|
+
when Hash
|
22
|
+
resulting_url += params_from_hash(params)
|
23
|
+
else
|
24
|
+
resulting_url += "#{params}"
|
25
|
+
end
|
26
|
+
|
27
|
+
if replace then replace(resulting_url) else resulting_url end
|
28
|
+
end
|
29
|
+
|
30
|
+
protected
|
31
|
+
|
32
|
+
def params_from_hash(hash)
|
33
|
+
q_params = ""
|
34
|
+
hash.each do |k,v|
|
35
|
+
case v
|
36
|
+
when Array
|
37
|
+
q_params += if q_params.length == 0 then "#{k}=" else "&#{k}=" end
|
38
|
+
q_params += params_from_array(v)
|
39
|
+
when Hash
|
40
|
+
q_params += if q_params.length == 0 then "#{k}=" else "&#{k}=" end
|
41
|
+
v.each { |kk,vv|
|
42
|
+
q_params += if v.keys.first == kk then "#{kk}%3A" else "%20#{kk}%3A" end
|
43
|
+
q_params += append_pivotal_params(vv, false)
|
44
|
+
}
|
45
|
+
else
|
46
|
+
q_params += if q_params.length == 0 then "#{k}=#{v}" else "&#{k}=#{v}" end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
q_params
|
50
|
+
end
|
51
|
+
|
52
|
+
def params_from_array(array)
|
53
|
+
q_params = ""
|
54
|
+
array.each { |vv| q_params += if array.index(vv) == 0 then "#{vv}" else ",#{vv}" end }
|
55
|
+
q_params
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -1,21 +1,65 @@
|
|
1
|
-
|
1
|
+
# PROPERTIES
|
2
|
+
# id int
|
3
|
+
# — Database id of the task. This field is read only. This field is always returned.
|
4
|
+
#
|
5
|
+
# story_id int
|
6
|
+
# — The id of the story to which the task is connected. This field is read only.
|
7
|
+
#
|
8
|
+
# description string[1000]
|
9
|
+
# Required On Create — Content of the task. This field is required on create.
|
10
|
+
#
|
11
|
+
# complete boolean
|
12
|
+
# — Flag showing the completion of the task.
|
13
|
+
#
|
14
|
+
# position int
|
15
|
+
# — Offset from the top of the task list. Positions start counting from 1 for the first task on a story.
|
16
|
+
#
|
17
|
+
# created_at datetime
|
18
|
+
# — Creation time. This field is read only.
|
19
|
+
#
|
20
|
+
# updated_at datetime
|
21
|
+
# — Time of last update. This field is read only.
|
22
|
+
#
|
23
|
+
# kind string
|
24
|
+
# — The type of this object: task. This field is read only.
|
25
|
+
|
26
|
+
module PivotalAPI
|
2
27
|
class Task < Base
|
3
28
|
|
4
29
|
attr_accessor :project_id, :story_id, :id, :description, :position, :complete, :created_at
|
5
30
|
|
6
|
-
def self.
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
31
|
+
def self.from_json(json)
|
32
|
+
return nil unless json
|
33
|
+
parse_task(json)
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
|
38
|
+
def self.parse_task(task)
|
39
|
+
new({
|
40
|
+
id: task[:id].to_i,
|
41
|
+
description: task[:description],
|
42
|
+
complete: task[:complete],
|
43
|
+
created_at: DateTime.parse(task[:created_at].to_s),
|
44
|
+
story_id: task[:id]
|
45
|
+
})
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Tasks < Task
|
50
|
+
|
51
|
+
def self.from_json(json)
|
52
|
+
return nil unless json
|
53
|
+
parse_tasks(json)
|
54
|
+
end
|
17
55
|
|
56
|
+
protected
|
57
|
+
|
58
|
+
def self.parse_tasks(tasks)
|
59
|
+
parsed_tasks = []
|
60
|
+
tasks.each { |task| parsed_tasks << parse_task(task) }
|
18
61
|
parsed_tasks
|
19
62
|
end
|
63
|
+
|
20
64
|
end
|
21
65
|
end
|
data/pivotal-tracker-api.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: pivotal-tracker-api 0.
|
5
|
+
# stub: pivotal-tracker-api 1.0.0 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "pivotal-tracker-api"
|
9
|
-
s.version = "0.
|
9
|
+
s.version = "1.0.0"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib"]
|
13
13
|
s.authors = ["jfox"]
|
14
|
-
s.date = "2016-
|
14
|
+
s.date = "2016-08-23"
|
15
15
|
s.description = "A ruby gem to communicate with the Picotal Tracker API v5"
|
16
16
|
s.email = "atljeremy@me.com"
|
17
17
|
s.extra_rdoc_files = [
|
@@ -36,19 +36,35 @@ Gem::Specification.new do |s|
|
|
36
36
|
"VERSION",
|
37
37
|
"lib/pivotal-tracker-api.rb",
|
38
38
|
"lib/pivotal-tracker-api/activity.rb",
|
39
|
-
"lib/pivotal-tracker-api/
|
39
|
+
"lib/pivotal-tracker-api/analytics.rb",
|
40
40
|
"lib/pivotal-tracker-api/base.rb",
|
41
41
|
"lib/pivotal-tracker-api/client.rb",
|
42
42
|
"lib/pivotal-tracker-api/comment.rb",
|
43
|
+
"lib/pivotal-tracker-api/core_ext/string.rb",
|
44
|
+
"lib/pivotal-tracker-api/cycle_time_details.rb",
|
45
|
+
"lib/pivotal-tracker-api/file_attachment.rb",
|
43
46
|
"lib/pivotal-tracker-api/iteration.rb",
|
47
|
+
"lib/pivotal-tracker-api/label.rb",
|
48
|
+
"lib/pivotal-tracker-api/me.rb",
|
44
49
|
"lib/pivotal-tracker-api/person.rb",
|
45
|
-
"lib/pivotal-tracker-api/pivotal_service.rb",
|
46
50
|
"lib/pivotal-tracker-api/project.rb",
|
51
|
+
"lib/pivotal-tracker-api/service.rb",
|
47
52
|
"lib/pivotal-tracker-api/story.rb",
|
53
|
+
"lib/pivotal-tracker-api/story_transition.rb",
|
54
|
+
"lib/pivotal-tracker-api/string_extensions.rb",
|
48
55
|
"lib/pivotal-tracker-api/task.rb",
|
49
56
|
"pivotal-tracker-api.gemspec",
|
50
57
|
"test/helper.rb",
|
51
|
-
"test/
|
58
|
+
"test/test_activity.rb",
|
59
|
+
"test/test_analytics.rb",
|
60
|
+
"test/test_cycle_time_details.rb",
|
61
|
+
"test/test_iteration.rb",
|
62
|
+
"test/test_label.rb",
|
63
|
+
"test/test_me.rb",
|
64
|
+
"test/test_service.rb",
|
65
|
+
"test/test_story.rb",
|
66
|
+
"test/test_story_transition.rb",
|
67
|
+
"test/test_string_extensions.rb"
|
52
68
|
]
|
53
69
|
s.homepage = "http://github.com/atljeremy/pivotal-tracker-api"
|
54
70
|
s.licenses = ["MIT"]
|
@@ -60,26 +76,23 @@ Gem::Specification.new do |s|
|
|
60
76
|
|
61
77
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
62
78
|
s.add_runtime_dependency(%q<rest-client>, ["~> 1.7"])
|
63
|
-
s.
|
79
|
+
s.add_runtime_dependency(%q<business_time>, ["~> 0.7.6"])
|
64
80
|
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
65
81
|
s.add_development_dependency(%q<bundler>, ["~> 1.0"])
|
66
|
-
s.add_development_dependency(%q<jeweler>, ["~> 1
|
67
|
-
s.add_development_dependency(%q<simplecov>, [">= 0"])
|
82
|
+
s.add_development_dependency(%q<jeweler>, ["~> 2.1"])
|
68
83
|
else
|
69
84
|
s.add_dependency(%q<rest-client>, ["~> 1.7"])
|
70
|
-
s.add_dependency(%q<
|
85
|
+
s.add_dependency(%q<business_time>, ["~> 0.7.6"])
|
71
86
|
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
72
87
|
s.add_dependency(%q<bundler>, ["~> 1.0"])
|
73
|
-
s.add_dependency(%q<jeweler>, ["~> 1
|
74
|
-
s.add_dependency(%q<simplecov>, [">= 0"])
|
88
|
+
s.add_dependency(%q<jeweler>, ["~> 2.1"])
|
75
89
|
end
|
76
90
|
else
|
77
91
|
s.add_dependency(%q<rest-client>, ["~> 1.7"])
|
78
|
-
s.add_dependency(%q<
|
92
|
+
s.add_dependency(%q<business_time>, ["~> 0.7.6"])
|
79
93
|
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
80
94
|
s.add_dependency(%q<bundler>, ["~> 1.0"])
|
81
|
-
s.add_dependency(%q<jeweler>, ["~> 1
|
82
|
-
s.add_dependency(%q<simplecov>, [">= 0"])
|
95
|
+
s.add_dependency(%q<jeweler>, ["~> 2.1"])
|
83
96
|
end
|
84
97
|
end
|
85
98
|
|
data/test/helper.rb
CHANGED
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestActivity < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "A PivotalAPI::Activity" do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@activity = PivotalAPI::Activity.from_json([{
|
9
|
+
project_id: 1,
|
10
|
+
occurred_at: "2016-08-17T11:03:53-04:00",
|
11
|
+
highlight: "some-string",
|
12
|
+
primary_resources: [{foo: "bar"}],
|
13
|
+
changes: [{abc: "123"}],
|
14
|
+
guid: "123abc",
|
15
|
+
kind: "some-kind",
|
16
|
+
performed_by_id: 2,
|
17
|
+
performed_by: {
|
18
|
+
id: 2,
|
19
|
+
name: "John Appleseed",
|
20
|
+
initials: "JA",
|
21
|
+
email: "john@email.com",
|
22
|
+
username: "johnapple"
|
23
|
+
},
|
24
|
+
message: "some message",
|
25
|
+
project_version: 3
|
26
|
+
}])
|
27
|
+
end
|
28
|
+
|
29
|
+
should "have a valid project_id" do
|
30
|
+
assert_equal(1, @activity[0].project_id)
|
31
|
+
end
|
32
|
+
|
33
|
+
should "have a valid occurred_at date" do
|
34
|
+
assert_equal(DateTime.parse("2016-08-17T11:03:53-04:00"), @activity[0].occurred_at)
|
35
|
+
end
|
36
|
+
|
37
|
+
should "have a valid highlight" do
|
38
|
+
assert_equal("some-string", @activity[0].highlight)
|
39
|
+
end
|
40
|
+
|
41
|
+
should "have valid primary_resources" do
|
42
|
+
assert_equal("bar", @activity[0].primary_resources[0][:foo])
|
43
|
+
end
|
44
|
+
|
45
|
+
should "have valid changes" do
|
46
|
+
assert_equal("123", @activity[0].changes[0][:abc])
|
47
|
+
end
|
48
|
+
|
49
|
+
should "have a valid guid" do
|
50
|
+
assert_equal("123abc", @activity[0].guid)
|
51
|
+
end
|
52
|
+
|
53
|
+
should "have a valid kind" do
|
54
|
+
assert_equal("some-kind", @activity[0].kind)
|
55
|
+
end
|
56
|
+
|
57
|
+
should "have a valid performed_by_id" do
|
58
|
+
assert_equal(2, @activity[0].performed_by_id)
|
59
|
+
end
|
60
|
+
|
61
|
+
should "have a valid performed_by person" do
|
62
|
+
person = @activity[0].performed_by
|
63
|
+
assert_equal(2, person.id)
|
64
|
+
assert_equal("John Appleseed", person.name)
|
65
|
+
assert_equal("JA", person.initials)
|
66
|
+
assert_equal("john@email.com", person.email)
|
67
|
+
assert_equal("johnapple", person.username)
|
68
|
+
end
|
69
|
+
|
70
|
+
should "have a valid message" do
|
71
|
+
assert_equal("some message", @activity[0].message)
|
72
|
+
end
|
73
|
+
|
74
|
+
should "have a valid project_version" do
|
75
|
+
assert_equal(3, @activity[0].project_version)
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestAnalytics < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "A PivotalAPI::Analytics" do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@analytics = PivotalAPI::Analytics.from_json({
|
9
|
+
stories_accepted: 5,
|
10
|
+
bugs_created: 2,
|
11
|
+
cycle_time: 343434,
|
12
|
+
rejection_rate: 33.8,
|
13
|
+
kind: "some-kind"
|
14
|
+
})
|
15
|
+
end
|
16
|
+
|
17
|
+
should "have a valid stories_accepted count" do
|
18
|
+
assert_equal(5, @analytics.stories_accepted)
|
19
|
+
end
|
20
|
+
|
21
|
+
should "have a valid bugs_created count" do
|
22
|
+
assert_equal(2, @analytics.bugs_created)
|
23
|
+
end
|
24
|
+
|
25
|
+
should "have a valid cycle_time" do
|
26
|
+
assert_equal(343434, @analytics.cycle_time)
|
27
|
+
end
|
28
|
+
|
29
|
+
should "have a valid rejection_rate" do
|
30
|
+
assert_equal(33.8, @analytics.rejection_rate)
|
31
|
+
end
|
32
|
+
|
33
|
+
should "have a valid kind" do
|
34
|
+
assert_equal("some-kind", @analytics.kind)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestAnalytics < Test::Unit::TestCase
|
4
|
+
|
5
|
+
|
6
|
+
context "A PivotalAPI::CycleTimeDetails" do
|
7
|
+
|
8
|
+
setup do
|
9
|
+
@cycle_time_details = PivotalAPI::CycleTimeDetails.from_json({
|
10
|
+
total_cycle_time: 12345,
|
11
|
+
started_time: 1111111111,
|
12
|
+
started_count: 2,
|
13
|
+
finished_time: 2222222222,
|
14
|
+
finished_count: 3,
|
15
|
+
delivered_time: 3333333333,
|
16
|
+
delivered_count: 4,
|
17
|
+
rejected_time: 4444444444,
|
18
|
+
rejected_count: 5,
|
19
|
+
story_id: 33,
|
20
|
+
kind: "some-kind"
|
21
|
+
})
|
22
|
+
end
|
23
|
+
|
24
|
+
should "have a valid total_cycle_time" do
|
25
|
+
assert_equal(12345, @cycle_time_details.total_cycle_time)
|
26
|
+
end
|
27
|
+
|
28
|
+
should "have a valid started_time" do
|
29
|
+
assert_equal(1111111111, @cycle_time_details.started_time)
|
30
|
+
end
|
31
|
+
|
32
|
+
should "have a valid started_count" do
|
33
|
+
assert_equal(2, @cycle_time_details.started_count)
|
34
|
+
end
|
35
|
+
|
36
|
+
should "have a valid finished_time" do
|
37
|
+
assert_equal(2222222222, @cycle_time_details.finished_time)
|
38
|
+
end
|
39
|
+
|
40
|
+
should "have a valid finished_count" do
|
41
|
+
assert_equal(3, @cycle_time_details.finished_count)
|
42
|
+
end
|
43
|
+
|
44
|
+
should "have a valid delivered_time" do
|
45
|
+
assert_equal(3333333333, @cycle_time_details.delivered_time)
|
46
|
+
end
|
47
|
+
|
48
|
+
should "have a valid delivered_count" do
|
49
|
+
assert_equal(4, @cycle_time_details.delivered_count)
|
50
|
+
end
|
51
|
+
|
52
|
+
should "have a valid rejected_time" do
|
53
|
+
assert_equal(4444444444, @cycle_time_details.rejected_time)
|
54
|
+
end
|
55
|
+
|
56
|
+
should "have a valid rejected_count" do
|
57
|
+
assert_equal(5, @cycle_time_details.rejected_count)
|
58
|
+
end
|
59
|
+
|
60
|
+
should "have a valid story_id" do
|
61
|
+
assert_equal(33, @cycle_time_details.story_id)
|
62
|
+
end
|
63
|
+
|
64
|
+
should "have a valid kind" do
|
65
|
+
assert_equal("some-kind", @cycle_time_details.kind)
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|