jira-ruby 1.5.0 → 1.6.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 (88) hide show
  1. checksums.yaml +5 -5
  2. data/Gemfile +7 -1
  3. data/Guardfile +1 -1
  4. data/Rakefile +4 -5
  5. data/http-basic-example.rb +13 -12
  6. data/jira-ruby.gemspec +9 -10
  7. data/lib/jira-ruby.rb +5 -2
  8. data/lib/jira/base.rb +49 -48
  9. data/lib/jira/base_factory.rb +1 -4
  10. data/lib/jira/client.rb +29 -20
  11. data/lib/jira/has_many_proxy.rb +0 -1
  12. data/lib/jira/http_client.rb +9 -10
  13. data/lib/jira/http_error.rb +3 -5
  14. data/lib/jira/oauth_client.rb +19 -20
  15. data/lib/jira/request_client.rb +3 -4
  16. data/lib/jira/resource/agile.rb +10 -8
  17. data/lib/jira/resource/applinks.rb +5 -8
  18. data/lib/jira/resource/attachment.rb +1 -2
  19. data/lib/jira/resource/board.rb +84 -0
  20. data/lib/jira/resource/comment.rb +0 -2
  21. data/lib/jira/resource/component.rb +1 -3
  22. data/lib/jira/resource/createmeta.rb +12 -14
  23. data/lib/jira/resource/field.rb +22 -22
  24. data/lib/jira/resource/filter.rb +2 -2
  25. data/lib/jira/resource/issue.rb +41 -39
  26. data/lib/jira/resource/issuelink.rb +3 -5
  27. data/lib/jira/resource/issuelinktype.rb +0 -1
  28. data/lib/jira/resource/issuetype.rb +1 -3
  29. data/lib/jira/resource/priority.rb +1 -3
  30. data/lib/jira/resource/project.rb +5 -7
  31. data/lib/jira/resource/rapidview.rb +28 -7
  32. data/lib/jira/resource/remotelink.rb +1 -4
  33. data/lib/jira/resource/resolution.rb +2 -4
  34. data/lib/jira/resource/serverinfo.rb +1 -2
  35. data/lib/jira/resource/sprint.rb +82 -18
  36. data/lib/jira/resource/sprint_report.rb +8 -0
  37. data/lib/jira/resource/status.rb +1 -3
  38. data/lib/jira/resource/transition.rb +2 -6
  39. data/lib/jira/resource/user.rb +12 -2
  40. data/lib/jira/resource/version.rb +1 -3
  41. data/lib/jira/resource/watcher.rb +1 -5
  42. data/lib/jira/resource/webhook.rb +3 -6
  43. data/lib/jira/resource/worklog.rb +3 -5
  44. data/lib/jira/version.rb +1 -1
  45. data/lib/tasks/generate.rake +4 -4
  46. data/spec/integration/attachment_spec.rb +15 -16
  47. data/spec/integration/comment_spec.rb +31 -34
  48. data/spec/integration/component_spec.rb +21 -24
  49. data/spec/integration/field_spec.rb +15 -18
  50. data/spec/integration/issue_spec.rb +44 -48
  51. data/spec/integration/issuelinktype_spec.rb +8 -11
  52. data/spec/integration/issuetype_spec.rb +5 -7
  53. data/spec/integration/priority_spec.rb +5 -8
  54. data/spec/integration/project_spec.rb +13 -20
  55. data/spec/integration/rapidview_spec.rb +17 -10
  56. data/spec/integration/resolution_spec.rb +7 -10
  57. data/spec/integration/status_spec.rb +5 -8
  58. data/spec/integration/transition_spec.rb +17 -20
  59. data/spec/integration/user_spec.rb +24 -8
  60. data/spec/integration/version_spec.rb +21 -25
  61. data/spec/integration/watcher_spec.rb +28 -34
  62. data/spec/integration/webhook.rb +8 -17
  63. data/spec/integration/worklog_spec.rb +30 -34
  64. data/spec/jira/base_factory_spec.rb +11 -12
  65. data/spec/jira/base_spec.rb +204 -228
  66. data/spec/jira/client_spec.rb +26 -28
  67. data/spec/jira/has_many_proxy_spec.rb +11 -12
  68. data/spec/jira/http_client_spec.rb +51 -52
  69. data/spec/jira/http_error_spec.rb +7 -9
  70. data/spec/jira/oauth_client_spec.rb +44 -46
  71. data/spec/jira/request_client_spec.rb +5 -5
  72. data/spec/jira/resource/agile_spec.rb +5 -7
  73. data/spec/jira/resource/attachment_spec.rb +25 -26
  74. data/spec/jira/resource/board_spec.rb +175 -0
  75. data/spec/jira/resource/createmeta_spec.rb +29 -32
  76. data/spec/jira/resource/field_spec.rb +42 -48
  77. data/spec/jira/resource/filter_spec.rb +40 -40
  78. data/spec/jira/resource/issue_spec.rb +87 -89
  79. data/spec/jira/resource/issuelink_spec.rb +1 -1
  80. data/spec/jira/resource/project_factory_spec.rb +2 -4
  81. data/spec/jira/resource/project_spec.rb +33 -33
  82. data/spec/jira/resource/sprint_spec.rb +78 -0
  83. data/spec/jira/resource/user_factory_spec.rb +6 -8
  84. data/spec/jira/resource/worklog_spec.rb +9 -11
  85. data/spec/spec_helper.rb +8 -9
  86. data/spec/support/clients_helper.rb +4 -4
  87. data/spec/support/shared_examples/integration.rb +60 -77
  88. metadata +59 -53
