gitnesse 0.1.3 → 0.12.5

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.md CHANGED
@@ -1,8 +1,10 @@
1
1
  # Gitnesse
2
2
 
3
- Gitnesse is a Cucumber-wiki integration tool.
4
- It enables a project to store cucumber features in a git-based wiki, and then test them against your code.
5
- Conceptually influenced by Fitnesse http://fitnesse.org/
3
+ Gitnesse is an acceptance testing tool.
4
+
5
+ It enables a project to store Cucumber feature stories in a git-based wiki, test them against your code, and then update the wiki with the latest test results.
6
+
7
+ Conceptually influenced by Fitnesse http://fitnesse.org/ thank you Uncle Bob!
6
8
 
7
9
  ## Installation
8
10
 
@@ -21,8 +23,10 @@ Or install it yourself as:
21
23
  Create a `gitnesse.rb` file somewhere in your project, and add something like
22
24
  the following to it:
23
25
 
24
- Gitnesse.config do
25
- repository_url "git@github.com:hybridgroup/gitnesse-demo.wiki"
26
+ Gitnesse.configure do |config|
27
+ config.repository_url = "git@github.com:hybridgroup/gitnesse-demo.wiki"
28
+ config.annotate_results = true
29
+ config.info = "Bob Martin's development laptop"
26
30
  end
27
31
 
28
32
  ## rake tasks
@@ -31,6 +35,7 @@ the following to it:
31
35
  $ rake gitnesse:push
32
36
  $ rake gitnesse:run
33
37
  $ rake gitnesse:info
38
+ $ rake gitnesse:push_results
34
39
 
35
40
  ## Usage In Rails 3
36
41
 
