cuki 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -2,6 +2,7 @@ source "http://rubygems.org"
2
2
 
3
3
  gem 'httpclient'
4
4
  gem 'nokogiri'
5
+ gem "parallel"
5
6
 
6
7
  group :development do
7
8
  gem "shoulda", ">= 0"
data/Gemfile.lock CHANGED
@@ -32,6 +32,7 @@ GEM
32
32
  rake
33
33
  json (1.6.1)
34
34
  nokogiri (1.5.0)
35
+ parallel (0.5.9)
35
36
  rack (1.3.4)
36
37
  rake (0.9.2)
37
38
  rcov (0.9.11)
@@ -60,6 +61,7 @@ DEPENDENCIES
60
61
  httpclient
61
62
  jeweler (~> 1.6.4)
62
63
  nokogiri
64
+ parallel
63
65
  rcov
64
66
  rspec
65
67
  shoulda
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.6
1
+ 0.0.7
data/cucumber.yml ADDED
@@ -0,0 +1,2 @@
1
+ ---
2
+ default: '--require features/'
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.6"
8
+ s.version = "0.0.7"
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-16"
12
+ s.date = "2011-10-17"
13
13
  s.description = ""
14
14
  s.email = "andy@andywaite.com"
15
15
  s.executables = ["cuki"]
@@ -28,10 +28,12 @@ Gem::Specification.new do |s|
28
28
  "Rakefile",
29
29
  "VERSION",
30
30
  "bin/cuki",
31
+ "cucumber.yml",
31
32
  "cuki.gemspec",
32
33
  "cuki.yaml.sample",
33
34
  "features/pull/pull.feature",
34
35
  "features/pull/pull_single.feature",
36
+ "features/pull/splitting.feature",
35
37
  "features/pull/tables.feature",
36
38
  "features/pull/tags.feature",
37
39
  "features/pull/textile.feature",
@@ -43,6 +45,7 @@ Gem::Specification.new do |s|
43
45
  "features/support/env.rb",
44
46
  "lib/cuki.rb",
45
47
  "lib/pusher.rb",
48
+ "lib/string_utils.rb",
46
49
  "spec/cuki_spec.rb",
47
50
  "spec/spec_helper.rb"
48
51
  ]
@@ -58,6 +61,7 @@ Gem::Specification.new do |s|
58
61
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
59
62
  s.add_runtime_dependency(%q<httpclient>, [">= 0"])
60
63
  s.add_runtime_dependency(%q<nokogiri>, [">= 0"])
64
+ s.add_runtime_dependency(%q<parallel>, [">= 0"])
61
65
  s.add_development_dependency(%q<shoulda>, [">= 0"])
62
66
  s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
63
67
  s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
@@ -66,6 +70,7 @@ Gem::Specification.new do |s|
66
70
  else
67
71
  s.add_dependency(%q<httpclient>, [">= 0"])
68
72
  s.add_dependency(%q<nokogiri>, [">= 0"])
73
+ s.add_dependency(%q<parallel>, [">= 0"])
69
74
  s.add_dependency(%q<shoulda>, [">= 0"])
70
75
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
71
76
  s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
@@ -75,6 +80,7 @@ Gem::Specification.new do |s|
75
80
  else
76
81
  s.add_dependency(%q<httpclient>, [">= 0"])
77
82
  s.add_dependency(%q<nokogiri>, [">= 0"])
83
+ s.add_dependency(%q<parallel>, [">= 0"])
78
84
  s.add_dependency(%q<shoulda>, [">= 0"])
79
85
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
80
86
  s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
@@ -38,12 +38,12 @@ Feature: Pull
38
38
  This feature describes removing a product
39
39
  </div>
40
40
  """
41
- When I run `cuki pull`
41
+ When I run `cuki pull --skip-autoformat --skip-header`
42
42
  Then the file "features/products/add_product.feature" should contain exactly:
43
43
  """
44
44
  Feature: Add Product
45
45
 
46
- http://example.com/pages/editpage.action?pageId=123
46
+ http://example.com/pages/viewpage.action?pageId=123
47
47
 
48
48
 
49
49
  This feature describes adding a product