@@ -1,6 +1,5 @@
1
1
  module JIRA
2
2
  module Resource
3
-
4
3
  class RemotelinkFactory < JIRA::BaseFactory # :nodoc:
5
4
  end
6
5
 
@@ -13,9 +12,7 @@ module JIRA
13
12
 
14
13
  def self.all(client, options = {})
15
14
  issue = options[:issue]
16
- unless issue
17
- raise ArgumentError.new("parent issue is required")
18
- end
15
+ raise ArgumentError, 'parent issue is required' unless issue
19
16
 
20
17
  path = "#{issue.self}/#{endpoint_name}"
21
18
  response = client.get(path)
@@ -1,10 +1,8 @@
1
1
  module JIRA
2
2
  module Resource
3
-
4
3
  class ResolutionFactory < JIRA::BaseFactory # :nodoc:
5
4
  end
6
5
 
7
- class Resolution < JIRA::Base ; end
8
-
6
+ class Resolution < JIRA::Base; end
9
7
  end
10
- end
8
+ end
@@ -1,6 +1,5 @@
1
1
  module JIRA
2
2
  module Resource
3
-
4
3
  class ServerInfoFactory < JIRA::BaseFactory # :nodoc:
5
4
  end
6
5
 
@@ -12,7 +11,7 @@ module JIRA
12
11
  def self.all(client, options = {})
13
12
  response = client.get(collection_path(client))
14
13
  json = parse_json(response.body)
15
- self.new(client, {:attrs => json}.merge(options))
14
+ new(client, { attrs: json }.merge(options))
16
15
  end
17
16
  end
18
17
  end
@@ -1,37 +1,101 @@
1
- require 'cgi'
2
-
3
1
  module JIRA
4
2
  module Resource
5
-
6
3
  class SprintFactory < JIRA::BaseFactory # :nodoc:
7
4
  end
8
5
 
9
6
  class Sprint < JIRA::Base
7
+ def self.find(client, key)
8
+ response = client.get("#{client.options[:site]}/rest/agile/1.0/sprint/#{key}")
9
+ json = parse_json(response.body)
10
+ client.Sprint.build(json)
11
+ end
10
12
 
11
- def self.all(client, key)
12
- response = client.get(path_base(client) + '/sprintquery/' + key.to_s)
13
- parse_json(response.body)
13
+ # get all issues of sprint
14
+ def issues(options = {})
15
+ jql = 'sprint = ' + id.to_s
16
+ jql += " and updated >= '#{options[:updated]}'" if options[:updated]
17
+ Issue.jql(client, jql)
14
18
  end
15
19
 
