sclemmer-jira-ruby 0.1.12

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 (107) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.travis.yml +6 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +46 -0
  6. data/README.rdoc +309 -0
  7. data/Rakefile +28 -0
  8. data/example.rb +119 -0
  9. data/http-basic-example.rb +112 -0
  10. data/lib/jira.rb +33 -0
  11. data/lib/jira/base.rb +497 -0
  12. data/lib/jira/base_factory.rb +49 -0
  13. data/lib/jira/client.rb +165 -0
  14. data/lib/jira/has_many_proxy.rb +43 -0
  15. data/lib/jira/http_client.rb +69 -0
  16. data/lib/jira/http_error.rb +16 -0
  17. data/lib/jira/oauth_client.rb +84 -0
  18. data/lib/jira/railtie.rb +10 -0
  19. data/lib/jira/request_client.rb +18 -0
  20. data/lib/jira/resource/attachment.rb +12 -0
  21. data/lib/jira/resource/comment.rb +14 -0
  22. data/lib/jira/resource/component.rb +10 -0
  23. data/lib/jira/resource/field.rb +10 -0
  24. data/lib/jira/resource/filter.rb +15 -0
  25. data/lib/jira/resource/issue.rb +80 -0
  26. data/lib/jira/resource/issuetype.rb +10 -0
  27. data/lib/jira/resource/priority.rb +10 -0
  28. data/lib/jira/resource/project.rb +31 -0
  29. data/lib/jira/resource/status.rb +10 -0
  30. data/lib/jira/resource/transition.rb +33 -0
  31. data/lib/jira/resource/user.rb +14 -0
  32. data/lib/jira/resource/version.rb +10 -0
  33. data/lib/jira/resource/worklog.rb +16 -0
  34. data/lib/jira/tasks.rb +0 -0
  35. data/lib/jira/version.rb +3 -0
  36. data/lib/tasks/generate.rake +18 -0
  37. data/sclemmer-jira-ruby.gemspec +28 -0
  38. data/spec/integration/attachment_spec.rb +23 -0
  39. data/spec/integration/comment_spec.rb +55 -0
  40. data/spec/integration/component_spec.rb +42 -0
  41. data/spec/integration/field_spec.rb +35 -0
  42. data/spec/integration/issue_spec.rb +94 -0
  43. data/spec/integration/issuetype_spec.rb +26 -0
  44. data/spec/integration/priority_spec.rb +27 -0
  45. data/spec/integration/project_spec.rb +56 -0
  46. data/spec/integration/status_spec.rb +27 -0
  47. data/spec/integration/transition_spec.rb +52 -0
  48. data/spec/integration/user_spec.rb +25 -0
  49. data/spec/integration/version_spec.rb +43 -0
  50. data/spec/integration/worklog_spec.rb +55 -0
  51. data/spec/jira/base_factory_spec.rb +46 -0
  52. data/spec/jira/base_spec.rb +583 -0
  53. data/spec/jira/client_spec.rb +188 -0
  54. data/spec/jira/has_many_proxy_spec.rb +47 -0
  55. data/spec/jira/http_client_spec.rb +109 -0
  56. data/spec/jira/http_error_spec.rb +26 -0
  57. data/spec/jira/oauth_client_spec.rb +111 -0
  58. data/spec/jira/request_client_spec.rb +14 -0
  59. data/spec/jira/resource/attachment_spec.rb +20 -0
  60. data/spec/jira/resource/filter_spec.rb +97 -0
  61. data/spec/jira/resource/issue_spec.rb +123 -0
  62. data/spec/jira/resource/project_factory_spec.rb +13 -0
  63. data/spec/jira/resource/project_spec.rb +70 -0
  64. data/spec/jira/resource/worklog_spec.rb +24 -0
  65. data/spec/mock_responses/attachment/10000.json +20 -0
  66. data/spec/mock_responses/component.post.json +28 -0
  67. data/spec/mock_responses/component/10000.invalid.put.json +5 -0
  68. data/spec/mock_responses/component/10000.json +39 -0
  69. data/spec/mock_responses/component/10000.put.json +39 -0
  70. data/spec/mock_responses/field.json +32 -0
  71. data/spec/mock_responses/field/1.json +15 -0
  72. data/spec/mock_responses/issue.json +1108 -0
  73. data/spec/mock_responses/issue.post.json +5 -0
  74. data/spec/mock_responses/issue/10002.invalid.put.json +6 -0
  75. data/spec/mock_responses/issue/10002.json +126 -0
  76. data/spec/mock_responses/issue/10002.put.missing_field_update.json +6 -0
  77. data/spec/mock_responses/issue/10002/comment.json +65 -0
  78. data/spec/mock_responses/issue/10002/comment.post.json +29 -0
  79. data/spec/mock_responses/issue/10002/comment/10000.json +29 -0
  80. data/spec/mock_responses/issue/10002/comment/10000.put.json +29 -0
  81. data/spec/mock_responses/issue/10002/transitions.json +49 -0
  82. data/spec/mock_responses/issue/10002/transitions.post.json +1 -0
  83. data/spec/mock_responses/issue/10002/worklog.json +98 -0
  84. data/spec/mock_responses/issue/10002/worklog.post.json +30 -0
  85. data/spec/mock_responses/issue/10002/worklog/10000.json +31 -0
  86. data/spec/mock_responses/issue/10002/worklog/10000.put.json +30 -0
  87. data/spec/mock_responses/issuetype.json +42 -0
  88. data/spec/mock_responses/issuetype/5.json +8 -0
  89. data/spec/mock_responses/priority.json +42 -0
  90. data/spec/mock_responses/priority/1.json +8 -0
  91. data/spec/mock_responses/project.json +12 -0
  92. data/spec/mock_responses/project/SAMPLEPROJECT.issues.json +1108 -0
  93. data/spec/mock_responses/project/SAMPLEPROJECT.json +84 -0
  94. data/spec/mock_responses/status.json +37 -0
  95. data/spec/mock_responses/status/1.json +7 -0
  96. data/spec/mock_responses/user_username=admin.json +17 -0
  97. data/spec/mock_responses/version.post.json +7 -0
  98. data/spec/mock_responses/version/10000.invalid.put.json +5 -0
  99. data/spec/mock_responses/version/10000.json +11 -0
  100. data/spec/mock_responses/version/10000.put.json +7 -0
  101. data/spec/spec_helper.rb +22 -0
  102. data/spec/support/clients_helper.rb +16 -0
  103. data/spec/support/matchers/have_attributes.rb +11 -0
  104. data/spec/support/matchers/have_many.rb +9 -0
  105. data/spec/support/matchers/have_one.rb +5 -0
  106. data/spec/support/shared_examples/integration.rb +194 -0
  107. metadata +302 -0
