confluencer 0.2.7 → 0.2.8
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/confluencer.gemspec +9 -3
- data/lib/confluence/client.rb +95 -36
- data/lib/confluence/record.rb +20 -17
- data/lib/confluence/session.rb +28 -14
- data/lib/confluencer.rb +7 -0
- data/spec/confluence.yaml.example +27 -1
- data/spec/confluence/bookmark_spec.rb +4 -0
- data/spec/confluence/client_spec.rb +74 -0
- data/spec/confluence/page_spec.rb +3 -3
- data/spec/confluence/record_spec.rb +9 -0
- data/spec/spec_helper.rb +6 -1
- metadata +9 -3
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.8
|
data/confluencer.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{confluencer}
|
8
|
-
s.version = "0.2.
|
8
|
+
s.version = "0.2.8"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Gabor Ratky"]
|
12
|
-
s.date = %q{2010-05-
|
12
|
+
s.date = %q{2010-05-11}
|
13
13
|
s.description = %q{ActiveRecord-like classes to access Confluence through XMLRPC.}
|
14
14
|
s.email = %q{rgabo@rgabostyle.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -37,7 +37,10 @@ Gem::Specification.new do |s|
|
|
37
37
|
"script/console",
|
38
38
|
"script/console_init.rb",
|
39
39
|
"spec/confluence.yaml.example",
|
40
|
+
"spec/confluence/bookmark_spec.rb",
|
41
|
+
"spec/confluence/client_spec.rb",
|
40
42
|
"spec/confluence/page_spec.rb",
|
43
|
+
"spec/confluence/record_spec.rb",
|
41
44
|
"spec/confluence/session_spec.rb",
|
42
45
|
"spec/confluencer_spec.rb",
|
43
46
|
"spec/spec.opts",
|
@@ -49,7 +52,10 @@ Gem::Specification.new do |s|
|
|
49
52
|
s.rubygems_version = %q{1.3.6}
|
50
53
|
s.summary = %q{Useful classes to manage Confluence.}
|
51
54
|
s.test_files = [
|
52
|
-
"spec/confluence/
|
55
|
+
"spec/confluence/bookmark_spec.rb",
|
56
|
+
"spec/confluence/client_spec.rb",
|
57
|
+
"spec/confluence/page_spec.rb",
|
58
|
+
"spec/confluence/record_spec.rb",
|
53
59
|
"spec/confluence/session_spec.rb",
|
54
60
|
"spec/confluencer_spec.rb",
|
55
61
|
"spec/spec_helper.rb"
|
data/lib/confluence/client.rb
CHANGED
@@ -1,67 +1,126 @@
|
|
1
1
|
require 'xmlrpc/client'
|
2
2
|
|
3
|
-
#
|
4
|
-
|
5
|
-
# A useful helper for running Confluence XML-RPC from Ruby. Takes care of
|
6
|
-
# adding the token to each method call (so you can call server.getSpaces()
|
7
|
-
# instead of server.getSpaces(token)). Also takes care of re-logging in
|
8
|
-
# if your login times out.
|
9
|
-
#
|
10
|
-
# Usage:
|
11
|
-
#
|
12
|
-
# client = Confluence::Client.new(:url => "http://confluence.atlassian.com")
|
13
|
-
# client.login("user", "password")
|
14
|
-
# puts client.getSpaces()
|
15
|
-
#
|
3
|
+
# Module containing Confluence-related classes.
|
16
4
|
module Confluence
|
5
|
+
# Originally confluence4r, available at: http://confluence.atlassian.com/display/DISC/Confluence4r
|
6
|
+
|
7
|
+
# A useful helper for running Confluence XML-RPC from Ruby. Takes care of
|
8
|
+
# adding the token to each method call (so you can call server.getSpaces()
|
9
|
+
# instead of server.getSpaces(token)).
|
10
|
+
#
|
11
|
+
# Usage:
|
12
|
+
#
|
13
|
+
# client = Confluence::Client.new(:url => "http://confluence.atlassian.com")
|
14
|
+
# client.login("user", "password")
|
15
|
+
# p client.getSpaces
|
16
|
+
#
|
17
17
|
class Client
|
18
18
|
PREFIX = "confluence1"
|
19
|
+
XMLRPC_SUFFIX = "/rpc/xmlrpc"
|
19
20
|
|
20
|
-
attr_reader :username, :token
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
21
|
+
attr_reader :url, :username, :token
|
22
|
+
|
23
|
+
# Initializes a new client with the given arguments.
|
24
|
+
#
|
25
|
+
# ==== Parameters
|
26
|
+
# arguments<Hash>:: Described below.
|
27
|
+
#
|
28
|
+
# ==== Arguments
|
29
|
+
# :url - The url of the Confluence instance. The trailing '/rpc/xmlrpc' path is optional.
|
30
|
+
# :token - An existing session token to reuse.
|
31
|
+
#
|
32
|
+
def initialize(arguments = {})
|
33
|
+
@url = arguments[:url]
|
34
|
+
@token = arguments[:token]
|
28
35
|
|
29
|
-
|
30
|
-
@token
|
36
|
+
Log4r::MDC.put('token', @token || 'nil')
|
37
|
+
log.info "initialized client (:url => #{@url}, :token => #{@token || 'nil'})"
|
31
38
|
end
|
32
|
-
|
39
|
+
|
40
|
+
# Returns true, if the client has a session token.
|
41
|
+
#
|
33
42
|
def has_token?
|
34
43
|
!@token.nil?
|
35
44
|
end
|
36
45
|
|
46
|
+
# Logs in and returns the newly acquired session token.
|
47
|
+
#
|
48
|
+
# ==== Parameters
|
49
|
+
# username<String>:: The username.
|
50
|
+
# password<String>:: The password.
|
51
|
+
#
|
37
52
|
def login(username, password)
|
38
|
-
|
39
|
-
|
53
|
+
handle_fault do
|
54
|
+
if @token = proxy.login(username, password)
|
55
|
+
Log4r::MDC.put('token', @token)
|
56
|
+
log.info "logged in as '#{username}' and acquired token."
|
40
57
|
|
41
|
-
|
42
|
-
|
58
|
+
@username = username
|
59
|
+
@password = password
|
60
|
+
end
|
43
61
|
end
|
62
|
+
|
63
|
+
@token
|
44
64
|
end
|
45
65
|
|
66
|
+
# Logs out and invalidates the session token.
|
67
|
+
#
|
46
68
|
def logout
|
47
|
-
|
48
|
-
|
69
|
+
handle_fault do
|
70
|
+
@token = nil if @token and result = proxy.logout(@token)
|
71
|
+
log.info "logged out"
|
72
|
+
Log4r::MDC.put('token', 'nil')
|
73
|
+
result
|
49
74
|
end
|
50
75
|
end
|
51
76
|
|
77
|
+
# Translates every call into XMLRPC calls.
|
78
|
+
#
|
52
79
|
def method_missing(method_name, *args)
|
53
|
-
|
54
|
-
|
80
|
+
handle_fault do
|
81
|
+
if args.empty?
|
82
|
+
log.debug "#{method_name}"
|
83
|
+
else
|
84
|
+
log.debug "#{method_name}(#{args.join(', ')})"
|
85
|
+
end
|
86
|
+
result = proxy.send(method_name, *([@token] + args))
|
87
|
+
log.debug(result.inspect)
|
88
|
+
result
|
55
89
|
end
|
56
90
|
end
|
57
91
|
|
58
92
|
private
|
59
|
-
|
60
|
-
|
93
|
+
|
94
|
+
# Returns the Confluence::Client logger.
|
95
|
+
def log
|
96
|
+
Log4r::Logger[Confluence::Client.to_s] || Log4r::Logger.root
|
97
|
+
end
|
98
|
+
|
99
|
+
# Returns the Confluence XMLRPC endpoint url.
|
100
|
+
#
|
101
|
+
def xmlrpc_url
|
102
|
+
unless @url[-11..-1] == XMLRPC_SUFFIX
|
103
|
+
@url + XMLRPC_SUFFIX
|
104
|
+
else
|
105
|
+
@url
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Returns the XMLRPC client proxy for the Confluence API v1.
|
110
|
+
#
|
111
|
+
def proxy
|
112
|
+
@proxy ||= XMLRPC::Client.new_from_uri(xmlrpc_url).proxy(PREFIX)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Yields and translates any XMLRPC::FaultExceptions raised by Confluence to Confluence::Errors.
|
116
|
+
#
|
117
|
+
def handle_fault(&block)
|
61
118
|
begin
|
62
|
-
block.call
|
119
|
+
block.call
|
63
120
|
rescue XMLRPC::FaultException => e
|
64
|
-
|
121
|
+
log.warn message = e.faultString.rpartition(':').last
|
122
|
+
|
123
|
+
case message
|
65
124
|
when /Transaction rolled back/
|
66
125
|
raise Confluence::Error, "Could not save or update record."
|
67
126
|
else
|
data/lib/confluence/record.rb
CHANGED
@@ -1,8 +1,16 @@
|
|
1
1
|
module Confluence
|
2
2
|
class Record
|
3
3
|
class << self
|
4
|
+
def client
|
5
|
+
raise "Confluence client is unavailable. Did you forget to use Confluence::Session.new?" unless @@client
|
6
|
+
@@client
|
7
|
+
end
|
8
|
+
|
9
|
+
def client=(value)
|
10
|
+
@@client = value
|
11
|
+
end
|
12
|
+
|
4
13
|
def record_attr_accessor(*args)
|
5
|
-
|
6
14
|
attributes = {}
|
7
15
|
|
8
16
|
# iterate through each argument
|
@@ -31,7 +39,12 @@ module Confluence
|
|
31
39
|
attr_accessor :attributes
|
32
40
|
|
33
41
|
def initialize(hash)
|
34
|
-
@attributes =
|
42
|
+
@attributes = {}
|
43
|
+
|
44
|
+
# iterate through each key/value pair and set attribute keyed by symbol
|
45
|
+
hash.each_pair do |key, value|
|
46
|
+
self[key.to_sym] = value
|
47
|
+
end
|
35
48
|
end
|
36
49
|
|
37
50
|
def [](attr)
|
@@ -47,27 +60,17 @@ module Confluence
|
|
47
60
|
end
|
48
61
|
|
49
62
|
def labels
|
50
|
-
client.getLabelsById(record_id).collect {|label| label["name"]}
|
63
|
+
@labels ||= client.getLabelsById(record_id).collect {|label| label["name"]}
|
51
64
|
end
|
52
65
|
|
53
66
|
def labels=(value)
|
54
|
-
|
55
|
-
|
56
|
-
added_labels = value - existing_labels
|
67
|
+
removed_labels = labels - value
|
68
|
+
added_labels = value - labels
|
57
69
|
|
58
70
|
client.removeLabelByName(removed_labels.join(" "), record_id) unless removed_labels.empty?
|
59
71
|
client.addLabelByName(added_labels.join(" "), record_id) unless added_labels.empty?
|
60
|
-
|
61
|
-
|
62
|
-
@@client = nil
|
63
|
-
|
64
|
-
def self.client
|
65
|
-
raise "Confluence client is unavailable. Did you forget to use Confluence::Session.new?" unless @@client
|
66
|
-
@@client
|
67
|
-
end
|
68
|
-
|
69
|
-
def self.client=(client)
|
70
|
-
@@client = client
|
72
|
+
|
73
|
+
@labels = value
|
71
74
|
end
|
72
75
|
|
73
76
|
def client
|
data/lib/confluence/session.rb
CHANGED
@@ -1,11 +1,22 @@
|
|
1
1
|
module Confluence
|
2
|
+
# Wraps a Confluence::Client and manages the lifetime of a session.
|
3
|
+
#
|
2
4
|
class Session
|
3
5
|
attr_reader :client
|
4
6
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
7
|
+
# Initializes a new session with the given arguments and sets it for other classes like Confluence::Page.
|
8
|
+
#
|
9
|
+
# If a block is given to initialize, initialize yields with the Confluence::Client and automatically logs out of the session afterwards.
|
10
|
+
# Otherwise Session#destroy should be called after finished.
|
11
|
+
#
|
12
|
+
# ==== Parameters
|
13
|
+
# arguments<Hash>:: Described below.
|
14
|
+
#
|
15
|
+
# ==== Arguments
|
16
|
+
# :url - The url of the Confluence instance.
|
17
|
+
# :username - The username.
|
18
|
+
# :password - The password.
|
19
|
+
#
|
9
20
|
def initialize(arguments = {})
|
10
21
|
raise ArgumentError, "Required argument 'url' is missing." unless arguments.key? :url
|
11
22
|
|
@@ -19,30 +30,33 @@ module Confluence
|
|
19
30
|
end
|
20
31
|
|
21
32
|
# set client for records
|
22
|
-
Confluence::Record
|
33
|
+
Confluence::Record.client = @client
|
23
34
|
|
35
|
+
# yield if block was given and destroy afterwards
|
24
36
|
if block_given?
|
25
|
-
|
26
|
-
yield @client
|
27
|
-
rescue RuntimeError => e
|
28
|
-
# strip non-message part of java exception message
|
29
|
-
raise e.message.split(":").last.strip
|
30
|
-
end
|
37
|
+
yield @client
|
31
38
|
|
32
39
|
self.destroy
|
33
40
|
end
|
34
41
|
end
|
35
42
|
|
43
|
+
# Returns the current session token.
|
44
|
+
#
|
45
|
+
def token
|
46
|
+
client.token if client
|
47
|
+
end
|
48
|
+
|
49
|
+
# Destroys the session by logging out and resets other classes like Confluence::Page.
|
50
|
+
#
|
36
51
|
def destroy
|
37
52
|
# invalidate the token
|
38
53
|
client.logout
|
39
54
|
|
40
|
-
# client
|
55
|
+
# client is not valid anymore
|
41
56
|
@client = nil
|
42
|
-
@token = nil
|
43
57
|
|
44
58
|
# reset client for records
|
45
|
-
Confluence::Record
|
59
|
+
Confluence::Record.client = nil
|
46
60
|
end
|
47
61
|
end
|
48
62
|
end
|
data/lib/confluencer.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
# ensure that lib is in the load path
|
2
2
|
$:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
3
|
|
4
|
+
require 'rubygems'
|
5
|
+
require 'log4r'
|
6
|
+
|
4
7
|
require 'confluence/error'
|
5
8
|
|
6
9
|
require 'confluence/client'
|
@@ -10,3 +13,7 @@ require 'confluence/record'
|
|
10
13
|
require 'confluence/page'
|
11
14
|
require 'confluence/bookmark'
|
12
15
|
require 'confluence/blog_entry'
|
16
|
+
|
17
|
+
module Confluencer
|
18
|
+
VERSION = "0.2.7"
|
19
|
+
end
|
@@ -4,4 +4,30 @@
|
|
4
4
|
:username: roger
|
5
5
|
:password: jessica
|
6
6
|
:space: confluencer
|
7
|
-
:page_title: Confluencer RSpec Test Page
|
7
|
+
:page_title: Confluencer RSpec Test Page
|
8
|
+
|
9
|
+
# Log4r configuration
|
10
|
+
log4r_config:
|
11
|
+
pre_config:
|
12
|
+
global:
|
13
|
+
level: DEBUG
|
14
|
+
root:
|
15
|
+
level: DEBUG
|
16
|
+
|
17
|
+
# loggers
|
18
|
+
loggers:
|
19
|
+
- name : Confluence::Client
|
20
|
+
level : DEBUG
|
21
|
+
additive : 'false'
|
22
|
+
trace : 'false'
|
23
|
+
outputters:
|
24
|
+
- stdout
|
25
|
+
|
26
|
+
# outputters
|
27
|
+
outputters:
|
28
|
+
- type : StdoutOutputter
|
29
|
+
name : stdout
|
30
|
+
level : DEBUG
|
31
|
+
formatter:
|
32
|
+
type : PatternFormatter
|
33
|
+
pattern : '%d %C (%X{token}) [%l]: %m'
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
2
|
+
|
3
|
+
describe Confluence::Client do
|
4
|
+
include ConfigurationHelperMethods
|
5
|
+
|
6
|
+
def new_client_from_config
|
7
|
+
Confluence::Client.new(config)
|
8
|
+
end
|
9
|
+
|
10
|
+
def logged_in_client
|
11
|
+
client = new_client_from_config
|
12
|
+
client.login(config[:username], config[:password])
|
13
|
+
client.has_token?.should be_true
|
14
|
+
client
|
15
|
+
end
|
16
|
+
|
17
|
+
it "can initialize a client with a url" do
|
18
|
+
client = Confluence::Client.new :url => "http://confluence.atlassian.com"
|
19
|
+
|
20
|
+
client.should_not be_nil
|
21
|
+
client.url.should_not be_nil
|
22
|
+
client.url.should == "http://confluence.atlassian.com"
|
23
|
+
end
|
24
|
+
|
25
|
+
it "can initialize a client with an existing token" do
|
26
|
+
client = Confluence::Client.new :url => "http://confluence.atlassian.com", :token => "abcdef"
|
27
|
+
client.token.should_not be_nil
|
28
|
+
client.token.should == "abcdef"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "can return whether a token is already available" do
|
32
|
+
client = Confluence::Client.new :url => "http://confluence.atlassian.com"
|
33
|
+
client.has_token?.should be_false
|
34
|
+
|
35
|
+
client = Confluence::Client.new :url => "http://confluence.atlassian.com", :token => "abcdef"
|
36
|
+
client.has_token?.should be_true
|
37
|
+
end
|
38
|
+
|
39
|
+
it "can log in and acquire a session token" do
|
40
|
+
client = new_client_from_config
|
41
|
+
client.has_token?.should be_false
|
42
|
+
|
43
|
+
token = client.login(config[:username], config[:password])
|
44
|
+
token.should_not be_nil
|
45
|
+
|
46
|
+
client.has_token?.should be_true
|
47
|
+
client.token.should == token
|
48
|
+
end
|
49
|
+
|
50
|
+
it "raises an error if it cannot login" do
|
51
|
+
client = new_client_from_config
|
52
|
+
|
53
|
+
lambda { client.login(config[:username], "bogus") }.should raise_exception(Confluence::Error, /incorrect password/)
|
54
|
+
client.has_token?.should be_false
|
55
|
+
|
56
|
+
lambda { client.login("bogus", "bogus") }.should raise_exception(Confluence::Error, /no user could be found/)
|
57
|
+
client.has_token?.should be_false
|
58
|
+
end
|
59
|
+
|
60
|
+
it "can logout and invalidate a session token" do
|
61
|
+
client = logged_in_client
|
62
|
+
|
63
|
+
client.logout.should be_true
|
64
|
+
client.has_token?.should be_false
|
65
|
+
end
|
66
|
+
|
67
|
+
it "can make XMLRPC calls" do
|
68
|
+
client = logged_in_client
|
69
|
+
|
70
|
+
server_info = client.getServerInfo
|
71
|
+
server_info.should_not be_nil
|
72
|
+
server_info["baseUrl"].should == client.url
|
73
|
+
end
|
74
|
+
end
|
@@ -21,9 +21,9 @@ describe Confluence::Page do
|
|
21
21
|
new_session do
|
22
22
|
begin
|
23
23
|
# check whether we need to remove the test page
|
24
|
-
|
24
|
+
test_page = Confluence::Page.find_by_title config[:space], config[:page_title]
|
25
25
|
test_page.remove if test_page
|
26
|
-
rescue
|
26
|
+
rescue Confluence::Error
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
@@ -31,7 +31,7 @@ describe Confluence::Page do
|
|
31
31
|
it "should add a new page in Confluence" do
|
32
32
|
page = nil
|
33
33
|
|
34
|
-
new_session do
|
34
|
+
new_session do |client|
|
35
35
|
# initialize test page
|
36
36
|
page = create_test_page
|
37
37
|
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
2
|
+
|
3
|
+
describe Confluence::Record do
|
4
|
+
it "should initialize new record from Confluence hash" do
|
5
|
+
record = Confluence::Record.new :foo => 'bar'
|
6
|
+
|
7
|
+
record[:foo].should == 'bar'
|
8
|
+
end
|
9
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -6,7 +6,12 @@ require 'spec'
|
|
6
6
|
require 'spec/autorun'
|
7
7
|
require 'yaml'
|
8
8
|
|
9
|
+
require 'log4r/yamlconfigurator'
|
10
|
+
|
9
11
|
Spec::Runner.configure do |config|
|
12
|
+
config.before :suite do
|
13
|
+
Log4r::YamlConfigurator.load_yaml_file(File.join(File.dirname(__FILE__), 'confluence.yaml'))
|
14
|
+
end
|
10
15
|
end
|
11
16
|
|
12
17
|
module ConfigurationHelperMethods
|
@@ -22,7 +27,7 @@ module SessionHelperMethods
|
|
22
27
|
def new_session
|
23
28
|
if block_given?
|
24
29
|
# initialize session and yield
|
25
|
-
Confluence::Session.new
|
30
|
+
Confluence::Session.new(config) {|client| yield client }
|
26
31
|
else
|
27
32
|
# initialize session and return
|
28
33
|
Confluence::Session.new config
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 2
|
8
|
-
-
|
9
|
-
version: 0.2.
|
8
|
+
- 8
|
9
|
+
version: 0.2.8
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Gabor Ratky
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-05-
|
17
|
+
date: 2010-05-11 00:00:00 +02:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -61,7 +61,10 @@ files:
|
|
61
61
|
- script/console
|
62
62
|
- script/console_init.rb
|
63
63
|
- spec/confluence.yaml.example
|
64
|
+
- spec/confluence/bookmark_spec.rb
|
65
|
+
- spec/confluence/client_spec.rb
|
64
66
|
- spec/confluence/page_spec.rb
|
67
|
+
- spec/confluence/record_spec.rb
|
65
68
|
- spec/confluence/session_spec.rb
|
66
69
|
- spec/confluencer_spec.rb
|
67
70
|
- spec/spec.opts
|
@@ -97,7 +100,10 @@ signing_key:
|
|
97
100
|
specification_version: 3
|
98
101
|
summary: Useful classes to manage Confluence.
|
99
102
|
test_files:
|
103
|
+
- spec/confluence/bookmark_spec.rb
|
104
|
+
- spec/confluence/client_spec.rb
|
100
105
|
- spec/confluence/page_spec.rb
|
106
|
+
- spec/confluence/record_spec.rb
|
101
107
|
- spec/confluence/session_spec.rb
|
102
108
|
- spec/confluencer_spec.rb
|
103
109
|
- spec/spec_helper.rb
|