16
- def self.find(client, key, options = {})
17
- options[:maxResults] ||= 100
18
- options[:startAt] ||= 0
19
- fields = options[:fields].join(',') unless options[:fields].nil?
20
- response = client.get("/rest/api/latest/search?jql=sprint=#{key}&fields=#{fields}&startAt=#{options[:startAt]}&maxResults=#{options[:maxResults]}")
21
- parse_json(response.body)
20
+ def add_issue(issue)
21
+ request_body = { issues: [issue.id] }.to_json
22
+ response = client.post(client.options[:site] + "/rest/agile/1.0/sprint/#{id}/issue", request_body)
23
+ true
22
24
  end
23
25
 
24
- private
26
+ def sprint_report
27
+ get_sprint_details_attribute('sprint_report')
28
+ end
25
29
 
26
- def self.path_base(client)
27
- client.options[:context_path] + '/rest/greenhopper/1.0'
30
+ def start_date
31
+ get_sprint_details_attribute('start_date')
28
32
  end
29
33
 
30
- def path_base(client)
31
- self.class.path_base(client)
34
+ def end_date
35
+ get_sprint_details_attribute('end_date')
32
36
  end
33
37
 
34
- end
38
+ def complete_date
39
+ get_sprint_details_attribute('complete_date')
40
+ end
41
+
42
+ def get_sprint_details_attribute(attribute_name)
43
+ attribute = instance_variable_get("@#{attribute_name}")
44
+ return attribute if attribute
45
+ get_sprint_details
46
+ instance_variable_get("@#{attribute_name}")
47
+ end
48
+
49
+ def get_sprint_details
50
+ search_url = client.options[:site] + '/rest/greenhopper/1.0/rapid/charts/sprintreport?rapidViewId=' +
51
+ rapidview_id.to_s + '&sprintId=' + id.to_s
52
+ begin
53
+ response = client.get(search_url)
54
+ rescue StandardError
55
+ return nil
56
+ end
57
+ json = self.class.parse_json(response.body)
58
+
59
+ @start_date = Date.parse(json['sprint']['startDate']) unless json['sprint']['startDate'] == 'None'
60
+ @end_date = Date.parse(json['sprint']['endDate']) unless json['sprint']['endDate'] == 'None'
61
+ @completed_date = Date.parse(json['sprint']['completeDate']) unless json['sprint']['completeDate'] == 'None'
62
+ @sprint_report = client.SprintReport.build(json['contents'])
63
+ end
35
64
 
65
+ def rapidview_id
66
+ return @attrs['rapidview_id'] if @attrs['rapidview_id']
67
+ search_url = client.options[:site] + '/secure/GHGoToBoard.jspa?sprintId=' + id.to_s
68
+ begin
69
+ response = client.get(search_url)
70
+ rescue JIRA::HTTPError => error
71
+ return unless error.response.instance_of? Net::HTTPFound
72
+ rapid_view_match = /rapidView=(\d+)&/.match(error.response['location'])
73
+ @attrs['rapidview_id'] = rapid_view_match[1] unless rapid_view_match.nil?
74
+ end
75
+ end
76
+
77
+ def save(attrs = {}, _path = nil)
78
+ attrs = @attrs if attrs.empty?
79
+ super(attrs, agile_url)
80
+ end
81
+
82
+ def save!(attrs = {}, _path = nil)
83
+ attrs = @attrs if attrs.empty?
84
+ super(attrs, agile_url)
85
+ end
86
+
87
+ # WORK IN PROGRESS
88
+ def complete
89
+ complete_url = "#{client.options[:site]}/rest/greenhopper/1.0/sprint/#{id}/complete"
90
+ response = client.put(complete_url)
91
+ self.class.parse_json(response.body)
92
+ end
93
+
94
+ private
95
+
96
+ def agile_url
97
+ "#{client.options[:site]}/rest/agile/1.0/sprint/#{id}"
98
+ end
99
+ end
36
100
  end
37
101
  end
@@ -0,0 +1,8 @@
1
+ module JIRA
2
+ module Resource
3
+ class SprintReportFactory < JIRA::BaseFactory # :nodoc:
4
+ end
5
+
6
+ class SprintReport < JIRA::Base; end
7
+ end
8
+ end
@@ -1,10 +1,8 @@
1
1
  module JIRA
2
2
  module Resource
