cukebase 0.0.1
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.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +56 -0
- data/Rakefile +2 -0
- data/cukebase.gemspec +21 -0
- data/lib/cukebase.rb +45 -0
- data/lib/cukebase/config.rb +43 -0
- data/lib/cukebase/project.rb +55 -0
- data/lib/cukebase/request.rb +16 -0
- data/lib/cukebase/ticket.rb +82 -0
- data/lib/cukebase/ticketing_category.rb +8 -0
- data/lib/cukebase/ticketing_status.rb +11 -0
- data/lib/cukebase/version.rb +3 -0
- metadata +109 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Emil Loer
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# Cukebase
|
2
|
+
|
3
|
+
This gem provides integration betweeen Cucumber and the Codebase ticketing
|
4
|
+
system. Whenever scenarios are run Cukebase will create tickets for any
|
5
|
+
scenarios it encounters. It sets the ticket status to the test result of the
|
6
|
+
scenario.
|
7
|
+
|
8
|
+
When you run Cucumber again, these tickets are updated to reflect the new
|
9
|
+
result status.
|
10
|
+
|
11
|
+
## Usage
|
12
|
+
|
13
|
+
Add this to your Gemfile:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
group :test do
|
17
|
+
gem 'cukebase'
|
18
|
+
end
|
19
|
+
```
|
20
|
+
|
21
|
+
Then go to Codebase to find your API credentials and add the following to your
|
22
|
+
`features/support/env.rb` file:
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
Cukebase.config do |c|
|
26
|
+
c.project = "your-project-name"
|
27
|
+
c.username = "yourcompany/youruser"
|
28
|
+
c.api_key = "YOUR_API_KEY"
|
29
|
+
end
|
30
|
+
```
|
31
|
+
|
32
|
+
And next time when you run Cucumber, there will be tickets made for every
|
33
|
+
scenario.
|
34
|
+
|
35
|
+
## Future work
|
36
|
+
|
37
|
+
Here are some ideas you can send pull requests for:
|
38
|
+
|
39
|
+
* Add an option to enable/disable Cukebase, e.g. to run it only on a CI server
|
40
|
+
but not on your development machine.
|
41
|
+
* Add the ability to read credentials from a file.
|
42
|
+
* Mark tickets as obsolete when a scenario is removed instead of being
|
43
|
+
completed.
|
44
|
+
|
45
|
+
## Contributing
|
46
|
+
|
47
|
+
1. Fork it
|
48
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
49
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
50
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
51
|
+
5. Create new Pull Request
|
52
|
+
|
53
|
+
## License
|
54
|
+
|
55
|
+
Cukebase is MIT-licensed. I'm sure you can find a copy somewhere if you aren't
|
56
|
+
able to recite it by heart.
|
data/Rakefile
ADDED
data/cukebase.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/cukebase/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Emil Loer"]
|
6
|
+
gem.email = ["emil@bartune.nl"]
|
7
|
+
gem.description = %q{Cukebase provides integration between Cucumber and the Codebase ticketing system}
|
8
|
+
gem.summary = %q{Cukebase provides integration between Cucumber and the Codebase ticketing system}
|
9
|
+
gem.homepage = ""
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "cukebase"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Cukebase::VERSION
|
17
|
+
|
18
|
+
gem.add_dependency 'httparty'
|
19
|
+
gem.add_dependency 'activemodel'
|
20
|
+
gem.add_dependency 'active_attr'
|
21
|
+
end
|
data/lib/cukebase.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require "httparty"
|
2
|
+
require "active_model"
|
3
|
+
require "active_attr"
|
4
|
+
require "cukebase/version"
|
5
|
+
require "cukebase/config"
|
6
|
+
require "cukebase/request"
|
7
|
+
require "cukebase/project"
|
8
|
+
require "cukebase/ticketing_category"
|
9
|
+
require "cukebase/ticketing_status"
|
10
|
+
require "cukebase/ticket"
|
11
|
+
|
12
|
+
module Cukebase
|
13
|
+
def self.current_project
|
14
|
+
@current_project ||= Project.new Cukebase.config.project
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
if defined? Cucumber
|
19
|
+
Around do |scenario, block|
|
20
|
+
ticket_name = "#{scenario.title} (#{scenario.feature.title})"
|
21
|
+
project = Cukebase.current_project
|
22
|
+
ticket = project.ticket_for_name ticket_name
|
23
|
+
|
24
|
+
block.call
|
25
|
+
|
26
|
+
ticket.status_id = case scenario.status
|
27
|
+
when :undefined
|
28
|
+
project.undefined_status
|
29
|
+
when :pending
|
30
|
+
project.pending_status
|
31
|
+
when :passed
|
32
|
+
project.passed_status
|
33
|
+
when :failed
|
34
|
+
project.failed_status
|
35
|
+
else
|
36
|
+
project.invalid_status
|
37
|
+
end
|
38
|
+
|
39
|
+
# We want empty features to be undefined instead of completed (which is
|
40
|
+
# what Cucumber tells us)
|
41
|
+
ticket.status_id = project.undefined_status if scenario.raw_steps.empty?
|
42
|
+
|
43
|
+
ticket.save
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Cukebase
|
2
|
+
class Config
|
3
|
+
attr_accessor :host
|
4
|
+
attr_accessor :protocol
|
5
|
+
|
6
|
+
attr_accessor :username
|
7
|
+
attr_accessor :api_key
|
8
|
+
|
9
|
+
attr_accessor :project
|
10
|
+
attr_accessor :category
|
11
|
+
|
12
|
+
attr_accessor :normal_type
|
13
|
+
attr_accessor :regression_type
|
14
|
+
|
15
|
+
attr_accessor :undefined_status
|
16
|
+
attr_accessor :pending_status
|
17
|
+
attr_accessor :failed_status
|
18
|
+
attr_accessor :passed_status
|
19
|
+
attr_accessor :invalid_status
|
20
|
+
|
21
|
+
def initialize
|
22
|
+
@host = "api3.codebasehq.com"
|
23
|
+
@protocol = "https"
|
24
|
+
|
25
|
+
@category = "Cucumber"
|
26
|
+
|
27
|
+
@normal_type = "Feature"
|
28
|
+
@regression_type = "Regression"
|
29
|
+
|
30
|
+
@undefined_status = "Open (undefined steps)"
|
31
|
+
@pending_status = "Open (pending steps)"
|
32
|
+
@failed_status = "Open (failing steps)"
|
33
|
+
@passed_status = "Completed"
|
34
|
+
@invalid_status = "Invalid"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.config
|
39
|
+
@config ||= Config.new
|
40
|
+
yield @config if block_given?
|
41
|
+
@config
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Cukebase
|
2
|
+
class Project
|
3
|
+
attr_reader :undefined_status
|
4
|
+
attr_reader :pending_status
|
5
|
+
attr_reader :failed_status
|
6
|
+
attr_reader :passed_status
|
7
|
+
attr_reader :invalid_status
|
8
|
+
|
9
|
+
def initialize name
|
10
|
+
@name = name
|
11
|
+
|
12
|
+
@category = ticketing_category_id_for_name Cukebase.config.category
|
13
|
+
|
14
|
+
@undefined_status = ticketing_status_id_for_name Cukebase.config.undefined_status
|
15
|
+
@pending_status = ticketing_status_id_for_name Cukebase.config.pending_status
|
16
|
+
@failed_status = ticketing_status_id_for_name Cukebase.config.failed_status
|
17
|
+
@passed_status = ticketing_status_id_for_name Cukebase.config.passed_status
|
18
|
+
@invalid_status = ticketing_status_id_for_name Cukebase.config.invalid_status
|
19
|
+
end
|
20
|
+
|
21
|
+
def ticketing_categories
|
22
|
+
@ticketing_categories ||= Request.get("#{@name}/tickets/categories").parsed_response["ticketing_categories"].map do |hash|
|
23
|
+
TicketingCategory.new hash
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def ticketing_statuses
|
28
|
+
@ticketing_statuses ||= Request.get("#{@name}/tickets/statuses").parsed_response["ticketing_statuses"].map do |hash|
|
29
|
+
TicketingStatus.new hash
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def ticket_for_name name
|
34
|
+
data = Request.get("#{@name}/tickets", query: { query: "subject:\"#{name}\" category:\"#{Cukebase.config.category}\"" }).parsed_response["tickets"].first
|
35
|
+
|
36
|
+
if data
|
37
|
+
Ticket.new data
|
38
|
+
else
|
39
|
+
Ticket.new summary: name, category_id: @category, ticket_type: Cukebase.config.normal_type
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def ticketing_category_id_for_name name
|
44
|
+
ticketing_categories.find do |ticketing_category|
|
45
|
+
ticketing_category.name == name
|
46
|
+
end.try(:id) or raise "Could not find a Codebase ticket category with name \"#{name}\". Please create it first."
|
47
|
+
end
|
48
|
+
|
49
|
+
def ticketing_status_id_for_name name
|
50
|
+
ticketing_statuses.find do |ticketing_status|
|
51
|
+
ticketing_status.name == name
|
52
|
+
end.try(:id) or raise "Could not find a Codebase ticket status with name \"#{name}\". Please create it first."
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Cukebase
|
2
|
+
class Request
|
3
|
+
include HTTParty
|
4
|
+
|
5
|
+
format :xml
|
6
|
+
headers 'Accept' => 'application/xml'
|
7
|
+
headers 'Content-type' => 'application/xml'
|
8
|
+
|
9
|
+
[:get, :post, :put, :delete].each do |method_name|
|
10
|
+
define_singleton_method method_name do |url, *args, &block|
|
11
|
+
basic_auth Cukebase.config.username, Cukebase.config.api_key
|
12
|
+
super "#{Cukebase.config.protocol}://#{Cukebase.config.host}/#{url}", *args, &block
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Cukebase
|
2
|
+
class Ticket
|
3
|
+
include ActiveAttr::Model
|
4
|
+
|
5
|
+
attribute :ticket_id
|
6
|
+
attribute :summary
|
7
|
+
attribute :ticket_type
|
8
|
+
attribute :reporter_id
|
9
|
+
attribute :assignee_id
|
10
|
+
attribute :assignee
|
11
|
+
attribute :reporter
|
12
|
+
attribute :category_id
|
13
|
+
attribute :category
|
14
|
+
attribute :priority_id
|
15
|
+
attribute :priority
|
16
|
+
attribute :status_id
|
17
|
+
attribute :status
|
18
|
+
attribute :milestone_id
|
19
|
+
attribute :milestone
|
20
|
+
attribute :deadline
|
21
|
+
attribute :tags
|
22
|
+
attribute :estimated_time
|
23
|
+
attribute :project_id
|
24
|
+
|
25
|
+
attribute :created_at
|
26
|
+
attribute :updated_at
|
27
|
+
|
28
|
+
def self.wrap_setter name
|
29
|
+
define_method "#{name}=" do |value|
|
30
|
+
@changes[name] = value if @changes && value != send(name)
|
31
|
+
super value
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize *args, &block
|
36
|
+
super
|
37
|
+
|
38
|
+
@changes = {}
|
39
|
+
end
|
40
|
+
|
41
|
+
wrap_setter :status_id
|
42
|
+
wrap_setter :priority_id
|
43
|
+
wrap_setter :category_id
|
44
|
+
wrap_setter :assignee_id
|
45
|
+
wrap_setter :milestone_id
|
46
|
+
wrap_setter :summary
|
47
|
+
wrap_setter :tags
|
48
|
+
|
49
|
+
def update_ticket content
|
50
|
+
data = {}
|
51
|
+
|
52
|
+
data[:changes] = @changes if @changes.any?
|
53
|
+
data[:content] = content if content && self.content != content
|
54
|
+
|
55
|
+
if data.any?
|
56
|
+
Request.post "#{Cukebase.config.project}/tickets/#{ticket_id}/notes", body: data.to_xml(root: "ticket-note", skip_types: true, skip_instruct: true)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def create_ticket content
|
61
|
+
data = {}
|
62
|
+
data[:summary] = summary if summary?
|
63
|
+
data[:description] = content if content
|
64
|
+
data[:ticket_type] = ticket_type if ticket_type?
|
65
|
+
data[:category_id] = category_id if category_id?
|
66
|
+
data[:priority_id] = priority_id if priority_id?
|
67
|
+
data[:status_id] = status_id if status_id?
|
68
|
+
data[:assignee_id] = assignee_id if assignee_id?
|
69
|
+
data[:milestone_id] = milestone_id if milestone_id?
|
70
|
+
|
71
|
+
Request.post "#{Cukebase.config.project}/tickets", body: data.to_xml(root: "ticket", skip_types: true, skip_instruct: true)
|
72
|
+
end
|
73
|
+
|
74
|
+
def save content=nil
|
75
|
+
if ticket_id?
|
76
|
+
update_ticket content
|
77
|
+
else
|
78
|
+
create_ticket content
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
metadata
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cukebase
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Emil Loer
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-11-14 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: httparty
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: activemodel
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: active_attr
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description: Cukebase provides integration between Cucumber and the Codebase ticketing
|
63
|
+
system
|
64
|
+
email:
|
65
|
+
- emil@bartune.nl
|
66
|
+
executables: []
|
67
|
+
extensions: []
|
68
|
+
extra_rdoc_files: []
|
69
|
+
files:
|
70
|
+
- .gitignore
|
71
|
+
- Gemfile
|
72
|
+
- LICENSE
|
73
|
+
- README.md
|
74
|
+
- Rakefile
|
75
|
+
- cukebase.gemspec
|
76
|
+
- lib/cukebase.rb
|
77
|
+
- lib/cukebase/config.rb
|
78
|
+
- lib/cukebase/project.rb
|
79
|
+
- lib/cukebase/request.rb
|
80
|
+
- lib/cukebase/ticket.rb
|
81
|
+
- lib/cukebase/ticketing_category.rb
|
82
|
+
- lib/cukebase/ticketing_status.rb
|
83
|
+
- lib/cukebase/version.rb
|
84
|
+
homepage: ''
|
85
|
+
licenses: []
|
86
|
+
post_install_message:
|
87
|
+
rdoc_options: []
|
88
|
+
require_paths:
|
89
|
+
- lib
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
none: false
|
92
|
+
requirements:
|
93
|
+
- - ! '>='
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
requirements: []
|
103
|
+
rubyforge_project:
|
104
|
+
rubygems_version: 1.8.24
|
105
|
+
signing_key:
|
106
|
+
specification_version: 3
|
107
|
+
summary: Cukebase provides integration between Cucumber and the Codebase ticketing
|
108
|
+
system
|
109
|
+
test_files: []
|