@@ -53,7 +53,7 @@ Feature: Pull
53
53
  """
54
54
  Feature: Remove Product
55
55
 
56
- http://example.com/pages/editpage.action?pageId=456
56
+ http://example.com/pages/viewpage.action?pageId=456
57
57
 
58
58
 
59
59
  This feature describes removing a product
@@ -23,7 +23,7 @@ Feature: Pull single
23
23
  This feature describes removing a product
24
24
  </div>
25
25
  """
26
- When I run `cuki pull features/products/add_product.feature`
26
+ When I run `cuki pull features/products/add_product.feature --skip-autoformat --skip-header`
27
27
  Then a file named "features/products/add_product.feature" should exist
28
28
  But the file "features/products/remove_product.feature" should not exist
29
29
 
@@ -0,0 +1,67 @@
1
+ Feature: Splitting
2
+
3
+ Instead of association one wiki page per feature file, you can split a wiki file across multiple feature files.
4
+
5
+ @announce
6
+ Scenario: Pull all features
7
+ Given a file named "config/cuki.yaml" with:
8
+ """
9
+ ---
10
+ host: http://example.com
11
+ container: !ruby/regexp '/h1\. Acceptance Criteria(.*)h1\./m'
12
+ mappings:
13
+ 123: features/products
14
+ """
15
+ And a Confluence page on "example.com" with id 123:
16
+ """
17
+ <input id="content-title" value="Product Management">
18
+ <div id="markupTextarea">
19
+ h1. Acceptance Criteria
20
+
21
+ Something
22
+
23
+ h2. Add Product
24
+
25
+ This feature describes adding a product
26
+
27
+ h6. Scenario: Scenario A
28
+
29
+ h2. Remove Product
30
+
31
+ This feature describes removing a product
32
+
33
+ h6. Scenario Outline: Scenario B
34
+
35
+ h1. Next Section
36
+ </div>
37
+ """
38
+ When I run `cuki pull --skip-autoformat --skip-header`
39
+ Then the file "features/products/add_product.feature" should contain exactly:
40
+ """
41
+ Feature: Add Product
42
+
43
+
44
+
45
+ http://example.com/pages/viewpage.action?pageId=123#ProductManagement-AddProduct
46
+
47
+ This feature describes adding a product
48
+
49
+ Scenario: Scenario A
50
+
51
+
52
+ """
53
+ And the file "features/products/remove_product.feature" should contain exactly:
54
+ """
55
+ Feature: Remove Product
56
+
57
+
58
+
59
+ http://example.com/pages/viewpage.action?pageId=123#ProductManagement-RemoveProduct
60
+
61
+ This feature describes removing a product
62
+
63
+ Scenario Outline: Scenario B
64
+
65
+
66
+ """
67
+
@@ -21,12 +21,12 @@ Feature: Tables
21
21
  | b | 2 |
22
22
  </div>
23
23
  """
24
- When I run `cuki pull`
24
+ When I run `cuki pull --skip-autoformat --skip-header`
25
25
  Then the file "features/products/add_product.feature" should contain exactly:
26
26
  """
27
27
  Feature: Add Product
28
28
 
29
- http://example.com/pages/editpage.action?pageId=123
29
+ http://example.com/pages/viewpage.action?pageId=123
30
30
 
31
31
 
32
32
  Scenario: Foo
@@ -18,13 +18,13 @@ Feature: Tags
18
18
  h5. Scenario: Foo
19
19
  </div>
20
20
  """
21
- When I run `cuki pull`
21
+ When I run `cuki pull --skip-autoformat --skip-header`
22
22
  Then the file "features/products/add_product.feature" should contain exactly:
23
23
  """
24
24
  @draft
25
25
  Feature: Add Product
26
26
 
27
- http://example.com/pages/editpage.action?pageId=123
27
+ http://example.com/pages/viewpage.action?pageId=123
28
28
 
29
29
 
30
30
  Scenario: Foo
@@ -17,12 +17,12 @@ Feature: Textile
17
17
  h6. Scenario Outline: Bar
18
18
  </div>
19
19
  """
20
- When I run `cuki pull`
20
+ When I run `cuki pull --skip-autoformat --skip-header`
21
21
  Then the file "features/products/add_product.feature" should contain exactly:
22
22
  """
