jira_client 1.0.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 (67) hide show
  1. data/.gitignore +19 -0
  2. data/.rspec +2 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +29 -0
  6. data/Rakefile +1 -0
  7. data/jira_client.gemspec +27 -0
  8. data/lib/jira_client.rb +121 -0
  9. data/lib/jira_client/api/comments.rb +19 -0
  10. data/lib/jira_client/api/issues.rb +62 -0
  11. data/lib/jira_client/api/projects.rb +19 -0
  12. data/lib/jira_client/api/server.rb +15 -0
  13. data/lib/jira_client/api/statuses.rb +20 -0
  14. data/lib/jira_client/api/users.rb +18 -0
  15. data/lib/jira_client/api/utils.rb +25 -0
  16. data/lib/jira_client/api/worklogs.rb +26 -0
  17. data/lib/jira_client/base.rb +54 -0
  18. data/lib/jira_client/comment.rb +12 -0
  19. data/lib/jira_client/configuration.rb +27 -0
  20. data/lib/jira_client/core_ext/string.rb +7 -0
  21. data/lib/jira_client/error/bad_request.rb +5 -0
  22. data/lib/jira_client/error/configuration_error.rb +5 -0
  23. data/lib/jira_client/error/issue_error.rb +5 -0
  24. data/lib/jira_client/error/resource_not_found.rb +5 -0
  25. data/lib/jira_client/error/unauthorized.rb +5 -0
  26. data/lib/jira_client/issue.rb +26 -0
  27. data/lib/jira_client/project.rb +5 -0
  28. data/lib/jira_client/server_info.rb +11 -0
  29. data/lib/jira_client/status.rb +7 -0
  30. data/lib/jira_client/timetracking.rb +6 -0
  31. data/lib/jira_client/user.rb +10 -0
  32. data/lib/jira_client/version.rb +3 -0
  33. data/lib/jira_client/worklog.rb +10 -0
  34. data/spec/fixtures/admin.json +17 -0
  35. data/spec/fixtures/basic_issue.json +6 -0
  36. data/spec/fixtures/comment.json +23 -0
  37. data/spec/fixtures/comments.json +30 -0
  38. data/spec/fixtures/invalid_assignee.json +6 -0
  39. data/spec/fixtures/invalid_comment.json +6 -0
  40. data/spec/fixtures/invalid_jql.json +6 -0
  41. data/spec/fixtures/issue_with_comments.json +33 -0
  42. data/spec/fixtures/issue_with_description.json +10 -0
  43. data/spec/fixtures/issue_with_status.json +15 -0
  44. data/spec/fixtures/issue_with_timetracking.json +16 -0
  45. data/spec/fixtures/issue_with_worklogs.json +34 -0
  46. data/spec/fixtures/issues.json +28 -0
  47. data/spec/fixtures/my_certificate.pem +52 -0
  48. data/spec/fixtures/no_issues_found.json +6 -0
  49. data/spec/fixtures/project.json +10 -0
  50. data/spec/fixtures/projects.json +22 -0
  51. data/spec/fixtures/server_info.json +14 -0
  52. data/spec/fixtures/status.json +7 -0
  53. data/spec/fixtures/statuses.json +16 -0
  54. data/spec/fixtures/user_doesnt_exist.json +6 -0
  55. data/spec/fixtures/users.json +22 -0
  56. data/spec/fixtures/worklog.json +31 -0
  57. data/spec/jira_client/api/comments_spec.rb +59 -0
  58. data/spec/jira_client/api/issues_spec.rb +314 -0
  59. data/spec/jira_client/api/projects_spec.rb +55 -0
  60. data/spec/jira_client/api/server_spec.rb +31 -0
  61. data/spec/jira_client/api/statuses_spec.rb +69 -0
  62. data/spec/jira_client/api/users_spec.rb +56 -0
  63. data/spec/jira_client/api/worklogs_spec.rb +86 -0
  64. data/spec/jira_client/configuration_spec.rb +78 -0
  65. data/spec/jira_client_spec.rb +49 -0
  66. data/spec/spec_helper.rb +56 -0
  67. metadata +226 -0