3
-
4
3
  class StatusFactory < JIRA::BaseFactory # :nodoc:
5
4
  end
6
5
 
7
- class Status < JIRA::Base ; end
8
-
6
+ class Status < JIRA::Base; end
9
7
  end
10
8
  end
@@ -1,11 +1,10 @@
1
1
  module JIRA
2
2
  module Resource
3
-
4
3
  class TransitionFactory < JIRA::BaseFactory # :nodoc:
5
4
  end
6
5
 
7
6
  class Transition < JIRA::Base
8
- has_one :to, :class => JIRA::Resource::Status
7
+ has_one :to, class: JIRA::Resource::Status
9
8
  belongs_to :issue
10
9
 
11
10
  nested_collections true
@@ -16,9 +15,7 @@ module JIRA
16
15
 
17
16
  def self.all(client, options = {})
18
17
  issue = options[:issue]
19
- unless issue
20
- raise ArgumentError.new("parent issue is required")
21
- end
18
+ raise ArgumentError, 'parent issue is required' unless issue
22
19
 
23
20
  path = "#{issue.self}/#{endpoint_name}?expand=transitions.fields"
24
21
  response = client.get(path)
@@ -28,6 +25,5 @@ module JIRA
28
25
  end
29
26
  end
30
27
  end
31
-
32
28
  end
33
29
  end
@@ -1,6 +1,5 @@
1
1
  module JIRA
2
2
  module Resource
3
-
4
3
  class UserFactory < JIRA::BaseFactory # :nodoc:
5
4
  def myself
6
5
  instance = build
@@ -11,10 +10,21 @@ module JIRA
11
10
  end
12
11
 
13
12
  class User < JIRA::Base
13
+ MAX_RESULTS = 1000
14
+
14
15
  def self.singular_path(client, key, prefix = '/')
15
16
  collection_path(client, prefix) + '?username=' + key
16
17
  end
17
- end
18
18
 
19
+ # Cannot retrieve more than 1,000 users through the api, please see: https://jira.atlassian.com/browse/JRASERVER-65089
20
+ def self.all(client)
21
+ response = client.get("/rest/api/2/user/search?username=_&maxResults=#{MAX_RESULTS}")
22
+ all_users = JSON.parse(response.body)
23
+
24
+ all_users.flatten.uniq.map do |user|
25
+ client.User.build(user)
26
+ end
27
+ end
28
+ end
19
29
  end
20
30
  end
@@ -1,10 +1,8 @@
1
1
  module JIRA
2
2
  module Resource
3
-
4
3
  class VersionFactory < JIRA::BaseFactory # :nodoc:
5
4
  end
6
5
 
7
- class Version < JIRA::Base ; end
8
-
6
+ class Version < JIRA::Base; end
9
7
  end
10
8
  end
@@ -1,6 +1,5 @@
1
1
  module JIRA
2
2
  module Resource
3
-
4
3
  class WatcherFactory < JIRA::BaseFactory # :nodoc:
5
4
  end
6
5
 
@@ -15,9 +14,7 @@ module JIRA
15
14
 
16
15
  def self.all(client, options = {})
17
16
  issue = options[:issue]
18
- unless issue
19
- raise ArgumentError.new("parent issue is required")
20
- end
17
+ raise ArgumentError, 'parent issue is required' unless issue
21
18
 
22
19
  path = "#{issue.self}/#{endpoint_name}"
23
20
  response = client.get(path)
@@ -27,6 +24,5 @@ module JIRA
27
24
  end
28
25
  end
29
26
  end
30
-
31
27
  end
32
28
  end
@@ -1,12 +1,10 @@
1
1
  module JIRA
2
2
  module Resource
3
-
4
3
  class WebhookFactory < JIRA::BaseFactory # :nodoc:
5
4
  end
6
5
 
7
6
  class Webhook < JIRA::Base
8
-
9
- REST_BASE_PATH = '/rest/webhooks/1.0'
7
+ REST_BASE_PATH = '/rest/webhooks/1.0'.freeze
10
8
 
11
9
  def self.endpoint_name
12
10
  'webhook'
@@ -17,14 +15,14 @@ module JIRA
17
15
  end
18
16
 
19
17
  def self.collection_path(client, prefix = '/')
