sappho-data-publisher 0.1.7 → 0.1.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/lib/sappho-data-publisher/atlassian_app.rb +56 -0
- data/lib/sappho-data-publisher/configuration.rb +3 -3
- data/lib/sappho-data-publisher/confluence.rb +14 -21
- data/lib/sappho-data-publisher/custom_liquid.rb +4 -2
- data/lib/sappho-data-publisher/jira.rb +19 -24
- data/lib/sappho-data-publisher/modules.rb +4 -0
- data/lib/sappho-data-publisher/version.rb +1 -1
- data/lib/sappho-data-publisher.rb +6 -2
- data/test/config/config.yml +10 -0
- data/test/data/config.yml +5 -0
- data/test/data/confluence-chunk.input +41 -0
- data/test/data/confluence-chunk.output +21 -0
- data/test/data/confluence-pages/page-op-tests/MYSPACE/Global Macros.wiki +1 -0
- data/test/data/confluence-pages/page-op-tests/MYSPACE/Home.wiki +1 -0
- data/test/data/confluence-pages/page-op-tests/MYSPACE/Page Specification.wiki +1 -0
- data/test/data/confluence-pages/page-op-tests/MYSPACE/Template.wiki +1 -0
- data/test/data/custom-liquid.content +6 -0
- data/test/data/custom-liquid.template +10 -0
- data/test/data/jira-results.yml +22 -0
- data/test/data/jira.yml +23 -0
- data/test/ruby/confluence_test.rb +75 -0
- data/test/ruby/custom_liquid_test.rb +28 -0
- data/test/ruby/helper.rb +51 -0
- data/test/ruby/jira_test.rb +105 -0
- data/test/ruby/mock_atlassian_app.rb +50 -0
- data/test/ruby/mock_confluence.rb +46 -0
- data/test/ruby/mock_jira.rb +39 -0
- metadata +44 -6
@@ -0,0 +1,56 @@
|
|
1
|
+
# See https://github.com/sappho/sappho-data-publisher/wiki for project documentation.
|
2
|
+
# This software is licensed under the GNU Affero General Public License, version 3.
|
3
|
+
# See http://www.gnu.org/licenses/agpl.html for full details of the license terms.
|
4
|
+
# Copyright 2012 Andrew Heald.
|
5
|
+
|
6
|
+
require 'sappho-data-publisher/modules'
|
7
|
+
|
8
|
+
module Sappho
|
9
|
+
module Data
|
10
|
+
module Publisher
|
11
|
+
|
12
|
+
class AtlassianApp
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@appName = self.class.name.split("::").last
|
16
|
+
@appServer = nil
|
17
|
+
@loggedIn = false
|
18
|
+
end
|
19
|
+
|
20
|
+
def connect
|
21
|
+
raise "you have already attempted to connect to #{@appName}" if @appServer or @loggedIn
|
22
|
+
modules = Modules.instance
|
23
|
+
@config = modules.get :configuration
|
24
|
+
@logger = modules.get :logger
|
25
|
+
url = @config.data["#{@appName.downcase}.url"]
|
26
|
+
mock = "mock#{@appName}"
|
27
|
+
@appServer = modules.set?(mock) ? modules.get(mock).mockInstance(url) : yield(url)
|
28
|
+
@token = @appServer.login @config.data["#{@appName.downcase}.username"], @config.data["#{@appName.downcase}.password"]
|
29
|
+
@logger.info "logged into #{@appName} #{url}"
|
30
|
+
@loggedIn = true
|
31
|
+
end
|
32
|
+
|
33
|
+
def shutdown
|
34
|
+
if loggedIn?
|
35
|
+
@appServer.logout @token
|
36
|
+
@logger.info "logged out of #{@appName}"
|
37
|
+
end
|
38
|
+
@loggedIn = false
|
39
|
+
@appServer = nil
|
40
|
+
end
|
41
|
+
|
42
|
+
def loggedIn?
|
43
|
+
@appServer and @loggedIn
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def checkLoggedIn
|
49
|
+
raise "you are not logged in to #{@appName}" unless loggedIn?
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -14,10 +14,10 @@ module Sappho
|
|
14
14
|
|
15
15
|
attr_reader :data
|
16
16
|
|
17
|
-
def initialize
|
18
|
-
filename = File.expand_path(
|
17
|
+
def initialize filename = ARGV[0]
|
18
|
+
filename = File.expand_path(filename || 'config.yml')
|
19
19
|
@data = YAML.load_file filename
|
20
|
-
Modules.instance.get(:logger).
|
20
|
+
Modules.instance.get(:logger).info "configuration loaded from #{filename}"
|
21
21
|
end
|
22
22
|
|
23
23
|
end
|
@@ -3,28 +3,24 @@
|
|
3
3
|
# See http://www.gnu.org/licenses/agpl.html for full details of the license terms.
|
4
4
|
# Copyright 2012 Andrew Heald.
|
5
5
|
|
6
|
-
require 'sappho-data-publisher/
|
6
|
+
require 'sappho-data-publisher/atlassian_app'
|
7
7
|
require 'xmlrpc/client'
|
8
8
|
|
9
9
|
module Sappho
|
10
10
|
module Data
|
11
11
|
module Publisher
|
12
12
|
|
13
|
-
class Confluence
|
13
|
+
class Confluence < AtlassianApp
|
14
14
|
|
15
|
-
def
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
@wiki = XMLRPC::Client.new2("#{url}/rpc/xmlrpc").proxy('confluence1')
|
20
|
-
@token = @wiki.login @config.data['confluence.username'], @config.data['confluence.password']
|
21
|
-
@logger.info "Confluence #{url} is online"
|
15
|
+
def connect
|
16
|
+
super do |url|
|
17
|
+
XMLRPC::Client.new2("#{url}/rpc/xmlrpc").proxy('confluence1')
|
18
|
+
end
|
22
19
|
end
|
23
20
|
|
24
21
|
def getGlobalConfiguration
|
25
22
|
pageName = @config.data['confluence.global.config.page.name']
|
26
|
-
|
27
|
-
''
|
23
|
+
pageName ? getPage(@config.data['confluence.config.space.key'], pageName) : ''
|
28
24
|
end
|
29
25
|
|
30
26
|
def getConfiguration
|
@@ -36,39 +32,36 @@ module Sappho
|
|
36
32
|
end
|
37
33
|
|
38
34
|
def getScript rawPage
|
39
|
-
rawPage.scan(
|
35
|
+
rawPage.scan(/^\{noformat.*?\}(.*?)^\{noformat\}/m).each { |pageData| yield pageData[0] }
|
40
36
|
end
|
41
37
|
|
42
38
|
def publish content, pageData, parameters
|
43
39
|
setPage parameters['space'], parameters['parent'], pageData['pagename'], content
|
44
40
|
end
|
45
41
|
|
46
|
-
def shutdown
|
47
|
-
@wiki.logout @token
|
48
|
-
@logger.info 'disconnected from Confluence'
|
49
|
-
end
|
50
|
-
|
51
42
|
private
|
52
43
|
|
53
44
|
def getPage spaceKey, pageName
|
45
|
+
checkLoggedIn
|
54
46
|
@logger.info "reading wiki page #{spaceKey}:#{pageName}"
|
55
|
-
@
|
47
|
+
@appServer.getPage(@token, spaceKey, pageName)['content']
|
56
48
|
end
|
57
49
|
|
58
50
|
def setPage spaceKey, parentPageName, pageName, content
|
51
|
+
checkLoggedIn
|
59
52
|
begin
|
60
|
-
page = @
|
53
|
+
page = @appServer.getPage(@token, spaceKey, pageName)
|
61
54
|
page['content'] = content
|
62
55
|
@logger.info "rewriting existing wiki page #{spaceKey}:#{pageName}"
|
63
56
|
rescue
|
64
57
|
page = {
|
65
58
|
'space' => spaceKey,
|
66
|
-
'parentId' => @
|
59
|
+
'parentId' => @appServer.getPage(@token, spaceKey, parentPageName)['id'],
|
67
60
|
'title' => pageName,
|
68
61
|
'content' => content }
|
69
62
|
@logger.info "creating new wiki page #{spaceKey}:#{pageName} as child of #{parentPageName}"
|
70
63
|
end
|
71
|
-
@
|
64
|
+
@appServer.storePage @token, page
|
72
65
|
end
|
73
66
|
|
74
67
|
end
|
@@ -24,10 +24,12 @@ module Sappho
|
|
24
24
|
|
25
25
|
def fullname username
|
26
26
|
begin
|
27
|
-
Modules.instance.get('AddressBook').getUserFullName(username)
|
27
|
+
name = Modules.instance.get('AddressBook').getUserFullName(username)
|
28
|
+
raise 'unknown person' unless name and name.length > 0
|
28
29
|
rescue
|
29
|
-
'** John Doe **'
|
30
|
+
name = '** John Doe **'
|
30
31
|
end
|
32
|
+
name
|
31
33
|
end
|
32
34
|
|
33
35
|
end
|
@@ -3,60 +3,55 @@
|
|
3
3
|
# See http://www.gnu.org/licenses/agpl.html for full details of the license terms.
|
4
4
|
# Copyright 2012 Andrew Heald.
|
5
5
|
|
6
|
-
require 'sappho-data-publisher/
|
6
|
+
require 'sappho-data-publisher/atlassian_app'
|
7
7
|
require 'soap/wsdlDriver'
|
8
8
|
|
9
9
|
module Sappho
|
10
10
|
module Data
|
11
11
|
module Publisher
|
12
12
|
|
13
|
-
class Jira
|
13
|
+
class Jira < AtlassianApp
|
14
14
|
|
15
|
-
def
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
@
|
20
|
-
@token = @jira.login config.data['jira.username'], config.data['jira.password']
|
21
|
-
@allCustomFields = @jira.getCustomFields @token
|
22
|
-
@logger.info "Jira #{url} is online"
|
15
|
+
def connect
|
16
|
+
super do |url|
|
17
|
+
SOAP::WSDLDriverFactory.new("#{url}/rpc/soap/jirasoapservice-v2?wsdl").create_rpc_driver
|
18
|
+
end
|
19
|
+
@allCustomFields = @appServer.getCustomFields @token
|
23
20
|
@users = {}
|
24
21
|
end
|
25
22
|
|
26
23
|
def gatherData pageData, parameters
|
24
|
+
checkLoggedIn
|
27
25
|
id = parameters['id']
|
28
26
|
@logger.info "reading Jira issue #{id}"
|
29
|
-
issue = @
|
27
|
+
issue = @appServer.getIssue @token, id
|
30
28
|
pageData['summary'] = summary = issue['summary']
|
31
29
|
pageData['pagename'] = summary unless pageData['pagename']
|
32
30
|
pageData['description'] = issue['description']
|
33
|
-
pageData['
|
31
|
+
pageData['cf'] = customFields = {}
|
34
32
|
@allCustomFields.each { |customField|
|
35
|
-
customFields[customField['id']] = {
|
36
|
-
'name' => customField['name'],
|
37
|
-
'values' => nil
|
38
|
-
}
|
33
|
+
customFields[cfname customField['id']] = { 'name' => customField['name'] }
|
39
34
|
}
|
40
35
|
issue['customFieldValues'].each { |customFieldValue|
|
41
|
-
customFields[customFieldValue['customfieldId']]['values'] =
|
36
|
+
customFields[cfname customFieldValue['customfieldId']]['values'] =
|
37
|
+
customFieldValue['values']
|
42
38
|
}
|
43
39
|
end
|
44
40
|
|
45
41
|
def getUserFullName username
|
42
|
+
checkLoggedIn
|
46
43
|
user = @users[username]
|
47
44
|
unless user
|
48
45
|
@logger.info "reading Jira user details for #{username}"
|
49
|
-
@users[username] = user = @
|
46
|
+
@users[username] = user = @appServer.getUser(@token, username)
|
50
47
|
end
|
51
48
|
user['fullname']
|
52
49
|
end
|
53
50
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
@logger.info 'disconnected from Jira'
|
59
|
-
end
|
51
|
+
private
|
52
|
+
|
53
|
+
def cfname name
|
54
|
+
name.sub /customfield_/, ''
|
60
55
|
end
|
61
56
|
|
62
57
|
end
|
@@ -27,9 +27,13 @@ module Sappho
|
|
27
27
|
modules = Modules.instance
|
28
28
|
modules.set :logger, logger
|
29
29
|
modules.set :configuration, Configuration.new
|
30
|
-
|
30
|
+
jira = Jira.new
|
31
|
+
jira.connect
|
32
|
+
modules.set 'Jira', jira
|
31
33
|
modules.set 'AddressBook', jira
|
32
|
-
|
34
|
+
confluence = Confluence.new
|
35
|
+
confluence.connect
|
36
|
+
modules.set 'Confluence', confluence
|
33
37
|
CustomLiquid.setup
|
34
38
|
Publisher.new.publish
|
35
39
|
modules.shutdown
|
@@ -0,0 +1,10 @@
|
|
1
|
+
config.module: Confluence
|
2
|
+
confluence.url: https://wiki.example.com
|
3
|
+
confluence.username: wikiuser
|
4
|
+
confluence.password: secretwikipassword
|
5
|
+
confluence.config.space.key: MYSPACE
|
6
|
+
confluence.global.config.page.name: Global Macros
|
7
|
+
confluence.config.page.name: Page Specification
|
8
|
+
jira.url: https://jira.example.com
|
9
|
+
jira.username: jiraadminuser
|
10
|
+
jira.password: secretjirapassword
|
@@ -0,0 +1,41 @@
|
|
1
|
+
This is ignored.
|
2
|
+
So is this.
|
3
|
+
{noformat}
|
4
|
+
This is not ignored.
|
5
|
+
|
6
|
+
And the above blank line should be included.
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
And the above blank lines, and below, should be included.
|
11
|
+
|
12
|
+
|
13
|
+
{noformat}
|
14
|
+
|
15
|
+
Try a one-liner.
|
16
|
+
{noformat}This one-liner is not ignored.
|
17
|
+
{noformat}
|
18
|
+
|
19
|
+
Try another one-liner.
|
20
|
+
{noformat}This one-liner is not ignored.{noformat} <- the trailing {noformat} will be included because it isn't at column 1.
|
21
|
+
{noformat}
|
22
|
+
|
23
|
+
This is ignored.
|
24
|
+
{noformat:nopanel=true}
|
25
|
+
This is not ignored, either.
|
26
|
+
{noformat} <- And this line should be included.
|
27
|
+
{noformat}
|
28
|
+
{noformat xx}
|
29
|
+
It does not matter about extra invalid stuff on the opening {noformat}.
|
30
|
+
{noformat}
|
31
|
+
|
32
|
+
Test for an invalid closing {noformat}.
|
33
|
+
{noformat}
|
34
|
+
Invalid closing: Line 1
|
35
|
+
{noformatx}
|
36
|
+
Invalid closing: Line 2
|
37
|
+
{noformat}
|
38
|
+
|
39
|
+
Finally, test what happens when a chunk is left open.
|
40
|
+
{noformat}
|
41
|
+
This will not end up in a chunk!
|
@@ -0,0 +1,21 @@
|
|
1
|
+
----
|
2
|
+
This is not ignored.
|
3
|
+
|
4
|
+
And the above blank line should be included.
|
5
|
+
|
6
|
+
|
7
|
+
|
8
|
+
And the above blank lines, and below, should be included.
|
9
|
+
|
10
|
+
|
11
|
+
----This one-liner is not ignored.
|
12
|
+
----This one-liner is not ignored.{noformat} <- the trailing {noformat} will be included because it isn't at column 1.
|
13
|
+
----
|
14
|
+
This is not ignored, either.
|
15
|
+
{noformat} <- And this line should be included.
|
16
|
+
----
|
17
|
+
It does not matter about extra invalid stuff on the opening {noformat}.
|
18
|
+
----
|
19
|
+
Invalid closing: Line 1
|
20
|
+
{noformatx}
|
21
|
+
Invalid closing: Line 2
|
@@ -0,0 +1 @@
|
|
1
|
+
Global macros go here.
|
@@ -0,0 +1 @@
|
|
1
|
+
Home Page.
|
@@ -0,0 +1 @@
|
|
1
|
+
Page specification goes here.
|
@@ -0,0 +1 @@
|
|
1
|
+
This is a template.
|
@@ -0,0 +1,10 @@
|
|
1
|
+
{% squash nothing %}User with username cgrant is {{ 'cgrant' | fullname }}.{% endsquash %}
|
2
|
+
User with username nobody is {{ 'nobody' | fullname }}.
|
3
|
+
{% squash nothing%}{% endsquash %}
|
4
|
+
{% empty %}
|
5
|
+
This stuff will be disposed of.
|
6
|
+
{% assign answer = 42 %}
|
7
|
+
The above assign should be executed, however, even though nothing will be output here.
|
8
|
+
{% endempty %}
|
9
|
+
{% squash blank%} {% endsquash %}
|
10
|
+
The answer to the ultimate question of life, the universe, and everything, is {{ answer }}.
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# Expected result sets used by Jira tests to verify results
|
2
|
+
# See http://yaml.org/spec for syntax help
|
3
|
+
|
4
|
+
TEST-42-A:
|
5
|
+
summary: Testing 123
|
6
|
+
pagename: Testing 123
|
7
|
+
description: This is a test.
|
8
|
+
cf:
|
9
|
+
!str 10500: { name: Service }
|
10
|
+
!str 10501: { name: Type, values: [ Business Process ] }
|
11
|
+
!str 10502: { name: Invoice Number }
|
12
|
+
!str 10503: { name: Customer, values: [ Bank of England ] }
|
13
|
+
|
14
|
+
TEST-42-B:
|
15
|
+
summary: Testing 123
|
16
|
+
pagename: Test Page
|
17
|
+
description: This is a test.
|
18
|
+
cf:
|
19
|
+
!str 10500: { name: Service }
|
20
|
+
!str 10501: { name: Type, values: [ Business Process ] }
|
21
|
+
!str 10502: { name: Invoice Number }
|
22
|
+
!str 10503: { name: Customer, values: [ Bank of England ] }
|
data/test/data/jira.yml
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# Data injected into mock Jira when Jira and custom Liquid tests run
|
2
|
+
# See http://yaml.org/spec for syntax help
|
3
|
+
|
4
|
+
users:
|
5
|
+
|
6
|
+
cgrant: { fullname: Cary Grant }
|
7
|
+
bholiday: { fullname: Billie Holiday }
|
8
|
+
|
9
|
+
issues:
|
10
|
+
|
11
|
+
TEST-42:
|
12
|
+
summary: Testing 123
|
13
|
+
description: This is a test.
|
14
|
+
customFieldValues:
|
15
|
+
- { customfieldId: customfield_10501, values: [ Business Process ] }
|
16
|
+
- { customfieldId: customfield_10503, values: [ Bank of England ] }
|
17
|
+
|
18
|
+
all_custom_fields:
|
19
|
+
|
20
|
+
- { id: customfield_10500, name: Service }
|
21
|
+
- { id: customfield_10501, name: Type }
|
22
|
+
- { id: customfield_10502, name: Invoice Number }
|
23
|
+
- { id: customfield_10503, name: Customer }
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# See https://github.com/sappho/sappho-data-publisher/wiki for project documentation.
|
2
|
+
# This software is licensed under the GNU Affero General Public License, version 3.
|
3
|
+
# See http://www.gnu.org/licenses/agpl.html for full details of the license terms.
|
4
|
+
# Copyright 2012 Andrew Heald.
|
5
|
+
|
6
|
+
require 'helper'
|
7
|
+
|
8
|
+
class ConfluenceTest < Test::Unit::TestCase
|
9
|
+
|
10
|
+
def setup
|
11
|
+
setupLogging
|
12
|
+
setupConfiguration
|
13
|
+
setupConfluence 'Confluence'
|
14
|
+
@mockConfluence.setScenario 'page-op-tests'
|
15
|
+
end
|
16
|
+
|
17
|
+
def teardown
|
18
|
+
assert @confluence.loggedIn?, 'Confluence should be logged in before shutdown'
|
19
|
+
super
|
20
|
+
assert !@confluence.loggedIn?, 'Confluence should not be logged in after shutdown'
|
21
|
+
end
|
22
|
+
|
23
|
+
def connect
|
24
|
+
assert !@confluence.loggedIn?, 'Confluence should not be logged in before connecting'
|
25
|
+
@confluence.connect
|
26
|
+
assert @confluence.loggedIn?, 'Confluence should be logged in after connecting'
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_get_global_config
|
30
|
+
connect
|
31
|
+
assert_equal 'Global macros go here.', @confluence.getGlobalConfiguration
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_get_config
|
35
|
+
connect
|
36
|
+
assert_equal 'Page specification goes here.', @confluence.getConfiguration
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_get_template
|
40
|
+
connect
|
41
|
+
assert_equal 'This is a template.',
|
42
|
+
@confluence.getTemplate({}, {
|
43
|
+
'templatespace' => 'MYSPACE',
|
44
|
+
'templatepage' => 'Template'})
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_publish_page
|
48
|
+
connect
|
49
|
+
spaceKey = 'MYSPACE'
|
50
|
+
pageName = 'Generated Page'
|
51
|
+
pageData = {
|
52
|
+
'pagename' => pageName
|
53
|
+
}
|
54
|
+
params = {
|
55
|
+
'space' => spaceKey,
|
56
|
+
'parent' => 'Home'
|
57
|
+
}
|
58
|
+
content = 'New page content.'
|
59
|
+
@confluence.publish content, pageData, params
|
60
|
+
@mockConfluence.assert_page_content spaceKey, pageName, content
|
61
|
+
content = 'Updated page content.'
|
62
|
+
@confluence.publish content, pageData, params
|
63
|
+
@mockConfluence.assert_page_content spaceKey, pageName, content
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_config_chunking
|
67
|
+
connect # not actually needed but keeps teardown happy
|
68
|
+
output = ''
|
69
|
+
@confluence.getScript File.open(testFilename('data/confluence-chunk.input'), 'rb').read do |chunk|
|
70
|
+
output += '----' + chunk
|
71
|
+
end
|
72
|
+
assert_equal File.open(testFilename('data/confluence-chunk.output'), 'rb').read, output
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# See https://github.com/sappho/sappho-data-publisher/wiki for project documentation.
|
2
|
+
# This software is licensed under the GNU Affero General Public License, version 3.
|
3
|
+
# See http://www.gnu.org/licenses/agpl.html for full details of the license terms.
|
4
|
+
# Copyright 2012 Andrew Heald.
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
gem 'liquid', '>= 2.3.0'
|
8
|
+
require 'liquid'
|
9
|
+
require 'sappho-data-publisher/custom_liquid'
|
10
|
+
require 'helper'
|
11
|
+
|
12
|
+
class CustomLiquidTest < Test::Unit::TestCase
|
13
|
+
|
14
|
+
def setup
|
15
|
+
setupLogging
|
16
|
+
setupConfiguration
|
17
|
+
setupJira 'AddressBook'
|
18
|
+
@jira.connect
|
19
|
+
Sappho::Data::Publisher::CustomLiquid.setup
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_page_generation
|
23
|
+
template = File.open(testFilename('data/custom-liquid.template'), 'rb').read
|
24
|
+
assert_equal File.open(testFilename('data/custom-liquid.content'), 'rb').read,
|
25
|
+
Liquid::Template.parse(template).render
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
data/test/ruby/helper.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# See https://github.com/sappho/sappho-data-publisher/wiki for project documentation.
|
2
|
+
# This software is licensed under the GNU Affero General Public License, version 3.
|
3
|
+
# See http://www.gnu.org/licenses/agpl.html for full details of the license terms.
|
4
|
+
# Copyright 2012 Andrew Heald.
|
5
|
+
|
6
|
+
require "test/unit"
|
7
|
+
require 'logger'
|
8
|
+
require 'yaml'
|
9
|
+
require 'sappho-data-publisher/modules'
|
10
|
+
require 'sappho-data-publisher/configuration'
|
11
|
+
require 'sappho-data-publisher/jira'
|
12
|
+
require 'sappho-data-publisher/confluence'
|
13
|
+
require 'mock_jira'
|
14
|
+
require 'mock_confluence'
|
15
|
+
|
16
|
+
class Test::Unit::TestCase
|
17
|
+
|
18
|
+
def setupLogging
|
19
|
+
@logger = Logger.new STDOUT
|
20
|
+
@logger.level = Logger::DEBUG
|
21
|
+
Sappho::Data::Publisher::Modules.instance.set :logger, @logger
|
22
|
+
end
|
23
|
+
|
24
|
+
def setupConfiguration (filename = testFilename('config/config.yml'))
|
25
|
+
config = Sappho::Data::Publisher::Configuration.new filename
|
26
|
+
Sappho::Data::Publisher::Modules.instance.set :configuration, config
|
27
|
+
end
|
28
|
+
|
29
|
+
def setupJira (moduleName, dataFilename = testFilename('data/jira.yml'))
|
30
|
+
@mockJira = MockJira.new dataFilename
|
31
|
+
Sappho::Data::Publisher::Modules.instance.set 'mockJira', @mockJira
|
32
|
+
@jira = Sappho::Data::Publisher::Jira.new
|
33
|
+
Sappho::Data::Publisher::Modules.instance.set moduleName, @jira
|
34
|
+
end
|
35
|
+
|
36
|
+
def setupConfluence moduleName
|
37
|
+
@mockConfluence = MockConfluence.new
|
38
|
+
Sappho::Data::Publisher::Modules.instance.set 'mockConfluence', @mockConfluence
|
39
|
+
@confluence = Sappho::Data::Publisher::Confluence.new
|
40
|
+
Sappho::Data::Publisher::Modules.instance.set moduleName, @confluence
|
41
|
+
end
|
42
|
+
|
43
|
+
def teardown
|
44
|
+
Sappho::Data::Publisher::Modules.instance.shutdown
|
45
|
+
end
|
46
|
+
|
47
|
+
def testFilename filename
|
48
|
+
"#{File.dirname(__FILE__)}/../#{filename}"
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# See https://github.com/sappho/sappho-data-publisher/wiki for project documentation.
|
2
|
+
# This software is licensed under the GNU Affero General Public License, version 3.
|
3
|
+
# See http://www.gnu.org/licenses/agpl.html for full details of the license terms.
|
4
|
+
# Copyright 2012 Andrew Heald.
|
5
|
+
|
6
|
+
require 'helper'
|
7
|
+
|
8
|
+
class JiraTest < Test::Unit::TestCase
|
9
|
+
|
10
|
+
def setup
|
11
|
+
setupLogging
|
12
|
+
setupConfiguration
|
13
|
+
setupJira 'Jira'
|
14
|
+
@expectedResults = YAML.load_file testFilename 'data/jira-results.yml'
|
15
|
+
end
|
16
|
+
|
17
|
+
def teardown
|
18
|
+
assert @jira.loggedIn?, 'Jira should be logged in before shutdown'
|
19
|
+
super
|
20
|
+
assert !@jira.loggedIn?, 'Jira should not be logged in after shutdown'
|
21
|
+
end
|
22
|
+
|
23
|
+
def connect
|
24
|
+
assert !@jira.loggedIn?, 'Jira should not be logged in before connecting'
|
25
|
+
@jira.connect
|
26
|
+
assert @jira.loggedIn?, 'Jira should be logged in after connecting'
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_get_user_full_name
|
30
|
+
@getUserCount = 0
|
31
|
+
# check a valid name but before connecting to Jira
|
32
|
+
@username = 'cgrant'
|
33
|
+
@fullName = 'Cary Grant'
|
34
|
+
assert_full_name_failure
|
35
|
+
# now connect to allow the test to proceed
|
36
|
+
connect
|
37
|
+
# check a valid name
|
38
|
+
assert_full_name
|
39
|
+
# test name caching
|
40
|
+
assert_full_name 0
|
41
|
+
# this won't be cached
|
42
|
+
@username = 'bholiday'
|
43
|
+
@fullName = 'Billie Holiday'
|
44
|
+
assert_full_name
|
45
|
+
# check an invalid name
|
46
|
+
@username = 'nobody'
|
47
|
+
assert_full_name_failure
|
48
|
+
# check an invalid name - there should be no caching
|
49
|
+
assert_full_name_failure
|
50
|
+
assert_get_user_count 2
|
51
|
+
# check a valid name again
|
52
|
+
@username = 'cgrant'
|
53
|
+
@fullName = 'Cary Grant'
|
54
|
+
assert_full_name 0
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_data_gathering_pagename_as_summary
|
58
|
+
# pagename will be a copy of the issue summary
|
59
|
+
assert_data_gathered({}, { 'id' => 'TEST-42' }, 'TEST-42-A')
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_data_gathering_pagename_as_supplied
|
63
|
+
# pagename supplied already so should not be set by data gatherer
|
64
|
+
assert_data_gathered({ 'pagename' => 'Test Page' }, { 'id' => 'TEST-42' }, 'TEST-42-B')
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_data_gathering_from_invalid_issue
|
68
|
+
assert_raise RuntimeError do
|
69
|
+
assert_data_gathered({}, { 'id' => 'TEST-999' }, nil)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_data_gathering_without_connecting
|
74
|
+
assert_raise RuntimeError do
|
75
|
+
# this would be okay if connected, but we're not
|
76
|
+
assert_data_gathered({}, { 'id' => 'TEST-42' }, 'TEST-42-A', true)
|
77
|
+
end
|
78
|
+
# keep the teardown happy by connecting anyway
|
79
|
+
connect
|
80
|
+
end
|
81
|
+
|
82
|
+
def assert_data_gathered pageData, parameters, expectedResults, noConnect = false
|
83
|
+
connect unless noConnect
|
84
|
+
@jira.gatherData pageData, parameters
|
85
|
+
assert_equal @expectedResults[expectedResults], pageData
|
86
|
+
end
|
87
|
+
|
88
|
+
def assert_full_name inc = 1
|
89
|
+
assert_equal @fullName, @jira.getUserFullName(@username),
|
90
|
+
"Incorrect full name obtained for user #{@username}"
|
91
|
+
assert_get_user_count inc
|
92
|
+
end
|
93
|
+
|
94
|
+
def assert_get_user_count inc
|
95
|
+
assert_equal (@getUserCount += inc), @mockJira.getUserCount,
|
96
|
+
'Incorrect number of calls to Jira\'s getUser function'
|
97
|
+
end
|
98
|
+
|
99
|
+
def assert_full_name_failure
|
100
|
+
assert_raise RuntimeError do
|
101
|
+
assert_full_name
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# See https://github.com/sappho/sappho-data-publisher/wiki for project documentation.
|
2
|
+
# This software is licensed under the GNU Affero General Public License, version 3.
|
3
|
+
# See http://www.gnu.org/licenses/agpl.html for full details of the license terms.
|
4
|
+
# Copyright 2012 Andrew Heald.
|
5
|
+
|
6
|
+
class MockAtlassianApp
|
7
|
+
|
8
|
+
def initialize expectedUrl, expectedUsername, expectedPassword
|
9
|
+
@expectedUrl = expectedUrl
|
10
|
+
@expectedUsername = expectedUsername
|
11
|
+
@expectedPassword = expectedPassword
|
12
|
+
@token = 'a-token-string'
|
13
|
+
@loggedIn = false
|
14
|
+
end
|
15
|
+
|
16
|
+
def mockInstance url
|
17
|
+
check_not_logged_in
|
18
|
+
assert_expected 'URL', url, @expectedUrl
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def login username, password
|
23
|
+
check_not_logged_in
|
24
|
+
assert_expected 'username', username, @expectedUsername
|
25
|
+
assert_expected 'password', password, @expectedPassword
|
26
|
+
@loggedIn = true
|
27
|
+
@token
|
28
|
+
end
|
29
|
+
|
30
|
+
def logout token
|
31
|
+
assert_token_valid token
|
32
|
+
@loggedIn = false
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def check_not_logged_in
|
38
|
+
raise 'you should not be logged in yet but you are' if @loggedIn
|
39
|
+
end
|
40
|
+
|
41
|
+
def assert_expected description, actual, expected
|
42
|
+
raise "expected #{description} of #{expected} but got #{actual}" unless actual == expected
|
43
|
+
end
|
44
|
+
|
45
|
+
def assert_token_valid token
|
46
|
+
raise 'you should be logged in by now but you are not' unless @loggedIn
|
47
|
+
assert_expected 'token', token, @token
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# See https://github.com/sappho/sappho-data-publisher/wiki for project documentation.
|
2
|
+
# This software is licensed under the GNU Affero General Public License, version 3.
|
3
|
+
# See http://www.gnu.org/licenses/agpl.html for full details of the license terms.
|
4
|
+
# Copyright 2012 Andrew Heald.
|
5
|
+
|
6
|
+
require 'mock_atlassian_app'
|
7
|
+
|
8
|
+
class MockConfluence < MockAtlassianApp
|
9
|
+
|
10
|
+
attr_reader :getUserCount
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
super 'https://wiki.example.com', 'wikiuser', 'secretwikipassword'
|
14
|
+
end
|
15
|
+
|
16
|
+
def setScenario scenario
|
17
|
+
@scenario = scenario
|
18
|
+
@pageCache = {}
|
19
|
+
end
|
20
|
+
|
21
|
+
def getPage token, spaceKey, pageName
|
22
|
+
assert_token_valid token
|
23
|
+
space = @pageCache[spaceKey]
|
24
|
+
@pageCache[spaceKey] = space = {} unless space
|
25
|
+
content = space[pageName]
|
26
|
+
unless content
|
27
|
+
space[pageName] = content =
|
28
|
+
File.open("#{File.dirname(__FILE__)}/../data/confluence-pages/#{@scenario}/#{spaceKey}/#{pageName}.wiki", 'rb').read
|
29
|
+
end
|
30
|
+
{
|
31
|
+
'space' => spaceKey,
|
32
|
+
'title' => pageName,
|
33
|
+
'content' => content
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
def storePage token, page
|
38
|
+
assert_token_valid token
|
39
|
+
@pageCache[page['space']][page['title']] = page['content']
|
40
|
+
end
|
41
|
+
|
42
|
+
def assert_page_content spaceKey, pageName, expectedContent
|
43
|
+
raise 'page content is not as expected' unless @pageCache[spaceKey][pageName] == expectedContent
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# See https://github.com/sappho/sappho-data-publisher/wiki for project documentation.
|
2
|
+
# This software is licensed under the GNU Affero General Public License, version 3.
|
3
|
+
# See http://www.gnu.org/licenses/agpl.html for full details of the license terms.
|
4
|
+
# Copyright 2012 Andrew Heald.
|
5
|
+
|
6
|
+
require 'mock_atlassian_app'
|
7
|
+
|
8
|
+
class MockJira < MockAtlassianApp
|
9
|
+
|
10
|
+
attr_reader :getUserCount
|
11
|
+
|
12
|
+
def initialize filename
|
13
|
+
super 'https://jira.example.com', 'jiraadminuser', 'secretjirapassword'
|
14
|
+
data = YAML.load_file filename
|
15
|
+
@users = data['users']
|
16
|
+
@issues = data['issues']
|
17
|
+
@allCustomFields = data['all_custom_fields']
|
18
|
+
@getUserCount = 0
|
19
|
+
end
|
20
|
+
|
21
|
+
def getCustomFields token
|
22
|
+
assert_token_valid token
|
23
|
+
@allCustomFields
|
24
|
+
end
|
25
|
+
|
26
|
+
def getIssue token, id
|
27
|
+
assert_token_valid token
|
28
|
+
raise 'issue does not exist' unless @issues.has_key? id
|
29
|
+
@issues[id]
|
30
|
+
end
|
31
|
+
|
32
|
+
def getUser token, username
|
33
|
+
assert_token_valid token
|
34
|
+
@getUserCount += 1
|
35
|
+
raise 'user unknown' unless @users.has_key? username
|
36
|
+
@users[username]
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sappho-data-publisher
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 11
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 8
|
10
|
+
version: 0.1.8
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Andrew Heald
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-03-
|
18
|
+
date: 2012-03-05 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: rake
|
@@ -61,6 +61,7 @@ extra_rdoc_files: []
|
|
61
61
|
|
62
62
|
files:
|
63
63
|
- bin/sappho-data-publisher
|
64
|
+
- lib/sappho-data-publisher/atlassian_app.rb
|
64
65
|
- lib/sappho-data-publisher/configuration.rb
|
65
66
|
- lib/sappho-data-publisher/confluence.rb
|
66
67
|
- lib/sappho-data-publisher/custom_liquid.rb
|
@@ -69,6 +70,25 @@ files:
|
|
69
70
|
- lib/sappho-data-publisher/publisher.rb
|
70
71
|
- lib/sappho-data-publisher/version.rb
|
71
72
|
- lib/sappho-data-publisher.rb
|
73
|
+
- test/config/config.yml
|
74
|
+
- test/data/config.yml
|
75
|
+
- test/data/confluence-chunk.input
|
76
|
+
- test/data/confluence-chunk.output
|
77
|
+
- test/data/confluence-pages/page-op-tests/MYSPACE/Global Macros.wiki
|
78
|
+
- test/data/confluence-pages/page-op-tests/MYSPACE/Home.wiki
|
79
|
+
- test/data/confluence-pages/page-op-tests/MYSPACE/Page Specification.wiki
|
80
|
+
- test/data/confluence-pages/page-op-tests/MYSPACE/Template.wiki
|
81
|
+
- test/data/custom-liquid.content
|
82
|
+
- test/data/custom-liquid.template
|
83
|
+
- test/data/jira-results.yml
|
84
|
+
- test/data/jira.yml
|
85
|
+
- test/ruby/confluence_test.rb
|
86
|
+
- test/ruby/custom_liquid_test.rb
|
87
|
+
- test/ruby/helper.rb
|
88
|
+
- test/ruby/jira_test.rb
|
89
|
+
- test/ruby/mock_atlassian_app.rb
|
90
|
+
- test/ruby/mock_confluence.rb
|
91
|
+
- test/ruby/mock_jira.rb
|
72
92
|
homepage: https://github.com/sappho/sappho-data-publisher/wiki
|
73
93
|
licenses: []
|
74
94
|
|
@@ -102,5 +122,23 @@ rubygems_version: 1.8.11
|
|
102
122
|
signing_key:
|
103
123
|
specification_version: 3
|
104
124
|
summary: Publishes aggregated data to formatted pages on a wiki
|
105
|
-
test_files:
|
106
|
-
|
125
|
+
test_files:
|
126
|
+
- test/config/config.yml
|
127
|
+
- test/data/config.yml
|
128
|
+
- test/data/confluence-chunk.input
|
129
|
+
- test/data/confluence-chunk.output
|
130
|
+
- test/data/confluence-pages/page-op-tests/MYSPACE/Global Macros.wiki
|
131
|
+
- test/data/confluence-pages/page-op-tests/MYSPACE/Home.wiki
|
132
|
+
- test/data/confluence-pages/page-op-tests/MYSPACE/Page Specification.wiki
|
133
|
+
- test/data/confluence-pages/page-op-tests/MYSPACE/Template.wiki
|
134
|
+
- test/data/custom-liquid.content
|
135
|
+
- test/data/custom-liquid.template
|
136
|
+
- test/data/jira-results.yml
|
137
|
+
- test/data/jira.yml
|
138
|
+
- test/ruby/confluence_test.rb
|
139
|
+
- test/ruby/custom_liquid_test.rb
|
140
|
+
- test/ruby/helper.rb
|
141
|
+
- test/ruby/jira_test.rb
|
142
|
+
- test/ruby/mock_atlassian_app.rb
|
143
|
+
- test/ruby/mock_confluence.rb
|
144
|
+
- test/ruby/mock_jira.rb
|