23
23
  Feature: Add Product
24
24
 
25
- http://example.com/pages/editpage.action?pageId=123
25
+ http://example.com/pages/viewpage.action?pageId=123
26
26
 
27
27
 
28
28
  Scenario: Foo
@@ -19,7 +19,7 @@ Feature: Push
19
19
  """
20
20
  This is my feature
21
21
  """
22
- When I run `cuki push features/products/add_product.feature`
22
+ When I run `cuki push features/products/add_product.feature --skip-autoformat
23
23
  Then the push should be successful
24
24
 
25
25
  @pending
@@ -4,7 +4,7 @@ Given /^a Confluence page on "([^"]*)" with id (\d+):$/ do |host, id, content|
4
4
  # the URLs to be stubbed
5
5
 
6
6
  @stubs ||= {}
7
- @stubs["http://#{host}/pages/editpage.action?pageId=#{id}"] = content
7
+ @stubs["http://#{host}/pages/viewpage.action?pageId=#{id}"] = content
8
8
 
9
9
  File.open('stubs.json', 'w') do |f|
10
10
  f.write @stubs.to_json
data/lib/cuki.rb CHANGED
@@ -4,6 +4,8 @@ require 'nokogiri'
4
4
  require 'yaml'
5
5
  require 'CGI'
6
6
  require 'json'
7
+ require 'parallel'
8
+ require File.dirname(__FILE__) + '/string_utils.rb'
7
9
 
8
10
  # terrible hack
9
11
  if File.exist?('stubs.json') || File.exist?('stubs.json')
@@ -25,18 +27,28 @@ class Cuki
25
27
  configure_http_client
26
28
 
27
29
  action = args.first
30
+ if args.include?('--skip-autoformat')
31
+ args.delete_if { |arg| '--skip-autoformat' == arg }
32
+ @skip_autoformat = true
33
+ end
34
+ if args.include?('--skip-header')
35
+ args.delete_if { |arg| '--skip-header' == arg }
36
+ @skip_header = true
37
+ end
28
38
  if 'pull' == action
29
39
  configure_pull_stubs
30
40
  verify_project
31
41
  file = args[1]
32
42
  if file
33
43
  id = @config['mappings'].invert[file]
34
- raise "could not get id for #{file}"
44
+ raise "could not get id for #{file}" unless id
35
45
  pull_feature id, file
36
46
  else
37
- @config['mappings'].each { |id, filepath| pull_feature id, filepath }
47
+ Parallel.map(@config['mappings'], :in_processes => 4) do |id, filepath|
48
+ pull_feature id, filepath
49
+ end
38
50
  end
39
- #autoformat
51
+ autoformat
40
52
  elsif 'push' == action
41
53
  configure_push_stubs
42
54
  Pusher.push file, @config
@@ -51,7 +63,7 @@ class Cuki
51
63
  def verify_project
52
64
  # check features folder exists
53
65
  raise "features folder not found" unless File.exists?('features')
54
- #autoformat
66
+ autoformat
55
67
  end
56
68
 
57
69
  def read_config
@@ -72,35 +84,80 @@ class Cuki
72
84
 
73
85
  def pull_feature(id, filepath)
74
86
  @content = ''
75
- wiki_link = @config['host'] + '/pages/editpage.action?pageId=' + id.to_s
76
- puts "Downloading #{wiki_link}"
77
- response = @client.get wiki_link
87
+ wiki_edit_link = @config['host'] + '/pages/editpage.action?pageId=' + id.to_s
88
+ wiki_view_link = @config['host'] + '/pages/viewpage.action?pageId=' + id.to_s
89
+ puts "Downloading #{wiki_edit_link}"
90
+ response = @client.get wiki_edit_link
78
91
  doc = Nokogiri(response.body)
79
-
92
+
80
93
  unless doc.at('#content-title')
81
94
  puts "Not a valid confluence page:"
82
95
  puts doc.to_s
83
96
  exit(1)
84
97
  end
85
98
 
86
- @content += "Feature: " + doc.at('#content-title')[:value] + "\n\n"
87
- @content += "#{wiki_link}\n\n"
88
- @content += CGI.unescapeHTML(doc.css('#markupTextarea').text)
99
+ if @config['container']
100
+ handle_multi doc, id
101
+ else
102
+
103
+ @content += "Feature: " + doc.at('#content-title')[:value] + "\n\n"
104
+ @content += "#{wiki_view_link}\n\n"
105
+ @content += get_markup(doc)
89
106
 
90
- clean
107
+ clean
91
108
 
92
- process_tags
109
+ process_tags
93
110
 
94
- save_file filepath
111
+ @content = "# Generated by Cuki (#{Time.now})\n" + @content unless @skip_header
112
+
113
+ save_file filepath
114
+ end
95
115
  end
96
116
 
97
117
  def autoformat
98
- `cucumber -a . --dry-run -P` unless ENV['SKIP_AUTOFORMAT']
118
+ `cucumber -a . --dry-run -P` unless @skip_autoformat
119
+ end
120
+
121
+ def handle_multi doc, id
122
+ feature_title_compressed = doc.at('#content-title')[:value].anchorize
123
+
124
+ @content += get_markup(doc)
125
+ acceptance_criteria_matches = @content.match(@config['container'])
126
+ unless acceptance_criteria_matches
127
+ puts "Could not match #{config['container']}"
128
+ exit(1)
129
+ end
130
+ acceptance_criteria = acceptance_criteria_matches[1]
131
+ scenario_titles = acceptance_criteria.scan(/h2. (.*)/).flatten
132
+ scenario_blocks = acceptance_criteria.split(/h2. .*/)
133
+ scenario_blocks.shift
134
+
135
+ combined = {}
136
+ scenario_titles.each_with_index do |title, index|
137
+ combined[title] = scenario_blocks[index].gsub(/h6. (.*)/, '\1')
138
+ end
139
+ combined.each do |title, content|
140
+ scenario_title_compressed = title.anchorize
141
+ feature_filename = title.parameterize
142
+
143
+ dirpath = @config['mappings'][id]
144
+
145
+ FileUtils.mkdir_p(dirpath)
146
+
147
+ fname = "#{dirpath}/#{feature_filename.gsub("\r", '')}.feature"
148
+ File.open(fname, 'w') do |f|
149
+ puts "Writing #{fname}"
150
+ f.write "Feature: #{title}\n\n"
151
+ link = @config['host'] + "/pages/viewpage.action?pageId=#{id}##{feature_title_compressed}-#{scenario_title_compressed}"
152
+ f.write "\n\n" + link
153
+ f.write content
154
+ end
155
+ end
99
156
  end
100
157
 
101
158
  def clean
102
159
 
103
- @content.gsub('&nbsp;', '')
160
+ @content.gsub!('&nbsp;', '')
104
161
 
105
162
  # remove the double pipes used for table headers in Confluence
106
163
  @content.gsub!('||', '|')
@@ -113,6 +170,13 @@ class Cuki
113
170
  # remove any unwanted headers
114
171
  @content.gsub!(/h\d\. (Scenario: .*)/, '\1')
115
172
  @content.gsub!(/h\d\. (Scenario Outline: .*)/, '\1')
173
+ @content.gsub!(/h\d\. (Background: .*)/, '\1')
174
+
175
+ #Remove fancy quotes
176
+ @content.gsub!('’', "'")
177
+ @content.gsub!('‘', "'")
178
+ @content.gsub!('“', '"')
179
+ @content.gsub!('”', '"')
116
180
 
117
181
  end
118
182
 
@@ -134,7 +198,7 @@ class Cuki
134
198
  def save_file(filepath)
135
199
  dir_path = File.dirname(filepath)
136
200
 
137
- Dir.mkdir(dir_path) unless File.exists?(dir_path)
201
+ FileUtils.mkdir_p(dir_path) unless File.exists?(dir_path)
138
202
 
139
203
  File.open(filepath, 'w') do |f|
140
204
  puts "Writing #{filepath}"
@@ -172,4 +236,8 @@ class Cuki
172
236
  end
173
237
  end
174
238
 
239
+ def get_markup(doc)
240
+ CGI.unescapeHTML(doc.css('#markupTextarea').text)
241
+ end
242
+
175
243
  end
@@ -0,0 +1,9 @@
1
+ class String
2
+ def anchorize
3
+ CGI.escape(self.gsub(' ', '').gsub("\r", ''))
4
+ end
5
+
6
+ def parameterize
7
+ self.downcase.gsub(' ', '_')
8
+ end
9
+ 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: 19
4
+ hash: 17
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 6
10
- version: 0.0.6
9
+ - 7
10
+ version: 0.0.7
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-16 00:00:00 Z
18
+ date: 2011-10-17 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  requirement: &id001 !ruby/object:Gem::Requirement
@@ -56,11 +56,25 @@ dependencies:
56
56
  - 0
57
57
  version: "0"
58
58
  version_requirements: *id003
59
+ name: parallel
60
+ prerelease: false
61
+ type: :runtime
62
+ - !ruby/object:Gem::Dependency
63
+ requirement: &id004 !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ hash: 3
69
+ segments:
70
+ - 0
71
+ version: "0"
72
+ version_requirements: *id004
59
73
  name: shoulda
60
74
  prerelease: false
61
75
  type: :development
62
76
  - !ruby/object:Gem::Dependency
63
- requirement: &id004 !ruby/object:Gem::Requirement
77
+ requirement: &id005 !ruby/object:Gem::Requirement
64
78
  none: false
65
79
  requirements:
66
80
  - - ~>
@@ -71,12 +85,12 @@ dependencies:
71
85
  - 0
72
86
  - 0
73
87
  version: 1.0.0
74
- version_requirements: *id004
88
+ version_requirements: *id005
75
89
  name: bundler
76
90
  prerelease: false
77
91
  type: :development
78
92
  - !ruby/object:Gem::Dependency
79
- requirement: &id005 !ruby/object:Gem::Requirement
93
+ requirement: &id006 !ruby/object:Gem::Requirement
80
94
  none: false
81
95
  requirements:
82
96
  - - ~>
@@ -87,12 +101,12 @@ dependencies:
87
101
  - 6
88
102
  - 4
89
103
  version: 1.6.4
90
- version_requirements: *id005
104
+ version_requirements: *id006
91
105
  name: jeweler
92
106
  prerelease: false
93
107
  type: :development
94
108
  - !ruby/object:Gem::Dependency
95
- requirement: &id006 !ruby/object:Gem::Requirement
109
+ requirement: &id007 !ruby/object:Gem::Requirement
96
110
  none: false
97
111
  requirements:
98
112
  - - ">="
@@ -101,12 +115,12 @@ dependencies:
101
115
  segments:
102
116
  - 0
103
117
  version: "0"
104
- version_requirements: *id006
118
+ version_requirements: *id007
105
119
  name: rcov
106
120
  prerelease: false
107
121
  type: :development
108
122
  - !ruby/object:Gem::Dependency
109
- requirement: &id007 !ruby/object:Gem::Requirement
123
+ requirement: &id008 !ruby/object:Gem::Requirement
110
124
  none: false
111
125
  requirements:
112
126
  - - ">="
@@ -115,7 +129,7 @@ dependencies:
115
129
  segments:
116
130
  - 0
117
131
  version: "0"
118
- version_requirements: *id007
132
+ version_requirements: *id008
119
133
  name: rspec
120
134
  prerelease: false
121
135
  type: :development
@@ -139,10 +153,12 @@ files:
139
153
  - Rakefile
140
154
  - VERSION
141
155
  - bin/cuki
156
+ - cucumber.yml
142
157
  - cuki.gemspec
143
158
  - cuki.yaml.sample
144
159
  - features/pull/pull.feature
145
160
  - features/pull/pull_single.feature
161
+ - features/pull/splitting.feature
146
162
  - features/pull/tables.feature
147
163
  - features/pull/tags.feature
148
164
  - features/pull/textile.feature
@@ -154,6 +170,7 @@ files:
154
170
  - features/support/env.rb
155
171
  - lib/cuki.rb
156
172
  - lib/pusher.rb
173
+ - lib/string_utils.rb
157
174
  - spec/cuki_spec.rb
158
175
  - spec/spec_helper.rb
159
176
  homepage: http://github.com/andyw8/cuki