confluencer 0.2.7 → 0.2.8

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/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.7
1
+ 0.2.8
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{confluencer}
8
- s.version = "0.2.7"
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-07}
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/page_spec.rb",
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"
@@ -1,67 +1,126 @@
1
1
  require 'xmlrpc/client'
2
2
 
3
- # Originally confluence4r, available at: http://confluence.atlassian.com/display/DISC/Confluence4r
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
- def initialize(options = {})
23
- server_url = options[:url]
24
- server_url += "/rpc/xmlrpc" unless server_url[-11..-1] == "/rpc/xmlrpc"
25
- @server_url = server_url
26
-
27
- client = XMLRPC::Client.new_from_uri(server_url)
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
- @confluence = client.proxy(PREFIX)
30
- @token = options[: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
- @username = username
39
- @password = password
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
- request do |confluence|
42
- @token = confluence.login(@username, @password)
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
- request do |confluence|
48
- confluence.logout(@token)
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
- request do |confluence|
54
- confluence.send(method_name, *([@token] + args))
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
- def request(&block)
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(@confluence)
119
+ block.call
63
120
  rescue XMLRPC::FaultException => e
64
- case message = e.faultString.rpartition(':').last
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
@@ -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 = Hash[*(hash.keys.map {|k| k.to_sym}).zip(hash.values).flatten]
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
- existing_labels = labels
55
- removed_labels = existing_labels - value
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
- end
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
@@ -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
- def token
6
- client.token if client
7
- end
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::client = @client
33
+ Confluence::Record.client = @client
23
34
 
35
+ # yield if block was given and destroy afterwards
24
36
  if block_given?
25
- begin
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 and token is not valid anymore
55
+ # client is not valid anymore
41
56
  @client = nil
42
- @token = nil
43
57
 
44
58
  # reset client for records
45
- Confluence::Record::client = nil
59
+ Confluence::Record.client = nil
46
60
  end
47
61
  end
48
62
  end
@@ -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,4 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ describe Confluence::Bookmark do
4
+ end
@@ -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
- test_page = Confluence::Page.find_by_title config[:space], config[:page_title]
24
+ test_page = Confluence::Page.find_by_title config[:space], config[:page_title]
25
25
  test_page.remove if test_page
26
- rescue RuntimeError
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
@@ -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 config { yield }
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
- - 7
9
- version: 0.2.7
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-07 00:00:00 +02:00
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