@@ -48,14 +53,15 @@ There is an example application using Sinatra located here: [https://github.com/
48
53
 
49
54
  ## Other Usage
50
55
 
51
- Want to use plain old Gitnesse? There is an executable that requires the path to the configuration file:
56
+ Want to use plain old Gitnesse? There is an executable, if you're allergic to rake tasks:
57
+
58
+ $ gitnesse
52
59
 
53
- $ GITNESSE_CONFIG='./gitnesse_config.rb' gitnesse
54
60
 
55
61
  ## TODO
56
62
 
57
- - test git push back to git wiki
58
- - pluggable feature runners, so can be used with Spinach, Cucumber-JS, or ?
63
+ - pluggable feature runners, so can be used with Spinach, Cucumber-JS, or ?
64
+ - standalone server so end users to run tests and see live results, just like Fitnesse
59
65
 
60
66
  ## Contributing
61
67
 
data/bin/gitnesse CHANGED
@@ -3,7 +3,7 @@
3
3
  require 'rubygems'
4
4
  require 'gitnesse'
5
5
 
6
- Gitnesse.load_config
6
+ Gitnesse::Configuration.load_using_search
7
7
 
8
8
  if ARGV[0].nil?
9
9
  Gitnesse.run
@@ -11,7 +11,7 @@ end
11
11
 
12
12
  def print_help
13
13
  puts "Gitnesse commands:"
14
- puts " run: pull remote features from git-based wiki to local, and run Cucumber"
14
+ puts " run: pull remote features from git-based wiki to local, and run Cucumber"
15
15
  puts " push: push local features to git-based wiki"
16
16
  puts " pull: pull remote features from git-based wiki to local"
17
17
  puts " info: print current Gitnesse configuration"
@@ -25,7 +25,9 @@ when "pull"
25
25
  when "run"
26
26
  Gitnesse.run
27
27
  when "info"
28
- puts Gitnesse.config_to_hash.to_yaml
28
+ puts Gitnesse.configuration.to_yaml
29
+ when "push_results"
30
+ Gitnesse.push_results
29
31
  when "help"
30
32
  print_help
31
33
  else
data/lib/gitnesse.rb CHANGED
@@ -2,77 +2,27 @@ require 'bundler/setup'
2
2
  require 'gollum'
3
3
  require 'fileutils'
4
4
  require 'tmpdir'
5
+ require 'gitnesse/configuration'
6
+ require 'gitnesse/git_config'
7
+ require 'gitnesse/dependencies'
8
+ require 'gitnesse/features'
9
+ require 'gitnesse/hooks'
10
+ require 'gitnesse/wiki'
5
11
  require 'gitnesse/railtie' if defined?(Rails)
6
12
 
7
13
  # core module
8
14
  module Gitnesse
9
-
10
- extend self
11
-
12
- # Public: Set url of the git-based wiki repo containing features.
13
- #
14
- # repository_url - A String containing your repo's url.
15
- #
16
- # Example:
17
- #
18
- # Gitnesse.config do
19
- # repository_url "git@github.com:luishurtado/gitnesse-wiki.wiki"
20
- # end
21
- #
22
- def self.repository_url(repository_url = false)
23
- if repository_url == false
24
- unless defined?(@@repository_url)
25
- puts "---"
26
- puts "No repository_url has been defined for Gitnesse."
27
- puts "Add a gitnesse.rb file to your project and use it to configure Gitnesse."
28
- puts "For more details, check out gitnesse.com"
29
- auts "---"
30
- exit 1
31
- end
32
- return @@repository_url
33
- else
34
- @@repository_url = repository_url
35
- end
15
+ class << self
16
+ attr_accessor :configuration
17
+ attr_accessor :commit_info
36
18
  end
37
19
 
38
- # Public: Set branch of the git-based wiki repo containing features.
39
- #
40
- # branch - A String containing which branch of your repo to use.
41
- #
42
- # Example:
43
- #
44
- # Gitnesse.config do
45
- # branch "master"
46
- # end
47
- #
48
- def self.branch(branch = false)
49
- if branch == false
50
- @@branch ||= "master"
51
- else
52
- @@branch = branch
53
- end
54
- end
20
+ self.configuration ||= Configuration.new
55
21
 
56
- # Public: Set local directory used to sync with git-wiki stored feature stories.
57
- #
58
- # target_directory - A String containing which directory to use.
59
- #
60
- # Example:
61
- #
62
- # Gitnesse.config do
63
- # target_directory "features"
64
- # end
65
- #
66
- def self.target_directory(target_directory = false)
67
- if target_directory == false
68
- @@target_directory ||= File.join(Dir.pwd, 'features')
69
- else
70
- @@target_directory = target_directory
71
- end
72
- end
22
+ extend self
73
23
 
74
- def self.config(&block)
75
- instance_eval &block
24
+ def self.configure
25
+ yield(configuration)
76
26
  end
77
27
 
78
28
  # -- all methods after this are module functions --
@@ -80,44 +30,52 @@ module Gitnesse
80
30
 
81
31
  def run
82
32
  if pull
33
+ Hooks.create
34
+ puts "Now going to run cucumber..."
35
+ exec("cucumber #{Gitnesse.configuration.target_directory}/*.feature")
36
+ end
37
+ end
38
+
39
+ def push_results
40
+ if push
41
+ Hooks.create
83
42
  puts "Now going to run cucumber..."
84
- exec("cucumber #{Gitnesse.target_directory}/*.feature")
43
+ exec("cucumber #{Gitnesse.configuration.target_directory}/*.feature")
85
44
  end
86
45
  end
87
46
 
88
47
  # pull features from git wiki, and sync up with features dir
89
48
  def pull
90
- ensure_git_available
91
- ensure_cucumber_available
92
- ensure_repository
49
+ Dependencies.check
93
50
 
94
- puts "Pulling features into #{Gitnesse.target_directory} from #{Gitnesse.repository_url}..."
51
+ puts "Pulling features into #{Gitnesse.configuration.target_directory} from #{Gitnesse.configuration.repository_url}..."
95
52
  Dir.mktmpdir do |tmp_dir|
96
53
  if clone_feature_repo(tmp_dir)
97
- FileUtils.mkdir(Gitnesse.target_directory) unless File.exists?(Gitnesse.target_directory)
98
-
99
- wiki_pages = Gollum::Wiki.new(tmp_dir).pages
100
- wiki_pages.each do |wiki_page|
101
- page_name = wiki_page.name.gsub('.feature', '')
102
- page_features = extract_features(wiki_page.raw_data)
103
- write_feature_file(page_name, page_features) unless page_features.empty?
54
+ FileUtils.mkdir(Gitnesse.configuration.target_directory) unless File.exists?(Gitnesse.configuration.target_directory)
55
+
56
+ wiki_pages = Wiki.new(tmp_dir).pages
57
+ wiki_pages.each do |page|
58
+ name = page.name.gsub('.feature', '')
59
+ filename = "#{Gitnesse.configuration.target_directory}/#{name}.feature"
60
+ features = Wiki.extract_features(page)
61
+ Features.write_file(filename, features) unless features.empty?
104
62
  end
105
63
  end
106
64
  end
107
- puts "DONE."
65
+ puts " Done pulling features."
66
+ true
108
67
  end
109
68
 
110
69
  # push features back up to git wiki from features directory
111
70
  def push
112
- ensure_git_available
113
- ensure_cucumber_available
114
- ensure_repository
115
- commit_info
71
+ Dependencies.check
72
+ generate_commit_info
116
73
 
117
- puts "Pushing features from #{Gitnesse.target_directory} to #{Gitnesse.repository_url}..."
74
+ puts "Pushing features from #{Gitnesse.configuration.target_directory} to #{Gitnesse.configuration.repository_url}..."
118
75
  Dir.mktmpdir do |tmp_dir|
119
76
  if clone_feature_repo(tmp_dir)
120
- load_feature_files_into_wiki(tmp_dir)
77
+ feature_files = Dir.glob("#{Gitnesse.configuration.target_directory}/*.feature")
78
+ Wiki.new(tmp_dir).load_feature_files(feature_files)
121
79
 
122
80
  # push the changes to the remote git
123
81
  Dir.chdir(tmp_dir) do
@@ -125,178 +83,21 @@ module Gitnesse
125
83
  end
126
84
  end
127
85
  end
128
- puts "DONE."
129
- end
130
-
131
- def load_feature_files_into_wiki(tmp_dir)
132
- wiki = Gollum::Wiki.new(tmp_dir)
133
- feature_files = Dir.glob("#{Gitnesse.target_directory}/*.feature")
134
-
135
- feature_files.each do |feature_file|
136
- feature_name = File.basename(feature_file, ".feature")
137
- feature_content = File.read(feature_file)
138
- wiki_page = wiki.page(feature_name)
139
- wiki_page ||= wiki.page("#{feature_name}.feature")
140
-
141
- if wiki_page
142
- update_wiki_page(wiki, wiki_page, feature_name, feature_content)
143
- else
144
- create_wiki_page(wiki, feature_name, feature_content)
145
- end
146
- end
147
- end
148
-
149
- def create_wiki_page(wiki, page_name, feature_content)
150
- new_page_content = build_page_content(feature_content)
151
-
152
- wiki.write_page(page_name, :markdown, new_page_content, commit_info)
153
- puts "==== Created page: #{page_name} ==="
154
- end
155
-
156
- def update_wiki_page(wiki, wiki_page, page_name, feature_content)
157
- wiki_page_content = wiki_page.raw_data
158
- new_page_content = build_page_content(feature_content, wiki_page_content)
159
-
160
- if new_page_content == wiki_page_content
161
- puts "=== Page #{page_name} didn't change ==="
162
- else
163
- wiki.update_page(wiki_page, page_name, :markdown, new_page_content, commit_info)
164
- puts "==== Updated page: #{page_name} ==="
165
- end
166
- end
167
-
168
- def build_page_content(feature_content, wiki_page_content = nil)
169
- return "```gherkin\n#{feature_content}\n```" if wiki_page_content.nil? || wiki_page_content.empty?
170
- features = extract_features(wiki_page_content)
171
-
172
- # replace the first feature found in the wiki page
173
- _, old_feature_content = features.shift
174
- wiki_page_content.sub(old_feature_content, feature_content)
175
- end
176
-
177
- # look thru wiki page for features
178
- def extract_features(data)
179
- features = {}
180
-
181
- if match_result = data.match(/\u0060{3}gherkin(.+)\u0060{3}/m)
182
- captures = match_result.captures
183
-
184
- # create hash with feature name as key and feature text as value
185
- captures.each do |capture|
186
- feature_definition_at = capture.index('Feature:')
187
- feature_text = capture[feature_definition_at,capture.size-1]
188
- feature_lines = feature_text.split("\n")
189
- feature_definition = feature_lines.grep(/^Feature:/).first
190
-
191
- if feature_definition
192
- feature_name = feature_definition.split(":").last.strip.gsub(" ","-").downcase
193
- features[feature_name] = feature_text
194
- end
195
- end
196
- end
197
-
198
- features
86
+ puts " Done pushing features."
87
+ true
199
88
  end
200
89
 
201
90
  def clone_feature_repo(dir)
202
- output = `git clone #{Gitnesse.repository_url} #{dir} 2>&1`
91
+ output = `git clone #{Gitnesse.configuration.repository_url} #{dir} 2>&1`
203
92
  puts output
204
93
  $?.success?
205
94
  end
206
95
 
207
- def commit_info
208
- @commit_info ||= begin
209
- user_name = read_git_config("user.name")
210
- email = read_git_config("user.email")
211
- raise "Can't read git's user.name config" if user_name.nil? || user_name.empty?
212
- raise "Can't read git's user.email config" if email.nil? || email.empty?
213
-
214
- {:name => user_name, :email => email, :message => "Update features with Gitnesse"}
215
- end
216
- end
217
-
218
- def commit_info=(commit_info)
219
- @commit_info = commit_info
220
- end
221
-
222
- def read_git_config(config_name)
223
- config_value = ""
224
- config_value = `git config --get #{config_name}`
225
- config_value = `git config --get --global #{config_name}` unless $?.success?
226
- config_value.strip
227
- end
228
-
229
- # we are going to support only one feature per page
230
- def gather_features(page_features)
231
- return "" if page_features.nil? or page_features.empty?
232
-
233
- features = ''
234
- feature_name, feature_content = page_features.shift
235
- puts "============================== Pulling Feature: #{feature_name} =============================="
236
- features = features + feature_content
237
-
238
- page_features.each do |_feature_name, _feature_content|
239
- puts "============================== WARNING! Discarded Feature: #{_feature_name} =============================="
240
- puts _feature_content
241
- end
242
-
243
- features
244
- end
245
-
246
- def write_feature_file(page_name, page_features)
247
- File.open("#{Gitnesse.target_directory}/#{page_name}.feature","w") {|f| f.write(gather_features(page_features)) }
248
- end
249
-
250
- def ensure_git_available
251
- raise "git not found or not working." unless Kernel.system("git --version")
252
- end
253
-
254
- def ensure_cucumber_available
255
- raise "cucumber not found or not working." unless Kernel.system("cucumber --version")
256
- end
257
-
258
- def ensure_repository
259
- raise "You must select a repository_url to run Gitnesse." if Gitnesse.repository_url.nil?
260
- end
261
-
262
- def load_config
263
- load(ENV['GITNESSE_CONFIG']) and return if ENV['GITNESSE_CONFIG']
264
-
265
- possible_config_files = Dir.glob(File.join("**", "gitnesse.rb"))
266
-
267
- files_with_config = possible_config_files.select do |file_name|
268
- if FileUtils.compare_file(__FILE__, file_name)
269
- false
270
- elsif File.fnmatch("vendor/**/*.rb", file_name)
271
- false
272
- else
273
- file_content = File.read(file_name)
274
- file_content.match("Gitnesse.config")
275
- end
276
- end
277
-
278
- case files_with_config.length
279
- when 0
280
- raise "Can't find a gitnesse.rb file with Gitnesse configuration."
281
- when 1
282
- load(File.absolute_path(files_with_config.first))
283
- else
284
- raise "Several config files found: #{files_with_config.join(", ")}"
285
- end
286
- end
287
-
288
- def config_to_hash
289
- { "repository_url" => Gitnesse.repository_url,
290
- "branch" => Gitnesse.branch,
291
- "target_directory" => Gitnesse.target_directory }
292
- end
293
-
294
- def method_missing(sym, *args, &block)
295
- unless ["to_str", "to_ary"].contains?(sym)
296
- raise "Invalid variable name for Gitnesse configuration.
297
- Allowed variables are repository_url, branch, and target_directory."
298
- else
299
- super
96
+ def generate_commit_info
97
+ self.commit_info ||= begin
98
+ user_name = GitConfig.read("user.name")
99
+ email = GitConfig.read("user.email")
100
+ { :name => user_name, :email => email, :message => "Update features with Gitnesse" }
300
101
  end
301
102
  end
302
103
  end
@@ -0,0 +1,54 @@
1
+ module Gitnesse
2
+ class Configuration
3
+ attr_accessor :repository_url
4
+ attr_accessor :branch
5
+ attr_accessor :target_directory
6
+ attr_accessor :annotate_results
7
+ attr_accessor :info
8
+
9
+ class NoConfigFileError < StandardError ; end
10
+ class MultipleConfigFileError < StandardError ; end
11
+
12
+ def initialize
13
+ @branch = 'master'
14
+ @target_directory = File.join(Dir.pwd, 'features')
15
+ @annotate_results = false
16
+ @info = nil
17
+ end
18
+
19
+ # Public: Returns the current Gitnesse configuration as a Hash
20
+ #
21
+ # Returns a hash containing the current Gitnesse configuration
22
+ def to_hash
23
+ { 'repository_url' => @repository_url,
24
+ 'branch' => @branch,
25
+ 'target_directory' => @target_directory }
26
+ end
27
+
28
+ def self.load_using_search
29
+ load(ENV['GITNESSE_CONFIG']) and return if ENV['GITNESSE_CONFIG']
30
+
31
+ possible_config_files = Dir.glob(File.join("**", "gitnesse.rb"))
32
+
33
+ files_with_config = possible_config_files.select do |file_name|
34
+ if FileUtils.compare_file(__FILE__, file_name)
35
+ false
36
+ elsif File.fnmatch("vendor/**/*.rb", file_name)
37
+ false
38
+ else
39
+ file_content = File.read(file_name)
40
+ file_content.match("Gitnesse.configure")
41
+ end
42
+ end
43
+
44
+ case files_with_config.length
45
+ when 0
46
+ raise NoConfigFileError, "Can't find a gitnesse.rb file with Gitnesse configuration."
47
+ when 1
48
+ load(File.absolute_path(files_with_config.first))
49
+ else
50
+ raise MultipleConfigFileError, "Several config files found: #{files_with_config.join(", ")}"
51
+ end
52
+ end
53
+ end
54
+ end