jirarest2 0.0.10 → 0.0.11
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.
- data.tar.gz.sig +0 -0
- data/History.txt +22 -0
- data/Manifest.txt +6 -2
- data/README.txt +2 -1
- data/bin/jira_comment +3 -3
- data/bin/jira_create_issue +5 -10
- data/bin/jira_watcher +3 -3
- data/{bin/create_issue.rb → lib/deb.rb} +9 -5
- data/lib/jirarest2.rb +4 -2
- data/lib/jirarest2/connect.rb +46 -40
- data/lib/jirarest2/cookie_credentials.rb +126 -0
- data/lib/jirarest2/credentials.rb +7 -9
- data/lib/jirarest2/exceptions.rb +9 -5
- data/lib/jirarest2/issue.rb +1 -1
- data/lib/jirarest2/madbitconfig.rb +1 -0
- data/lib/jirarest2/password_credentials.rb +63 -0
- data/lib/jirarest2/services/issuelinktype.rb +1 -1
- data/lib/jirarest2bin.rb +62 -10
- data/test/data/cookiejar +0 -0
- data/test/test_comment.rb +1 -1
- data/test/test_connect.rb +8 -7
- data/test/test_cookie_credentials.rb +72 -0
- data/test/test_credentials.rb +8 -20
- data/test/test_issue.rb +1 -1
- data/test/test_issuelink.rb +2 -2
- data/test/test_issuelinktype.rb +1 -1
- data/test/test_madbitconfig.rb +1 -1
- data/test/test_password_credentials.rb +26 -0
- data/test/test_result.rb +1 -1
- data/test/test_watcher.rb +3 -3
- metadata +11 -7
- metadata.gz.sig +0 -0
- data/bin/jira_create_issue.rb +0 -23
data.tar.gz.sig
CHANGED
Binary file
|
data/History.txt
CHANGED
@@ -1,3 +1,25 @@
|
|
1
|
+
=== 0.0.11 / 2012-08-05
|
2
|
+
|
3
|
+
* 1 major enhancements:
|
4
|
+
|
5
|
+
* Added support to authenticate with cookies (default with the scripts)
|
6
|
+
|
7
|
+
* 2 minor enhancements:
|
8
|
+
|
9
|
+
* Refactored Connect
|
10
|
+
* Refactored Credentials
|
11
|
+
|
12
|
+
* 1 bug fixes:
|
13
|
+
|
14
|
+
* fixed #7 It's now possible to use the scripts in (unix) pipes as well
|
15
|
+
|
16
|
+
* 3 unknowns:
|
17
|
+
|
18
|
+
* Added deb.rb to find debug information at compile stage (reacts to environment variable "DEBUG")
|
19
|
+
* Deleted deprecated files
|
20
|
+
* corrected spelling errors
|
21
|
+
|
22
|
+
|
1
23
|
=== 0.0.10 / 2012-08-02
|
2
24
|
|
3
25
|
* 1 major enhancement:
|
data/Manifest.txt
CHANGED
@@ -4,18 +4,19 @@ History.txt
|
|
4
4
|
Manifest.txt
|
5
5
|
README.txt
|
6
6
|
Rakefile
|
7
|
-
bin/create_issue.rb
|
8
7
|
bin/jira_comment
|
9
8
|
bin/jira_create_issue
|
10
|
-
bin/jira_create_issue.rb
|
11
9
|
bin/jira_watcher
|
12
10
|
copyright
|
11
|
+
lib/deb.rb
|
13
12
|
lib/jirarest2.rb
|
14
13
|
lib/jirarest2/connect.rb
|
14
|
+
lib/jirarest2/cookie_credentials.rb
|
15
15
|
lib/jirarest2/credentials.rb
|
16
16
|
lib/jirarest2/exceptions.rb
|
17
17
|
lib/jirarest2/issue.rb
|
18
18
|
lib/jirarest2/madbitconfig.rb
|
19
|
+
lib/jirarest2/password_credentials.rb
|
19
20
|
lib/jirarest2/result.rb
|
20
21
|
lib/jirarest2/services.rb
|
21
22
|
lib/jirarest2/services/comment.rb
|
@@ -23,6 +24,7 @@ lib/jirarest2/services/issuelink.rb
|
|
23
24
|
lib/jirarest2/services/issuelinktype.rb
|
24
25
|
lib/jirarest2/services/watcher.rb
|
25
26
|
lib/jirarest2bin.rb
|
27
|
+
test/data/cookiejar
|
26
28
|
test/data/get-comments.txt
|
27
29
|
test/data/issuespec.txt
|
28
30
|
test/data/test.config.data
|
@@ -32,10 +34,12 @@ test/data/test.nojson1
|
|
32
34
|
test/data/ticket.json
|
33
35
|
test/test_comment.rb
|
34
36
|
test/test_connect.rb
|
37
|
+
test/test_cookie_credentials.rb
|
35
38
|
test/test_credentials.rb
|
36
39
|
test/test_issue.rb
|
37
40
|
test/test_issuelink.rb
|
38
41
|
test/test_issuelinktype.rb
|
39
42
|
test/test_madbitconfig.rb
|
43
|
+
test/test_password_credentials.rb
|
40
44
|
test/test_result.rb
|
41
45
|
test/test_watcher.rb
|
data/README.txt
CHANGED
@@ -8,7 +8,7 @@ jirarest2 is yet another implementation of the JIRA(tm) REST-API[https://develop
|
|
8
8
|
|
9
9
|
It is intended to be called within the shell to create and verify JIRA(tm) issues fast without a browser. There was no particular need for perfomance at the time of writing.
|
10
10
|
|
11
|
-
This implementation is still a for cry from others like http://rubygems.org/gems/jira-ruby which requires oauth
|
11
|
+
This implementation is still a for cry from others like http://rubygems.org/gems/jira-ruby which requires oauth authentication.
|
12
12
|
|
13
13
|
There are scripts to create new issues with watchers and link those to existing issues and to manipulate watchers on existing issues.
|
14
14
|
|
@@ -23,6 +23,7 @@ There are scripts to create new issues with watchers and link those to existing
|
|
23
23
|
* jira_create_issue allows you to create new issues with watchers and link those to existing issues
|
24
24
|
* jira_watcher allows you to manipulate watchers on existing issues
|
25
25
|
* jira_comment allows you to add read and update comments. (The latter only if you know the right comment id)
|
26
|
+
* Uses cookie_auth by default. First login will be done via basic auth though.
|
26
27
|
|
27
28
|
== SYNOPSIS:
|
28
29
|
|
data/bin/jira_comment
CHANGED
@@ -17,7 +17,7 @@
|
|
17
17
|
|
18
18
|
|
19
19
|
require "jirarest2bin"
|
20
|
-
require "
|
20
|
+
require "deb"
|
21
21
|
|
22
22
|
# Check for the minimum ruby version we need
|
23
23
|
Jirarest2Bin::check_ruby_version
|
@@ -98,7 +98,7 @@ end
|
|
98
98
|
# @param [Array] issues An Array containing the issuekeys
|
99
99
|
# @param [Fixnum] id Identidication number of the comment to view
|
100
100
|
def view_comments(issues,id = nil)
|
101
|
-
connection = Jirarest2Bin::
|
101
|
+
connection = Jirarest2Bin::command(@scriptopts,@connection,:connection)
|
102
102
|
result = Array.new
|
103
103
|
if id.nil? then
|
104
104
|
issues.each { |issue|
|
@@ -119,7 +119,7 @@ end
|
|
119
119
|
# @param [String] method Kind of work to be done
|
120
120
|
# @param [Fixnum] id Identifier of the comment
|
121
121
|
def work(issues,text,method,id = nil)
|
122
|
-
connection = Jirarest2Bin::
|
122
|
+
connection = Jirarest2Bin::command(@scriptopts,@connection,:connection)
|
123
123
|
issues.each{ |issue|
|
124
124
|
connectedissue = Comment.new(connection, issue, id)
|
125
125
|
connectedissue.send method, text
|
data/bin/jira_create_issue
CHANGED
@@ -18,7 +18,7 @@
|
|
18
18
|
#
|
19
19
|
|
20
20
|
require "jirarest2bin"
|
21
|
-
require "
|
21
|
+
require "deb"
|
22
22
|
|
23
23
|
# Check for the minimum ruby version we need
|
24
24
|
Jirarest2Bin::check_ruby_version
|
@@ -146,14 +146,7 @@ def open_issue
|
|
146
146
|
if @issueopts.issue.nil? then
|
147
147
|
Jirarest2Bin::required_argument("issue")
|
148
148
|
end
|
149
|
-
issue=
|
150
|
-
rescue Jirarest2::AuthentificationError => e
|
151
|
-
puts "Password not accepted."
|
152
|
-
@scriptopts.pass = Jirarest2Bin.get_password(@scriptopts.username)
|
153
|
-
retry
|
154
|
-
rescue Jirarest2::AuthentificationCaptchaError => e
|
155
|
-
puts "Wrong Password too many times.\nCaptcha time at #{e.to_s} to reenable your account."
|
156
|
-
exit 1
|
149
|
+
@connection,issue = Jirarest2Bin::command(@scriptopts,@connection,:issue,@issueopts.project,@issueopts.issue)
|
157
150
|
rescue Jirarest2::WrongProjectException => e
|
158
151
|
no_issue("project",e)
|
159
152
|
rescue Jirarest2::WrongIssuetypeException => e
|
@@ -255,7 +248,9 @@ end
|
|
255
248
|
=end
|
256
249
|
def create_new_ticket(issue)
|
257
250
|
begin
|
258
|
-
connection = Jirarest2Bin::get_connection(@scriptopts,@connection) # We need it so often in the next few lines that I prefer to get the result in a variable
|
251
|
+
# connection = Jirarest2Bin::get_connection(@scriptopts,@connection) # We need it so often in the next few lines that I prefer to get the result in a variable
|
252
|
+
connection = Jirarest2Bin::command(@scriptopts,@connection,:connection)
|
253
|
+
|
259
254
|
result = issue.persist(connection).result
|
260
255
|
# Set the watchers
|
261
256
|
if @issueopts.watchers then
|
data/bin/jira_watcher
CHANGED
@@ -17,7 +17,7 @@
|
|
17
17
|
|
18
18
|
|
19
19
|
require "jirarest2bin"
|
20
|
-
require "
|
20
|
+
require "deb"
|
21
21
|
|
22
22
|
# Check for the minimum ruby version we need
|
23
23
|
Jirarest2Bin::check_ruby_version
|
@@ -67,7 +67,7 @@ end # class
|
|
67
67
|
# It will then print those issues and their watchers to STDOUT
|
68
68
|
# @param [Array] issues An Array containing the issuekeys
|
69
69
|
def view_watchers(issues)
|
70
|
-
connection =
|
70
|
+
connection = Jirarest2Bin::command(@scriptopts,@connection,:connection)
|
71
71
|
issues.each { |issue|
|
72
72
|
connectedissue = Watcher.new(connection, issue)
|
73
73
|
watchers = connectedissue.get_watchers
|
@@ -87,7 +87,7 @@ end
|
|
87
87
|
# @param [Array] users Users to work with
|
88
88
|
# @param [Array] toto Kind of work to be done
|
89
89
|
def work_watchers(issues,users,todo)
|
90
|
-
connection =
|
90
|
+
connection = Jirarest2Bin::command(@scriptopts,@connection,:connection)
|
91
91
|
issues.each{ |issue|
|
92
92
|
connectedissue = Watcher.new(connection, issue)
|
93
93
|
method = todo + "_watcher" # the name of the method we want to call with send
|
@@ -1,6 +1,5 @@
|
|
1
|
-
|
1
|
+
# This files only purpose is to have one place to control all debugging information
|
2
2
|
|
3
|
-
# Script to create a new issue with jira.
|
4
3
|
# Copyright (C) 2012 Cyril Bitterich
|
5
4
|
#
|
6
5
|
# This program is free software: you can redistribute it and/or modify
|
@@ -17,7 +16,12 @@
|
|
17
16
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
18
17
|
#
|
19
18
|
|
20
|
-
puts "File has been renamed to jira_create_issue"
|
21
|
-
newfile = File.dirname($0) + "/jira_create_issue"
|
22
|
-
puts "Please use: #{newfile} #{$*.join(" ")}"
|
23
19
|
|
20
|
+
if ENV['DEBUG'] then
|
21
|
+
require "pp"
|
22
|
+
# Version of pp that will result in errors if the environment Variable "DEBUG" is not set.
|
23
|
+
# A way to find forgotten debug info before shipping?
|
24
|
+
def ppp(data)
|
25
|
+
pp data
|
26
|
+
end
|
27
|
+
end
|
data/lib/jirarest2.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Jirarest2 is a gem to connect to the REST interface of JIRA(tm) . It uses Basic
|
1
|
+
# Jirarest2 is a gem to connect to the REST interface of JIRA(tm) . It uses Basic authentication and not oauth
|
2
2
|
|
3
3
|
|
4
4
|
# Copyright (C) 2012 Cyril Bitterich
|
@@ -17,11 +17,13 @@
|
|
17
17
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
18
18
|
#
|
19
19
|
|
20
|
-
VERSION = "0.0.
|
20
|
+
VERSION = "0.0.11"
|
21
21
|
|
22
22
|
require_relative "jirarest2/connect"
|
23
23
|
require_relative "jirarest2/issue"
|
24
24
|
require_relative "jirarest2/credentials"
|
25
|
+
require_relative "jirarest2/password_credentials"
|
26
|
+
require_relative "jirarest2/cookie_credentials"
|
25
27
|
require_relative "jirarest2/exceptions"
|
26
28
|
require_relative "jirarest2/services/watcher"
|
27
29
|
require_relative "jirarest2/services"
|
data/lib/jirarest2/connect.rb
CHANGED
@@ -19,31 +19,31 @@
|
|
19
19
|
require 'net/http'
|
20
20
|
require 'jirarest2/exceptions'
|
21
21
|
require 'jirarest2/result'
|
22
|
-
require "
|
22
|
+
require "deb"
|
23
23
|
|
24
24
|
|
25
25
|
|
26
26
|
# A Connect object encasulates the connection to jira via REST. It takes an Credentials object and returns a Jirarest2::Result object or an exception if something went wrong.
|
27
27
|
class Connect
|
28
|
-
|
29
|
-
|
30
|
-
|
28
|
+
# Get the credentials
|
29
|
+
attr_reader :credentials
|
30
|
+
|
31
|
+
# Create an instance of Connect.
|
32
|
+
# @param [Credentials] credentials
|
31
33
|
def initialize(credentials)
|
32
|
-
@
|
33
|
-
@user = credentials.username
|
34
|
-
@CONNECTURL = credentials.connecturl
|
34
|
+
@credentials = credentials
|
35
35
|
end
|
36
36
|
|
37
37
|
|
38
38
|
|
39
|
-
# Execute the request
|
40
|
-
# @param [String, "Get", "Post", "Delete", "Put"] operation HTTP method: GET, POST, DELETE, PUT
|
41
|
-
# @param [String] uritail The last part of the REST URI
|
42
|
-
# @param [Hash] data Data to be sent.
|
43
|
-
# @return [Jirarest2::Result]
|
39
|
+
# Execute the request
|
40
|
+
# @param [String, "Get", "Post", "Delete", "Put"] operation HTTP method: GET, POST, DELETE, PUT
|
41
|
+
# @param [String] uritail The last part of the REST URI
|
42
|
+
# @param [Hash] data Data to be sent.
|
43
|
+
# @return [Jirarest2::Result]
|
44
44
|
def execute(operation,uritail,data)
|
45
45
|
uri = nil
|
46
|
-
uri = URI(@
|
46
|
+
uri = URI(@credentials.connecturl+uritail)
|
47
47
|
if data != "" then
|
48
48
|
if ! (operation == "Post" || operation == "Put") then # POST carries the payload in the body that's why we have to wait
|
49
49
|
uri.query = URI.encode_www_form(data)
|
@@ -51,8 +51,10 @@ class Connect
|
|
51
51
|
end
|
52
52
|
|
53
53
|
req = nil
|
54
|
-
req = Net::HTTP::const_get(operation).new(uri.request_uri)
|
55
|
-
|
54
|
+
req = Net::HTTP::const_get(operation).new(uri.request_uri)
|
55
|
+
# Authentication Header is built up in a credential class
|
56
|
+
@credentials.get_auth_header(req)
|
57
|
+
|
56
58
|
req["Content-Type"] = "application/json;charset=UTF-8"
|
57
59
|
|
58
60
|
if data != "" then
|
@@ -67,16 +69,21 @@ class Connect
|
|
67
69
|
result = Net::HTTP.start(uri.host, uri.port) {|http|
|
68
70
|
http.request(req)
|
69
71
|
}
|
70
|
-
|
71
72
|
# deal with output
|
72
73
|
case result
|
73
74
|
when Net::HTTPBadRequest # 400
|
74
75
|
raise Jirarest2::BadRequestError, result.body
|
75
76
|
when Net::HTTPUnauthorized # 401 No login-credentials oder wrong ones.
|
76
|
-
|
77
|
+
if @credentials.instance_of?(PasswordCredentials) then
|
78
|
+
raise Jirarest2::PasswordAuthenticationError, result.body
|
79
|
+
elsif @credentials.instance_of?(CookieCredentials) then
|
80
|
+
raise Jirarest2::CookieAuthenticationError, result.body
|
81
|
+
else
|
82
|
+
raise Jirarest2::AuthenticationError, result.body
|
83
|
+
end
|
77
84
|
when Net::HTTPForbidden # 403
|
78
85
|
if result.get_fields("x-authentication-denied-reason")[0] =~ /.*login-url=(.*)/ then #Captcha-Time
|
79
|
-
raise Jirarest2::
|
86
|
+
raise Jirarest2::AuthenticationCaptchaError, $1
|
80
87
|
else
|
81
88
|
raise Jirarest2::ForbiddenError, result.body
|
82
89
|
end
|
@@ -84,30 +91,29 @@ class Connect
|
|
84
91
|
raise Jirarest2::NotFoundError, result.body
|
85
92
|
|
86
93
|
end
|
87
|
-
|
88
|
-
|
94
|
+
ret = Jirarest2::Result.new(result)
|
95
|
+
@credentials.bake_cookies(ret.header["set.cookie"]) if @credentials.instance_of?(CookieCredentials) # Make sure cookies are always up to date if we use them.
|
96
|
+
return ret
|
89
97
|
end # execute
|
90
98
|
|
91
99
|
|
92
|
-
# Is the rest API really at the destination we think it is?
|
93
|
-
# @return [Boolean]
|
100
|
+
# Is the rest API really at the destination we think it is?
|
101
|
+
# @return [Boolean]
|
94
102
|
def check_uri
|
95
|
-
begin
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
return false
|
103
|
-
end
|
103
|
+
begin
|
104
|
+
ret = (execute("Get","dashboard","").code == "200")
|
105
|
+
# TODO is the 404 really possible?
|
106
|
+
rescue Jirarest2::NotFoundError
|
107
|
+
return false
|
108
|
+
rescue Jirarest2::BadRequestError
|
109
|
+
return false
|
104
110
|
end
|
105
111
|
end
|
106
112
|
|
107
|
-
# Try to be nice. Parse the URI and see if you can find a pattern to the problem
|
108
|
-
# @param [String] url
|
109
|
-
# @return [String] a fixed URL
|
110
|
-
def heal_uri(url = @
|
113
|
+
# Try to be nice. Parse the URI and see if you can find a pattern to the problem
|
114
|
+
# @param [String] url
|
115
|
+
# @return [String] a fixed URL
|
116
|
+
def heal_uri(url = @credentials.connecturl)
|
111
117
|
splitURI = URI.split(url) # [Scheme,Userinfo,Host,Port,Registry,Path,Opaque,Query,Fragment]
|
112
118
|
splitURI[5].gsub!(/^(.*)2$/,'\12/')
|
113
119
|
splitURI[5].gsub!(/\/+/,'/') # get rid of duplicate /
|
@@ -123,16 +129,16 @@ class Connect
|
|
123
129
|
end
|
124
130
|
|
125
131
|
|
126
|
-
# try to fix the connecturl of this instance
|
127
|
-
# @return [String,Jirarest2::CouldNotHealURIError] Fixed URL or Exception
|
132
|
+
# try to fix the connecturl of this instance
|
133
|
+
# @return [String,Jirarest2::CouldNotHealURIError] Fixed URL or Exception
|
128
134
|
def heal_uri!
|
129
135
|
if ! check_uri then
|
130
|
-
@
|
136
|
+
@credentials.connecturl = heal_uri(@credentials.connecturl)
|
131
137
|
end
|
132
138
|
if check_uri then
|
133
|
-
return @
|
139
|
+
return @credentials.connecturl
|
134
140
|
else
|
135
|
-
raise Jirarest2::CouldNotHealURIError, @
|
141
|
+
raise Jirarest2::CouldNotHealURIError, @credentials.connecturl
|
136
142
|
end
|
137
143
|
end
|
138
144
|
|
@@ -0,0 +1,126 @@
|
|
1
|
+
# Copyright (C) 2012 Cyril Bitterich
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
#
|
16
|
+
|
17
|
+
require_relative "credentials"
|
18
|
+
require_relative "password_credentials"
|
19
|
+
require_relative "result"
|
20
|
+
require_relative "connect"
|
21
|
+
require "pstore"
|
22
|
+
|
23
|
+
# Cookies as credential for the server
|
24
|
+
# login uses basic auth to log in and then cookies are used
|
25
|
+
class CookieCredentials < Credentials
|
26
|
+
|
27
|
+
# Location of the file the cookie is persited on a harddrive. Default is "~/.jirarest2.cookie
|
28
|
+
attr_accessor :cookiestore
|
29
|
+
|
30
|
+
# @param [String] url URL to JIRA(tm) instance
|
31
|
+
# @param [Boolean] autosave Save the cookie on the harddisk whenever something happens?
|
32
|
+
def initialize(connecturl, autosave = false )
|
33
|
+
super(connecturl)
|
34
|
+
@cookiejar = {}
|
35
|
+
@autosave = autosave
|
36
|
+
@cookiestore = "~/.jirarest2.cookie"
|
37
|
+
end
|
38
|
+
|
39
|
+
# Setup new cookies or update the existing jar.
|
40
|
+
# @param [Array] header Header after a request
|
41
|
+
def bake_cookies(header)
|
42
|
+
return if !header
|
43
|
+
header.each do |cookie|
|
44
|
+
next unless (pair = cookie.gsub(/[;]*\s*Path=\S+[,]*/,'').split(/\=/)).length == 2
|
45
|
+
@cookiejar[pair.first] = pair.last
|
46
|
+
end
|
47
|
+
store_cookiejar if @autosave
|
48
|
+
return @cookiejar
|
49
|
+
end
|
50
|
+
|
51
|
+
# Name alias for bake_cookies
|
52
|
+
# @param [String] header Header after a request
|
53
|
+
def set_cookies(header)
|
54
|
+
return bake_cookies(header)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Get the cookies in the format to send as header
|
58
|
+
def get_cookies
|
59
|
+
@cookiejar.map { |cookie| cookie * '=' }.join('; ')
|
60
|
+
end
|
61
|
+
|
62
|
+
# Get the auth header to send to the server
|
63
|
+
# @param [Net:::HTTP::Post,Net:::HTTP::Put,Net:::HTTP::Get,Net:::HTTP::Delete] request Request object
|
64
|
+
# @raise [Jirarest2::AuthenticationError] if there is no JSESSIONID cookie entry
|
65
|
+
# @return [String] Header-Line
|
66
|
+
def get_auth_header(request)
|
67
|
+
if @cookiejar["JSESSIONID"].nil? then
|
68
|
+
raise Jirarest2::CookieAuthenticationError, "No valid cookies"
|
69
|
+
end
|
70
|
+
if get_cookies == "" then
|
71
|
+
# This code should never be executed as the AuthenticationError above will catch more cases
|
72
|
+
request["Cookie"] = "JSESSIONID=0"
|
73
|
+
else
|
74
|
+
request["Cookie"] = get_cookies
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Login per username and password in case the cookie is invalid or missing
|
79
|
+
# Uses basic auth to authenticate
|
80
|
+
# @param [String] username Username to use for login
|
81
|
+
# @param [String] password Password to use for login
|
82
|
+
def login(username,password)
|
83
|
+
pconnecturl = @connecturl.gsub(/\/*rest\/api\/.+/,"/rest/") # Unfortunately the session information is not in the same tree as all the other rest calls
|
84
|
+
pcred = PasswordCredentials.new(pconnecturl,username,password)
|
85
|
+
pconnect = Connect.new(pcred)
|
86
|
+
result = pconnect.execute("Post","auth/latest/session",{"username" => username, "password" => password})
|
87
|
+
bake_cookies(result.header["set-cookie"]) # I already had them seperated into an Array.
|
88
|
+
return @cookiejar["JSESSIONID"]
|
89
|
+
end
|
90
|
+
|
91
|
+
# Invalidates the current cookie
|
92
|
+
# @return [Boolean] true if successful
|
93
|
+
def logout
|
94
|
+
originalConnectUrl = @connecturl
|
95
|
+
begin
|
96
|
+
@connecturl = @connecturl.gsub(/rest\/api\/.+/,"rest/") # Unfortunately the session information is not in the same tree as all the other rest calls
|
97
|
+
con = Connect.new(self)
|
98
|
+
ret = con.execute("Delete","auth/latest/session","").code
|
99
|
+
store_cookiejar if @autosave
|
100
|
+
return true if ret == "204"
|
101
|
+
rescue
|
102
|
+
raise
|
103
|
+
ensure
|
104
|
+
@connecturl = originalConnectUrl
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Loads a cookiejar from disk
|
109
|
+
def load_cookiejar
|
110
|
+
storage = PStore.new(File.expand_path(@cookiestore))
|
111
|
+
storage.transaction do
|
112
|
+
@cookiejar = storage["cookiejar"]
|
113
|
+
end
|
114
|
+
@cookiejar = {} if @cookiejar.nil? # Fix a not so nice feature of PStore if it doesn't find content in the file
|
115
|
+
end
|
116
|
+
|
117
|
+
# Writes the cookiejar to disk
|
118
|
+
def store_cookiejar
|
119
|
+
storage = PStore.new(File.expand_path(@cookiestore))
|
120
|
+
storage.transaction do
|
121
|
+
storage["cookiejar"] = @cookiejar
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
end
|
@@ -21,20 +21,12 @@ require "uri"
|
|
21
21
|
# A Credentials object contains the data required to connect to a JIRA(tm) instance.
|
22
22
|
class Credentials
|
23
23
|
|
24
|
-
# username to use
|
25
|
-
attr_accessor :username
|
26
|
-
# password for the connection
|
27
|
-
attr_accessor :password
|
28
24
|
# url to connect to the JIRA(tm) instance
|
29
25
|
attr_reader :connecturl
|
30
26
|
|
31
27
|
|
32
28
|
# @param [String] url URL to JIRA(tm) instance
|
33
|
-
|
34
|
-
# @param [String] password
|
35
|
-
def initialize(url,username,password)
|
36
|
-
@username = username
|
37
|
-
@password = password
|
29
|
+
def initialize(url)
|
38
30
|
uri = URI(url)
|
39
31
|
if uri.instance_of?(URI::HTTP) || uri.instance_of?(URI::HTTPS) then
|
40
32
|
@connecturl = url
|
@@ -54,4 +46,10 @@ class Credentials
|
|
54
46
|
end
|
55
47
|
end
|
56
48
|
|
49
|
+
# Get the auth header to send to the server
|
50
|
+
# @param [Net:::HTTP::Post,Net:::HTTP::Put,Net:::HTTP::Get,Net:::HTTP::Delete] request Request object
|
51
|
+
def get_auth_header(request)
|
52
|
+
|
53
|
+
end
|
54
|
+
|
57
55
|
end
|
data/lib/jirarest2/exceptions.rb
CHANGED
@@ -21,11 +21,15 @@ module Jirarest2
|
|
21
21
|
|
22
22
|
# 400 -
|
23
23
|
class BadRequestError < StandardError ; end
|
24
|
-
# 401
|
25
|
-
class
|
26
|
-
#
|
27
|
-
class
|
28
|
-
#
|
24
|
+
# 401 Authentication failed
|
25
|
+
class AuthenticationError < StandardError ; end
|
26
|
+
# 401 Authentication failed with password authentication
|
27
|
+
class PasswordAuthenticationError < AuthenticationError ; end
|
28
|
+
# 401 Authentication failed with cookie authentication
|
29
|
+
class CookieAuthenticationError < AuthenticationError ; end
|
30
|
+
# 403 Authentication failed and JIRA(tm) requires a login with captcha to continue
|
31
|
+
class AuthenticationCaptchaError < StandardError ; end
|
32
|
+
# 403 Forbidden
|
29
33
|
class ForbiddenError < StandardError ; end
|
30
34
|
# 404 - Results in HTML body - not JSON
|
31
35
|
class NotFoundError < StandardError ; end
|
data/lib/jirarest2/issue.rb
CHANGED
@@ -233,7 +233,7 @@ class Issue
|
|
233
233
|
# Set the watchers for this Ticket
|
234
234
|
# @param [Connection] connection
|
235
235
|
# @param [Array] watchers Watchers to be added
|
236
|
-
# @return [Boolean] True if
|
236
|
+
# @return [Boolean] True if successful for all
|
237
237
|
def add_watchers(connection,watchers)
|
238
238
|
success = false # Return whether we were successful with the watchers
|
239
239
|
watch = Watcher.new(connection,@issuekey)
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# A Credentials object contains the data required to connect to a JIRA(tm) instance.
|
2
|
+
|
3
|
+
# Copyright (C) 2012 Cyril Bitterich
|
4
|
+
#
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
#
|
18
|
+
|
19
|
+
require_relative "credentials"
|
20
|
+
|
21
|
+
# A Credentials object contains the data required to connect to a JIRA(tm) instance.
|
22
|
+
class PasswordCredentials < Credentials
|
23
|
+
|
24
|
+
# username to use
|
25
|
+
attr_accessor :username
|
26
|
+
# password for the connection
|
27
|
+
attr_accessor :password
|
28
|
+
|
29
|
+
# @param [String] url URL to JIRA(tm) instance
|
30
|
+
# @param [String] username
|
31
|
+
# @param [String] password
|
32
|
+
def initialize(url,username,password)
|
33
|
+
super(url)
|
34
|
+
@username = username
|
35
|
+
@password = password
|
36
|
+
=begin
|
37
|
+
uri = URI(url)
|
38
|
+
if uri.instance_of?(URI::HTTP) || uri.instance_of?(URI::HTTPS) then
|
39
|
+
@connecturl = url
|
40
|
+
else
|
41
|
+
raise Jirarest2::NotAnURLError
|
42
|
+
end
|
43
|
+
=end
|
44
|
+
end
|
45
|
+
=begin
|
46
|
+
# Throws an Jirarest2::NotAnURLError if the given String is not an URI.
|
47
|
+
# @param [String] url
|
48
|
+
def connecturl=(url)
|
49
|
+
uri = URI(url)
|
50
|
+
if uri.instance_of?(URI::HTTP) || uri.instance_of?(URI::HTTPS) then
|
51
|
+
@connecturl = url
|
52
|
+
else
|
53
|
+
raise Jirarest2::NotAnURLError
|
54
|
+
end
|
55
|
+
end
|
56
|
+
=end
|
57
|
+
# Get the auth header to send to the server
|
58
|
+
# @param [Net:::HTTP::Post,Net:::HTTP::Put,Net:::HTTP::Get,Net:::HTTP::Delete] request Request object
|
59
|
+
def get_auth_header(request)
|
60
|
+
request.basic_auth @username, @password
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
@@ -72,7 +72,7 @@ public
|
|
72
72
|
|
73
73
|
#Get the internal name and direction instead of the one in the UI.
|
74
74
|
# @param [String] uiname the way the linktype is shown in the browser
|
75
|
-
# @return [Array, nil] Array with the name and the direction ("inward" or "outward") if
|
75
|
+
# @return [Array, nil] Array with the name and the direction ("inward" or "outward") if successful , nil if not
|
76
76
|
def name(uiname)
|
77
77
|
return uiname if @types.has_key?(uiname) # If the name is already correct just bounce it back
|
78
78
|
@types.each { |name,singletype|
|
data/lib/jirarest2bin.rb
CHANGED
@@ -49,6 +49,11 @@ module Jirarest2Bin
|
|
49
49
|
text["username"] = "#{scriptopts.username}"
|
50
50
|
end
|
51
51
|
text["#password"] = "Your!PassW0rd"
|
52
|
+
if scriptopts.nocookieauth.nil? || scriptopts.nocookieauth then
|
53
|
+
text["nocookieauth"] = "false"
|
54
|
+
else
|
55
|
+
text["nocookieauth"] = "true"
|
56
|
+
end
|
52
57
|
begin
|
53
58
|
if scriptopts.writeconf == :forcewrite then
|
54
59
|
MadbitConfig::write_configfile(scriptopts.configfile,text,:force)
|
@@ -75,6 +80,7 @@ module Jirarest2Bin
|
|
75
80
|
# @param [String] username The Username to show
|
76
81
|
# @return [String] the password as read from the command line
|
77
82
|
def self.get_password(username)
|
83
|
+
STDIN.reopen '/dev/tty'
|
78
84
|
password = ask("Enter your password for user \"#{username}\": ") { |q|
|
79
85
|
q.echo = "*"
|
80
86
|
}
|
@@ -98,25 +104,31 @@ module Jirarest2Bin
|
|
98
104
|
puts e
|
99
105
|
filefail = false
|
100
106
|
end
|
101
|
-
scriptopts.url = scriptopts.url + "/rest/api/2/"
|
102
|
-
|
103
|
-
if scriptopts.pass.nil? && !( scriptopts.username.nil?) then
|
104
|
-
scriptopts.pass = Jirarest2Bin::get_password(scriptopts.username)
|
105
|
-
end
|
106
|
-
|
107
|
+
scriptopts.url = (scriptopts.url + "/rest/api/2/") if !( scriptopts.url =~ /\/rest\/api\/2\/$/)
|
107
108
|
missing = Array.new
|
108
109
|
missing << "URL" if scriptopts.url.nil?
|
109
110
|
missing << "username" if scriptopts.username.nil?
|
110
111
|
if missing != [] then
|
111
112
|
puts "Missing essential parameter(s) #{missing.join(",")}. Exiting..."
|
112
113
|
exit 1
|
114
|
+
end
|
115
|
+
|
116
|
+
if !scriptopts.nocookieauth then
|
117
|
+
credentials = CookieCredentials.new(scriptopts.url,true)
|
118
|
+
credentials.load_cookiejar
|
119
|
+
return credentials
|
120
|
+
# TODO What to do if the cookie expired?
|
113
121
|
else
|
114
|
-
|
122
|
+
if scriptopts.pass.nil? && !( scriptopts.username.nil?) then
|
123
|
+
scriptopts.pass = Jirarest2Bin::get_password(scriptopts.username)
|
124
|
+
end
|
125
|
+
return PasswordCredentials.new(scriptopts.url, scriptopts.username, scriptopts.pass)
|
115
126
|
end
|
116
127
|
end # get_credentials
|
117
128
|
|
118
129
|
|
119
130
|
# If there is already a connection known returns that connection. If not or if the parameter is true it tries to create a new Connect object
|
131
|
+
# @note Don't call this directly as it will fail if your credentials are wrong.
|
120
132
|
# @param [Openstruct] scriptopts The Openstruct object that contains all the options relevant for the script
|
121
133
|
# @param [Connect] connection An existing connection. Will be nil the first time we use it.
|
122
134
|
# @param [Boolean] reconnect Loose an existing connection and build a new one
|
@@ -126,7 +138,10 @@ module Jirarest2Bin
|
|
126
138
|
begin
|
127
139
|
connection = Connect.new(get_credentials(scriptopts))
|
128
140
|
connection.heal_uri! # We want to be sure so we try to heal the connection_url if possible
|
129
|
-
|
141
|
+
connection
|
142
|
+
rescue Jirarest2::CookieAuthenticationError => e
|
143
|
+
connection.credentials.login(scriptopts.username,scriptopts.pass)
|
144
|
+
retry
|
130
145
|
rescue Jirarest2::CouldNotHealURIError => e
|
131
146
|
puts "REST API not found at #{e.to_s}"
|
132
147
|
exit 3
|
@@ -135,7 +150,40 @@ module Jirarest2Bin
|
|
135
150
|
return connection
|
136
151
|
end
|
137
152
|
end # get_connection
|
138
|
-
|
153
|
+
|
154
|
+
# Execute a command to the server
|
155
|
+
# This version is safe if the credentials are wrong. Extend the case if more requests should be safeguarded.
|
156
|
+
# @param [Array] scriptopts Command line options from the calling script
|
157
|
+
# @param [Connection,Nil] connection a connection we er to use
|
158
|
+
# @param [Symbol] command to execute
|
159
|
+
# @param [Array] *args Arguments for the commands to call
|
160
|
+
# @return [Connection] The connection we used
|
161
|
+
# @return [Object] The object that was called in the command
|
162
|
+
# @example get a Connection object
|
163
|
+
# connection = Jirarest2Bin::command(@scriptopts,@connection,:connection)
|
164
|
+
def self.command(scriptopts,connection,command,*args)
|
165
|
+
begin
|
166
|
+
if connection.nil? then
|
167
|
+
connection = get_connection(scriptopts,connection)
|
168
|
+
end
|
169
|
+
case command
|
170
|
+
when :issue
|
171
|
+
return connection, Issue.new(args[0],args[1],connection)
|
172
|
+
when :connection
|
173
|
+
return connection
|
174
|
+
end
|
175
|
+
rescue Jirarest2::PasswordAuthenticationError => e
|
176
|
+
scriptopts.pass = Jirarest2Bin.get_password(scriptopts.username)
|
177
|
+
retry
|
178
|
+
rescue Jirarest2::CookieAuthenticationError => e
|
179
|
+
connection.credentials.login(scriptopts.username,scriptopts.pass)
|
180
|
+
retry
|
181
|
+
rescue Jirarest2::AuthenticationCaptchaError => e
|
182
|
+
puts "Wrong Password too many times.\nCaptcha time at #{e.to_s} to reenable your account."
|
183
|
+
exit 1
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
139
187
|
|
140
188
|
# This method is here because I am to lazy to rewrite the options every time
|
141
189
|
# use it with scriptopts = Jirarest2Bin::defaultoptions(opts,scriptopts)
|
@@ -161,7 +209,7 @@ module Jirarest2Bin
|
|
161
209
|
end
|
162
210
|
|
163
211
|
|
164
|
-
opts.on_tail("-u", "--username USERNAME", "Your Jira Username if
|
212
|
+
opts.on_tail("-u", "--username USERNAME", "Your Jira Username if it is not the one in the master file") do |u|
|
165
213
|
scriptopts.username = u
|
166
214
|
end
|
167
215
|
|
@@ -176,6 +224,10 @@ module Jirarest2Bin
|
|
176
224
|
scriptopts.url = url
|
177
225
|
end
|
178
226
|
|
227
|
+
opts.on_tail("--no-cookie", "Don't try to authenticate via cookies") do |nocookie|
|
228
|
+
scriptopts.nocookieauth = true
|
229
|
+
end
|
230
|
+
|
179
231
|
opts.on_tail("-h", "--help", "Display this screen") do
|
180
232
|
puts opts
|
181
233
|
exit
|
data/test/data/cookiejar
ADDED
Binary file
|
data/test/test_comment.rb
CHANGED
@@ -6,7 +6,7 @@ require "jirarest2/services/comment"
|
|
6
6
|
|
7
7
|
class TestComment < MiniTest::Unit::TestCase
|
8
8
|
def setup
|
9
|
-
cred =
|
9
|
+
cred = PasswordCredentials.new("http://localhost:2990/jira/rest/api/2/","test","1234")
|
10
10
|
@con = Connect.new(cred)
|
11
11
|
end
|
12
12
|
|
data/test/test_connect.rb
CHANGED
@@ -1,16 +1,17 @@
|
|
1
1
|
require "minitest/autorun"
|
2
2
|
require "jirarest2/connect"
|
3
|
-
require "jirarest2/
|
3
|
+
require "jirarest2/password_credentials"
|
4
|
+
require "jirarest2/cookie_credentials"
|
4
5
|
require "webmock/minitest"
|
5
6
|
|
6
7
|
class TestConnect < MiniTest::Unit::TestCase
|
7
8
|
def setup
|
8
|
-
cred =
|
9
|
+
cred = PasswordCredentials.new("http://localhost:2990/jira/rest/api/2/","test","1234")
|
9
10
|
@con = Connect.new(cred)
|
10
11
|
end
|
11
12
|
|
12
13
|
def test_access
|
13
|
-
stub_request(:any,"http://localhost:2990/
|
14
|
+
stub_request(:any,"http://localhost:2990/jira/rest/api/2/").with(:headers => {"Content-Type:" => "application/json;charset=UTF-8"})
|
14
15
|
end
|
15
16
|
|
16
17
|
def test_executeGET
|
@@ -32,7 +33,7 @@ class TestConnect < MiniTest::Unit::TestCase
|
|
32
33
|
|
33
34
|
def test_check_uri_false
|
34
35
|
stub_request(:get, "http://test:1234@localhost:2990/rest/api/2/dashboard").with(:headers => {'Accept'=>'*/*', 'Content-Type'=>'application/json;charset=UTF-8', 'User-Agent'=>'Ruby'}).to_return(:status => 400, :body => "", :headers => {})
|
35
|
-
cred =
|
36
|
+
cred = PasswordCredentials.new("http://localhost:2990/rest/api/2/","test","1234")
|
36
37
|
con1 = Connect.new(cred)
|
37
38
|
assert_equal false,con1.check_uri
|
38
39
|
end
|
@@ -40,7 +41,7 @@ class TestConnect < MiniTest::Unit::TestCase
|
|
40
41
|
def test_heal_uri
|
41
42
|
stub_request(:get, "http://test:1234@localhost:2990/jira/rest/api/2/dashboard").with(:headers => {'Accept'=>'*/*', 'Content-Type'=>'application/json;charset=UTF-8', 'User-Agent'=>'Ruby'}).to_return(:status => 200, :body => "", :headers => {})
|
42
43
|
|
43
|
-
cred =
|
44
|
+
cred = PasswordCredentials.new("http://localhost:2990/jira//rest/api//2//","test","1234")
|
44
45
|
con = Connect.new(cred)
|
45
46
|
assert_equal "http://localhost:2990/jira/rest/api/2/",con.heal_uri
|
46
47
|
assert_equal "http://localhost:2990/jira/rest/api/2/",con.heal_uri("http://localhost:2990/jira/rest/api/2/rest/api/2/")
|
@@ -59,7 +60,7 @@ class TestConnect < MiniTest::Unit::TestCase
|
|
59
60
|
stub_request(:get, "http://test:1234@localhost:2990/jira//rest/api//2//dashboard").with(:headers => {'Accept'=>'*/*', 'Content-Type'=>'application/json;charset=UTF-8', 'User-Agent'=>'Ruby'}).to_return(:status => 404, :body => '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><status><status-code>404</status-code><message>null for uri: http://localhost:2990/jira//rest/api//2//dashboard</message></status>', :headers => {"X-AUSERNAME" => "test" })
|
60
61
|
|
61
62
|
## First an URL we can fix
|
62
|
-
cred =
|
63
|
+
cred = PasswordCredentials.new("http://localhost:2990/jira//rest/api//2//","test","1234")
|
63
64
|
con = Connect.new(cred)
|
64
65
|
assert_equal false,con.check_uri
|
65
66
|
|
@@ -71,7 +72,7 @@ class TestConnect < MiniTest::Unit::TestCase
|
|
71
72
|
def test_notworking_heal_uri!
|
72
73
|
stub_request(:get, "http://test:1234@localhost:2990/secure/Dashboard.jspadashboard").with(:headers => {'Accept'=>'*/*', 'Content-Type'=>'application/json;charset=UTF-8', 'User-Agent'=>'Ruby'}).to_return(:status => 400, :body => "", :headers => {})
|
73
74
|
## And now one we cant't fix
|
74
|
-
cred =
|
75
|
+
cred = PasswordCredentials.new("http://localhost:2990/secure/Dashboard.jspa","test","1234")
|
75
76
|
con = Connect.new(cred)
|
76
77
|
assert_equal false,con.check_uri
|
77
78
|
assert_raises(Jirarest2::CouldNotHealURIError){ con.heal_uri! }
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require "minitest/autorun"
|
2
|
+
require "jirarest2/cookie_credentials"
|
3
|
+
require "net/http"
|
4
|
+
require "webmock/minitest"
|
5
|
+
require "deb"
|
6
|
+
|
7
|
+
class TestCookieCredentials < MiniTest::Unit::TestCase
|
8
|
+
|
9
|
+
def setup
|
10
|
+
@cred = CookieCredentials.new("http://localhost:2990/jira/rest/api/2/")
|
11
|
+
@header = ["a.xsrf.token=BP8Q-WXN6-SKX3-NB5M|11ca22ad2bf3467bee711e5b912536d1fb046a4a|lout; Path=/myapp", "JSESSIONID=6C3AE9205FFC6E0DEC3353C2D10745D8; Path=/"]
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
def test_bake_cookies
|
16
|
+
result = {"a.xsrf.token"=> "BP8Q-WXN6-SKX3-NB5M|11ca22ad2bf3467bee711e5b912536d1fb046a4a|lout", "JSESSIONID"=>"6C3AE9205FFC6E0DEC3353C2D10745D8"}
|
17
|
+
assert_equal result, @cred.bake_cookies(@header)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_set_cookies
|
21
|
+
test_bake_cookies
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_get_cookies
|
25
|
+
result = "a.xsrf.token=BP8Q-WXN6-SKX3-NB5M|11ca22ad2bf3467bee711e5b912536d1fb046a4a|lout; JSESSIONID=6C3AE9205FFC6E0DEC3353C2D10745D8"
|
26
|
+
@cred.bake_cookies(@header) # If this fails please see if test_bake_cookies fails as well
|
27
|
+
assert_equal result, @cred.get_cookies
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_get_auth_header
|
31
|
+
result = "a.xsrf.token=BP8Q-WXN6-SKX3-NB5M|11ca22ad2bf3467bee711e5b912536d1fb046a4a|lout; JSESSIONID=6C3AE9205FFC6E0DEC3353C2D10745D8"
|
32
|
+
uri = URI(@cred.connecturl)
|
33
|
+
@cred.bake_cookies(@header) # If this fails please see if test_bake_cookies fails as well
|
34
|
+
req = Net::HTTP::Get.new(uri.request_uri)
|
35
|
+
@cred.get_auth_header(req)
|
36
|
+
assert_instance_of Net::HTTP::Get, req # make sure we still got the right requestor class
|
37
|
+
assert_equal result,req["Cookie"]
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_login_failed
|
41
|
+
stub_request(:post, "http://test:12345@localhost:2990/jira/rest/auth/latest/session").with(:body => "{\"username\":\"test\",\"password\":\"12345\"}",:headers => {'Accept'=>'*/*', 'Content-Type'=>'application/json;charset=UTF-8', 'User-Agent'=>'Ruby'}).to_return(:status => 401, :body => "", :headers => {})
|
42
|
+
assert_raises(Jirarest2::PasswordAuthenticationError) {
|
43
|
+
@cred.login("test","12345")
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_login_successful
|
48
|
+
stub_request(:post, "http://test:1234@localhost:2990/jira/rest/auth/latest/session").with(:body => "{\"username\":\"test\",\"password\":\"1234\"}",:headers => {'Accept'=>'*/*', 'Content-Type'=>'application/json;charset=UTF-8'}).to_return(:status => 200, :body => '{"session":{"name":"JSESSIONID","value":"E8FE2A7CDB3306672665739A8E88D674"}}', :headers => {"Set-Cookie" => ["JSESSIONID=E8FE2A7CDB3306672665739A8E88D674; Path=/","a.xsrf.token=BP8Q-WXN6-SKX3-NB5M|39554775813b531f7dcba4aa28bb13b20e602eb9|lin; Path=/jira"]})
|
49
|
+
assert_equal "E8FE2A7CDB3306672665739A8E88D674", @cred.login("test","1234")
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_logout # requires test_login_successful to succeed, so not really good :( )
|
53
|
+
stub_request(:post, "http://test:1234@localhost:2990/jira/rest/auth/latest/session").with(:body => "{\"username\":\"test\",\"password\":\"1234\"}",:headers => {'Accept'=>'*/*', 'Content-Type'=>'application/json;charset=UTF-8'}).to_return(:status => 200, :body => '{"session":{"name":"JSESSIONID","value":"E8FE2A7CDB3306672665739A8E88D674"}}', :headers => {"Set-Cookie" => ["JSESSIONID=E8FE2A7CDB3306672665739A8E88D674; Path=/","a.xsrf.token=BP8Q-WXN6-SKX3-NB5M|39554775813b531f7dcba4aa28bb13b20e602eb9|lin; Path=/jira"]})
|
54
|
+
stub_request(:delete, "http://localhost:2990/jira/rest/auth/latest/session").with(:headers => {'Accept'=>'*/*', 'Content-Type'=>'application/json;charset=UTF-8', 'Cookie'=>'JSESSIONID=E8FE2A7CDB3306672665739A8E88D674; a.xsrf.token=BP8Q-WXN6-SKX3-NB5M|39554775813b531f7dcba4aa28bb13b20e602eb9|lin', 'User-Agent'=>'Ruby'}).to_return(:status => 204, :body => "", :headers => {})
|
55
|
+
@cred.login("test","1234")
|
56
|
+
assert_equal true,@cred.logout
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_store_cookiejar
|
60
|
+
@cred.cookiestore = File.dirname(__FILE__) + "/data/cookiejar"
|
61
|
+
@cred.bake_cookies(@header)
|
62
|
+
expect = {"a.xsrf.token"=>"BP8Q-WXN6-SKX3-NB5M|11ca22ad2bf3467bee711e5b912536d1fb046a4a|lout", "JSESSIONID"=>"6C3AE9205FFC6E0DEC3353C2D10745D8"}
|
63
|
+
assert_equal expect, @cred.store_cookiejar
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_load_cookiejar
|
67
|
+
@cred.cookiestore = File.dirname(__FILE__) + "/data/cookiejar"
|
68
|
+
@cred.load_cookiejar
|
69
|
+
assert_equal "a.xsrf.token=BP8Q-WXN6-SKX3-NB5M|11ca22ad2bf3467bee711e5b912536d1fb046a4a|lout; JSESSIONID=6C3AE9205FFC6E0DEC3353C2D10745D8", @cred.get_cookies
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
data/test/test_credentials.rb
CHANGED
@@ -1,38 +1,26 @@
|
|
1
1
|
require "minitest/autorun"
|
2
|
-
require "jirarest2"
|
2
|
+
require "jirarest2/credentials"
|
3
|
+
require "jirarest2/exceptions"
|
3
4
|
|
4
5
|
class TestCredentials < MiniTest::Unit::TestCase
|
5
6
|
def setup
|
6
|
-
@cred = Credentials.new("https://localhost:2990"
|
7
|
-
@credc = Credentials.new("https://localhost:2990","username","password")
|
7
|
+
@cred = Credentials.new("https://localhost:2990")
|
8
8
|
end
|
9
9
|
|
10
10
|
def testInitialize
|
11
|
-
assert_instance_of(Credentials, Credentials.new("https://localhost:2990"
|
11
|
+
assert_instance_of(Credentials, Credentials.new("https://localhost:2990"))
|
12
12
|
assert_raises(Jirarest2::NotAnURLError) {
|
13
|
-
Credentials.new("localhost:2990"
|
13
|
+
Credentials.new("localhost:2990")
|
14
14
|
}
|
15
15
|
assert_equal "https://localhost:2990", @cred.connecturl
|
16
|
-
assert_equal "username", @cred.username
|
17
|
-
assert_equal "password", @cred.password
|
18
16
|
end
|
19
17
|
|
20
18
|
def testSetURL
|
21
|
-
@
|
22
|
-
assert_equal "http://localhost:80", @
|
19
|
+
@cred.connecturl = "http://localhost:80"
|
20
|
+
assert_equal "http://localhost:80", @cred.connecturl
|
23
21
|
assert_raises(Jirarest2::NotAnURLError) {
|
24
|
-
@
|
22
|
+
@cred.connecturl = "localhost:80"
|
25
23
|
}
|
26
24
|
end
|
27
25
|
|
28
|
-
def testSetPassword
|
29
|
-
@credc.password = "1234"
|
30
|
-
assert_equal "1234", @credc.password
|
31
|
-
end
|
32
|
-
|
33
|
-
def testSetUsername
|
34
|
-
@credc.username = "test"
|
35
|
-
assert_equal "test", @credc.username
|
36
|
-
end
|
37
|
-
|
38
26
|
end
|
data/test/test_issue.rb
CHANGED
@@ -5,7 +5,7 @@ require "webmock/minitest"
|
|
5
5
|
|
6
6
|
class TestIssue < MiniTest::Unit::TestCase
|
7
7
|
def setup
|
8
|
-
@credentials =
|
8
|
+
@credentials = PasswordCredentials.new("http://localhost:2990/jira/rest/api/2/","test","1234")
|
9
9
|
@connect = Connect.new(@credentials)
|
10
10
|
raw_response_file = File.new(File.dirname(__FILE__)+"/data/issuespec.txt")
|
11
11
|
stub_request(:get, "http://test:1234@localhost:2990/jira/rest/api/2/issue/createmeta/?expand=projects.issuetypes.fields&issuetypeNames=My%20issue%20type&projectKeys=MFTP").with(:headers => {'Accept'=>'*/*', 'Content-Type'=>'application/json;charset=UTF-8', 'User-Agent'=>'Ruby'}).to_return(raw_response_file)
|
data/test/test_issuelink.rb
CHANGED
@@ -8,7 +8,7 @@ require "webmock/minitest"
|
|
8
8
|
|
9
9
|
class TestIssueLink < MiniTest::Unit::TestCase
|
10
10
|
def setup
|
11
|
-
cred =
|
11
|
+
cred = PasswordCredentials.new("http://localhost:2990/jira/rest/api/2/","test","1234")
|
12
12
|
@con = Connect.new(cred)
|
13
13
|
stub_request(:get, "http://test:1234@localhost:2990/jira/rest/api/2/issueLinkType").with(:headers => {'Accept'=>'*/*', 'Content-Type'=>'application/json;charset=UTF-8', 'User-Agent'=>'Ruby'}).to_return(:status => 200, :body => '{"issueLinkTypes":[{"id":"10000","name":"Blocks","inward":"is blocked by","outward":"blocks","self":"http://localhost:2990/jira/rest/api/2/issueLinkType/10000"},{"id":"10001","name":"Cloners","inward":"is cloned by","outward":"clones","self":"http://localhost:2990/jira/rest/api/2/issueLinkType/10001"},{"id":"10002","name":"Duplicate","inward":"is duplicated by","outward":"duplicates","self":"http://localhost:2990/jira/rest/api/2/issueLinkType/10002"},{"id":"10003","name":"Relates","inward":"relates to","outward":"relates to","self":"http://localhost:2990/jira/rest/api/2/issueLinkType/10003"}]}', :headers => {})
|
14
14
|
@link = IssueLink.new(@con)
|
@@ -18,7 +18,7 @@ class TestIssueLink < MiniTest::Unit::TestCase
|
|
18
18
|
def test_link_issue_access
|
19
19
|
# check for right to link.
|
20
20
|
stub_request(:post, "http://test:1234@localhost:2990/jira/rest/api/2/issueLink").with(:body => "{\"type\":{\"name\":\"Blocks\"},\"inwardIssue\":{\"key\":\"MFTP-6\"},\"outwardIssue\":{\"key\":\"SP-2\"}}",:headers => {'Accept'=>'*/*', 'Content-Type'=>'application/json;charset=UTF-8', 'User-Agent'=>'Ruby'}).to_return(:status => 401, :body => '{"errorMessages":["No Link Issue Permission for issue \'MFTP-6\'"],"errors":{}}', :headers => {})
|
21
|
-
assert_raises(Jirarest2::
|
21
|
+
assert_raises(Jirarest2::PasswordAuthenticationError) {
|
22
22
|
@link.link_issue("MFTP-6","SP-2","Blocks")
|
23
23
|
}
|
24
24
|
end
|
data/test/test_issuelinktype.rb
CHANGED
@@ -8,7 +8,7 @@ require "webmock/minitest"
|
|
8
8
|
|
9
9
|
class TestIssueLinkType < MiniTest::Unit::TestCase
|
10
10
|
def setup
|
11
|
-
cred =
|
11
|
+
cred = PasswordCredentials.new("http://localhost:2990/jira/rest/api/2/","test","1234")
|
12
12
|
@con = Connect.new(cred)
|
13
13
|
end
|
14
14
|
|
data/test/test_madbitconfig.rb
CHANGED
@@ -0,0 +1,26 @@
|
|
1
|
+
require "minitest/autorun"
|
2
|
+
require "jirarest2/password_credentials"
|
3
|
+
|
4
|
+
class TestPasswordCredentials < MiniTest::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
@cred = PasswordCredentials.new("https://localhost:2990","username","password")
|
7
|
+
end
|
8
|
+
|
9
|
+
def testInitialize
|
10
|
+
assert_instance_of(PasswordCredentials, @cred)
|
11
|
+
assert_equal "https://localhost:2990", @cred.connecturl
|
12
|
+
assert_equal "username", @cred.username
|
13
|
+
assert_equal "password", @cred.password
|
14
|
+
end
|
15
|
+
|
16
|
+
def testSetPassword
|
17
|
+
@cred.password = "1234"
|
18
|
+
assert_equal "1234", @cred.password
|
19
|
+
end
|
20
|
+
|
21
|
+
def testSetUsername
|
22
|
+
@cred.username = "test"
|
23
|
+
assert_equal "test", @cred.username
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
data/test/test_result.rb
CHANGED
@@ -6,7 +6,7 @@ require "webmock/minitest"
|
|
6
6
|
|
7
7
|
class TestResult < MiniTest::Unit::TestCase
|
8
8
|
def setup
|
9
|
-
cred =
|
9
|
+
cred = PasswordCredentials.new("http://localhost:2990/jira/rest/api/2/","test","1234")
|
10
10
|
@con = Connect.new(cred)
|
11
11
|
end
|
12
12
|
|
data/test/test_watcher.rb
CHANGED
@@ -7,7 +7,7 @@ require "webmock/minitest"
|
|
7
7
|
|
8
8
|
class TestWatcher < MiniTest::Unit::TestCase
|
9
9
|
def setup
|
10
|
-
cred =
|
10
|
+
cred = PasswordCredentials.new("http://localhost:2990/jira/rest/api/2/","test","1234")
|
11
11
|
@con = Connect.new(cred)
|
12
12
|
end
|
13
13
|
|
@@ -27,7 +27,7 @@ class TestWatcher < MiniTest::Unit::TestCase
|
|
27
27
|
stub_request(:delete, "http://test:1234@localhost:2990/jira/rest/api/2/issue/MFTP-7/watchers?username=cebit").with(:headers => {'Accept'=>'*/*', 'Content-Type'=>'application/json;charset=UTF-8', 'User-Agent'=>'Ruby'}).to_return(:status => 401, :body => '{"errorMessages":["User \'test\' is not allowed to remove watchers from issue \'MFTP-7\'"],"errors":{}}', :headers => {})
|
28
28
|
|
29
29
|
watchers = Watcher.new(@con,"MFTP-7")
|
30
|
-
assert_raises(Jirarest2::
|
30
|
+
assert_raises(Jirarest2::PasswordAuthenticationError) {
|
31
31
|
watchers.remove_watcher("cebit")
|
32
32
|
}
|
33
33
|
end
|
@@ -36,7 +36,7 @@ class TestWatcher < MiniTest::Unit::TestCase
|
|
36
36
|
stub_request(:post, "http://test:1234@localhost:2990/jira/rest/api/2/issue/MFTP-2/watchers").with(:body => "\"cebit\"", :headers => {'Accept'=>'*/*', 'Content-Type'=>'application/json;charset=UTF-8', 'User-Agent'=>'Ruby'}).to_return(:status => 401, :body => '{"errorMessages":["User \'test\' is not allowed to add watchers to issue \'MFTP-2\'"],"errors":{}}', :headers => {})
|
37
37
|
|
38
38
|
watcherna = Watcher.new(@con, "MFTP-2")
|
39
|
-
assert_raises(Jirarest2::
|
39
|
+
assert_raises(Jirarest2::PasswordAuthenticationError) {
|
40
40
|
watcherna.add_watcher("cebit")
|
41
41
|
}
|
42
42
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jirarest2
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.11
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -50,7 +50,7 @@ cert_chain:
|
|
50
50
|
-----END CERTIFICATE-----
|
51
51
|
|
52
52
|
'
|
53
|
-
date: 2012-08-
|
53
|
+
date: 2012-08-05 00:00:00.000000000 Z
|
54
54
|
dependencies:
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: json
|
@@ -136,7 +136,7 @@ description: ! "jirarest2 is yet another implementation of the JIRA(tm) REST-API
|
|
136
136
|
. This one for Ruby1.9.1\n\nIt is intended to be called within the shell to create
|
137
137
|
and verify JIRA(tm) issues fast without a browser. There was no particular need
|
138
138
|
for perfomance at the time of writing.\n\nThis implementation is still a for cry
|
139
|
-
from others like http://rubygems.org/gems/jira-ruby which requires oauth
|
139
|
+
from others like http://rubygems.org/gems/jira-ruby which requires oauth authentication.
|
140
140
|
\n\nThere are scripts to create new issues with watchers and link those to existing
|
141
141
|
issues and to manipulate watchers on existing issues.\n\n *Use it at your own risk.
|
142
142
|
Most of the API features are not implemented.*\n\n *Ruby1.9.1 is needed. Ruby1.8
|
@@ -144,10 +144,8 @@ description: ! "jirarest2 is yet another implementation of the JIRA(tm) REST-API
|
|
144
144
|
email:
|
145
145
|
- cebit-jirarest@gunnet.de
|
146
146
|
executables:
|
147
|
-
- create_issue.rb
|
148
147
|
- jira_comment
|
149
148
|
- jira_create_issue
|
150
|
-
- jira_create_issue.rb
|
151
149
|
- jira_watcher
|
152
150
|
extensions: []
|
153
151
|
extra_rdoc_files:
|
@@ -161,18 +159,19 @@ files:
|
|
161
159
|
- Manifest.txt
|
162
160
|
- README.txt
|
163
161
|
- Rakefile
|
164
|
-
- bin/create_issue.rb
|
165
162
|
- bin/jira_comment
|
166
163
|
- bin/jira_create_issue
|
167
|
-
- bin/jira_create_issue.rb
|
168
164
|
- bin/jira_watcher
|
169
165
|
- copyright
|
166
|
+
- lib/deb.rb
|
170
167
|
- lib/jirarest2.rb
|
171
168
|
- lib/jirarest2/connect.rb
|
169
|
+
- lib/jirarest2/cookie_credentials.rb
|
172
170
|
- lib/jirarest2/credentials.rb
|
173
171
|
- lib/jirarest2/exceptions.rb
|
174
172
|
- lib/jirarest2/issue.rb
|
175
173
|
- lib/jirarest2/madbitconfig.rb
|
174
|
+
- lib/jirarest2/password_credentials.rb
|
176
175
|
- lib/jirarest2/result.rb
|
177
176
|
- lib/jirarest2/services.rb
|
178
177
|
- lib/jirarest2/services/comment.rb
|
@@ -180,6 +179,7 @@ files:
|
|
180
179
|
- lib/jirarest2/services/issuelinktype.rb
|
181
180
|
- lib/jirarest2/services/watcher.rb
|
182
181
|
- lib/jirarest2bin.rb
|
182
|
+
- test/data/cookiejar
|
183
183
|
- test/data/get-comments.txt
|
184
184
|
- test/data/issuespec.txt
|
185
185
|
- test/data/test.config.data
|
@@ -189,11 +189,13 @@ files:
|
|
189
189
|
- test/data/ticket.json
|
190
190
|
- test/test_comment.rb
|
191
191
|
- test/test_connect.rb
|
192
|
+
- test/test_cookie_credentials.rb
|
192
193
|
- test/test_credentials.rb
|
193
194
|
- test/test_issue.rb
|
194
195
|
- test/test_issuelink.rb
|
195
196
|
- test/test_issuelinktype.rb
|
196
197
|
- test/test_madbitconfig.rb
|
198
|
+
- test/test_password_credentials.rb
|
197
199
|
- test/test_result.rb
|
198
200
|
- test/test_watcher.rb
|
199
201
|
- .gemtest
|
@@ -228,10 +230,12 @@ summary: jirarest2 is yet another implementation of the JIRA(tm) REST-API[https:
|
|
228
230
|
test_files:
|
229
231
|
- test/test_madbitconfig.rb
|
230
232
|
- test/test_connect.rb
|
233
|
+
- test/test_cookie_credentials.rb
|
231
234
|
- test/test_issuelinktype.rb
|
232
235
|
- test/test_comment.rb
|
233
236
|
- test/test_credentials.rb
|
234
237
|
- test/test_issue.rb
|
238
|
+
- test/test_password_credentials.rb
|
235
239
|
- test/test_result.rb
|
236
240
|
- test/test_issuelink.rb
|
237
241
|
- test/test_watcher.rb
|
metadata.gz.sig
CHANGED
Binary file
|
data/bin/jira_create_issue.rb
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
# Script to create a new issue with jira.
|
4
|
-
# Copyright (C) 2012 Cyril Bitterich
|
5
|
-
#
|
6
|
-
# This program is free software: you can redistribute it and/or modify
|
7
|
-
# it under the terms of the GNU General Public License as published by
|
8
|
-
# the Free Software Foundation, either version 3 of the License, or
|
9
|
-
# (at your option) any later version.
|
10
|
-
#
|
11
|
-
# This program is distributed in the hope that it will be useful,
|
12
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
-
# GNU General Public License for more details.
|
15
|
-
#
|
16
|
-
# You should have received a copy of the GNU General Public License
|
17
|
-
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
18
|
-
#
|
19
|
-
|
20
|
-
puts "File has been renamed to jira_create_issue"
|
21
|
-
newfile = File.dirname($0) + "/jira_create_issue"
|
22
|
-
puts "Please use: #{newfile} #{$*.join(" ")}"
|
23
|
-
|