jira_client 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +19 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/jira_client.gemspec +27 -0
- data/lib/jira_client.rb +121 -0
- data/lib/jira_client/api/comments.rb +19 -0
- data/lib/jira_client/api/issues.rb +62 -0
- data/lib/jira_client/api/projects.rb +19 -0
- data/lib/jira_client/api/server.rb +15 -0
- data/lib/jira_client/api/statuses.rb +20 -0
- data/lib/jira_client/api/users.rb +18 -0
- data/lib/jira_client/api/utils.rb +25 -0
- data/lib/jira_client/api/worklogs.rb +26 -0
- data/lib/jira_client/base.rb +54 -0
- data/lib/jira_client/comment.rb +12 -0
- data/lib/jira_client/configuration.rb +27 -0
- data/lib/jira_client/core_ext/string.rb +7 -0
- data/lib/jira_client/error/bad_request.rb +5 -0
- data/lib/jira_client/error/configuration_error.rb +5 -0
- data/lib/jira_client/error/issue_error.rb +5 -0
- data/lib/jira_client/error/resource_not_found.rb +5 -0
- data/lib/jira_client/error/unauthorized.rb +5 -0
- data/lib/jira_client/issue.rb +26 -0
- data/lib/jira_client/project.rb +5 -0
- data/lib/jira_client/server_info.rb +11 -0
- data/lib/jira_client/status.rb +7 -0
- data/lib/jira_client/timetracking.rb +6 -0
- data/lib/jira_client/user.rb +10 -0
- data/lib/jira_client/version.rb +3 -0
- data/lib/jira_client/worklog.rb +10 -0
- data/spec/fixtures/admin.json +17 -0
- data/spec/fixtures/basic_issue.json +6 -0
- data/spec/fixtures/comment.json +23 -0
- data/spec/fixtures/comments.json +30 -0
- data/spec/fixtures/invalid_assignee.json +6 -0
- data/spec/fixtures/invalid_comment.json +6 -0
- data/spec/fixtures/invalid_jql.json +6 -0
- data/spec/fixtures/issue_with_comments.json +33 -0
- data/spec/fixtures/issue_with_description.json +10 -0
- data/spec/fixtures/issue_with_status.json +15 -0
- data/spec/fixtures/issue_with_timetracking.json +16 -0
- data/spec/fixtures/issue_with_worklogs.json +34 -0
- data/spec/fixtures/issues.json +28 -0
- data/spec/fixtures/my_certificate.pem +52 -0
- data/spec/fixtures/no_issues_found.json +6 -0
- data/spec/fixtures/project.json +10 -0
- data/spec/fixtures/projects.json +22 -0
- data/spec/fixtures/server_info.json +14 -0
- data/spec/fixtures/status.json +7 -0
- data/spec/fixtures/statuses.json +16 -0
- data/spec/fixtures/user_doesnt_exist.json +6 -0
- data/spec/fixtures/users.json +22 -0
- data/spec/fixtures/worklog.json +31 -0
- data/spec/jira_client/api/comments_spec.rb +59 -0
- data/spec/jira_client/api/issues_spec.rb +314 -0
- data/spec/jira_client/api/projects_spec.rb +55 -0
- data/spec/jira_client/api/server_spec.rb +31 -0
- data/spec/jira_client/api/statuses_spec.rb +69 -0
- data/spec/jira_client/api/users_spec.rb +56 -0
- data/spec/jira_client/api/worklogs_spec.rb +86 -0
- data/spec/jira_client/configuration_spec.rb +78 -0
- data/spec/jira_client_spec.rb +49 -0
- data/spec/spec_helper.rb +56 -0
- metadata +226 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
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"
|
data/jira_client.gemspec
ADDED
@@ -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
|
data/lib/jira_client.rb
ADDED
@@ -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
|