@@ -0,0 +1,12 @@
1
+ module JIRA
2
+ module Resource
3
+
4
+ class AttachmentFactory < JIRA::BaseFactory # :nodoc:
5
+ end
6
+
7
+ class Attachment < JIRA::Base
8
+ has_one :author, :class => JIRA::Resource::User
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ module JIRA
2
+ module Resource
3
+
4
+ class CommentFactory < JIRA::BaseFactory # :nodoc:
5
+ end
6
+
7
+ class Comment < JIRA::Base
8
+ belongs_to :issue
9
+
10
+ nested_collections true
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ module JIRA
2
+ module Resource
3
+
4
+ class ComponentFactory < JIRA::BaseFactory # :nodoc:
5
+ end
6
+
7
+ class Component < JIRA::Base ; end
8
+
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ module JIRA
2
+ module Resource
3
+
4
+ class FieldFactory < JIRA::BaseFactory # :nodoc:
5
+ end
6
+
7
+ class Field < JIRA::Base ; end
8
+
9
+ end
10
+ end
@@ -0,0 +1,15 @@
1
+ module JIRA
2
+ module Resource
3
+ class FilterFactory < JIRA::BaseFactory # :nodoc:
4
+ end
5
+
6
+ class Filter < JIRA::Base
7
+ has_one :owner, :class => JIRA::Resource::User
8
+
9
+ # Returns all the issues for this filter
10
+ def issues
11
+ Issue.jql(self.client, self.jql)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,80 @@
1
+ require 'cgi'
2
+
3
+ module JIRA
4
+ module Resource
5
+
6
+ class IssueFactory < JIRA::BaseFactory # :nodoc:
7
+ end
8
+
9
+ class Issue < JIRA::Base
10
+
11
+ has_one :reporter, :class => JIRA::Resource::User,
12
+ :nested_under => 'fields'
13
+ has_one :assignee, :class => JIRA::Resource::User,
14
+ :nested_under => 'fields'
15
+ has_one :project, :nested_under => 'fields'
16
+
17
+ has_one :issuetype, :nested_under => 'fields'
18
+
19
+ has_one :priority, :nested_under => 'fields'
20
+
21
+ has_one :status, :nested_under => 'fields'
22
+
23
+ has_many :transitions
24
+
25
+ has_many :components, :nested_under => 'fields'
26
+
27
+ has_many :comments, :nested_under => ['fields','comment']
28
+
29
+ has_many :attachments, :nested_under => 'fields',
30
+ :attribute_key => 'attachment'
31
+
32
+ has_many :versions, :nested_under => 'fields'
33
+
34
+ has_many :worklogs, :nested_under => ['fields','worklog']
35
+
36
+ def self.all(client)
37
+ response = client.get(
38
+ client.options[:rest_base_path] + "/search",
39
+ :expand => 'transitions.fields'
40
+ )
41
+ json = parse_json(response.body)
42
+ json['issues'].map do |issue|
43
+ client.Issue.build(issue)
44
+ end
45
+ end
46
+
47
+ def self.jql(client, jql, options = {fields: nil, start_at: nil, max_results: nil})
48
+ url = client.options[:rest_base_path] + "/search?jql=" + CGI.escape(jql)
49
+
50
+ url << "&fields=#{options[:fields].map{ |value| CGI.escape(value.to_s) }.join(',')}" if options[:fields]
51
+ url << "&startAt=#{CGI.escape(options[:start_at].to_s)}" if options[:start_at]
52
+ url << "&maxResults=#{CGI.escape(options[:max_results].to_s)}" if options[:max_results]
53
+
54
+ response = client.get(url)
55
+ json = parse_json(response.body)
56
+ json['issues'].map do |issue|
57
+ client.Issue.build(issue)
58
+ end
59
+ end
60
+
61
+ def respond_to?(method_name)
62
+ if attrs.keys.include?('fields') && attrs['fields'].keys.include?(method_name.to_s)
63
+ true
64
+ else
65
+ super(method_name)
66
+ end
67
+ end
68
+
69
+ def method_missing(method_name, *args, &block)
70
+ if attrs.keys.include?('fields') && attrs['fields'].keys.include?(method_name.to_s)
71
+ attrs['fields'][method_name.to_s]
72
+ else
73
+ super(method_name)
74
+ end
75
+ end
76
+
77
+ end
78
+
79
+ end
80
+ end
@@ -0,0 +1,10 @@
1
+ module JIRA
2
+ module Resource
3
+
4
+ class IssuetypeFactory < JIRA::BaseFactory # :nodoc:
5
+ end
6
+
7
+ class Issuetype < JIRA::Base ; end
8
+
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ module JIRA
2
+ module Resource
3
+
4
+ class PriorityFactory < JIRA::BaseFactory # :nodoc:
5
+ end
6
+
7
+ class Priority < JIRA::Base ; end
8
+
9
+ end
10
+ end
@@ -0,0 +1,31 @@
1
+ module JIRA
2
+ module Resource
3
+
4
+ class ProjectFactory < JIRA::BaseFactory # :nodoc:
5
+ end
6
+
7
+ class Project < JIRA::Base
8
+
9
+ has_one :lead, :class => JIRA::Resource::User
10
+ has_many :components
11
+ has_many :issuetypes, :attribute_key => 'issueTypes'
12
+ has_many :versions
13
+
14
+ def self.key_attribute
15
+ :key
16
+ end
17
+
18
+ # Returns all the issues for this project
19
+ def issues(options={})
20
+ search_url = client.options[:rest_base_path] + '/search'
21
+ query_params = {:jql => "project=\"#{key}\""}
22
+ query_params.update Base.query_params_for_search(options)
23
+ response = client.get(url_with_query_params(search_url, query_params))
24
+ json = self.class.parse_json(response.body)
25
+ json['issues'].map do |issue|
26
+ client.Issue.build(issue)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,10 @@
1
+ module JIRA
2
+ module Resource
3
+
4
+ class StatusFactory < JIRA::BaseFactory # :nodoc:
5
+ end
6
+
7
+ class Status < JIRA::Base ; end
8
+
9
+ end
10
+ end
@@ -0,0 +1,33 @@
1
+ module JIRA
2
+ module Resource
3
+
4
+ class TransitionFactory < JIRA::BaseFactory # :nodoc:
5
+ end
6
+
7
+ class Transition < JIRA::Base
8
+ has_one :to, :class => JIRA::Resource::Status
9
+ belongs_to :issue
10
+
11
+ nested_collections true
12
+
13
+ def self.endpoint_name
14
+ 'transitions'
15
+ end
16
+
17
+ def self.all(client, options = {})
18
+ issue = options[:issue]
19
+ unless issue
20
+ raise ArgumentError.new("parent issue is required")
21
+ end
22
+
23
+ path = "#{issue.self}/#{endpoint_name}?expand=transitions.fields"
24
+ response = client.get(path)
25
+ json = parse_json(response.body)
26
+ json['transitions'].map do |transition|
27
+ issue.transitions.build(transition)
28
+ end
29
+ end
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,14 @@
1
+ module JIRA
2
+ module Resource
3
+
4
+ class UserFactory < JIRA::BaseFactory # :nodoc:
5
+ end
6
+
7
+ class User < JIRA::Base
8
+ def self.singular_path(client, key, prefix = '/')
9
+ collection_path(client, prefix) + '?username=' + key
10
+ end
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ module JIRA
2
+ module Resource
3
+
4
+ class VersionFactory < JIRA::BaseFactory # :nodoc:
5
+ end
6
+
7
+ class Version < JIRA::Base ; end
8
+
9
+ end
10
+ end
@@ -0,0 +1,16 @@
1
+ module JIRA
2
+ module Resource
3
+
4
+ class WorklogFactory < JIRA::BaseFactory # :nodoc:
5
+ end
6
+
7
+ 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"
11
+ belongs_to :issue
12
+ nested_collections true
13
+ end
14
+
15
+ end
16
+ end
data/lib/jira/tasks.rb ADDED
File without changes
@@ -0,0 +1,3 @@
1
+ module JIRA
2
+ VERSION = "0.1.12"
3
+ end
@@ -0,0 +1,18 @@
1
+ require 'securerandom'
2
+
3
+ namespace :jira do
4
+ desc "Generate a consumer key for your application"
5
+ task :generate_consumer_key do
6
+ key = SecureRandom.hex(16)
7
+ puts "You can use this as your consumer key: #{key}"
8
+ end
9
+
10
+ desc "Run the system call to generate a RSA public certificate"
11
+ task :generate_public_cert do
12
+ puts "Executing 'openssl req -x509 -nodes -newkey rsa:1024 -sha1 -keyout rsakey.pem -out rsacert.pem'"
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
+ 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")
17
+ end
18
+ end
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "jira/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "sclemmer-jira-ruby"
7
+ s.version = JIRA::VERSION
8
+ s.authors = ["SUMO Heavy Industries"]
9
+ s.homepage = "http://www.sumoheavy.com"
10
+ s.summary = %q{Ruby Gem for use with the Atlassian JIRA REST API}
11
+ s.description = %q{API for JIRA}
12
+ s.licenses = ["OSL-3.0"]
13
+
14
+ s.rubyforge_project = "jira-ruby"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_development_dependency "railties", '~> 4.1.4'
22
+ s.add_runtime_dependency "oauth", '~> 0.4.7'
23
+ s.add_runtime_dependency "activesupport", '~> 4.1.4'
24
+ s.add_development_dependency "webmock", '~> 1.18.0'
25
+ s.add_development_dependency "rspec", '~> 3.0.0'
26
+ s.add_development_dependency "rake", '~> 10.3.2'
27
+ end
28
+
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe JIRA::Resource::Attachment do
4
+
5
+ with_each_client do |site_url, client|
6
+ let(:client) { client }
7
+ let(:site_url) { site_url }
8
+
9
+ let(:key) { "10000" }
10
+
11
+ let(:expected_attributes) do
12
+ {
13
+ 'self' => "http://localhost:2990/jira/rest/api/2/attachment/10000",
14
+ 'size' => 15360,
15
+ 'filename' => "ballmer.png"
16
+ }
17
+ end
18
+
19
+ it_should_behave_like "a resource"
20
+ it_should_behave_like "a resource with a singular GET endpoint"
21
+ it_should_behave_like "a resource with a DELETE endpoint"
22
+ end
23
+ end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ describe JIRA::Resource::Comment do
4
+
5
+ with_each_client do |site_url, client|
6
+ let(:client) { client }
7
+ let(:site_url) { site_url }
8
+
9
+ let(:key) { "10000" }
10
+
11
+ let(:target) { JIRA::Resource::Comment.new(client, :attrs => {'id' => '99999'}, :issue_id => '54321') }
12
+
13
+ let(:expected_collection_length) { 2 }
14
+
15
+ let(:belongs_to) {
16
+ JIRA::Resource::Issue.new(client, :attrs => {
17
+ 'id' => '10002',
18
+ 'fields' => {
19
+ 'comment' => {'comments' => []}
20
+ }
21
+ })
22
+ }
23
+
24
+ let(:expected_attributes) do
25
+ {
26
+ 'self' => "http://localhost:2990/jira/rest/api/2/issue/10002/comment/10000",
27
+ 'id' => key,
28
+ 'body' => "This is a comment. Creative."
29
+ }
30
+ end
31
+
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"
52
+
53
+ end
54
+
55
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe JIRA::Resource::Component do
4
+
5
+
6
+ with_each_client do |site_url, client|
7
+ let(:client) { client }
8
+ let(:site_url) { site_url }
9
+
10
+ let(:key) { "10000" }
11
+
12
+ let(:expected_attributes) do
13
+ {
14
+ 'self' => "http://localhost:2990/jira/rest/api/2/component/10000",
15
+ 'id' => key,
16
+ 'name' => "Cheesecake"
17
+ }
18
+ end
19
+
20
+ let(:attributes_for_post) {
21
+ {"name" => "Test component", "project" => "SAMPLEPROJECT" }
22
+ }
23
+ let(:expected_attributes_from_post) {
24
+ { "id" => "10001", "name" => "Test component" }
25
+ }
26
+
27
+ let(:attributes_for_put) {
28
+ {"name" => "Jammy", "project" => "SAMPLEPROJECT" }
29
+ }
30
+ let(:expected_attributes_from_put) {
31
+ { "id" => "10000", "name" => "Jammy" }
32
+ }
33
+
34
+ it_should_behave_like "a resource"
35
+ it_should_behave_like "a resource with a singular GET endpoint"
36
+ it_should_behave_like "a resource with a DELETE endpoint"
37
+ it_should_behave_like "a resource with a POST endpoint"
38
+ it_should_behave_like "a resource with a PUT endpoint"
39
+ it_should_behave_like "a resource with a PUT endpoint that rejects invalid fields"
40
+
41
+ end
42
+ end