taskmapper-kanbanpad 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/.document +5 -0
  2. data/.rbenv-gemsets +1 -0
  3. data/.rbenv-version +1 -0
  4. data/.travis.yml +4 -0
  5. data/Gemfile +15 -0
  6. data/Gemfile.lock +51 -0
  7. data/LICENSE +22 -0
  8. data/README.md +39 -0
  9. data/Rakefile +43 -0
  10. data/VERSION +1 -0
  11. data/lib/kanbanpad/kanbanpad-api.rb +126 -0
  12. data/lib/provider/comment.rb +69 -0
  13. data/lib/provider/kanbanpad.rb +34 -0
  14. data/lib/provider/project.rb +78 -0
  15. data/lib/provider/ticket.rb +127 -0
  16. data/lib/taskmapper-kanbanpad.rb +6 -0
  17. data/spec/fixtures/comments.json +1 -0
  18. data/spec/fixtures/comments/4ef2719bf17365000110df9e.json +1 -0
  19. data/spec/fixtures/projects.json +8 -0
  20. data/spec/fixtures/projects.xml +23 -0
  21. data/spec/fixtures/projects/be74b643b64e3dc79aa0.json +2 -0
  22. data/spec/fixtures/projects/be74b643b64e3dc79aa0.xml +13 -0
  23. data/spec/fixtures/projects/create.json +1 -0
  24. data/spec/fixtures/projects/create.xml +1 -0
  25. data/spec/fixtures/projects/test.rb +7 -0
  26. data/spec/fixtures/steps/4dc312f49bd0ff6c37000040.json +1 -0
  27. data/spec/fixtures/tasks.json +2 -0
  28. data/spec/fixtures/tasks.xml +25 -0
  29. data/spec/fixtures/tasks/4cd428c496f0734eef000007.json +3 -0
  30. data/spec/fixtures/tasks/4cd428c496f0734eef000007.xml +14 -0
  31. data/spec/fixtures/tasks/4cd428c496f0734eef000008.json +1 -0
  32. data/spec/fixtures/tasks/4cd428c496f0734eef000008.xml +13 -0
  33. data/spec/fixtures/tasks/4dc31c4c9bd0ff6c3700004e.json +1 -0
  34. data/spec/fixtures/tasks/create.xml +1 -0
  35. data/spec/project_comments_spec.rb +37 -0
  36. data/spec/projects_spec.rb +49 -0
  37. data/spec/spec.opts +3 -0
  38. data/spec/spec_helper.rb +14 -0
  39. data/spec/ticket_comments_spec.rb +55 -0
  40. data/spec/ticketmaster-kanbanpad_spec.rb +11 -0
  41. data/spec/tickets_spec.rb +105 -0
  42. data/taskmapper-kanbanpad.gemspec +98 -0
  43. metadata +172 -0
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ EADME.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.rbenv-gemsets ADDED
@@ -0,0 +1 @@
1
+ ticketmaster-kanbanpad
data/.rbenv-version ADDED
@@ -0,0 +1 @@
1
+ 1.9.3-rc1
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ gem "taskmapper", "~> 0.8"
7
+ # Add dependencies to develop your gem here.
8
+ # Include everything needed to run rake, tests, features, etc.
9
+ group :development do
10
+ gem "rspec", "~> 2.8"
11
+ gem "bundler", "~> 1.1"
12
+ gem "jeweler", "~> 1.6"
13
+ gem "simplecov", "~> 0.5", :platforms => :ruby_19
14
+ gem "rcov", "~> 1.0", :platforms => :ruby_18
15
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,51 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activemodel (3.2.3)
5
+ activesupport (= 3.2.3)
6
+ builder (~> 3.0.0)
7
+ activeresource (3.2.3)
8
+ activemodel (= 3.2.3)
9
+ activesupport (= 3.2.3)
10
+ activesupport (3.2.3)
11
+ i18n (~> 0.6)
12
+ multi_json (~> 1.0)
13
+ builder (3.0.0)
14
+ diff-lcs (1.1.3)
15
+ git (1.2.5)
16
+ hashie (1.2.0)
17
+ i18n (0.6.0)
18
+ jeweler (1.6.4)
19
+ bundler (~> 1.0)
20
+ git (>= 1.2.5)
21
+ rake
22
+ multi_json (1.0.4)
23
+ rake (0.9.2.2)
24
+ rcov (1.0.0)
25
+ rspec (2.8.0)
26
+ rspec-core (~> 2.8.0)
27
+ rspec-expectations (~> 2.8.0)
28
+ rspec-mocks (~> 2.8.0)
29
+ rspec-core (2.8.0)
30
+ rspec-expectations (2.8.0)
31
+ diff-lcs (~> 1.1.2)
32
+ rspec-mocks (2.8.0)
33
+ simplecov (0.5.4)
34
+ multi_json (~> 1.0.3)
35
+ simplecov-html (~> 0.5.3)
36
+ simplecov-html (0.5.3)
37
+ taskmapper (0.8.0)
38
+ activeresource (~> 3.0)
39
+ activesupport (~> 3.0)
40
+ hashie (~> 1.2)
41
+
42
+ PLATFORMS
43
+ ruby
44
+
45
+ DEPENDENCIES
46
+ bundler (~> 1.1)
47
+ jeweler (~> 1.6)
48
+ rcov (~> 1.0)
49
+ rspec (~> 2.8)
50
+ simplecov (~> 0.5)
51
+ taskmapper (~> 0.8)
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2010 YOU
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ NONE
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,39 @@
1
+ # taskmapper-kanbanpad
2
+
3
+ This is the provider for interaction with [kanbanpad](https://www.kanbanpad.com) using [taskmapper](http://ticketrb.com)
4
+
5
+ # Usage
6
+
7
+ Initialize the kanbanpad taskmapper instance using a username and api key:
8
+
9
+ kanbanpad = taskmapper.new(:kanbanpad, :username => 'you', :password => 'api_key')
10
+
11
+
12
+ ## Requirements
13
+
14
+ * rubygems (obviously)
15
+ * taskmapper gem (latest version preferred)
16
+ * jeweler gem (only if you want to repackage and develop)
17
+
18
+ The taskmapper gem should automatically be installed during the installation of this gem if it is not already installed.
19
+
20
+ ## Other Notes
21
+
22
+ Since this and the taskmapper gem is still primarily a work-in-progress, minor changes may be incompatible with previous versions. Please be careful about using and updating this gem in production.
23
+
24
+ If you see or find any issues, feel free to open up an issue report.
25
+
26
+
27
+ ## Note on Patches/Pull Requests
28
+
29
+ * Fork the project.
30
+ * Make your feature addition or bug fix.
31
+ * Add tests for it. This is important so I don't break it in a
32
+ future version unintentionally.
33
+ * Commit, do not mess with rakefile, version, or history.
34
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
35
+ * Send me a pull request. Bonus points for topic branches.
36
+
37
+ ## Copyright
38
+
39
+ Copyright (c) 2010-2011 The Hybrid Group. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,43 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "taskmapper-kanbanpad"
8
+ gem.summary = %Q{taskmapper Provider for Kanbanpad}
9
+ gem.description = %Q{Allows taskmapper to interact with kanbanpad.}
10
+ gem.email = "sonia@hybridgroup.com"
11
+ gem.homepage = "http://github.com/hybridgroup/taskmapper-kanbanpad"
12
+ gem.authors = ["HybridGroup"]
13
+ gem.add_development_dependency "rspec", ">= 1.2.9"
14
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
19
+ end
20
+
21
+ require 'rspec/core'
22
+ require 'rspec/core/rake_task'
23
+ RSpec::Core::RakeTask.new(:spec) do |spec|
24
+ spec.pattern = FileList['spec/**/*_spec.rb']
25
+ end
26
+
27
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
28
+ spec.pattern = 'spec/**/*_spec.rb'
29
+ spec.rcov = true
30
+ end
31
+
32
+ task :default => :spec
33
+
34
+ require 'rake/rdoctask' # TODO This produces a warning
35
+ #require 'rdoc/task'
36
+ Rake::RDocTask.new do |rdoc|
37
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
38
+
39
+ rdoc.rdoc_dir = 'rdoc'
40
+ rdoc.title = "taskmapper-kanbanpad#{version}"
41
+ rdoc.rdoc_files.include('README*')
42
+ rdoc.rdoc_files.include('lib/**/*.rb')
43
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.7.0
@@ -0,0 +1,126 @@
1
+ require 'rubygems'
2
+ require 'active_support'
3
+ require 'active_resource'
4
+
5
+ # Ruby lib for working with the Kanbanpad API's XML interface.
6
+ # You should set the authentication using your login
7
+ # credentials with HTTP Basic Authentication.
8
+ #
9
+ # using email and user api key
10
+ # KanbanpadAPI.authenticate('rick@techno-weenie.net', '70b4b722d55387286b817642289392a64d20b25e')
11
+ #
12
+ #
13
+ # This library is a small wrapper around the REST interface.
14
+
15
+ module KanbanpadAPI
16
+ class Error < StandardError; end
17
+ class << self
18
+
19
+ # Sets up basic authentication credentials for all the resources.
20
+ def authenticate(email, password)
21
+ @email = email
22
+ @password = password
23
+ self::Base.user = email
24
+ self::Base.password = password
25
+ end
26
+
27
+ def resources
28
+ @resources ||= []
29
+ end
30
+ end
31
+
32
+ class Base < ActiveResource::Base
33
+ self.site = "https://www.kanbanpad.com/api/v1/"
34
+ self.format = :json
35
+ def self.inherited(base)
36
+ KanbanpadAPI.resources << base
37
+ super
38
+ end
39
+ end
40
+
41
+ # Find projects
42
+ #
43
+ # KanbanpadAPI::Project.find(:all) # find all projects for the current account.
44
+ # KanbanpadAPI::Project.find('7e2cad4b3cbe5954950c') # find individual project by slug
45
+ #
46
+ #
47
+ # Finding tickets
48
+ #
49
+ # project = KanbanpadAPI::Project.find('7e2cad4b3cbe5954950c')
50
+ # project.tickets
51
+ #
52
+ # Finding finished tickets from project
53
+ #
54
+ # KanbanpadAPI::Task.finished('7e2cad4b3cbe5954950c')
55
+ #
56
+
57
+ class Project < Base
58
+
59
+ def tasks(slug, options = {})
60
+ Task.find(:all, :params => options.update(:project_id => slug, :backlog => 'yes', :finished => 'yes'))
61
+ end
62
+
63
+ def steps(options = {})
64
+ Step.find(:all, :params => options.update(:project_id => slug))
65
+ end
66
+
67
+ def comments(options = {})
68
+ ProjectComment.find(:all, :params => options.update(:project_id => slug))
69
+ end
70
+ end
71
+
72
+ class TaskList < Base
73
+ self.element_name = 'task'
74
+ self.site += 'projects/:project_id/'
75
+
76
+ def self.finished(project_id, options = {})
77
+ find(:all, :params => options.merge(:slug => project_id), :from => :finished)
78
+ end
79
+
80
+ def self.backlog(project_id, options = {})
81
+ find(:all, :params => options.merge(:slug => project_id), :from => :backlog)
82
+ end
83
+
84
+ def comments(options = {})
85
+ TaskComment.find(:all, :params => options.merge(prefix_options).update(:id => id))
86
+ end
87
+ end
88
+
89
+ class Task < Base
90
+ self.site += 'projects/:project_id/steps/:step_id/'
91
+ end
92
+
93
+ class Step < Base
94
+ self.site += 'projects/:project_id/'
95
+
96
+ def tickets(options = {})
97
+ Task.find(:all, :params => options.merge(prefix_options))
98
+ end
99
+ end
100
+
101
+ class ProjectComment < Base
102
+ self.site += 'projects/:project_id/'
103
+ self.element_name = 'comment'
104
+ end
105
+
106
+ class TaskComment < Base
107
+ self.site += 'projects/:project_id/tasks/:task_id'
108
+ self.element_name = 'comment'
109
+
110
+ def self.element_path(id, prefix_options = {}, query_options = nil)
111
+ prefix_options, query_options = split_options(prefix_options) if query_options.nil?
112
+ "#{prefix(prefix_options)}#{collection_name}.#{format.extension}#{query_string(query_options)}"
113
+ end
114
+ end
115
+
116
+ class TaskCommentCreator < Base
117
+ self.site += 'projects/:project_id/steps/:step_id/tasks/:task_id'
118
+ self.element_name = 'comment'
119
+
120
+ def self.element_path(id, prefix_options = {}, query_options = nil)
121
+ prefix_options, query_options = split_options(prefix_options) if query_options.nil?
122
+ "#{prefix(prefix_options)}#{collection_name}.#{format.extension}#{query_string(query_options)}"
123
+ end
124
+
125
+ end
126
+ end
@@ -0,0 +1,69 @@
1
+ module TaskMapper::Provider
2
+ module Kanbanpad
3
+ # The comment class for taskmapper-kanbanpad
4
+ #
5
+ # Do any mapping between taskmapper and your system's comment model here
6
+ # versions of the ticket.
7
+ #
8
+ # Not supported by Kanbanpad API
9
+ class Comment < TaskMapper::Provider::Base::Comment
10
+ # declare needed overloaded methods here
11
+ API = KanbanpadAPI::TaskComment
12
+
13
+ def initialize(*object)
14
+ if object.first
15
+ object = object.first
16
+ unless object.is_a? Hash
17
+ hash = {:id => object.id,
18
+ :author => object.author,
19
+ :body => object.body,
20
+ :created_at => object.created_at,
21
+ :updated_at => object.updated_at}
22
+ else
23
+ hash = object
24
+ end
25
+ super hash
26
+ end
27
+ end
28
+
29
+ def self.find_by_id(project_id, ticket_id, id)
30
+ self.search(project_id, ticket_id).select { |ticket| ticket.id == id }.first
31
+ end
32
+
33
+ def self.find_by_attributes(project_id, ticket_id, attributes = {})
34
+ search_by_attribute(self.search(project_id, ticket_id), attributes)
35
+ end
36
+
37
+ def self.search(project_id, ticket_id, options = {}, limit = 1000)
38
+ comments = API.find(:all, :params => {:project_id => project_id, :task_id => ticket_id}).collect { |comment| self.new comment }
39
+ end
40
+
41
+ def updated_at
42
+ @updated_at ||= begin
43
+ Time.parse(self[:updated_at])
44
+ rescue
45
+ self[:updated_at]
46
+ end
47
+ end
48
+
49
+ def created_at
50
+ @updated_at ||= begin
51
+ Time.parse(self[:created_at])
52
+ rescue
53
+ self[:created_at]
54
+ end
55
+ end
56
+
57
+ def self.create(project_id, ticket_id, step_id, *options)
58
+ options.first.merge!(
59
+ :project_id => project_id,
60
+ :task_id => ticket_id,
61
+ :step_id => step_id)
62
+ task_comment = KanbanpadAPI::TaskCommentCreator.new(options.first)
63
+ task_comment.save
64
+ self.new task_comment
65
+ end
66
+
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,34 @@
1
+ module TaskMapper::Provider
2
+ # This is the Kanbanpad Provider for taskmapper
3
+
4
+ module Kanbanpad
5
+ include TaskMapper::Provider::Base
6
+ TICKET_API = KanbanpadAPI::Task
7
+ PROJECT_API = KanbanpadAPI::Project
8
+
9
+ # This is for cases when you want to instantiate using TaskMapper::Provider::Kanbanpad.new(auth)
10
+ def self.new(auth = {})
11
+ TaskMapper.new(:kanbanpad, auth)
12
+ end
13
+
14
+ # The authorize and initializer for this provider
15
+ def authorize(auth = {})
16
+ @authentication ||= TaskMapper::Authenticator.new(auth)
17
+ auth = @authentication
18
+ if (auth.username.blank? and auth.email.blank?) and (auth.token.blank? and auth.password.blank?)
19
+ raise "Please provide at least a set of username and password)"
20
+ end
21
+ KanbanpadAPI.authenticate((auth.username.blank? ? auth.email : auth.username), (auth.password.blank? ? auth.token : auth.password))
22
+ end
23
+
24
+ def valid?
25
+ begin
26
+ PROJECT_API.find(:first).nil?
27
+ true
28
+ rescue
29
+ false
30
+ end
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,78 @@
1
+ module TaskMapper::Provider
2
+ module Kanbanpad
3
+ # Project class for taskmapper-kanbanpad
4
+ #
5
+ #
6
+ class Project < TaskMapper::Provider::Base::Project
7
+ # declare needed overloaded methods here
8
+ API = KanbanpadAPI::Project
9
+ COMMENT_API = KanbanpadAPI::ProjectComment
10
+
11
+ def initialize(*object)
12
+ if object.first
13
+ object = object.first
14
+ @system_data = {:client => object}
15
+ unless object.is_a? Hash
16
+ hash = {:id => object.slug,
17
+ :name => object.name,
18
+ :slug => object.slug,
19
+ :created_at => object.created_at,
20
+ :updated_at => object.updated_at}
21
+ else
22
+ hash = object
23
+ end
24
+ super hash
25
+ end
26
+ end
27
+
28
+ # copy from this.copy(that) copies that into this
29
+ def copy(project)
30
+ project.tickets.each do |ticket|
31
+ copy_ticket = self.ticket!(:title => ticket.title, :description => ticket.description)
32
+ ticket.comments.each do |comment|
33
+ copy_ticket.comment!(:body => comment.body)
34
+ sleep 1
35
+ end
36
+ end
37
+ end
38
+
39
+ def id
40
+ self[:slug]
41
+ end
42
+
43
+ def created_at
44
+ begin
45
+ Time.parse(self[:created_at])
46
+ rescue
47
+ self[:created_at]
48
+ end
49
+ end
50
+
51
+ def updated_at
52
+ begin
53
+ Time.parse(self[:updated_at])
54
+ rescue
55
+ self[:updated_at]
56
+ end
57
+ end
58
+
59
+ def comment!(attributes)
60
+ comment = create_comment attributes
61
+ Comment.new(comment.attributes.merge :project_id => id) if comment.save
62
+ end
63
+
64
+ def comments
65
+ find_comments.map { |c| Comment.new c.attributes }
66
+ end
67
+
68
+ private
69
+ def find_comments
70
+ COMMENT_API.find(:all, :params => { :project_id => id })
71
+ end
72
+
73
+ def create_comment(attributes)
74
+ COMMENT_API.new(attributes.merge(:project_id => id))
75
+ end
76
+ end
77
+ end
78
+ end