@@ -0,0 +1,28 @@
1
+ {
2
+ "expand": "schema,names",
3
+ "startAt": 0,
4
+ "maxResults": 50,
5
+ "total": 2,
6
+ "issues": [
7
+ {
8
+ "expand": "editmeta,renderedFields,transitions,changelog,operations",
9
+ "id": "10100",
10
+ "self": "http://localhost:2990/jira/rest/api/2/issue/10100",
11
+ "key": "TEST-2",
12
+ "fields": {
13
+ "summary": "Something doesnt work",
14
+ "description": null
15
+ }
16
+ },
17
+ {
18
+ "expand": "editmeta,renderedFields,transitions,changelog,operations",
19
+ "id": "10000",
20
+ "self": "http://localhost:2990/jira/rest/api/2/issue/10000",
21
+ "key": "TEST-1",
22
+ "fields": {
23
+ "summary": "Testing new feature",
24
+ "description": null
25
+ }
26
+ }
27
+ ]
28
+ }
@@ -0,0 +1,52 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ Proc-Type: 4,ENCRYPTED
3
+ DEK-Info: DES-EDE3-CBC,39EDD4C0F9F5B97D
4
+
5
+ ar3c/LrtleaNgO17p+SN3zH30VSCXm4Lg5CNBcnMceWjgVQo3zHnyyxvKZ+zRvT0
6
+ wZPEpCOG4vZ0j8UUeNrPxZKX2uioNhPYEkhR0N+W57ukzJafQy3TptVmTHkk/t5Y
7
+ 9f88fMgyLoFh+xBuD0iYOv8wp/V9UEFuLTIXExVyGV5Rqv+maKpfYVgIx185qwDE
8
+ S2gYNEaJBJKu0TOpwO2iLRq2xC2cULJAH5rBlAcVlcX+/MHOa86Yd5WM6/5NJxfG
9
+ psx0dQj7nZBbjjfzKGUSN230qd3/jwsfuvekHtjvNzERBelqMrpqeLiTI4aCYdpz
10
+ 7vP066/CCLB6k4Zm5rQXID50arDQWfgCMSsBFPZfPHZhshCbHA/IRQg3HWBzSgzP
11
+ zsIUoTw4carUnaT8KAiooqSY+6iaZFk0gacV6Ax0TRUXc9GtqQ1bRoi58lOkEWjm
12
+ wyB4xRqSGC7k0wiFGZKSTQSHFkQpy5imSy8XV5yAWxgniFb5zsX0WWvg4FR+wR+h
13
+ 2cYPZuXX4qyFZ8YoeQM5aP0XtrXaSlpWLTrqwIJFQvI/w1MPOj+CI4vZP133UME9
14
+ Wvog46Yyka4VCFEmvSQvz2OjbSehNrDFIlb2tNhA8VQZ/H3XCm/xmmSm+4ssy1hc
15
+ ELoJXFickj+ILK9/Ppw7BhvE19N6ZxAAj7zH6PyEdAKtAHdWxOS2qe/+IpEyxTFr
16
+ XWzhhFRuCixUThVWPwimW1lm5BZ9/IwyeLhbP8jtuwm6lC0DqP/ui4LLzMeinJIY
17
+ uAzm5tO3ioAlijAUPwgLQuJmZt1hJ994uyAGt0IbdR75QKfFVk3KY07Fci/YV/VX
18
+ tRlMPtsmVD2uJONpEPwsXZCoOFepU9nuL3woosOHkqbL/EYGbMfP1c8Z696662fS
19
+ gbTiH5hqTeOsWGylN0+SM+mneRk+czJQd9JwIF6gn225nbV0ymrA9RKE5ISDKrGN
20
+ 7Yi6WefdDxV3GgO2buFiFEXZiLq7lsYHnOqGRH/aM8apkK8Lt9FfecUDewfpnM10
21
+ pX04U2Kb8iYbY68DPUDlpEmwc1qDS9xyY3n5Z9UiYqRpqdBuIuGnLZenx0LRUX16
22
+ 8t/83vc0AKtMDIb35/PLUltDJzPDIEqF6xF1KE7IRRp9a2Pv+a+4l2wse0aPfes6
23
+ niI0cEoQAcxyt638T3h6kaWlmXqbM4XhEmFTEXe+24Au9rq2mf41mW1G5KKLupBA
24
+ OEiHe0OsHF5pUeliVpewyHOYfee9bO8thS9HhiuAahSjMVbOaSSzBxcr4hgHlL7v
25
+ qwnlfYD0Hd6bhEthLMCnMmFk0A9Y/2Hx7NVhJ1fdvcP/zVmYiJTdSNIFd2izXVn8
26
+ obu4eFtzj0+cgIER1OM0ln5o2s5GlYFnG11lw7qruSTb9UGZptTaR0zeoIiwBjEn
27
+ 7j3gI3h86DGOT33/J1MKeLZtnkcpD023y4EBtvX8oH4hM8n9oNK6FO87OPeUks6d
28
+ xCb1riGDc41+gnbKtmxreChuP4CeAG6RpLUdVL6oasy+5gyonWgr1a8OLuCKnHsq
29
+ fe91FE4hvlAIX7V+mbMf3d0U0N3Rx2Pa74LY2aU+6b6sNqaMMAKlgQ==
30
+ -----END RSA PRIVATE KEY-----
31
+ -----BEGIN CERTIFICATE-----
32
+ MIIDtTCCAp2gAwIBAgIJAPHGRV8yrekRMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
33
+ BAYTAlVLMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
34
+ aWRnaXRzIFB0eSBMdGQwHhcNMTMwNTA3MDY0MDEzWhcNMTMwNjA2MDY0MDEzWjBF
35
+ MQswCQYDVQQGEwJVSzETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50
36
+ ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
37
+ CgKCAQEAuGHmEDYI0bL3ctMjHPS99QMyE3h8luzcNEDvyLo/cIsYHscs4x10wTwC
38
+ opzUWLEie0FNFNEPDIhZ1JqalbivTGJmynQ3bQK0RjL0zKeE6cY5z5ie7SmpLED/
39
+ 6ftvPq6HiJCt3X/dCpax+HUYyAIyEJWbxD2IM5ma53rUBXswyfc/bSmGswmIlv0U
40
+ p5EY10YnQ4n9JUhztl9dP7ag5g3eaZ/1g79OtodUF6mz8TcgTh16Oi7XcNWbYS+T
41
+ FPOyKKxMFc9HubFhQZ9IZIzIrIDunynre6gPjow+Zdq66NIXVjPtMhYDx50vnYGF
42
+ 4TOhlHGDXfDMaJsl3yKviJZNMz/p2QIDAQABo4GnMIGkMB0GA1UdDgQWBBSQeSrx
43
+ MLciO7Uv9HLZfqORHEckezB1BgNVHSMEbjBsgBSQeSrxMLciO7Uv9HLZfqORHEck
44
+ e6FJpEcwRTELMAkGA1UEBhMCVUsxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV
45
+ BAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAPHGRV8yrekRMAwGA1UdEwQF
46
+ MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAf2SjiQXa+0xwdi1Tvr0/UqJevg4/aO
47
+ lUBWE06DEB8K4QFQpVdRIA/V2kwN+pEJLloMfgmHpjNLIF22USKE3tfWOS1GfFnD
48
+ ouonv+ULZBFBA3y3pCoRr8+MnJX+8DxxjzauD48EhfCABoaQ5et5QHQEbMXoyjUg
49
+ 1NXwnpT3onmH8M9sFa+uImzXDNxzBd/bD1qjRDLsfAsGixUhttiR+u2WOioiIhEL
50
+ Nc5QwA7NGBhHVzFyULB5p+C1JoLdzCrE4VJjTnmgaPWM84VdiX8GLzv9SXsQBXwH
51
+ lfyM/BGfrFznxRaJ4lYOeHbhk46VJqgPEyDHwHOJnI+B1aAs52Ia9tY=
52
+ -----END CERTIFICATE-----
@@ -0,0 +1,6 @@
1
+ {
2
+ "startAt": 0,
3
+ "maxResults": 50,
4
+ "total": 0,
5
+ "issues": []
6
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "self": "http://www.example.com/jira/rest/api/2/project/ABC",
3
+ "id": "10001",
4
+ "key": "ABC",
5
+ "name": "Alphabetical",
6
+ "avatarUrls": {
7
+ "16x16": "http://www.example.com/jira/secure/projectavatar?size=small&pid=10001",
8
+ "48x48": "http://www.example.com/jira/secure/projectavatar?size=large&pid=10001"
9
+ }
10
+ }
@@ -0,0 +1,22 @@
1
+ [
2
+ {
3
+ "self": "http://www.example.com/jira/rest/api/2/project/EX",
4
+ "id": "10000",
5
+ "key": "EX",
6
+ "name": "Example",
7
+ "avatarUrls": {
8
+ "16x16": "http://www.example.com/jira/secure/projectavatar?size=small&pid=10000",
9
+ "48x48": "http://www.example.com/jira/secure/projectavatar?size=large&pid=10000"
10
+ }
11
+ },
12
+ {
13
+ "self": "http://www.example.com/jira/rest/api/2/project/ABC",
14
+ "id": "10001",
15
+ "key": "ABC",
16
+ "name": "Alphabetical",
17
+ "avatarUrls": {
18
+ "16x16": "http://www.example.com/jira/secure/projectavatar?size=small&pid=10001",
19
+ "48x48": "http://www.example.com/jira/secure/projectavatar?size=large&pid=10001"
20
+ }
21
+ }
22
+ ]
@@ -0,0 +1,14 @@
1
+ {
2
+ "baseUrl": "https://example.jira.com",
3
+ "version": "5.1.8",
4
+ "versionNumbers": [
5
+ 5,
6
+ 1,
7
+ 8
8
+ ],
9
+ "buildNumber": 787,
10
+ "buildDate": "2012-10-29T00:00:00.000+0000",
11
+ "serverTime": "2013-04-24T22:01:45.802+0100",
12
+ "scmInfo": "823790ce17da57e7ed0220e49723c7b00a6d54dc",
13
+ "serverTitle": "Example JIRA"
14
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "self": "http://localhost:8090/jira/rest/api/2.0/status/10000",
3
+ "description": "The issue is currently being worked on.",
4
+ "iconUrl": "http://localhost:8090/jira/images/icons/progress.gif",
5
+ "name": "In Progress",
6
+ "id": "10000"
7
+ }
@@ -0,0 +1,16 @@
1
+ [
2
+ {
3
+ "self": "http://localhost:8090/jira/rest/api/2.0/status/10000",
4
+ "description": "The issue is currently being worked on.",
5
+ "iconUrl": "http://localhost:8090/jira/images/icons/progress.gif",
6
+ "name": "In Progress",
7
+ "id": "10000"
8
+ },
9
+ {
10
+ "self": "http://localhost:8090/jira/rest/api/2.0/status/5",
11
+ "description": "The issue is closed.",
12
+ "iconUrl": "http://localhost:8090/jira/images/icons/closed.gif",
13
+ "name": "Closed",
14
+ "id": "5"
15
+ }
16
+ ]
@@ -0,0 +1,6 @@
1
+ {
2
+ "errorMessages": [
3
+ "The user named 'doesnt_exist' does not exist"
4
+ ],
5
+ "errors": {}
6
+ }
@@ -0,0 +1,22 @@
1
+ [
2
+ {
3
+ "self": "http://www.example.com/jira/rest/api/2/user?username=fred",
4
+ "name": "fred",
5
+ "avatarUrls": {
6
+ "16x16": "http://www.example.com/jira/secure/useravatar?size=small&ownerId=fred",
7
+ "48x48": "http://www.example.com/jira/secure/useravatar?size=large&ownerId=fred"
8
+ },
9
+ "displayName": "Fred F. User",
10
+ "active": false
11
+ },
12
+ {
13
+ "self": "http://www.example.com/jira/rest/api/2/user?username=andrew",
14
+ "name": "andrew",
15
+ "avatarUrls": {
16
+ "16x16": "http://www.example.com/jira/secure/useravatar?size=small&ownerId=andrew",
17
+ "48x48": "http://www.example.com/jira/secure/useravatar?size=large&ownerId=andrew"
18
+ },
19
+ "displayName": "Andrew Anderson",
20
+ "active": false
21
+ }
22
+ ]
@@ -0,0 +1,31 @@
1
+ {
2
+ "startAt": 0,
3
+ "maxResults": 1,
4
+ "total": 1,
5
+ "worklogs": [
6
+ {
7
+ "self": "http://www.example.com/jira/rest/api/2.0/issue/10010/worklog/10000",
8
+ "author": {
9
+ "self": "http://www.example.com/jira/rest/api/2.0/user?username=fred",
10
+ "name": "fred",
11
+ "displayName": "Fred F. User",
12
+ "active": false
13
+ },
14
+ "updateAuthor": {
15
+ "self": "http://www.example.com/jira/rest/api/2.0/user?username=fred",
16
+ "name": "fred",
17
+ "displayName": "Fred F. User",
18
+ "active": false
19
+ },
20
+ "comment": "I did some work here.",
21
+ "started": "2012-02-15T17:34:37.937-0600",
22
+ "timeSpent": "3h 20m",
23
+ "timeSpentSeconds": 12000,
24
+ "id": "100028",
25
+ "visibility": {
26
+ "type": "group",
27
+ "value": "jira-developers"
28
+ }
29
+ }
30
+ ]
31
+ }
@@ -0,0 +1,59 @@
1
+ require "spec_helper"
2
+
3
+ describe JiraClient::API::Comments do
4
+
5
+ describe "#find_issue_comments" do
6
+
7
+ before do
8
+ stub_get("/issue/PROJECT-1234/comment").to_return(:body => fixture("comments.json"), :headers => {:content_type => "application/json; charset=utf-8"})
9
+ @comments = JiraClient.find_issue_comments "PROJECT-1234"
10
+ end
11
+
12
+ it "requests the correct resource" do
13
+ expect(a_get("/issue/PROJECT-1234/comment")).to have_been_made
14
+ end
15
+ it "returns an array of JiraClient::Comment objects" do
16
+ @comments.should be_a_kind_of Array
17
+ @comments.each do |comment|
18
+ comment.should be_a_kind_of JiraClient::Comment
19
+ end
20
+ end
21
+ it "assigns the correct information" do
22
+ comment = @comments.first
23
+ comment.body.should == "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eget venenatis elit. Duis eu justo eget augue iaculis fermentum. Sed semper quam laoreet nisi egestas at posuere augue semper."
24
+ comment.author.should be_a_kind_of JiraClient::User
25
+ comment.update_author.should be_a_kind_of JiraClient::User
26
+ comment.created.should be_a_kind_of DateTime
27
+ comment.updated.should be_a_kind_of DateTime
28
+ end
29
+ end
30
+
31
+ describe "#comment_on_issue" do
32
+
33
+ before do
34
+ stub_post("/issue/PROJECT-1234/comment").with(:body => {"body" => "This is a comment"}).to_return(:status => 201, :body => fixture("comment.json"))
35
+ @comment = JiraClient.comment_on_issue("PROJECT-1234", "This is a comment")
36
+ end
37
+
38
+ it "requests the correct resource" do
39
+ expect(a_post("/issue/PROJECT-1234/comment").with(:body => {:body => "This is a comment"})).to have_been_made
40
+ end
41
+ it "returns the comment object" do
42
+ @comment.should be_a_kind_of JiraClient::Comment
43
+ end
44
+ it "with the comment text set on the comment object" do
45
+ @comment.body.should == "This is a comment"
46
+ end
47
+ context "without a comment body" do
48
+
49
+ before do
50
+ stub_post("/issue/PROJECT-1234/comment").to_return(:status => 400, :body => fixture("invalid_comment.json"))
51
+ end
52
+
53
+ it "raises a JiraClient::Error::BadRequest" do
54
+ expect { JiraClient.comment_on_issue("PROJECT-1234", "") }.to raise_error(JiraClient::Error::BadRequest)
55
+ end
56
+ end
57
+ end
58
+
59
+ end
@@ -0,0 +1,314 @@
1
+ require "spec_helper"
2
+
3
+ describe JiraClient::API::Issues do
4
+
5
+ describe "#find_issue_by_key" do
6
+ context "with no extra data" do
7
+
8
+ before do
9
+ stub_get("/issue/PROJECT-1234").to_return(:body => fixture('basic_issue.json'), :headers => {:content_type => "application/json; charset=utf-8"})
10
+ end
11
+
12
+ it "requests the correct resource" do
13
+ JiraClient.find_issue_by_key("PROJECT-1234")
14
+ expect(a_get("/issue/PROJECT-1234")).to have_been_made
15
+ end
16
+ it "returns a JiraClient::Issue object" do
17
+ issue = JiraClient.find_issue_by_key("PROJECT-1234")
18
+ expect(issue).to be_a_kind_of JiraClient::Issue
19
+ end
20
+ it "sets the correct attributes" do
21
+ issue = JiraClient.find_issue_by_key("PROJECT-1234")
22
+ expect(issue.key).to eq("PROJECT-1234")
23
+ end
24
+ end
25
+ context "with summary and description" do
26
+
27
+ before do
28
+ stub_get("/issue/PROJECT-1235").with(:query => {:fields => "summary,description"}).to_return(:body => fixture('issue_with_description.json'), :headers => {:content_type => "application/json; charset=utf-8"})
29
+ @issue = JiraClient.find_issue_by_key("PROJECT-1235", :fields => [:summary, :description])
30
+ end
31
+
32
+ it "requests the correct resource" do
33
+ expect(a_get("/issue/PROJECT-1235?fields=summary,description")).to have_been_made
34
+ end
35
+ it "sets the correct attributes" do
36
+ expect(@issue.key).to eq("PROJECT-1235")
37
+ expect(@issue.summary?).to be_true
38
+ expect(@issue.description?).to be_true
39
+ expect(@issue.summary).to eq("This is an issue summary")
40
+ expect(@issue.description).to eq("This is a description")
41
+ end
42
+ end
43
+ context "with a status" do
44
+
45
+ before do
46
+ stub_get("/issue/PROJECT-1236").with(:query => {:fields => "status"}).to_return(:body => fixture("issue_with_status.json"), :headers => {:content_type => "application/json; charset=utf-8"})
47
+ @issue = JiraClient.find_issue_by_key("PROJECT-1236", :fields => [:status])
48
+ end
49
+
50
+ it "requests the correct resource" do
51
+ expect(a_get("/issue/PROJECT-1236?fields=status")).to have_been_made
52
+ end
53
+ it "sets the correct attributes" do
54
+ expect(@issue.key).to eq("PROJECT-1236")
55
+ expect(@issue.status?).to be_true
56
+ expect(@issue.status).to be_a_kind_of JiraClient::Status
57
+ end
58
+ end
59
+ context "with timetracking" do
60
+
61
+ before do
62
+ stub_get("/issue/PROJECT-1234").with(:query => {:fields => "timetracking"}).to_return(:body => fixture("issue_with_timetracking.json"))
63
+ @issue = JiraClient.find_issue_by_key("PROJECT-1234", :fields => [:timetracking])
64
+ end
65
+
66
+ it "requests the correct resource" do
67
+ expect(a_get("/issue/PROJECT-1234?fields=timetracking")).to have_been_made
68
+ end
69
+ it "returns a timetracking object" do
70
+ expect(@issue.timetracking).to be_a_kind_of JiraClient::Timetracking
71
+ end
72
+ end
73
+ context "with worklogs" do
74
+
75
+ before do
76
+ stub_get("/issue/PROJECT-1234").with(:query => {:fields => "worklog"}).to_return(:body => fixture("issue_with_worklogs.json"))
77
+ @issue = JiraClient.find_issue_by_key("PROJECT-1234", :fields => [:worklog])
78
+ end
79
+
80
+ it "requests the correct resource" do
81
+ expect(a_get("/issue/PROJECT-1234?fields=worklog")).to have_been_made
82
+ end
83
+ it "returns an array of worklog items" do
84
+ @issue.worklog.should be_a_kind_of Array
85
+ @issue.worklog.each do |worklog|
86
+ worklog.should be_a_kind_of JiraClient::Worklog
87
+ worklog.author.should be_a_kind_of JiraClient::User
88
+ end
89
+ end
90
+ end
91
+ context "with comments" do
92
+
93
+ before do
94
+ stub_get("/issue/PROJECT-1234").with(:query => {:fields => "comment"}).to_return(:body => fixture("issue_with_comments.json"))
95
+ @issue = JiraClient.find_issue_by_key("PROJECT-1234", :fields => [:comment])
96
+ end
97
+
98
+ it "requests the correct resource" do
99
+ expect(a_get("/issue/PROJECT-1234?fields=comment")).to have_been_made
100
+ end
101
+ it "returns an array of comment objects" do
102
+ @issue.comment.should be_a_kind_of Array
103
+ @issue.comment.each do |comment|
104
+ comment.should be_a_kind_of JiraClient::Comment
105
+ end
106
+ end
107
+ end
108
+ end
109
+
110
+ describe "#assign_issue" do
111
+
112
+ before do
113
+ stub_put("/issue/PROJECT-1234/assignee").with(:body => {"name" => "testuser"}).to_return(:status => 204)
114
+ JiraClient.assign_issue("PROJECT-1234", "testuser")
115
+ end
116
+
117
+ it "requests the correct resource" do
118
+ expect(a_put("/issue/PROJECT-1234/assignee")).to have_been_made
119
+ end
120
+ context "with invalid username" do
121
+
122
+ before do
123
+ stub_put("/issue/PROJECT-1234/assignee").with(:body => {"name" => "invalid_user"}).to_return(:status => 400, :body => fixture("invalid_assignee.json"))
124
+ end
125
+
126
+ it "raises a JiraClient::Error::BadRequest error" do
127
+ expect { JiraClient.assign_issue("PROJECT-1234", "invalid_user") }.to raise_error(JiraClient::Error::BadRequest)
128
+ end
129
+ end
130
+ context "with invalid permissions" do
131
+
132
+ before do
133
+ stub_put("/issue/PROJECT-1234/assignee").with(:body => {"name" => "insufficient_permission_user"}).to_return(:status => 401, :body => fixture("invalid_assignee.json"))
134
+ end
135
+
136
+ it "raises JiraClient::Error::Unauthorized" do
137
+ expect { JiraClient.assign_issue("PROJECT-1234", "insufficient_permission_user") }.to raise_error(JiraClient::Error::Unauthorized)
138
+ end
139
+ end
140
+ context "with an issue that doesnt exist" do
141
+
142
+ before do
143
+ stub_put("/issue/NOEXIST/assignee").with(:body => {"name" => "admin"}).to_return(:status => 404, :body => fixture("invalid_assignee.json"))
144
+ end
145
+
146
+ it "raises JiraClient::Error::ResourceNotFound" do
147
+ expect { JiraClient.assign_issue("NOEXIST", "admin") }.to raise_error(JiraClient::Error::ResourceNotFound)
148
+ end
149
+ end
150
+ context "with a user that doesnt exist" do
151
+
152
+ before do
153
+ stub_put("/issue/PROJECT-1234/assignee").with(:body => {"name" => "no_exist_user"}).to_return(:status => 404, :body => fixture("invalid_assignee.json"))
154
+ end
155
+
156
+ it "raises JiraClient::Error::ResourceNotFound" do
157
+ expect { JiraClient.assign_issue("PROJECT-1234", "no_exist_user") }.to raise_error(JiraClient::Error::ResourceNotFound)
158
+ end
159
+ end
160
+ end
161
+
162
+ describe "#resolve_issue" do
163
+
164
+ before do
165
+ stub_post("/issue/PROJECT-1234/transitions").to_return(:status => 204)
166
+ end
167
+
168
+ it "sends data to the correct resource" do
169
+ JiraClient.resolve_issue "PROJECT-1234"
170
+ expect(a_post('/issue/PROJECT-1234/transitions')).to have_been_made
171
+ end
172
+ it "sends the correct transition ID" do
173
+ JiraClient.resolve_issue "PROJECT-1234"
174
+ expect(a_post('/issue/PROJECT-1234/transitions').with(:body => transition_to(JiraClient::Status::RESOLVE))).to have_been_made
175
+ end
176
+ it "sends the resolution if provided" do
177
+ JiraClient.resolve_issue "PROJECT-1234", :as => "Won't Fix"
178
+ expect(a_post('/issue/PROJECT-1234/transitions').with(:body => transition_to(JiraClient::Status::RESOLVE, :resolution => "Won't Fix"))).to have_been_made
179
+ end
180
+ it "sends a comment if provided" do
181
+ JiraClient.resolve_issue "PROJECT-1234", :comment => "This is a comment"
182
+ expect(a_post('/issue/PROJECT-1234/transitions').with(:body => transition_to(JiraClient::Status::RESOLVE, :comment => "This is a comment"))).to have_been_made
183
+ end
184
+ it "sends both a comment and a resolution if provided" do
185
+ JiraClient.resolve_issue "PROJECT-1234", :as => "Can't Reproduce", :comment => "This is a comment"
186
+ expect(a_post('/issue/PROJECT-1234/transitions').with(:body => transition_to(JiraClient::Status::RESOLVE, :comment => "This is a comment", :resolution => "Can't Reproduce"))).to have_been_made
187
+ end
188
+ end
189
+
190
+ describe "#close_issue" do
191
+
192
+ before do
193
+ stub_post("/issue/PROJECT-1234/transitions").to_return(:status => 204)
194
+ end
195
+
196
+ it "sends data to the correct resource" do
197
+ JiraClient.close_issue "PROJECT-1234"
198
+ expect(a_post('/issue/PROJECT-1234/transitions')).to have_been_made
199
+ end
200
+ it "sends the correct transition ID" do
201
+ JiraClient.close_issue "PROJECT-1234"
202
+ expect(a_post('/issue/PROJECT-1234/transitions').with(:body => transition_to(JiraClient::Status::CLOSE))).to have_been_made
203
+ end
204
+ it "sends a comment if provided" do
205
+ JiraClient.close_issue "PROJECT-1234", :comment => "This is a comment"
206
+ expect(a_post('/issue/PROJECT-1234/transitions').with(:body => transition_to(JiraClient::Status::CLOSE, :comment => "This is a comment"))).to have_been_made
207
+ end
208
+ end
209
+
210
+ describe "#reopen_issue" do
211
+
212
+ before do
213
+ stub_post("/issue/PROJECT-1234/transitions").to_return(:status => 204)
214
+ end
215
+
216
+ it "sends data to the correct resource" do
217
+ JiraClient.reopen_issue "PROJECT-1234"
218
+ expect(a_post('/issue/PROJECT-1234/transitions')).to have_been_made
219
+ end
220
+ it "sends the correct transition ID" do
221
+ JiraClient.reopen_issue "PROJECT-1234"
222
+ expect(a_post('/issue/PROJECT-1234/transitions').with(:body => transition_to(JiraClient::Status::REOPEN))).to have_been_made
223
+ end
224
+ it "sends a comment if provided" do
225
+ JiraClient.reopen_issue "PROJECT-1234", :comment => "This is a comment"
226
+ expect(a_post('/issue/PROJECT-1234/transitions').with(:body => transition_to(JiraClient::Status::REOPEN, :comment => "This is a comment"))).to have_been_made
227
+ end
228
+ end
229
+
230
+ describe "#start_progress_on_issue" do
231
+
232
+ before do
233
+ stub_post("/issue/PROJECT-1234/transitions").to_return(:status => 204)
234
+ end
235
+
236
+ it "sends data to the correct resource" do
237
+ JiraClient.start_progress_on_issue "PROJECT-1234"
238
+ expect(a_post('/issue/PROJECT-1234/transitions')).to have_been_made
239
+ end
240
+ it "sends the correct transition ID (6)" do
241
+ JiraClient.start_progress_on_issue "PROJECT-1234"
242
+ expect(a_post('/issue/PROJECT-1234/transitions').with(:body => transition_to(JiraClient::Status::START_PROGRESS))).to have_been_made
243
+ end
244
+ it "sends a comment if provided" do
245
+ JiraClient.start_progress_on_issue "PROJECT-1234", :comment => "This is a comment"
246
+ expect(a_post('/issue/PROJECT-1234/transitions').with(:body => transition_to(JiraClient::Status::START_PROGRESS, :comment => "This is a comment"))).to have_been_made
247
+ end
248
+ end
249
+
250
+ describe "#find_issues" do
251
+
252
+ before do
253
+ stub_post("/search").with(:body => {:jql => "project = TEST"}).to_return(:status => 200, :body => fixture("issues.json"))
254
+ @issues = JiraClient.find_issues(:jql => "project = TEST")
255
+ end
256
+
257
+ it "requests the correct resource" do
258
+ expect(a_post("/search").with(:body => {"jql" => "project = TEST"})).to have_been_made
259
+ end
260
+ it "accepts an array of fields to be returned" do
261
+ stub_post("/search").with(:body => {:fields => ["summary", "description"]}).to_return(:status => 200, :body => fixture("issues.json"))
262
+ @issues = JiraClient.find_issues(:fields => [:summary, :description])
263
+ expect(a_post("/search").with(:body => {:fields => ["summary", "description"]})).to have_been_made
264
+ end
265
+ it "returns an array of issue objects" do
266
+ @issues.should be_a_kind_of Array
267
+ @issues.each do |issue|
268
+ issue.should be_a_kind_of JiraClient::Issue
269
+ end
270
+ end
271
+ context "when there are no results" do
272
+
273
+ before do
274
+ stub_post("/search").with(:body => {:jql => "project = TEST and status = 'In Progress'"}).to_return(:status => 200, :body => fixture("no_issues_found.json"))
275
+ end
276
+
277
+ it "returns an empty array" do
278
+ @issues = JiraClient.find_issues(:jql => "project = TEST and status = 'In Progress'")
279
+ @issues.should be_a_kind_of Array
280
+ @issues.should be_empty
281
+ end
282
+ end
283
+ context "when there is a problem with the JQL" do
284
+
285
+ before do
286
+ stub_post("/search").with(:body => {:jql => "project = DOESNT_EXIST"}).to_return(:status => 400, :body => fixture("invalid_jql.json"))
287
+ end
288
+
289
+ it "raises a bad request error" do
290
+ expect { JiraClient.find_issues(:jql => "project = DOESNT_EXIST") }.to raise_error(JiraClient::Error::BadRequest)
291
+ end
292
+ it "hints at the problem with the jql" do
293
+ begin
294
+ JiraClient.find_issues(:jql => "project = DOESNT_EXIST")
295
+ rescue JiraClient::Error::BadRequest => e
296
+ e.message.should include "project"
297
+ e.message.should include "DOESNT_EXIST"
298
+ e.message.should include "does not exist"
299
+ end
300
+ end
301
+ end
302
+
303
+ end
304
+
305
+ private
306
+
307
+ def transition_to(id, opts = {})
308
+ body = {"transition" => {"id" => id}}
309
+ body["update"] = {"comment" => [{"add" => {"body" => opts[:comment]}}]} if opts.has_key? :comment
310
+ body["fields"] = {"resolution" => {"name" => opts[:resolution]}} if opts.has_key? :resolution
311
+ body
312
+ end
313
+
314
+ end