cuki 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/README.rdoc +5 -4
- data/VERSION +1 -1
- data/cuki.gemspec +2 -3
- data/cuki.yaml.sample +3 -3
- data/features/pull/error_handling.feature +23 -1
- data/features/pull/pull.feature +56 -55
- data/features/pull/pull_single.feature +14 -9
- data/features/pull/splitting.feature +7 -6
- data/features/pull/tables.feature +9 -6
- data/features/pull/tags.feature +12 -7
- data/features/pull/textile.feature +9 -6
- data/lib/confluence_page.rb +25 -1
- data/lib/cuki.rb +76 -165
- data/lib/link_builder.rb +4 -2
- metadata +4 -5
- data/lib/cleaner.rb +0 -32
data/README.rdoc
CHANGED
@@ -2,13 +2,11 @@
|
|
2
2
|
|
3
3
|
Cuki provides an easy way to import acceptance criteria from a Confluence wiki into Cucumber feature files
|
4
4
|
|
5
|
-
- Supports a mapping between Confluence pages and feature files
|
6
5
|
- Converts Confluence tables to Cucumber tables
|
7
6
|
- Strips out unnecessary Confluence formatting (headers, etc.)
|
8
7
|
- Includes a link back to the original Confluence page
|
9
8
|
- Formats the feature using Cucumber's auto-formatter (optional)
|
10
9
|
- Support client SSL certificates for use within an organisation's secure intranet
|
11
|
-
- Assign tags to a feature based on the wiki page content
|
12
10
|
|
13
11
|
It can be used as part of a CI process or just for ad-hoc imports.
|
14
12
|
|
@@ -45,6 +43,11 @@ You can also pull a single feature:
|
|
45
43
|
|
46
44
|
cuki pull features/add_product.feature
|
47
45
|
|
46
|
+
== Tags
|
47
|
+
|
48
|
+
You can add tags to a feature based on the wiki page content. See the sample configuration file.
|
49
|
+
|
50
|
+
|
48
51
|
== Options
|
49
52
|
|
50
53
|
- --skip--autoformat to avoid reformatting features (runs over the whole features directory)
|
@@ -60,8 +63,6 @@ If your Confluence installation requires a client certificate, you can supply th
|
|
60
63
|
|
61
64
|
- Will only work with Confluence setups which have no password, or use client certificates for authentication
|
62
65
|
- Only provides one-way sync, i.e. you can't edit a file locally and push it to Confluence
|
63
|
-
- Fails if the AC block is the last h1. section of the page
|
64
|
-
- Should fail if no features found in container block
|
65
66
|
|
66
67
|
== TODO
|
67
68
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.11
|
data/cuki.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "cuki"
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.11"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Andy Waite"]
|
12
|
-
s.date = "2011-10-
|
12
|
+
s.date = "2011-10-23"
|
13
13
|
s.description = ""
|
14
14
|
s.email = "andy@andywaite.com"
|
15
15
|
s.executables = ["cuki"]
|
@@ -44,7 +44,6 @@ Gem::Specification.new do |s|
|
|
44
44
|
"features/step_defs/pull_steps.rb",
|
45
45
|
"features/step_defs/push_steps.rb",
|
46
46
|
"features/support/env.rb",
|
47
|
-
"lib/cleaner.rb",
|
48
47
|
"lib/confluence_page.rb",
|
49
48
|
"lib/cuki.rb",
|
50
49
|
"lib/feature_file.rb",
|
data/cuki.yaml.sample
CHANGED
@@ -2,10 +2,10 @@
|
|
2
2
|
# the mappings associate the page IDs on Confluence with local feature files
|
3
3
|
---
|
4
4
|
host: http://mywiki
|
5
|
+
container: "h1. Acceptance Criteria"
|
5
6
|
tags:
|
6
7
|
draft: "{info:title=Draft version}"
|
7
8
|
signed_off: "{info:title=Signed-off}"
|
8
9
|
mappings:
|
9
|
-
123: features/products
|
10
|
-
124: features/
|
11
|
-
125: features/admin # folder mapping
|
10
|
+
123: features/products
|
11
|
+
124: features/admin
|
@@ -13,4 +13,26 @@ Feature: Error Handling
|
|
13
13
|
Then it should fail with:
|
14
14
|
"""
|
15
15
|
No config file found at config/cuki.yaml
|
16
|
-
"""
|
16
|
+
"""
|
17
|
+
|
18
|
+
Scenario: Missing scenarios
|
19
|
+
Given a file named "config/cuki.yaml" with:
|
20
|
+
"""
|
21
|
+
---
|
22
|
+
host: http://example.com
|
23
|
+
mappings:
|
24
|
+
123: features/products
|
25
|
+
"""
|
26
|
+
And a Confluence page on "example.com" with id 123:
|
27
|
+
"""
|
28
|
+
<input id="content-title" value="Add Product">
|
29
|
+
<div id="markupTextarea">
|
30
|
+
h1. Acceptance Criteria
|
31
|
+
</div>
|
32
|
+
"""
|
33
|
+
When I run `cuki pull --skip-autoformat`
|
34
|
+
Then it should fail with:
|
35
|
+
"""
|
36
|
+
No scenarios found in doc 123
|
37
|
+
"""
|
38
|
+
|
data/features/pull/pull.feature
CHANGED
@@ -1,55 +1,56 @@
|
|
1
|
-
Feature: Pull
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
1
|
+
# Feature: Pull
|
2
|
+
#
|
3
|
+
# @focus @announc
|
4
|
+
# Scenario: Pull all features
|
5
|
+
# Given a file named "config/cuki.yaml" with:
|
6
|
+
# """
|
7
|
+
# ---
|
8
|
+
# host: http://example.com
|
9
|
+
# mappings:
|
10
|
+
# 123: features/products/add_product.feature
|
11
|
+
# 456: features/products/remove_product.feature
|
12
|
+
# """
|
13
|
+
# And a Confluence page on "example.com" with id 123:
|
14
|
+
# """
|
15
|
+
# <input id="content-title" value="Add Product">
|
16
|
+
# <div id="markupTextarea">
|
17
|
+
# This feature describes adding a product
|
18
|
+
#
|
19
|
+
# # Some comment
|
20
|
+
#
|
21
|
+
# Blah
|
22
|
+
# </div>
|
23
|
+
# """
|
24
|
+
# And a Confluence page on "example.com" with id 456:
|
25
|
+
# """
|
26
|
+
# <input id="content-title" value="Remove Product">
|
27
|
+
# <div id="markupTextarea">
|
28
|
+
# This feature describes removing a product
|
29
|
+
# </div>
|
30
|
+
# """
|
31
|
+
# When I run `cuki pull --skip-autoformat`
|
32
|
+
# Then the file "features/products/add_product.feature" should contain exactly:
|
33
|
+
# """
|
34
|
+
# Feature: Add Product
|
35
|
+
#
|
36
|
+
# http://example.com/pages/viewpage.action?pageId=123
|
37
|
+
#
|
38
|
+
#
|
39
|
+
# This feature describes adding a product
|
40
|
+
#
|
41
|
+
# - Some comment
|
42
|
+
#
|
43
|
+
# Blah
|
44
|
+
#
|
45
|
+
# """
|
46
|
+
# And the file "features/products/remove_product.feature" should contain exactly:
|
47
|
+
# """
|
48
|
+
# Feature: Remove Product
|
49
|
+
#
|
50
|
+
# http://example.com/pages/viewpage.action?pageId=456
|
51
|
+
#
|
52
|
+
#
|
53
|
+
# This feature describes removing a product
|
54
|
+
#
|
55
|
+
# """
|
56
|
+
#
|
@@ -1,29 +1,34 @@
|
|
1
1
|
Feature: Pull single
|
2
2
|
|
3
|
-
|
3
|
+
@focus @announce
|
4
|
+
Scenario: Pull single feature
|
4
5
|
Given a file named "config/cuki.yaml" with:
|
5
6
|
"""
|
6
7
|
---
|
7
8
|
host: http://example.com
|
8
9
|
mappings:
|
9
|
-
123: features/products
|
10
|
-
456: features/
|
10
|
+
123: features/products
|
11
|
+
456: features/admin
|
11
12
|
"""
|
12
13
|
And a Confluence page on "example.com" with id 123:
|
13
14
|
"""
|
14
|
-
<input id="content-title" value="
|
15
|
+
<input id="content-title" value="Products">
|
15
16
|
<div id="markupTextarea">
|
16
|
-
|
17
|
+
h1. Acceptance Criteria
|
18
|
+
h2. Add Product
|
19
|
+
h6. Scenario
|
17
20
|
</div>
|
18
21
|
"""
|
19
22
|
And a Confluence page on "example.com" with id 456:
|
20
23
|
"""
|
21
|
-
<input id="content-title" value="
|
24
|
+
<input id="content-title" value="Admin">
|
22
25
|
<div id="markupTextarea">
|
23
|
-
|
26
|
+
h1. Acceptance Criteria
|
27
|
+
h2. Edit User
|
28
|
+
h6. Scenario
|
24
29
|
</div>
|
25
30
|
"""
|
26
|
-
When I run `cuki pull features/products
|
31
|
+
When I run `cuki pull features/products --skip-autoformat`
|
27
32
|
Then a file named "features/products/add_product.feature" should exist
|
28
|
-
But the file "features/
|
33
|
+
But the file "features/admin/edit_user.feature" should not exist
|
29
34
|
|
@@ -36,7 +36,7 @@ Feature: Splitting
|
|
36
36
|
h1. Next Section
|
37
37
|
</div>
|
38
38
|
"""
|
39
|
-
When I run `cuki pull --skip-autoformat
|
39
|
+
When I run `cuki pull --skip-autoformat`
|
40
40
|
Then the file "features/products/add_product.feature" should contain exactly:
|
41
41
|
"""
|
42
42
|
Feature: Add Product
|
@@ -62,7 +62,7 @@ Feature: Splitting
|
|
62
62
|
|
63
63
|
"""
|
64
64
|
|
65
|
-
@announce
|
65
|
+
@announce
|
66
66
|
Scenario: Pull all features (specified container)
|
67
67
|
Given a file named "config/cuki.yaml" with:
|
68
68
|
"""
|
@@ -89,7 +89,7 @@ Feature: Splitting
|
|
89
89
|
h1. Next Section
|
90
90
|
</div>
|
91
91
|
"""
|
92
|
-
When I run `cuki pull --skip-autoformat
|
92
|
+
When I run `cuki pull --skip-autoformat`
|
93
93
|
Then the file "features/products/add_product.feature" should contain exactly:
|
94
94
|
"""
|
95
95
|
Feature: Add Product
|
@@ -104,7 +104,7 @@ Feature: Splitting
|
|
104
104
|
"""
|
105
105
|
|
106
106
|
@announce
|
107
|
-
Scenario:Special Chars
|
107
|
+
Scenario: Special Chars
|
108
108
|
Given a file named "config/cuki.yaml" with:
|
109
109
|
"""
|
110
110
|
---
|
@@ -129,7 +129,7 @@ Feature: Splitting
|
|
129
129
|
h1. Next Section
|
130
130
|
</div>
|
131
131
|
"""
|
132
|
-
When I run `cuki pull --skip-autoformat
|
132
|
+
When I run `cuki pull --skip-autoformat`
|
133
133
|
Then the file "features/products/add_remove_product.feature" should contain exactly:
|
134
134
|
"""
|
135
135
|
Feature: Add/Remove Product
|
@@ -141,4 +141,5 @@ Feature: Splitting
|
|
141
141
|
Scenario: Scenario A
|
142
142
|
|
143
143
|
|
144
|
-
"""
|
144
|
+
"""
|
145
|
+
|
@@ -7,13 +7,17 @@ Feature: Tables
|
|
7
7
|
---
|
8
8
|
host: http://example.com
|
9
9
|
mappings:
|
10
|
-
123: features/products
|
10
|
+
123: features/products
|
11
11
|
"""
|
12
12
|
And a Confluence page on "example.com" with id 123:
|
13
13
|
"""
|
14
|
-
<input id="content-title" value="
|
14
|
+
<input id="content-title" value="Products">
|
15
15
|
<div id="markupTextarea">
|
16
|
-
|
16
|
+
h1. Acceptance Criteria
|
17
|
+
|
18
|
+
h2. Add Product
|
19
|
+
|
20
|
+
h6. Scenario: Foo
|
17
21
|
|
18
22
|
Given this:
|
19
23
|
|| foo || bar ||
|
@@ -21,13 +25,12 @@ Feature: Tables
|
|
21
25
|
| b | 2 |
|
22
26
|
</div>
|
23
27
|
"""
|
24
|
-
When I run `cuki pull --skip-autoformat
|
28
|
+
When I run `cuki pull --skip-autoformat`
|
25
29
|
Then the file "features/products/add_product.feature" should contain exactly:
|
26
30
|
"""
|
27
31
|
Feature: Add Product
|
28
32
|
|
29
|
-
http://example.com/pages/viewpage.action?pageId=123
|
30
|
-
|
33
|
+
http://example.com/pages/viewpage.action?pageId=123#Products-AddProduct
|
31
34
|
|
32
35
|
Scenario: Foo
|
33
36
|
|
data/features/pull/tags.feature
CHANGED
@@ -9,23 +9,28 @@ Feature: Tags
|
|
9
9
|
draft: "{info:title=Draft version}"
|
10
10
|
signed_off: "{info:title=Signed-off}"
|
11
11
|
mappings:
|
12
|
-
123: features/products
|
12
|
+
123: features/products
|
13
13
|
"""
|
14
14
|
And a Confluence page on "example.com" with id 123:
|
15
15
|
"""
|
16
|
-
<input id="content-title" value="
|
17
|
-
<div id="markupTextarea">
|
18
|
-
|
16
|
+
<input id="content-title" value="Products">
|
17
|
+
<div id="markupTextarea">
|
18
|
+
h1. Acceptance Criteria
|
19
|
+
|
20
|
+
{info:title=Draft version}
|
21
|
+
|
22
|
+
h2. Add Product
|
23
|
+
|
24
|
+
h6. Scenario: Foo
|
19
25
|
</div>
|
20
26
|
"""
|
21
|
-
When I run `cuki pull --skip-autoformat
|
27
|
+
When I run `cuki pull --skip-autoformat`
|
22
28
|
Then the file "features/products/add_product.feature" should contain exactly:
|
23
29
|
"""
|
24
30
|
@draft
|
25
31
|
Feature: Add Product
|
26
32
|
|
27
|
-
http://example.com/pages/viewpage.action?pageId=123
|
28
|
-
|
33
|
+
http://example.com/pages/viewpage.action?pageId=123#Products-AddProduct
|
29
34
|
|
30
35
|
Scenario: Foo
|
31
36
|
|
@@ -6,24 +6,27 @@ Feature: Textile
|
|
6
6
|
---
|
7
7
|
host: http://example.com
|
8
8
|
mappings:
|
9
|
-
123: features/products
|
9
|
+
123: features/products
|
10
10
|
"""
|
11
11
|
And a Confluence page on "example.com" with id 123:
|
12
12
|
"""
|
13
|
-
<input id="content-title" value="
|
13
|
+
<input id="content-title" value="Products">
|
14
14
|
<div id="markupTextarea">
|
15
|
-
|
15
|
+
h1. Acceptance Criteria
|
16
|
+
|
17
|
+
h2. Add Product
|
18
|
+
|
19
|
+
h6. Scenario: Foo
|
16
20
|
|
17
21
|
h6. Scenario Outline: Bar
|
18
22
|
</div>
|
19
23
|
"""
|
20
|
-
When I run `cuki pull --skip-autoformat
|
24
|
+
When I run `cuki pull --skip-autoformat`
|
21
25
|
Then the file "features/products/add_product.feature" should contain exactly:
|
22
26
|
"""
|
23
27
|
Feature: Add Product
|
24
28
|
|
25
|
-
http://example.com/pages/viewpage.action?pageId=123
|
26
|
-
|
29
|
+
http://example.com/pages/viewpage.action?pageId=123#Products-AddProduct
|
27
30
|
|
28
31
|
Scenario: Foo
|
29
32
|
|
data/lib/confluence_page.rb
CHANGED
@@ -11,7 +11,31 @@ class ConfluencePage
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def content
|
14
|
-
CGI.unescapeHTML @doc.css('#markupTextarea').text
|
14
|
+
content = CGI.unescapeHTML @doc.css('#markupTextarea').text
|
15
|
+
|
16
|
+
content.gsub!(' ', '')
|
17
|
+
|
18
|
+
# remove the double pipes used for table headers in Confluence
|
19
|
+
content.gsub!('||', '|')
|
20
|
+
|
21
|
+
# remove other noise
|
22
|
+
content.gsub!("\r\n", "\n")
|
23
|
+
content.gsub!("\\\\\n", '')
|
24
|
+
content.gsub!('\\', '')
|
25
|
+
|
26
|
+
# remove any unwanted headers
|
27
|
+
content.gsub!(/h\d\. (Scenario: .*)/, '\1')
|
28
|
+
content.gsub!(/h\d\. (Scenario Outline: .*)/, '\1')
|
29
|
+
content.gsub!(/h\d\. (Background: .*)/, '\1')
|
30
|
+
|
31
|
+
#Remove fancy quotes
|
32
|
+
content.gsub!('’', "'")
|
33
|
+
content.gsub!('‘', "'")
|
34
|
+
content.gsub!('“', '"')
|
35
|
+
content.gsub!('”', '"')
|
36
|
+
|
37
|
+
content.gsub!(/^#(.*)/, '-' + '\1')
|
38
|
+
content
|
15
39
|
end
|
16
40
|
|
17
41
|
end
|
data/lib/cuki.rb
CHANGED
@@ -6,7 +6,6 @@ require 'json'
|
|
6
6
|
require 'parallel'
|
7
7
|
require File.dirname(__FILE__) + '/string_utils'
|
8
8
|
require File.dirname(__FILE__) + '/link_builder'
|
9
|
-
require File.dirname(__FILE__) + '/cleaner'
|
10
9
|
require File.dirname(__FILE__) + '/confluence_page'
|
11
10
|
require File.dirname(__FILE__) + '/feature_file'
|
12
11
|
require File.dirname(__FILE__) + '/test_bits'
|
@@ -14,226 +13,138 @@ require File.dirname(__FILE__) + '/test_bits'
|
|
14
13
|
class Cuki
|
15
14
|
|
16
15
|
CONFIG_PATH = 'config/cuki.yaml'
|
16
|
+
DEFAULT_CONTAINER = /h1\. Acceptance Criteria/
|
17
|
+
PRIMARY_HEADER = "h1\."
|
18
|
+
FEATURE_HEADER = "h2\."
|
19
|
+
SCENARIO_HEADER = "h6\."
|
20
|
+
|
21
|
+
FLAGS = {:skip_autoformat => '--skip-autoformat'}
|
17
22
|
|
18
23
|
def self.invoke(args)
|
19
24
|
new(args)
|
20
25
|
end
|
21
26
|
|
22
27
|
def initialize(args)
|
23
|
-
|
28
|
+
@args = args
|
29
|
+
validate_args
|
24
30
|
read_config
|
25
31
|
configure_http_client
|
26
|
-
|
32
|
+
@link_builder = LinkBuilder.new(@config['host'])
|
27
33
|
action = args.first
|
28
|
-
if args.include?(
|
29
|
-
args.delete_if { |arg|
|
34
|
+
if args.include?(FLAGS[:skip_autoformat])
|
35
|
+
args.delete_if { |arg| FLAGS[:skip_autoformat] == arg }
|
30
36
|
@skip_autoformat = true
|
31
37
|
end
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
file = args[1]
|
40
|
-
if file
|
41
|
-
id = @config['mappings'].invert[file]
|
42
|
-
raise "could not get id for #{file}" unless id
|
43
|
-
pull_feature id, file
|
44
|
-
else
|
45
|
-
Parallel.map(@config['mappings'], :in_processes => 4) do |id, filepath|
|
46
|
-
pull_feature id, filepath
|
47
|
-
end
|
48
|
-
end
|
49
|
-
autoformat
|
38
|
+
configure_pull_stubs
|
39
|
+
verify_project
|
40
|
+
file = args[1]
|
41
|
+
if file
|
42
|
+
id = mappings.invert[file]
|
43
|
+
terminate "could not get id for #{file}" unless id
|
44
|
+
pull_feature id, file
|
50
45
|
else
|
51
|
-
|
52
|
-
|
46
|
+
Parallel.map(mappings, :in_processes => 4) do |id, filepath|
|
47
|
+
pull_feature id, filepath
|
48
|
+
end
|
53
49
|
end
|
50
|
+
autoformat!
|
54
51
|
end
|
55
52
|
|
56
53
|
private
|
57
|
-
|
54
|
+
|
58
55
|
def verify_project
|
59
|
-
|
60
|
-
|
61
|
-
autoformat
|
56
|
+
terminate "features folder not found" unless File.exists?('features')
|
57
|
+
`cucumber --dry-run -P`
|
62
58
|
end
|
63
|
-
|
59
|
+
|
64
60
|
def read_config
|
65
|
-
unless File.exist?(CONFIG_PATH)
|
66
|
-
puts "No config file found at #{CONFIG_PATH}"
|
67
|
-
exit(1)
|
68
|
-
end
|
61
|
+
terminate "No config file found at #{CONFIG_PATH}" unless File.exist?(CONFIG_PATH)
|
69
62
|
@config = YAML::load( File.open( CONFIG_PATH ) )
|
70
|
-
unless @config["host"]
|
71
|
-
|
72
|
-
exit(1)
|
73
|
-
end
|
74
|
-
unless @config["mappings"]
|
75
|
-
puts "Mappings not found in #{CONFIG_PATH}"
|
76
|
-
exit(1)
|
77
|
-
end
|
63
|
+
terminate "Host not found in #{CONFIG_PATH}" unless @config["host"]
|
64
|
+
terminate "Mappings not found in #{CONFIG_PATH}" unless @config["mappings"]
|
78
65
|
end
|
79
|
-
|
66
|
+
|
80
67
|
def configure_http_client
|
81
68
|
@client = HTTPClient.new
|
82
69
|
@client.ssl_config.set_trust_ca(ENV['CER']) if ENV['CER']
|
83
70
|
@client.ssl_config.set_client_cert_file(ENV['PEM'], ENV['PEM']) if ENV['PEM']
|
84
71
|
end
|
85
|
-
|
72
|
+
|
86
73
|
def pull_feature(id, filepath)
|
87
|
-
|
88
|
-
|
89
|
-
link_builder = LinkBuilder.new(@config['host'])
|
90
|
-
|
91
|
-
wiki_edit_link = link_builder.edit(id)
|
92
|
-
wiki_view_link = link_builder.view(id)
|
93
|
-
|
74
|
+
wiki_edit_link = @link_builder.edit(id)
|
94
75
|
puts "Downloading #{wiki_edit_link}"
|
95
76
|
response = @client.get wiki_edit_link
|
96
|
-
|
97
|
-
confluence_page = ConfluencePage.new(response.body)
|
98
|
-
|
99
|
-
unless confluence_page.content
|
100
|
-
puts "Not a valid confluence page:"
|
101
|
-
puts response.body
|
102
|
-
exit(1)
|
103
|
-
end
|
104
|
-
|
105
|
-
unless filepath.include?('.feature')
|
106
|
-
|
107
|
-
@config['container'] ||= /h1\. Acceptance Criteria/
|
108
|
-
|
109
|
-
handle_multi response.body, id
|
110
|
-
else
|
111
|
-
|
112
|
-
feature_file = FeatureFile.new
|
113
|
-
feature_file.title = confluence_page.title
|
114
|
-
feature_file.link = wiki_view_link
|
115
|
-
feature_file.content = confluence_page.content
|
116
|
-
|
117
|
-
content = Cleaner.clean(feature_file.to_s)
|
118
|
-
|
119
|
-
content = process_tags content
|
120
|
-
|
121
|
-
content = generated_by + content unless @skip_header
|
122
|
-
|
123
|
-
save_file content, filepath
|
124
|
-
end
|
77
|
+
handle_multi response.body, id
|
125
78
|
end
|
126
|
-
|
127
|
-
def
|
128
|
-
|
79
|
+
|
80
|
+
def container
|
81
|
+
@config['container'] ||= DEFAULT_CONTAINER
|
129
82
|
end
|
130
|
-
|
131
|
-
def autoformat
|
83
|
+
|
84
|
+
def autoformat!
|
132
85
|
`cucumber -a . --dry-run -P` unless @skip_autoformat
|
133
86
|
end
|
134
|
-
|
87
|
+
|
135
88
|
def handle_multi response_body, id
|
136
89
|
confluence_page = ConfluencePage.new(response_body)
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
puts "Could not find acceptance criteria container"
|
146
|
-
exit(1)
|
147
|
-
end
|
148
|
-
acceptance_criteria_block = @content.split(@config['container']).last
|
149
|
-
if acceptance_criteria_block.match(/h1\./)
|
150
|
-
acceptance_criteria_block = acceptance_criteria_block.split(/h1\./).first
|
151
|
-
end
|
152
|
-
unless acceptance_criteria_block
|
153
|
-
puts "Could not match #{@config['container']} in #{id}"
|
154
|
-
exit(1)
|
90
|
+
|
91
|
+
content = confluence_page.content
|
92
|
+
|
93
|
+
terminate "Could not find acceptance criteria container" unless content.match(container)
|
94
|
+
|
95
|
+
acceptance_criteria = content.split(container).last
|
96
|
+
if acceptance_criteria.include?(PRIMARY_HEADER)
|
97
|
+
acceptance_criteria = acceptance_criteria.split(/#{PRIMARY_HEADER}/).first
|
155
98
|
end
|
156
|
-
|
157
|
-
|
158
|
-
|
99
|
+
|
100
|
+
terminate "Could not match #{container} in #{id}" unless acceptance_criteria
|
101
|
+
|
102
|
+
scenario_titles = acceptance_criteria.scan(/#{FEATURE_HEADER} (.*)/).flatten
|
103
|
+
scenario_blocks = acceptance_criteria.split(/#{FEATURE_HEADER} .*/)
|
159
104
|
scenario_blocks.shift
|
160
105
|
|
161
106
|
combined = {}
|
162
107
|
found = 0
|
163
108
|
scenario_titles.each_with_index do |title, index|
|
164
|
-
combined[title] = scenario_blocks[index].gsub(
|
109
|
+
combined[title] = scenario_blocks[index].gsub(/#{SCENARIO_HEADER} (.*)/, '\1')
|
165
110
|
found += 1
|
166
111
|
end
|
167
|
-
if 0 == found
|
168
|
-
puts "No scenarios found in doc #{id}"
|
169
|
-
exit(1)
|
170
|
-
end
|
171
|
-
combined.each do |title, content|
|
172
|
-
|
173
|
-
tags = []
|
174
|
-
if @config['tags']
|
175
|
-
@config['tags'].each_pair do |tag, snippet|
|
176
|
-
tags << "@#{tag}" if @content.include?(snippet)
|
177
|
-
end
|
178
|
-
end
|
179
|
-
unless tags.empty?
|
180
|
-
content = tags.join(' ') + "\n" + content
|
181
|
-
# tags.each do |tag|
|
182
|
-
# content.gsub!(@config['tags'][tag.gsub('@', '')], '')
|
183
|
-
# end
|
184
|
-
end
|
185
|
-
|
186
|
-
scenario_title_compressed = title.anchorize
|
187
|
-
feature_filename = title.parameterize
|
188
112
|
|
189
|
-
|
113
|
+
terminate "No scenarios found in doc #{id}" if 0 == found
|
114
|
+
combined.each do |title, content|
|
190
115
|
|
116
|
+
feature_filename = title.parameterize
|
117
|
+
dirpath = mappings[id]
|
191
118
|
FileUtils.mkdir_p(dirpath)
|
192
|
-
|
119
|
+
|
193
120
|
fname = "#{dirpath}/#{feature_filename.gsub("\r", '').parameterize}.feature"
|
121
|
+
puts "Writing #{fname}"
|
194
122
|
File.open(fname, 'w') do |f|
|
195
|
-
|
196
|
-
|
123
|
+
if @config['tags']
|
124
|
+
@config['tags'].each do |tag, token|
|
125
|
+
f.write "@#{tag}\n" if acceptance_criteria.include?(token)
|
126
|
+
end
|
127
|
+
end
|
197
128
|
f.write "Feature: #{title}\n\n"
|
198
|
-
|
199
|
-
f.write link
|
129
|
+
f.write @link_builder.view(id, confluence_page.title, title)
|
200
130
|
f.write content
|
201
131
|
end
|
202
132
|
end
|
203
133
|
end
|
204
|
-
|
205
|
-
def process_tags(content)
|
206
|
-
tags = []
|
207
|
-
if @config['tags']
|
208
|
-
@config['tags'].each_pair do |tag, snippet|
|
209
|
-
tags << "@#{tag}" if content.include?(snippet)
|
210
|
-
end
|
211
|
-
end
|
212
|
-
unless tags.empty?
|
213
|
-
content = tags.join(' ') + "\n" + content
|
214
|
-
tags.each do |tag|
|
215
|
-
content.gsub!(@config['tags'][tag.gsub('@', '')], '')
|
216
|
-
end
|
217
|
-
end
|
218
|
-
content
|
219
|
-
end
|
220
|
-
|
221
|
-
def save_file(content, filepath)
|
222
|
-
dir_path = File.dirname(filepath)
|
223
134
|
|
224
|
-
|
135
|
+
def validate_args
|
136
|
+
terminate "No action given" if @args.empty?
|
137
|
+
command = @args.first
|
138
|
+
terminate "Unknown action '#{@args.first}'" unless 'pull' == command
|
139
|
+
end
|
225
140
|
|
226
|
-
|
227
|
-
|
228
|
-
f.puts content
|
229
|
-
end
|
141
|
+
def mappings
|
142
|
+
@config['mappings']
|
230
143
|
end
|
231
144
|
|
232
|
-
def
|
233
|
-
|
234
|
-
|
235
|
-
exit(1)
|
236
|
-
end
|
145
|
+
def terminate(message)
|
146
|
+
puts message
|
147
|
+
exit(1)
|
237
148
|
end
|
238
|
-
|
149
|
+
|
239
150
|
end
|
data/lib/link_builder.rb
CHANGED
@@ -8,8 +8,10 @@ class LinkBuilder
|
|
8
8
|
@host + '/pages/editpage.action?pageId=' + id.to_s
|
9
9
|
end
|
10
10
|
|
11
|
-
def view(id)
|
12
|
-
@host + '/pages/viewpage.action?pageId=' + id.to_s
|
11
|
+
def view(id, feature=nil, scenario=nil)
|
12
|
+
link = @host + '/pages/viewpage.action?pageId=' + id.to_s
|
13
|
+
link += '#' + feature.anchorize if feature
|
14
|
+
link += '-' + scenario.anchorize if scenario
|
13
15
|
end
|
14
16
|
|
15
17
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cuki
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 9
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 11
|
10
|
+
version: 0.0.11
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Andy Waite
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-10-
|
18
|
+
date: 2011-10-23 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
requirement: &id001 !ruby/object:Gem::Requirement
|
@@ -169,7 +169,6 @@ files:
|
|
169
169
|
- features/step_defs/pull_steps.rb
|
170
170
|
- features/step_defs/push_steps.rb
|
171
171
|
- features/support/env.rb
|
172
|
-
- lib/cleaner.rb
|
173
172
|
- lib/confluence_page.rb
|
174
173
|
- lib/cuki.rb
|
175
174
|
- lib/feature_file.rb
|
data/lib/cleaner.rb
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
class Cleaner
|
2
|
-
|
3
|
-
def self.clean(content)
|
4
|
-
|
5
|
-
content.gsub!(' ', '')
|
6
|
-
|
7
|
-
# remove the double pipes used for table headers in Confluence
|
8
|
-
content.gsub!('||', '|')
|
9
|
-
|
10
|
-
# remove other noise
|
11
|
-
content.gsub!("\r\n", "\n")
|
12
|
-
content.gsub!("\\\\\n", '')
|
13
|
-
content.gsub!('\\', '')
|
14
|
-
|
15
|
-
# remove any unwanted headers
|
16
|
-
content.gsub!(/h\d\. (Scenario: .*)/, '\1')
|
17
|
-
content.gsub!(/h\d\. (Scenario Outline: .*)/, '\1')
|
18
|
-
content.gsub!(/h\d\. (Background: .*)/, '\1')
|
19
|
-
|
20
|
-
#Remove fancy quotes
|
21
|
-
content.gsub!('’', "'")
|
22
|
-
content.gsub!('‘', "'")
|
23
|
-
content.gsub!('“', '"')
|
24
|
-
content.gsub!('”', '"')
|
25
|
-
|
26
|
-
content.gsub!(/^#(.*)/, '-' + '\1')
|
27
|
-
|
28
|
-
content
|
29
|
-
|
30
|
-
end
|
31
|
-
|
32
|
-
end
|