jira-ruby 0.1.16 → 0.1.17

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: 2e40d5ee749de621839801a5e80f92e4cda3325d
4
- data.tar.gz: 35a5726e608c149b40ee31fbbd5d262876bfc710
3
+ metadata.gz: 2ff744bcd9ad2d2787f07ecf627888484805cadf
4
+ data.tar.gz: ae9c78df7d9b0de9fb35bdfb0671119240211a91
5
5
  SHA512:
6
- metadata.gz: cdc3298da60ff9bd8553253c6abe2d87c7402bd970678d49e889f6b642f774654f80a234ab2a58ae2d066db84d9c1e5d329d72c59ac6c48a87226eba15e0ca8f
7
- data.tar.gz: 42c0599010e58238193759fd88d0ad8b4a529311862432610f8e175fa3e584f8e3264dbebca71a029c1be791341aa280e6ebe6c2521e5045699cecb18ecda002
6
+ metadata.gz: d118f8da88f23970bb406d4cfabec43eb19fc4178fddc4c9ec9e9c893933dff4b0aa6c3aa56fdcfc92a1ee43817f8ba39d1b03d2a1645c950528bf104eebcbcd
7
+ data.tar.gz: 4a9a20b2c3ecb34c7ff79c87cbf0546ec5bbb89700a3655066fd4060d5b9fa4e8dbaf68e66d40f7a8ec02b36c96712be8af4889d6618f50a603ed85f91611c6f
@@ -1,6 +1,6 @@
1
1
  = JIRA API Gem