20
- self.full_url(client) + prefix + self.endpoint_name
18
+ full_url(client) + prefix + endpoint_name
21
19
  end
22
20
 
23
21
  def self.all(client, options = {})
24
22
  response = client.get(collection_path(client))
25
23
  json = parse_json(response.body)
26
24
  json.map do |attrs|
27
- self.new(client, {:attrs => attrs}.merge(options))
25
+ new(client, { attrs: attrs }.merge(options))
28
26
  end
29
27
  end
30
28
 
@@ -34,7 +32,6 @@ module JIRA
34
32
  # def self.delete(options={})
35
33
 
36
34
  # end
37
-
38
35
  end
39
36
  end
40
37
  end
@@ -1,16 +1,14 @@
1
1
  module JIRA
2
2
  module Resource
3
-
4
3
  class WorklogFactory < JIRA::BaseFactory # :nodoc:
5
4
  end
6
5
 
7
6
  class Worklog < JIRA::Base
8
- has_one :author, :class => JIRA::Resource::User
9
- has_one :update_author, :class => JIRA::Resource::User,
10
- :attribute_key => "updateAuthor"
7
+ has_one :author, class: JIRA::Resource::User
8
+ has_one :update_author, class: JIRA::Resource::User,
9
+ attribute_key: 'updateAuthor'
11
10
  belongs_to :issue
12
11
  nested_collections true
13
12
  end
14
-
15
13
  end
16
14
  end
@@ -1,3 +1,3 @@
1
1
  module JIRA
2
- VERSION = '1.5.0'
2
+ VERSION = '1.6.0'.freeze
3
3
  end
@@ -1,18 +1,18 @@
1
1
  require 'securerandom'
2
2
 
3
3
  namespace :jira do
4
- desc "Generate a consumer key for your application"
4
+ desc 'Generate a consumer key for your application'
5
5
  task :generate_consumer_key do
6
6
  key = SecureRandom.hex(16)
7
7
  puts "You can use this as your consumer key: #{key}"
8
8
  end
9
9
 
10
- desc "Run the system call to generate a RSA public certificate"
10
+ desc 'Run the system call to generate a RSA public certificate'
11
11
  task :generate_public_cert do
12
12
  puts "Executing 'openssl req -x509 -nodes -newkey rsa:1024 -sha1 -keyout rsakey.pem -out rsacert.pem'"
13
13
  system('openssl req -x509 -subj "/C=US/ST=New York/L=New York/O=SUMO Heavy Industries/CN=www.sumoheavy.com" -nodes -newkey rsa:1024 -sha1 -keyout rsakey.pem -out rsacert.pem')
14
14
  puts "Done. The RSA-SHA1 private keyfile is in the current directory: \'rsakey.pem\'."
15
- puts "You will need to copy the following certificate into your application link configuration in Jira:"
16
- system("cat rsacert.pem")
15
+ puts 'You will need to copy the following certificate into your application link configuration in Jira:'
16
+ system('cat rsacert.pem')
17
17
  end
18
18
  end
@@ -1,33 +1,32 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe JIRA::Resource::Attachment do
4
-
5
4
  with_each_client do |site_url, client|
6
5
  let(:client) { client }
7
6
  let(:site_url) { site_url }
8
7
 
9
- let(:key) { "10000" }
8
+ let(:key) { '10000' }
10
9
 
11
- let(:target) { JIRA::Resource::Attachment.new(client, :attrs => {'id' => '99999'}, :issue_id => '10002') }
10
+ let(:target) { JIRA::Resource::Attachment.new(client, attrs: { 'id' => '99999' }, issue_id: '10002') }
12
11
 
13
12
  let(:expected_attributes) do
14
13
  {
15
- 'self' => "http://localhost:2990/jira/rest/api/2/attachment/10000",
16
- 'size' => 15360,
17
- 'filename' => "ballmer.png"
14
+ 'self' => 'http://localhost:2990/jira/rest/api/2/attachment/10000',
15
+ 'size' => 15_360,
16
+ 'filename' => 'ballmer.png'
18
17
  }
19
18
  end
20
19
 
