jira-ruby 1.4.3 → 1.5.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.
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