jira-ruby 1.4.3 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b066da05cd7aa4ef9d974970eeeaecff4934c1d5
4
- data.tar.gz: 25cad58db8476f90d18437d0508e2a1f6b9fb5a9
3
+ metadata.gz: 8705a4ea4d0393dbb5868ad95f420a45f58cea68
4
+ data.tar.gz: c8abf36c5a0a0d7cf4b2bd7f592d8cc5b32b7f64
5
5
  SHA512:
6
- metadata.gz: 1847cdcd17d471c02628540c313ed61d14cd260cd7217f79228b7ddead56ff0e5425afaf983cca7d08763dddf6544d60348f27f03a7377fb35a5ccae25c48383
7
- data.tar.gz: 041a206f7eaf3c564150d85bb330a3b2e8e9a6d4f1362c5da982c7e11d30da4e2b0d285081762b3e37ae06330ad8476728dd1bde70352d4b2f60cb523164e427
6
+ metadata.gz: 65f8792ced5b13ce0d3c2e629d7600ce1802cf1479c99f2aed61fc782748819482ef3a45e19affeebff6e23c9d57a8078f86901a8d43e557ba528c05644b052f
7
+ data.tar.gz: 72c988b648ae5a272a93b9cb4e655e90cadc4643fb2f6d51329d2dbd7d343d82599fbde0782d7100b58555923b9313a6edbb9a3419bf68a31f30e1f1eaf20d6a
data/.gitignore CHANGED
@@ -8,3 +8,4 @@ pkg/*
8
8
  *.pem
9
9
  .DS_STORE
10
10
  doc
11
+ .ruby-version
@@ -1,7 +1,8 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.3.1
3
+ - 2.3
4
+ - 2.4
4
5
  - ruby-head
5
6
  before_script:
6
7
  - rake jira:generate_public_cert
7
- script: bundle exec rake spec
8
+ script: bundle exec rake spec
data/README.md CHANGED
@@ -87,6 +87,8 @@ key.
87
87
  > After you have entered all the information click OK and ensure OAuth authentication is
88
88
  > enabled.
89
89
 
90
+ For 2 legged oauth in server mode only, not in cloud based JIRA, make sure to `Allow 2-Legged OAuth`
91
+
90
92
  ## Configuring JIRA to use HTTP Basic Auth
91
93
 
92
94
  Follow the same steps described above to set up a new Application Link in JIRA,
@@ -389,3 +391,33 @@ class App < Sinatra::Base
389
391
  end
390
392
  end
391
393
  ```
394
+
395
+ ## Using the API Gem in a 2 legged context
396
+
397
+ Here's an example on how to use 2 legged OAuth:
398
+ ```ruby
399
+ require 'rubygems'
400
+ require 'pp'
401
+ require 'jira-ruby'
402
+
403
+ options = {
404
+ :site => 'http://localhost:2990',
405
+ :context_path => '/jira',
406
+ :signature_method => 'RSA-SHA1',
407
+ :private_key_file => "rsakey.pem",
408
+ :rest_base_path => "/rest/api/2",
409
+ :auth_type => :oauth_2legged,
410
+ :consumer_key => "jira-ruby-example"
411
+ }
412
+
413
+ client = JIRA::Client.new(options)
414
+
415
+ client.set_access_token("","")
416
+
417
+ # Show all projects
418
+ projects = client.Project.all
419
+
420
+ projects.each do |project|
421
+ puts "Project -> key: #{project.key}, name: #{project.name}"
422
+ end
423
+ ```
data/example.rb CHANGED
@@ -99,7 +99,16 @@ client.Issue.jql(a_normal_jql_search, max_results: 500)
99
99
  # # Create an issue
100
100
  # # ---------------
101
101
  # issue = client.Issue.build
102
- # issue.save({"fields"=>{"summary"=>"blarg from in example.rb","project"=>{"id"=>"10001"},"issuetype"=>{"id"=>"3"}}})
102
+ # labels = ['label1', 'label2']
103
+ # issue.save({
104
+ # "fields" => {
105
+ # "summary" => "blarg from in example.rb",
106
+ # "project" => {"key" => "SAMPLEPROJECT"},
107
+ # "issuetype" => {"id" => "3"},
108
+ # "labels" => labels,
109
+ # "priority" => {"id" => "1"}
110
+ # }
111
+ # })
103
112
  # issue.fetch
104
113
  # pp issue
105
114
  #
@@ -447,7 +447,7 @@ module JIRA
447
447
  # [07/Jun/2015:15:17:18 +0400] "PUT /jira/rest/api/2/issue/10111 HTTP/1.1" 204 -
448
448
  def patched_url
449
449
  result = url
450
- return result if result.start_with?('/')
450
+ return result if result.start_with?('/', 'http')
451
451
  "/#{result}"
452
452
  end
453
453
 
@@ -52,6 +52,7 @@ module JIRA
52
52
  :rest_base_path => "/rest/api/2",
53
53
  :ssl_verify_mode => OpenSSL::SSL::VERIFY_PEER,
54
54
  :use_ssl => true,
55
+ :use_client_cert => false,
55
56
  :auth_type => :oauth,
56
57
  :http_debug => false
57
58
  }
@@ -61,8 +62,15 @@ module JIRA
61
62
  @options = options
62
63
  @options[:rest_base_path] = @options[:context_path] + @options[:rest_base_path]
63
64
 
65
+ if options[:use_client_cert]
66
+ raise ArgumentError, 'Options: :cert_path must be set when :use_client_cert is true' unless @options[:cert_path]
67
+ raise ArgumentError, 'Options: :key_path must be set when :use_client_cert is true' unless @options[:key_path]
68
+ @options[:cert] = OpenSSL::X509::Certificate.new(File.read(@options[:cert_path]))
69
+ @options[:key] = OpenSSL::PKey::RSA.new(File.read(@options[:key_path]))
70
+ end
71
+
64
72
  case options[:auth_type]
65
- when :oauth
73
+ when :oauth, :oauth_2legged
66
74
  @request_client = OauthClient.new(@options)
67
75
  @consumer = @request_client.consumer
68
76
  when :basic
@@ -75,7 +83,7 @@ module JIRA
75
83
  @options.delete(:username)
76
84
  @options.delete(:password)
77
85
  else
78
- raise ArgumentError, 'Options: ":auth_type" must be ":oauth", ":cookie" or ":basic"'
86
+ raise ArgumentError, 'Options: ":auth_type" must be ":oauth",":oauth_2legged", ":cookie" or ":basic"'
79
87
  end
80
88
 
81
89
  @http_debug = @options[:http_debug]
@@ -50,6 +50,10 @@ module JIRA
50
50
  end
51
51
  http_conn = http_class.new(uri.host, uri.port)
52
52
  http_conn.use_ssl = @options[:use_ssl]
53
+ if @options[:use_client_cert]
54
+ http_conn.cert = @options[:cert]
55
+ http_conn.key = @options[:key]
56
+ end
53
57
  http_conn.verify_mode = @options[:ssl_verify_mode]
54
58
  http_conn.read_timeout = @options[:read_timeout]
55
59
  http_conn
@@ -74,6 +74,18 @@ module JIRA
74
74
  end
75
75
 
76
76
  def make_request(http_method, path, body='', headers={})
77
+ # When using oauth_2legged we need to add an empty oauth_token parameter to every request.
78
+ if @options[:auth_type] == :oauth_2legged
79
+ oauth_params_str = "oauth_token="
80
+ uri = URI.parse(path)
81
+ if uri.query.to_s == ""
82
+ uri.query = oauth_params_str
83
+ else
84
+ uri.query = uri.query + "&" + oauth_params_str
85
+ end
86
+ path = uri.to_s
87
+ end
88
+
77
89
  case http_method
78
90
  when :delete, :get, :head
79
91
  response = access_token.send http_method, path, headers
@@ -43,12 +43,21 @@ module JIRA
43
43
  :nested_under => ['fields', 'watches']
44
44
 
45
45
  def self.all(client)
46
- url = client.options[:rest_base_path] + "/search?expand=transitions.fields"
47
- response = client.get(url)
48
- json = parse_json(response.body)
49
- json['issues'].map do |issue|
50
- client.Issue.build(issue)
46
+ start_at = 0
47
+ max_results = 1000
48
+ result = []
49
+ loop do
50
+ url = client.options[:rest_base_path] +
51
+ "/search?expand=transitions.fields&maxResults=#{max_results}&startAt=#{start_at}"
52
+ response = client.get(url)
53
+ json = parse_json(response.body)
54
+ json['issues'].map do |issue|
55
+ result.push(client.Issue.build(issue))
56
+ end
57
+ break if json['issues'].size == 0
58
+ start_at += json['issues'].size
51
59
  end
60
+ result
52
61
  end
53
62
 
54
63
  def self.jql(client, jql, options = {fields: nil, start_at: nil, max_results: nil, expand: nil, validate_query: true})
@@ -1,3 +1,3 @@
1
1
  module JIRA
2
- VERSION = '1.4.3'
2
+ VERSION = '1.5.0'
3
3
  end
@@ -46,8 +46,11 @@ describe JIRA::Resource::Issue do
46
46
  }
47
47
  }
48
48
  before(:each) do
49
- stub_request(:get, site_url + "/jira/rest/api/2/search?expand=transitions.fields").
49
+ stub_request(:get, site_url + "/jira/rest/api/2/search?expand=transitions.fields&maxResults=1000&startAt=0").
50
50
  to_return(:status => 200, :body => get_mock_response('issue.json'))
51
+
52
+ stub_request(:get, site_url + "/jira/rest/api/2/search?expand=transitions.fields&maxResults=1000&startAt=11").
53
+ to_return(:status => 200, :body => get_mock_response('empty_issues.json'))
51
54
  end
52
55
  it_should_behave_like "a resource with a collection GET endpoint"
53
56
  end
@@ -74,6 +74,36 @@ RSpec.shared_examples 'HttpClient tests' do
74
74
  end
75
75
  end
76
76
 
77
+ RSpec.shared_examples 'OAuth Common Tests' do
78
+ include_examples 'Client Common Tests'
79
+
80
+ specify { expect(subject.request_client).to be_a JIRA::OauthClient }
81
+
82
+ it 'allows setting an access token' do
83
+ token = double
84
+ expect(OAuth::AccessToken).to receive(:new).with(subject.consumer, '', '').and_return(token)
85
+
86
+ expect(subject.authenticated?).to be_falsey
87
+ access_token = subject.set_access_token('', '')
88
+ expect(access_token).to eq(token)
89
+ expect(subject.access_token).to eq(token)
90
+ expect(subject.authenticated?).to be_truthy
91
+ end
92
+
93
+ describe 'that call a oauth client' do
94
+ specify 'which makes a request' do
95
+ [:delete, :get, :head].each do |method|
96
+ expect(subject.request_client).to receive(:make_request).with(method, '/path', nil, headers).and_return(successful_response)
97
+ subject.send(method, '/path', {})
98
+ end
99
+ [:post, :put].each do |method|
100
+ expect(subject.request_client).to receive(:make_request).with(method, '/path', '', merged_headers).and_return(successful_response)
101
+ subject.send(method, '/path', '', {})
102
+ end
103
+ end
104
+ end
105
+ end
106
+
77
107
  describe JIRA::Client do
78
108
  let(:request) { subject.request_client.class }
79
109
  let(:successful_response) do
@@ -178,51 +208,16 @@ describe JIRA::Client do
178
208
  end
179
209
  end
180
210
 
181
- context 'oath2 authentication' do
211
+ context 'oauth authentication' do
182
212
  subject { JIRA::Client.new(consumer_key: 'foo', consumer_secret: 'bar') }
183
213
 
184
- include_examples 'Client Common Tests'
185
-
186
- specify { expect(subject.request_client).to be_a JIRA::OauthClient }
187
-
188
- it 'allows setting an access token' do
189
- token = double
190
- expect(OAuth::AccessToken).to receive(:new).with(subject.consumer, 'foo', 'bar').and_return(token)
191
-
192
- expect(subject.authenticated?).to be_falsey
193
- access_token = subject.set_access_token('foo', 'bar')
194
- expect(access_token).to eq(token)
195
- expect(subject.access_token).to eq(token)
196
- expect(subject.authenticated?).to be_truthy
197
- end
214
+ include_examples 'OAuth Common Tests'
215
+ end
198
216
 
199
- it 'allows initializing the access token' do
200
- request_token = OAuth::RequestToken.new(subject.consumer)
201
- allow(subject.consumer).to receive(:get_request_token).and_return(request_token)
202
- mock_access_token = double
203
- expect(request_token).to receive(:get_access_token).with(:oauth_verifier => 'abc123').and_return(mock_access_token)
204
- subject.init_access_token(:oauth_verifier => 'abc123')
205
- expect(subject.access_token).to eq(mock_access_token)
206
- end
217
+ context 'with oauth_2legged' do
218
+ subject { JIRA::Client.new(consumer_key: 'foo', consumer_secret: 'bar', auth_type: :oauth_2legged) }
207
219
 
208
- specify 'that has specific default options' do
209
- [:signature_method, :private_key_file].each do |key|
210
- expect(subject.options[key]).to eq(JIRA::Client::DEFAULT_OPTIONS[key])
211
- end
212
- end
213
-
214
- describe 'that call a oauth client' do
215
- specify 'which makes a request' do
216
- [:delete, :get, :head].each do |method|
217
- expect(subject.request_client).to receive(:make_request).with(method, '/path', nil, headers).and_return(successful_response)
218
- subject.send(method, '/path', {})
219
- end
220
- [:post, :put].each do |method|
221
- expect(subject.request_client).to receive(:make_request).with(method, '/path', '', merged_headers).and_return(successful_response)
222
- subject.send(method, '/path', '', {})
223
- end
224
- end
225
- end
220
+ include_examples 'OAuth Common Tests'
226
221
  end
227
222
  end
228
223
 
@@ -28,6 +28,15 @@ describe JIRA::HttpClient do
28
28
  JIRA::HttpClient.new(options)
29
29
  end
30
30
 
31
+ let(:basic_client_cert_client) do
32
+ options = JIRA::Client::DEFAULT_OPTIONS.merge(JIRA::HttpClient::DEFAULT_OPTIONS).merge(
33
+ :use_client_cert => true,
34
+ :cert => 'public certificate contents',
35
+ :key => 'private key contents'
36
+ )
37
+ JIRA::HttpClient.new(options)
38
+ end
39
+
31
40
  let(:response) do
32
41
  response = double("response")
33
42
  allow(response).to receive(:kind_of?).with(Net::HTTPSuccess).and_return(true)
@@ -170,6 +179,22 @@ describe JIRA::HttpClient do
170
179
  expect(basic_client.http_conn(uri)).to eq(http_conn)
171
180
  end
172
181
 
182
+ it 'can use client certificates' do
183
+ http_conn = double
184
+ uri = double
185
+ host = double
186
+ port = double
187
+ expect(Net::HTTP).to receive(:new).with(host, port).and_return(http_conn)
188
+ expect(uri).to receive(:host).and_return(host)
189
+ expect(uri).to receive(:port).and_return(port)
190
+ expect(http_conn).to receive(:use_ssl=).with(basic_client.options[:use_ssl])
191
+ expect(http_conn).to receive(:verify_mode=).with(basic_client.options[:ssl_verify_mode])
192
+ expect(http_conn).to receive(:read_timeout=).with(basic_client.options[:read_timeout])
193
+ expect(http_conn).to receive(:cert=).with(basic_client_cert_client.options[:cert])
194
+ expect(http_conn).to receive(:key=).with(basic_client_cert_client.options[:key])
195
+ expect(basic_client_cert_client.http_conn(uri)).to eq(http_conn)
196
+ end
197
+
173
198
  it "returns a http connection" do
174
199
  http_conn = double()
175
200
  uri = double()
@@ -107,5 +107,41 @@ describe JIRA::OauthClient do
107
107
  oauth_client.request(:get, '/foo', body, headers)
108
108
  end
109
109
  end
110
+
111
+ describe "auth type is oauth_2legged" do
112
+ let(:oauth__2legged_client) do
113
+ options = { :consumer_key => 'foo', :consumer_secret => 'bar', :auth_type => :oauth_2legged }
114
+ options = JIRA::Client::DEFAULT_OPTIONS.merge(options)
115
+ JIRA::OauthClient.new(options)
116
+ end
117
+
118
+ it "responds to the http methods adding oauth_token parameter" do
119
+ headers = double()
120
+ mock_access_token = double()
121
+ allow(oauth__2legged_client).to receive(:access_token).and_return(mock_access_token)
122
+ [:delete, :get, :head].each do |method|
123
+ expect(mock_access_token).to receive(method).with('/path?oauth_token=', headers).and_return(response)
124
+ oauth__2legged_client.make_request(method, '/path', '', headers)
125
+ end
126
+ [:post, :put].each do |method|
127
+ expect(mock_access_token).to receive(method).with('/path?oauth_token=', '', headers).and_return(response)
128
+ oauth__2legged_client.make_request(method, '/path', '', headers)
129
+ end
130
+ end
131
+
132
+ it "responds to the http methods adding oauth_token parameter to any existing parameters" do
133
+ headers = double()
134
+ mock_access_token = double()
135
+ allow(oauth__2legged_client).to receive(:access_token).and_return(mock_access_token)
136
+ [:delete, :get, :head].each do |method|
137
+ expect(mock_access_token).to receive(method).with('/path?any_param=toto&oauth_token=', headers).and_return(response)
138
+ oauth__2legged_client.make_request(method, '/path?any_param=toto', '', headers)
139
+ end
140
+ [:post, :put].each do |method|
141
+ expect(mock_access_token).to receive(method).with('/path?any_param=toto&oauth_token=', '', headers).and_return(response)
142
+ oauth__2legged_client.make_request(method, '/path?any_param=toto', '', headers)
143
+ end
144
+ end
145
+ end
110
146
  end
111
147
  end
@@ -37,11 +37,16 @@ describe JIRA::Resource::Issue do
37
37
 
38
38
  it "should find all issues" do
39
39
  response = double()
40
+ empty_response = double()
40
41
  issue = double()
41
42
 
42
43
  allow(response).to receive(:body).and_return('{"issues":[{"id":"1","summary":"Bugs Everywhere"}]}')
43
- expect(client).to receive(:get).with('/jira/rest/api/2/search?expand=transitions.fields').
44
+ expect(client).to receive(:get).with('/jira/rest/api/2/search?expand=transitions.fields&maxResults=1000&startAt=0').
44
45
  and_return(response)
46
+ allow(empty_response).to receive(:body).and_return('{"issues":[]}')
47
+ expect(client).to receive(:get).with('/jira/rest/api/2/search?expand=transitions.fields&maxResults=1000&startAt=1').
48
+ and_return(empty_response)
49
+
45
50
  expect(client).to receive(:Issue).and_return(issue)
46
51
  expect(issue).to receive(:build).with({"id"=>"1","summary"=>"Bugs Everywhere"})
47
52
 
@@ -0,0 +1,8 @@
1
+ {
2
+ "expand": "schema,names",
3
+ "startAt": 11,
4
+ "maxResults": 1000,
5
+ "total": 0,
6
+ "issues": [
7
+ ]
8
+ }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "expand": "schema,names",
3
3
  "startAt": 0,
4
- "maxResults": 50,
4
+ "maxResults": 1000,
5
5
  "total": 11,
6
6
  "issues": [
7
7
  {
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jira-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.3
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - SUMO Heavy Industries
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-08-25 00:00:00.000000000 Z
12
+ date: 2018-01-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: oauth
@@ -200,7 +200,6 @@ extensions: []
200
200
  extra_rdoc_files: []
201
201
  files:
202
202
  - ".gitignore"
203
- - ".ruby-version"
204
203
  - ".travis.yml"
205
204
  - Gemfile
206
205
  - Guardfile
@@ -292,6 +291,7 @@ files:
292
291
  - spec/mock_responses/component/10000.invalid.put.json
293
292
  - spec/mock_responses/component/10000.json
294
293
  - spec/mock_responses/component/10000.put.json
294
+ - spec/mock_responses/empty_issues.json
295
295
  - spec/mock_responses/field.json
296
296
  - spec/mock_responses/field/1.json
297
297
  - spec/mock_responses/issue.json
@@ -365,7 +365,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
365
365
  version: '0'
366
366
  requirements: []
367
367
  rubyforge_project: jira-ruby
368
- rubygems_version: 2.5.2
368
+ rubygems_version: 2.6.14
369
369
  signing_key:
370
370
  specification_version: 4
371
371
  summary: Ruby Gem for use with the Atlassian JIRA REST API
@@ -413,6 +413,7 @@ test_files:
413
413
  - spec/mock_responses/component/10000.invalid.put.json
414
414
  - spec/mock_responses/component/10000.json
415
415
  - spec/mock_responses/component/10000.put.json
416
+ - spec/mock_responses/empty_issues.json
416
417
  - spec/mock_responses/field.json
417
418
  - spec/mock_responses/field/1.json
418
419
  - spec/mock_responses/issue.json
@@ -1 +0,0 @@
1
- 2.3.3