21
- let(:belongs_to) {
22
- JIRA::Resource::Issue.new(client, :attrs => {
23
- 'id' => '10002',
24
- 'fields' => {
25
- 'attachment' => {'attachments' => []}
26
- }
27
- })
28
- }
20
+ let(:belongs_to) do
21
+ JIRA::Resource::Issue.new(client, attrs: {
22
+ 'id' => '10002',
23
+ 'fields' => {
24
+ 'attachment' => { 'attachments' => [] }
25
+ }
26
+ })
27
+ end
29
28
 
30
- it_should_behave_like "a resource with a singular GET endpoint"
31
- it_should_behave_like "a resource with a DELETE endpoint"
29
+ it_should_behave_like 'a resource with a singular GET endpoint'
30
+ it_should_behave_like 'a resource with a DELETE endpoint'
32
31
  end
33
32
  end
@@ -1,55 +1,52 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe JIRA::Resource::Comment do
4
-
5
4
  with_each_client do |site_url, client|
6
5
  let(:client) { client }
7
6
  let(:site_url) { site_url }
8
7
 
9
- let(:key) { "10000" }
8
+ let(:key) { '10000' }
10
9
 
11
- let(:target) { JIRA::Resource::Comment.new(client, :attrs => {'id' => '99999'}, :issue_id => '54321') }
10
+ let(:target) { JIRA::Resource::Comment.new(client, attrs: { 'id' => '99999' }, issue_id: '54321') }
12
11
 
13
12
  let(:expected_collection_length) { 2 }
14
13
 
15
- let(:belongs_to) {
16
- JIRA::Resource::Issue.new(client, :attrs => {
17
- 'id' => '10002',
18
- 'fields' => {
19
- 'comment' => {'comments' => []}
20
- }
21
- })
22
- }
14
+ let(:belongs_to) do
15
+ JIRA::Resource::Issue.new(client, attrs: {
16
+ 'id' => '10002',
17
+ 'fields' => {
18
+ 'comment' => { 'comments' => [] }
19
+ }
20
+ })
21
+ end
23
22
 
24
23
  let(:expected_attributes) do
25
24
  {
26
- 'self' => "http://localhost:2990/jira/rest/api/2/issue/10002/comment/10000",
25
+ 'self' => 'http://localhost:2990/jira/rest/api/2/issue/10002/comment/10000',
27
26
  'id' => key,
28
- 'body' => "This is a comment. Creative."
27
+ 'body' => 'This is a comment. Creative.'
29
28
  }
30
29
  end
31
30
 
32
- let(:attributes_for_post) {
33
- { "body" => "new comment" }
34
- }
35
- let(:expected_attributes_from_post) {
36
- { "id" => "10001", "body" => "new comment"}
37
- }
38
-
39
- let(:attributes_for_put) {
40
- {"body" => "new body"}
41
- }
42
- let(:expected_attributes_from_put) {
43
- { "id" => "10000", "body" => "new body" }
44
- }
45
-
46
- it_should_behave_like "a resource"
47
- it_should_behave_like "a resource with a collection GET endpoint"
48
- it_should_behave_like "a resource with a singular GET endpoint"
49
- it_should_behave_like "a resource with a DELETE endpoint"
50
- it_should_behave_like "a resource with a POST endpoint"
51
- it_should_behave_like "a resource with a PUT endpoint"
31
+ let(:attributes_for_post) do
32
+ { 'body' => 'new comment' }
33
+ end
34
+ let(:expected_attributes_from_post) do
35
+ { 'id' => '10001', 'body' => 'new comment' }
36
+ end
37
+
38
+ let(:attributes_for_put) do
39
+ { 'body' => 'new body' }
40
+ end
41
+ let(:expected_attributes_from_put) do
42
+ { 'id' => '10000', 'body' => 'new body' }
43
+ end
52
44
 
45
+ it_should_behave_like 'a resource'
46
+ it_should_behave_like 'a resource with a collection GET endpoint'
47
+ it_should_behave_like 'a resource with a singular GET endpoint'
48
+ it_should_behave_like 'a resource with a DELETE endpoint'
49
+ it_should_behave_like 'a resource with a POST endpoint'
50
+ it_should_behave_like 'a resource with a PUT endpoint'
53
51
  end
54
-
55
52
  end