jira_client 1.0.0

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.
Files changed (67) hide show
  1. data/.gitignore +19 -0
  2. data/.rspec +2 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +29 -0
  6. data/Rakefile +1 -0
  7. data/jira_client.gemspec +27 -0
  8. data/lib/jira_client.rb +121 -0
  9. data/lib/jira_client/api/comments.rb +19 -0
  10. data/lib/jira_client/api/issues.rb +62 -0
  11. data/lib/jira_client/api/projects.rb +19 -0
  12. data/lib/jira_client/api/server.rb +15 -0
  13. data/lib/jira_client/api/statuses.rb +20 -0
  14. data/lib/jira_client/api/users.rb +18 -0
  15. data/lib/jira_client/api/utils.rb +25 -0
  16. data/lib/jira_client/api/worklogs.rb +26 -0
  17. data/lib/jira_client/base.rb +54 -0
  18. data/lib/jira_client/comment.rb +12 -0
  19. data/lib/jira_client/configuration.rb +27 -0
  20. data/lib/jira_client/core_ext/string.rb +7 -0
  21. data/lib/jira_client/error/bad_request.rb +5 -0
  22. data/lib/jira_client/error/configuration_error.rb +5 -0
  23. data/lib/jira_client/error/issue_error.rb +5 -0
  24. data/lib/jira_client/error/resource_not_found.rb +5 -0
  25. data/lib/jira_client/error/unauthorized.rb +5 -0
  26. data/lib/jira_client/issue.rb +26 -0
  27. data/lib/jira_client/project.rb +5 -0
  28. data/lib/jira_client/server_info.rb +11 -0
  29. data/lib/jira_client/status.rb +7 -0
  30. data/lib/jira_client/timetracking.rb +6 -0
  31. data/lib/jira_client/user.rb +10 -0
  32. data/lib/jira_client/version.rb +3 -0
  33. data/lib/jira_client/worklog.rb +10 -0
  34. data/spec/fixtures/admin.json +17 -0
  35. data/spec/fixtures/basic_issue.json +6 -0
  36. data/spec/fixtures/comment.json +23 -0
  37. data/spec/fixtures/comments.json +30 -0
  38. data/spec/fixtures/invalid_assignee.json +6 -0
  39. data/spec/fixtures/invalid_comment.json +6 -0
  40. data/spec/fixtures/invalid_jql.json +6 -0
  41. data/spec/fixtures/issue_with_comments.json +33 -0
  42. data/spec/fixtures/issue_with_description.json +10 -0
  43. data/spec/fixtures/issue_with_status.json +15 -0
  44. data/spec/fixtures/issue_with_timetracking.json +16 -0
  45. data/spec/fixtures/issue_with_worklogs.json +34 -0
  46. data/spec/fixtures/issues.json +28 -0
  47. data/spec/fixtures/my_certificate.pem +52 -0
  48. data/spec/fixtures/no_issues_found.json +6 -0
  49. data/spec/fixtures/project.json +10 -0
  50. data/spec/fixtures/projects.json +22 -0
  51. data/spec/fixtures/server_info.json +14 -0
  52. data/spec/fixtures/status.json +7 -0
  53. data/spec/fixtures/statuses.json +16 -0
  54. data/spec/fixtures/user_doesnt_exist.json +6 -0
  55. data/spec/fixtures/users.json +22 -0
  56. data/spec/fixtures/worklog.json +31 -0
  57. data/spec/jira_client/api/comments_spec.rb +59 -0
  58. data/spec/jira_client/api/issues_spec.rb +314 -0
  59. data/spec/jira_client/api/projects_spec.rb +55 -0
  60. data/spec/jira_client/api/server_spec.rb +31 -0
  61. data/spec/jira_client/api/statuses_spec.rb +69 -0
  62. data/spec/jira_client/api/users_spec.rb +56 -0
  63. data/spec/jira_client/api/worklogs_spec.rb +86 -0
  64. data/spec/jira_client/configuration_spec.rb +78 -0
  65. data/spec/jira_client_spec.rb +49 -0
  66. data/spec/spec_helper.rb +56 -0
  67. metadata +226 -0
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ coverage
19
+ *.idea
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in jira-client.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Matthew Williams
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,29 @@
1
+ # JiraClient::Client
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'jira-client'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install jira-client
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'jira_client/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "jira_client"
8
+ spec.version = JiraClient::VERSION
9
+ spec.authors = ["Matthew Williams"]
10
+ spec.email = ["m.williams@me.com"]
11
+ spec.description = %q{A Ruby client for the Jira 5 REST API}
12
+ spec.summary = %q{A Ruby client for the Jira 5 REST API...}
13
+ spec.homepage = "https://github.com/mrwillihog/jira_client"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+
24
+ spec.add_runtime_dependency "rest-client"
25
+ spec.add_runtime_dependency "json"
26
+ spec.add_runtime_dependency "chronic_duration"
27
+ end
@@ -0,0 +1,121 @@
1
+ require "rest-client"
2
+ require "json"
3
+
4
+ require "jira_client/base"
5
+ require "jira_client/comment"
6
+ require "jira_client/configuration"
7
+ require "jira_client/issue"
8
+ require "jira_client/project"
9
+ require "jira_client/status"
10
+ require "jira_client/timetracking"
11
+ require "jira_client/user"
12
+ require "jira_client/worklog"
13
+ require "jira_client/api/comments"
14
+ require "jira_client/api/issues"
15
+ require "jira_client/api/projects"
16
+ require "jira_client/api/server"
17
+ require "jira_client/api/statuses"
18
+ require "jira_client/api/users"
19
+ require "jira_client/api/worklogs"
20
+ require "jira_client/core_ext/string"
21
+ require "jira_client/error/configuration_error"
22
+ require "jira_client/error/bad_request"
23
+ require "jira_client/error/issue_error"
24
+ require "jira_client/error/resource_not_found"
25
+ require "jira_client/error/unauthorized"
26
+
27
+ module JiraClient
28
+ class << self
29
+ include JiraClient::API::Comments
30
+ include JiraClient::API::Issues
31
+ include JiraClient::API::Projects
32
+ include JiraClient::API::Server
33
+ include JiraClient::API::Statuses
34
+ include JiraClient::API::Users
35
+ include JiraClient::API::Worklogs
36
+
37
+ attr_accessor :configuration
38
+ def configure
39
+ self.configuration ||= Configuration.new
40
+ begin
41
+ yield(configuration)
42
+ rescue NoMethodError => e
43
+ raise JiraClient::Error::ConfigurationError, "Unrecognized configuration option provided #{e.message}"
44
+ end
45
+ end
46
+
47
+ def reset!
48
+ self.configuration = nil
49
+ @resource = nil
50
+ end
51
+
52
+ private
53
+
54
+ def get(path, params={})
55
+ request(:get, path, :params => params)
56
+ end
57
+
58
+ def post(path, params={})
59
+ request(:post, path, params.to_json)
60
+ end
61
+
62
+ def put(path, params={})
63
+ request(:put, path, params.to_json)
64
+ end
65
+
66
+ def request(method, path, params={})
67
+ begin
68
+ response = resource[URI.encode(path)].send(method.to_sym, params)
69
+ snake_case!(JSON.parse(response, :symbolize_names => true)) unless response.empty?
70
+ rescue RestClient::ResourceNotFound => e
71
+ raise_error JiraClient::Error::ResourceNotFound, e
72
+ rescue RestClient::BadRequest => e
73
+ raise_error JiraClient::Error::BadRequest, e
74
+ rescue RestClient::Unauthorized => e
75
+ raise_error JiraClient::Error::Unauthorized, e
76
+ end
77
+ end
78
+
79
+ def raise_error(error_type, message_response)
80
+ raise error_type, JSON.parse(message_response.response)["errorMessages"].join
81
+ end
82
+
83
+ # Returns a RestClient resource
84
+ def resource
85
+ raise JiraClient::Error::ConfigurationError, "No configuration found. Please run JiraClient.configure" if JiraClient.configuration.nil?
86
+ @resource ||= begin
87
+ url = JiraClient.configuration.full_url
88
+ options = {
89
+ :headers => {:content_type => :json, :accept => :json}
90
+ }
91
+
92
+ RestClient.proxy = JiraClient.configuration.proxy
93
+
94
+ unless JiraClient.configuration.certificate.nil?
95
+ options[:ssl_client_cert] = OpenSSL::X509::Certificate.new File.read(JiraClient.configuration.certificate)
96
+ options[:ssl_client_key] = OpenSSL::PKey::RSA.new File.read(JiraClient.configuration.certificate), JiraClient.configuration.certificate_passphrase
97
+ options[:verify_ssl] = OpenSSL::SSL::VERIFY_NONE
98
+ else
99
+ # RestClient will ignore basic auth parameters if nil
100
+ options[:user] = JiraClient.configuration.username
101
+ options[:password] = JiraClient.configuration.password
102
+ end
103
+
104
+ RestClient::Resource.new(url, options)
105
+ end
106
+ end
107
+
108
+ # Convert CamelCaseKeys to snake_case_keys
109
+ def snake_case!(value)
110
+ case value
111
+ when Array
112
+ value.map {|v| snake_case!(v)}
113
+ when Hash
114
+ Hash[value.map {|k, v| [k.to_s.underscore.to_sym, snake_case!(v)] }]
115
+ else
116
+ value
117
+ end
118
+ end
119
+
120
+ end
121
+ end
@@ -0,0 +1,19 @@
1
+ require "jira_client/api/utils"
2
+
3
+ module JiraClient
4
+ module API
5
+ module Comments
6
+ include JiraClient::API::Utils
7
+
8
+ def find_issue_comments(key)
9
+ response = get("/issue/#{key}/comment")
10
+ response[:comments].map {|c| JiraClient::Comment.from_response c}
11
+ end
12
+
13
+ def comment_on_issue(key, message)
14
+ object_from_response(JiraClient::Comment, :post, "/issue/#{key}/comment", {:body => message})
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,62 @@
1
+ require "jira_client/api/utils"
2
+
3
+ module JiraClient
4
+ module API
5
+ module Issues
6
+ include JiraClient::API::Utils
7
+
8
+ def find_issues(params={})
9
+ response = post("/search", params)
10
+ response[:issues].map {|i| JiraClient::Issue.from_response i}
11
+ end
12
+
13
+ def find_issue_by_key(key, params={})
14
+ fields = params[:fields].join "," if params.has_key? :fields
15
+ url = "/issue/#{key}"
16
+ url << "?fields=#{fields}" if fields
17
+ object_from_response(JiraClient::Issue, :get, url)
18
+ end
19
+
20
+ def assign_issue(key, username)
21
+ put("/issue/#{key}/assignee", :name => username)
22
+ end
23
+
24
+ def close_issue(key, params={})
25
+ transition_to(key, JiraClient::Status::CLOSE, params)
26
+ end
27
+
28
+ def reopen_issue(key, params={})
29
+ transition_to(key, JiraClient::Status::REOPEN, params)
30
+ end
31
+
32
+ def resolve_issue(key, params={})
33
+ transition_to(key, JiraClient::Status::RESOLVE, params)
34
+ end
35
+
36
+ def start_progress_on_issue(key, params={})
37
+ transition_to(key, JiraClient::Status::START_PROGRESS, params)
38
+ end
39
+
40
+ private
41
+
42
+ def transition_to(key, transition, params={})
43
+ opts = {:transition => {:id => transition}}
44
+ if params.has_key? :as
45
+ opts[:fields] ||= {}
46
+ opts[:fields][:resolution] = {:name => params[:as]}
47
+ end
48
+ opts[:update] = comment_hash(params[:comment])
49
+
50
+ # Remove keys with nil values
51
+ opts.reject! {|k,v| v.nil?}
52
+ post("/issue/#{key}/transitions", opts)
53
+ end
54
+
55
+ def comment_hash(comment)
56
+ return unless comment
57
+ {:comment => [{:add => {:body => comment}}]}
58
+ end
59
+
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,19 @@
1
+ require "jira_client/api/utils"
2
+ require "jira_client/project"
3
+
4
+ module JiraClient
5
+ module API
6
+ module Projects
7
+ include JiraClient::API::Utils
8
+
9
+ def find_projects
10
+ objects_from_response(JiraClient::Project, :get, '/project')
11
+ end
12
+
13
+ def find_project_by_key(key)
14
+ object_from_response(JiraClient::Project, :get, "/project/#{key.to_s}")
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,15 @@
1
+ require "jira_client/api/utils"
2
+ require "jira_client/server_info"
3
+
4
+ module JiraClient
5
+ module API
6
+ module Server
7
+ include JiraClient::API::Utils
8
+
9
+ def server_info
10
+ object_from_response(JiraClient::ServerInfo, :get, "/serverInfo")
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,20 @@
1
+ require 'jira_client/api/utils'
2
+ require "jira_client/status"
3
+
4
+ module JiraClient
5
+ module API
6
+ module Statuses
7
+ include JiraClient::API::Utils
8
+
9
+ def find_statuses
10
+ objects_from_response(JiraClient::Status, :get, '/status')
11
+ end
12
+
13
+ def find_status_by_id(id)
14
+ object_from_response(JiraClient::Status, :get, "/status/#{id}")
15
+ end
16
+ alias :find_status_by_name :find_status_by_id
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,18 @@
1
+ require "jira_client/api/utils"
2
+
3
+ module JiraClient
4
+ module API
5
+ module Users
6
+ include JiraClient::API::Utils
7
+
8
+ def find_users(username)
9
+ objects_from_response(JiraClient::User, :get, "/user/search", :username => username)
10
+ end
11
+
12
+ def find_user_by_username(username)
13
+ object_from_response(JiraClient::User, :get, "/user", :username => username)
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,25 @@
1
+ module JiraClient
2
+ module API
3
+ module Utils
4
+
5
+ private
6
+
7
+ def objects_from_response(klass, request_method, path, options={})
8
+ response = send(request_method.to_sym, path, options)
9
+ objects_from_array(klass, response)
10
+ end
11
+
12
+ def objects_from_array(klass, array)
13
+ array.map do |element|
14
+ klass.from_response(element)
15
+ end
16
+ end
17
+
18
+ def object_from_response(klass, request_method, path, options={})
19
+ response = send(request_method.to_sym, path, options)
20
+ klass.from_response(response)
21
+ end
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,26 @@
1
+ require "chronic_duration"
2
+
3
+ module JiraClient
4
+ module API
5
+ module Worklogs
6
+
7
+ def create_worklog(key, time, opts={})
8
+ url = "/issue/#{key}/worklog"
9
+ url += "?adjustEstimate=new&newEstimate=#{opts[:remaining_estimate]}" if opts.has_key? :remaining_estimate
10
+ url += "?adjustEstimate=manual&reduceBy=#{opts[:reduce_estimate]}" if opts.has_key? :reduce_estimate
11
+ time_in_seconds = ChronicDuration.parse(time)
12
+ params = {
13
+ :timeSpentSeconds => time_in_seconds
14
+ }
15
+ params[:comment] = opts[:comment] if opts.has_key? :comment
16
+ post(url, params)
17
+ end
18
+
19
+ def find_issue_worklogs(key)
20
+ response = get("/issue/#{key}/worklog")
21
+ response[:worklogs].map {|w| JiraClient::Worklog.from_response w}
22
+ end
23
+
24
+ end
25
+ end
26
+ end