2
2
  {<img src="https://codeclimate.com/github/sumoheavy/jira-ruby.png" />}[https://codeclimate.com/github/sumoheavy/jira-ruby]
3
- {<img src="https://travis-ci.org/sumoheavy/jira-ruby.png?branch=master"}[https://travis-ci.org/sumoheavy/jira-ruby]
3
+ {<img src="https://travis-ci.org/sumoheavy/jira-ruby.png?branch=master" />}[https://travis-ci.org/sumoheavy/jira-ruby]
4
4
 
5
5
  This gem provides access to the Atlassian JIRA REST API.
6
6
 
@@ -80,7 +80,7 @@ of JIRA.
80
80
  require 'pp'
81
81
  require 'jira'
82
82
 
83
- # Consider the use of :use_ssl and :ssl_verify_mode options if running locally
83
+ # Consider the use of :use_ssl and :ssl_verify_mode options if running locally
84
84
  # for tests.
85
85
 
86
86
  username = "myremoteuser"
@@ -91,14 +91,15 @@ of JIRA.
91
91
  :password => password,
92
92
  :site => 'http://localhost:8080/',
93
93
  :context_path => '/myjira',
94
- :auth_type => :basic
94
+ :auth_type => :basic,
95
+ :read_timeout => 120
95
96
  }
96
97
 
97
98
  client = JIRA::Client.new(options)
98
99
 
99
100
  # Show all projects
100
101
  projects = client.Project.all
101
-
102
+
102
103
  projects.each do |project|
103
104
  puts "Project -> key: #{project.key}, name: #{project.name}"
104
105
  end
@@ -135,7 +136,7 @@ errors are handled gracefully
135
136
  private
136
137
 
137
138
  def get_jira_client
138
-
139
+
139
140
  # add any extra configuration options for your instance of JIRA,
140
141
  # e.g. :use_ssl, :ssl_verify_mode, :context_path, :site
141
142
  options = {
@@ -148,8 +149,8 @@ errors are handled gracefully
148
149
  # Add AccessToken if authorised previously.
149
150
  if session[:jira_auth]
150
151
  @jira_client.set_access_token(
151
- session[:jira_auth][:access_token],
152
- session[:jira_auth][:access_key]
152
+ session[:jira_auth]['access_token'],
153
+ session[:jira_auth]['access_key']
153
154
  )
154
155
  end
155
156
  end
@@ -253,7 +254,7 @@ Here's the same example as a Sinatra application:
253
254
  if !session[:jira_auth]
254
255
  # not logged in
255
256
  <<-eos
256
- <h1>jira-ruby (JIRA 5 Ruby Gem) demo </h1>You're not signed in. Why don't you
257
+ <h1>jira-ruby (JIRA 5 Ruby Gem) demo </h1>You're not signed in. Why don't you
257
258
  <a href=/signin>sign in</a> first.
258
259
  eos
259
260
  else
@@ -262,25 +263,25 @@ Here's the same example as a Sinatra application:
262
263
 
263
264
  # HTTP response inlined with bind data below...
264
265
  <<-eos
265
- You're now signed in. There #{@issues.count == 1 ? "is" : "are"} #{@issues.count}
266
+ You're now signed in. There #{@issues.count == 1 ? "is" : "are"} #{@issues.count}
266
267
  issue#{@issues.count == 1 ? "" : "s"} in this JIRA instance. <a href='/signout'>Signout</a>
267
268
  eos
268
269
  end
269
270
  end
270
271
 
271
272
  # http://<yourserver>/signin
272
- # Initiates the OAuth dance by first requesting a token then redirecting to
273
+ # Initiates the OAuth dance by first requesting a token then redirecting to
273
274
  # http://<yourserver>/auth to get the @access_token
274
275
  get '/signin' do
275
276
  request_token = @jira_client.request_token
276
277
  session[:request_token] = request_token.token
277
278
  session[:request_secret] = request_token.secret
278
279
 
279
- redirect request_token.authorize_url
280
+ redirect request_token.authorize_url
280
281
  end
281
282
 
282
283
  # http://<yourserver>/callback
283
- # Retrieves the @access_token then stores it inside a session cookie. In a real app,
284
+ # Retrieves the @access_token then stores it inside a session cookie. In a real app,
284
285
  # you'll want to persist the token in a datastore associated with the user.
285
286
  get "/callback/" do
286
287
  request_token = @jira_client.set_request_token(
data/example.rb CHANGED
@@ -117,3 +117,60 @@ pp issue
117
117
  # # Update an existing comment
118
118
  # # --------------------------
119
119
  # issue.comments.first.save({"body" => "an updated comment frome example.rb"})
120
+
121
+ # List all available link types
122
+ # ------------------------------
123
+ pp client.Issuelinktype.all
124
+
125
+ # List issue's links
126
+ # -------------------------
127
+ issue = client.Issue.find("10002")
128
+ pp issue.issuelinks
129
+
130
+ # Link two issues (on the same Jira instance)
131
+ # --------------------------------------------
132
+ link = client.Issuelink.build
133
+ link.save(
134
+ {
135
+ :type => {:name => 'Relates'},
136
+ :inwardIssue => {:key => 'AL-1'},
137
+ :outwardIssue => {:key => 'AL-2'}
138
+ }
139
+ )
140
+
141
+ # List issue's remote links
142
+ # -------------------------
143
+ pp issue.remotelink.all
144
+
145
+ # Link two remote issues (on the different Jira instance)
146
+ # In order to add remote links, you have to add
147
+ # Application Links between two Jira instances first.
148
+ # More information:
149
+ # https://developer.atlassian.com/jiradev/jira-platform/guides/other/guide-jira-remote-issue-links/fields-in-remote-issue-links
150
+ # http://stackoverflow.com/questions/29850252/jira-api-issuelink-connect-two-different-instances
151
+ # -------------------------------------------------------
152
+ client_1 = JIRA::Client.new(options)
153
+ client_2 = JIRA::Client.new(options)
154
+
155
+ # you have to search for your app id here, instead of getting the first
156
+ client_2_app_link = client_2.ApplicationLink.manifest
157
+ issue_1 = client_1.Issue.find('BB-2')
158
+ issue_2 = client_2.Issue.find('AA-1')
159
+
160
+ remote_link = issue_2.remotelink.build
161
+
162
+ remote_link.save(
163
+ {
164
+ :globalId => "appId=#{client_2_app_link.id}&issueId=#{issue_1.id}",
165
+ :application => {
166
+ :type => 'com.atlassian.jira',
167
+ :name => client_2_app_link['name']
168
+ },
169
+ :relationship => 'relates to',
170
+
171
+ :object => {
172
+ :url => client_1.options[:site] + client_1.options[:context_path] + "/browse/#{issue_1.key}",
173
+ :title => issue_1.key,
174
+ }
175
+ }
176
+ )
@@ -21,10 +21,15 @@ require 'jira/resource/project'
21
21
  require 'jira/resource/priority'
22
22
  require 'jira/resource/comment'
23
23
  require 'jira/resource/worklog'
24
+ require 'jira/resource/applinks'
25
+ require 'jira/resource/issuelinktype'
26
+ require 'jira/resource/issuelink'
27
+ require 'jira/resource/remotelink'
24
28
  require 'jira/resource/issue'
25
29
  require 'jira/resource/filter'
26
30
  require 'jira/resource/field'
27
31
  require 'jira/resource/rapidview'
32
+ require 'jira/resource/serverinfo'
28
33
 
29
34
  require 'jira/request_client'
30
35
  require 'jira/oauth_client'
@@ -365,7 +365,16 @@ module JIRA
365
365
  save_status = save!(attrs)
366
366
  rescue JIRA::HTTPError => exception
367
367
  puts ">>>>>>>>> Exception response: #{exception.response.body}"
368
- set_attrs_from_response(exception.response) rescue JSON::ParserError # Merge error status generated by JIRA REST API
368
+ begin
369
+ set_attrs_from_response(exception.response) # Merge error status generated by JIRA REST API
370
+ rescue JSON::ParserError => parse_exception
371
+ set_attrs("exception" => {
372
+ "class" => exception.response.class.name,
373
+ "code" => exception.response.code,
374
+ "message" => exception.response.message
375
+ }
376
+ )
377
+ end
369
378
  save_status = false
370
379
  end
371
380
  save_status
@@ -129,6 +129,26 @@ module JIRA
129
129
  JIRA::Resource::RapidViewFactory.new(self)
130
130
  end
131
131
 
132
+ def ServerInfo
133
+ JIRA::Resource::ServerInfoFactory.new(self)
134
+ end
135
+
136
+ def ApplicationLink
137
+ JIRA::Resource::ApplicationLinkFactory.new(self)
138
+ end
139
+
140
+ def Issuelink
141
+ JIRA::Resource::IssuelinkFactory.new(self)
142
+ end
143
+
144
+ def Issuelinktype
145
+ JIRA::Resource::IssuelinktypeFactory.new(self)
146
+ end
147
+
148
+ def Remotelink
149
+ JIRA::Resource::RemotelinkFactory.new(self)
150
+ end
151
+
132
152
  # HTTP methods without a body
133
153
  def delete(path, headers = {})
134
154
  request(:delete, path, nil, merge_default_headers(headers))
@@ -40,6 +40,7 @@ module JIRA
40
40
  http_conn = http_class.new(uri.host, uri.port)
41
41
  http_conn.use_ssl = @options[:use_ssl]
42
42
  http_conn.verify_mode = @options[:ssl_verify_mode]
43
+ http_conn.read_timeout = @options[:read_timeout]
43
44
  http_conn
44
45
  end
45
46
 
@@ -0,0 +1,42 @@
1
+ module JIRA
2
+ module Resource
3
+
4
+ class ApplicationLinkFactory < JIRA::BaseFactory # :nodoc:
5
+ delegate_to_target_class :manifest
6
+ end
7
+
8
+ class ApplicationLink < JIRA::Base
9
+
10
+ REST_BASE_PATH = '/rest/applinks/1.0'
11
+
12
+ def self.endpoint_name
13
+ 'listApplicationlinks'
14
+ end
15
+
16
+ def self.full_url(client)
17
+ client.options[:context_path] + REST_BASE_PATH
18
+ end
19
+
20
+ def self.collection_path(client, prefix = '/')
21
+ self.full_url(client) + prefix + self.endpoint_name
22
+ end
23
+
24
+ def self.all(client, options = {})
25
+ response = client.get(collection_path(client))
26
+ json = parse_json(response.body)
27
+ json = json['list']
28
+ json.map do |attrs|
29
+ self.new(client, {:attrs => attrs}.merge(options))
30
+ end
31
+ end
32
+
33
+ def self.manifest(client)
34
+ url = self.full_url(client) + '/manifest'
35
+ response = client.get(url)
36
+ json = parse_json(response.body)
37
+ JIRA::Base.new(client, {:attrs => json})
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -35,6 +35,10 @@ module JIRA
35
35
 
36
36
  has_many :worklogs, :nested_under => ['fields','worklog']
37
37
 
38
+ has_many :issuelinks, :nested_under => 'fields'
39
+
40
+ has_many :remotelink, :class => JIRA::Resource::Remotelink
41
+
38
42
  def self.all(client)
39
43
  url = client.options[:rest_base_path] + "/search?expand=transitions.fields"
40
44
  response = client.get(url)
@@ -0,0 +1,22 @@
1
+ module JIRA
2
+ module Resource
3
+
4
+ class IssuelinkFactory < JIRA::BaseFactory # :nodoc:
5
+ end
6
+
7
+ # Because of circular dependency Issue->IssueLink->Issue
8
+ # we have to declare JIRA::Resource::Issue class.
9
+ class Issue < JIRA::Base; end
10
+
11
+ class Issuelink < JIRA::Base
12
+ has_one :type, :class => JIRA::Resource::Issuelinktype
13
+ has_one :inwardIssue, :class => JIRA::Resource::Issue
14
+ has_one :outwardIssue, :class => JIRA::Resource::Issue
15
+
16
+ def self.endpoint_name
17
+ 'issueLink'
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,15 @@
1
+ module JIRA
2
+ module Resource
3
+
4
+ class IssuelinktypeFactory < JIRA::BaseFactory # :nodoc:
5
+ end
6
+
7
+ class Issuelinktype < JIRA::Base
8
+ nested_collections true
9
+
10
+ def self.endpoint_name
11
+ 'issueLinkType'
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,29 @@
1
+ module JIRA
2
+ module Resource
3
+
4
+ class RemotelinkFactory < JIRA::BaseFactory # :nodoc:
5
+ end
6
+
7
+ class Remotelink < JIRA::Base
8
+ belongs_to :issue
9
+
10
+ def self.endpoint_name
11
+ 'remotelink'
12
+ end
13
+
14
+ def self.all(client, options = {})
15
+ issue = options[:issue]
16
+ unless issue
17
+ raise ArgumentError.new("parent issue is required")
18
+ end
19
+
20
+ path = "#{issue.self}/#{endpoint_name}"
21
+ response = client.get(path)
22
+ json = parse_json(response.body)
23
+ json.map do |link|
24
+ issue.remotelink.build(link)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,19 @@
1
+ module JIRA
2
+ module Resource
3
+
4
+ class ServerInfoFactory < JIRA::BaseFactory # :nodoc:
5
+ end
6
+
7
+ class ServerInfo < JIRA::Base
8
+ def self.endpoint_name
9
+ 'serverInfo'
10
+ end
11
+
12
+ def self.all(client, options = {})
13
+ response = client.get(collection_path(client))
14
+ json = parse_json(response.body)
15
+ self.new(client, {:attrs => json}.merge(options))
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,3 +1,3 @@
1
1
  module JIRA
2
- VERSION = "0.1.16"
2
+ VERSION = "0.1.17"
3
3
  end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe JIRA::Resource::Issuelinktype do
4
+
5
+ with_each_client do |site_url, client|
6
+ let(:client) { client }
7
+ let(:site_url) { site_url }
8
+
9
+
10
+ let(:key) { "10000" }
11
+
12
+ let(:expected_attributes) do
13
+ {
14
+ 'id' => key,
15
+ "self"=>"http://localhost:2990/jira/rest/api/2/issueLinkType/10000",
16
+ "name"=>"Blocks",
17
+ "inward"=>"is blocked by",
18
+ "outward"=>"blocks"
19
+ }
20
+ end
21
+
22
+ let(:expected_collection_length) { 3 }
23
+
24
+ it_should_behave_like "a resource"
25
+ it_should_behave_like "a resource with a collection GET endpoint"
26
+ it_should_behave_like "a resource with a singular GET endpoint"
27
+
28
+ end
29
+ end
@@ -270,6 +270,13 @@ describe JIRA::Base do
270
270
  expect(subject.save("invalid_field" => "foobar")).to be_falsey
271
271
  end
272
272
 
273
+ it "returns false with exception details when non json response body (unauthorized)" do # Unauthorized requests return a non-json body. This makes sure we can handle non-json bodies on HTTPError
274
+ response = double("Response", body: 'totally invalid json', code: 401, message: "Unauthorized")
275
+ expect(client).to receive(:post).with('/foo/bar','{"foo":"bar"}').and_raise(JIRA::HTTPError.new(response))
276
+ expect(subject.save("foo" => "bar")).to be_falsey
277
+ expect(subject.attrs["exception"]["code"]).to eq(401)
278
+ expect(subject.attrs["exception"]["message"]).to eq("Unauthorized")
279
+ end
273
280
  end
274
281
 
275
282
  describe "save!" do
@@ -96,6 +96,7 @@ describe JIRA::HttpClient do
96
96
  expect(Net::HTTP).to receive(:new).with(host, port).and_return(http_conn)
97
97
  expect(http_conn).to receive(:use_ssl=).with(basic_client.options[:use_ssl]).and_return(http_conn)
98
98
  expect(http_conn).to receive(:verify_mode=).with(basic_client.options[:ssl_verify_mode]).and_return(http_conn)
99
+ expect(http_conn).to receive(:read_timeout=).with(basic_client.options[:read_timeout]).and_return(http_conn)
99
100
  expect(basic_client.http_conn(uri)).to eq(http_conn)
100
101
  end
101
102
 
@@ -0,0 +1,14 @@
1
+ # require 'spec_helper'
2
+ #
3
+ # describe JIRA::Resource::Issuelink do
4
+ # let(:client) { double() }
5
+ #
6
+ # describe "links" do
7
+ # subject {
8
+ # JIRA::Resource::Issuelink.new(client, :attrs => {
9
+ #
10
+ # }
11
+ # )
12
+ # }
13
+ # end
14
+ # end
@@ -0,0 +1,25 @@
1
+ {
2
+ "issueLinkTypes": [
3
+ {
4
+ "id": "10000",
5
+ "name": "Blocks",
6
+ "inward": "is blocked by",
7
+ "outward": "blocks",
8
+ "self": "http://localhost:2990/jira/rest/api/2/issueLinkType/10000"
9
+ },
10
+ {
11
+ "id": "10400",
12
+ "name": "Cloners",
13
+ "inward": "is cloned by",
14
+ "outward": "clones",
15
+ "self": "http://localhost:2990/jira/rest/api/2/issueLinkType/10400"
16
+ },
17
+ {
18
+ "id": "10401",
19
+ "name": "Duplicate",
20
+ "inward": "is duplicated by",
21
+ "outward": "duplicates",
22
+ "self": "http://localhost:2990/jira/rest/api/2/issueLinkType/10401"
23
+ }
24
+ ]
25
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "id": "10000",
3
+ "self": "http://localhost:2990/jira/rest/api/2/issueLinkType/10000",
4
+ "name": "Blocks",
5
+ "inward": "is blocked by",
6
+ "outward": "blocks"
7
+ }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jira-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.16
4
+ version: 0.1.17
5
5
  platform: ruby
6
6
  authors:
7
7
  - SUMO Heavy Industries
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-27 00:00:00.000000000 Z
11
+ date: 2015-12-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -119,16 +119,21 @@ files:
119
119
  - lib/jira/oauth_client.rb
120
120
  - lib/jira/railtie.rb
121
121
  - lib/jira/request_client.rb
122
+ - lib/jira/resource/applinks.rb
122
123
  - lib/jira/resource/attachment.rb
123
124
  - lib/jira/resource/comment.rb
124
125
  - lib/jira/resource/component.rb
125
126
  - lib/jira/resource/field.rb
126
127
  - lib/jira/resource/filter.rb
127
128
  - lib/jira/resource/issue.rb
129
+ - lib/jira/resource/issuelink.rb
130
+ - lib/jira/resource/issuelinktype.rb
128
131
  - lib/jira/resource/issuetype.rb
129
132
  - lib/jira/resource/priority.rb
130
133
  - lib/jira/resource/project.rb
131
134
  - lib/jira/resource/rapidview.rb
135
+ - lib/jira/resource/remotelink.rb
136
+ - lib/jira/resource/serverinfo.rb
132
137
  - lib/jira/resource/status.rb
133
138
  - lib/jira/resource/transition.rb
134
139
  - lib/jira/resource/user.rb
@@ -142,6 +147,7 @@ files:
142
147
  - spec/integration/component_spec.rb
143
148
  - spec/integration/field_spec.rb
144
149
  - spec/integration/issue_spec.rb
150
+ - spec/integration/issuelinktype_spec.rb
145
151
  - spec/integration/issuetype_spec.rb
146
152
  - spec/integration/priority_spec.rb
147
153
  - spec/integration/project_spec.rb
@@ -162,6 +168,7 @@ files:
162
168
  - spec/jira/resource/attachment_spec.rb
163
169
  - spec/jira/resource/filter_spec.rb
164
170
  - spec/jira/resource/issue_spec.rb
171
+ - spec/jira/resource/issuelink_spec.rb
165
172
  - spec/jira/resource/project_factory_spec.rb
166
173
  - spec/jira/resource/project_spec.rb
167
174
  - spec/jira/resource/worklog_spec.rb
@@ -187,6 +194,8 @@ files:
187
194
  - spec/mock_responses/issue/10002/worklog.post.json
188
195
  - spec/mock_responses/issue/10002/worklog/10000.json
189
196
  - spec/mock_responses/issue/10002/worklog/10000.put.json
197
+ - spec/mock_responses/issueLinkType.json
198
+ - spec/mock_responses/issueLinkType/10000.json
190
199
  - spec/mock_responses/issuetype.json
191
200
  - spec/mock_responses/issuetype/5.json
192
201
  - spec/mock_responses/priority.json
@@ -241,6 +250,7 @@ test_files:
241
250
  - spec/integration/component_spec.rb
242
251
  - spec/integration/field_spec.rb
243
252
  - spec/integration/issue_spec.rb
253
+ - spec/integration/issuelinktype_spec.rb
244
254
  - spec/integration/issuetype_spec.rb
245
255
  - spec/integration/priority_spec.rb
246
256
  - spec/integration/project_spec.rb
@@ -261,6 +271,7 @@ test_files:
261
271
  - spec/jira/resource/attachment_spec.rb
262
272
  - spec/jira/resource/filter_spec.rb
263
273
  - spec/jira/resource/issue_spec.rb
274
+ - spec/jira/resource/issuelink_spec.rb
264
275
  - spec/jira/resource/project_factory_spec.rb
265
276
  - spec/jira/resource/project_spec.rb
266
277
  - spec/jira/resource/worklog_spec.rb
@@ -286,6 +297,8 @@ test_files:
286
297
  - spec/mock_responses/issue/10002/worklog.post.json
287
298
  - spec/mock_responses/issue/10002/worklog/10000.json
288
299
  - spec/mock_responses/issue/10002/worklog/10000.put.json
300
+ - spec/mock_responses/issueLinkType.json
301
+ - spec/mock_responses/issueLinkType/10000.json
289
302
  - spec/mock_responses/issuetype.json
290
303
  - spec/mock_responses/issuetype/5.json
291
304
  - spec/mock_responses/priority.json