gitnesse 0.1.3 → 0.12.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +15 -9
- data/bin/gitnesse +5 -3
- data/lib/gitnesse.rb +48 -247
- data/lib/gitnesse/configuration.rb +54 -0
- data/lib/gitnesse/dependencies.rb +38 -0
- data/lib/gitnesse/features.rb +38 -0
- data/lib/gitnesse/git_config.rb +39 -0
- data/lib/gitnesse/hooks.rb +50 -0
- data/lib/gitnesse/railtie.rb +2 -2
- data/lib/gitnesse/support/hook.rb +11 -0
- data/lib/gitnesse/tasks.rake +12 -6
- data/lib/gitnesse/version.rb +1 -1
- data/lib/gitnesse/wiki.rb +173 -0
- data/test/lib/gitnesse/build_page_content_test.rb +12 -3
- data/test/lib/gitnesse/commit_info_test.rb +8 -20
- data/test/lib/gitnesse/{config_to_hash_test.rb → configuration_to_hash_test.rb} +8 -7
- data/test/lib/gitnesse/custom_branch_test.rb +8 -9
- data/test/lib/gitnesse/dependencies_check_test.rb +60 -0
- data/test/lib/gitnesse/extract_features_test.rb +2 -2
- data/test/lib/gitnesse/{gather_features_test.rb → gather_test.rb} +6 -6
- data/test/lib/gitnesse/load_feature_files_into_wiki_test.rb +1 -1
- data/test/lib/gitnesse/read_git_config_test.rb +9 -11
- data/test/lib/gitnesse/strip_results_test.rb +52 -0
- data/test/lib/gitnesse/write_file_test.rb +18 -0
- metadata +21 -12
- data/test/lib/gitnesse/check_dependencies_test.rb +0 -45
- data/test/lib/gitnesse/write_feature_file_test.rb +0 -18
@@ -0,0 +1,38 @@
|
|
1
|
+
module Gitnesse
|
2
|
+
class Dependencies
|
3
|
+
class NoGitError < StandardError ; end
|
4
|
+
class NoCucumberError < StandardError ; end
|
5
|
+
class NoRepositoryURLError < StandardError ; end
|
6
|
+
class NoAnnotationInfoError < StandardError ; end
|
7
|
+
|
8
|
+
# Checks Gitnesse's dependencies, and throws an error if one of them is
|
9
|
+
# missing.
|
10
|
+
def self.check
|
11
|
+
check_git
|
12
|
+
check_cucumber
|
13
|
+
check_repository_url
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
def self.check_git
|
19
|
+
raise NoGitError, "git not found or not working." unless Kernel.system("git --version")
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.check_cucumber
|
23
|
+
raise NoCucumberError, "cucumber not found or not working." unless Kernel.system("cucumber --version")
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.check_repository_url
|
27
|
+
raise NoRepositoryURLError, "You must select a repository_url to run Gitnesse." if Gitnesse.configuration.repository_url.nil?
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.check_annotation_info
|
31
|
+
if Gitnesse.configuration.annotate_results
|
32
|
+
if Gitnesse.configuration.info.nil?
|
33
|
+
raise NoAnnotationInfoError, "You must enter local information to annotate test results in the wiki"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Gitnesse
|
2
|
+
class Features
|
3
|
+
|
4
|
+
# Public: Writes a feature to disk, given the filename and the
|
5
|
+
# features.
|
6
|
+
#
|
7
|
+
# filename - the filename to use for the feature
|
8
|
+
# features - the features to write to disk
|
9
|
+
#
|
10
|
+
def self.write_file(filename, features)
|
11
|
+
File.open(filename, "w") do |file|
|
12
|
+
file.write(gather(features))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Public: Gathers features for placing into files. Currently only supports
|
17
|
+
# one feature per page. Others are discarded
|
18
|
+
#
|
19
|
+
# page_features - the features
|
20
|
+
#
|
21
|
+
# Returns a string containing the
|
22
|
+
def self.gather(page_features)
|
23
|
+
return '' if page_features.nil? || page_features.empty?
|
24
|
+
|
25
|
+
features = ''
|
26
|
+
|
27
|
+
name, content = page_features.shift
|
28
|
+
puts " # Pulling Feature: #{name}"
|
29
|
+
features += content
|
30
|
+
|
31
|
+
page_features.each do |name, feature|
|
32
|
+
puts " # WARNING! Discarding Feature: #{name}"
|
33
|
+
end
|
34
|
+
|
35
|
+
features
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Gitnesse
|
2
|
+
class GitConfig
|
3
|
+
class NoValueSetError < StandardError ; end
|
4
|
+
|
5
|
+
# Public: Reads a value from the system's git config.
|
6
|
+
#
|
7
|
+
# key - the value to look up from the git config
|
8
|
+
#
|
9
|
+
# Returns a string containing the git config value or GitConfigNotFoundError
|
10
|
+
def self.read(key)
|
11
|
+
value = get_from_git_config key
|
12
|
+
|
13
|
+
if value.empty? || value == ''
|
14
|
+
raise NoValueSetError, "Cannot read git config value for #{key}"
|
15
|
+
end
|
16
|
+
|
17
|
+
value
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
# Private: Tries to fetch a value using git config --get
|
23
|
+
#
|
24
|
+
# key - the value to look up from the git config
|
25
|
+
#
|
26
|
+
# Returns a string containing the value supplied by git
|
27
|
+
def self.get_from_git_config(key)
|
28
|
+
value = ''
|
29
|
+
|
30
|
+
value = `git config --get #{key}`
|
31
|
+
|
32
|
+
if value.empty? || value == ''
|
33
|
+
value = `git config --get --global #{key}`
|
34
|
+
end
|
35
|
+
|
36
|
+
value.strip
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Gitnesse
|
2
|
+
class Hooks
|
3
|
+
@dir = File.join(Dir.home, ".gitnesse")
|
4
|
+
|
5
|
+
# Public: Sets up ~/.gitnesse for appending scenario results
|
6
|
+
#
|
7
|
+
# Returns nothing
|
8
|
+
def self.setup
|
9
|
+
Gitnesse::Configuration.load_using_search
|
10
|
+
FileUtils.rm_rf(@dir) if File.directory?(@dir)
|
11
|
+
Dir.mkdir(@dir)
|
12
|
+
`git clone #{Gitnesse.configuration.repository_url} #{@dir}`
|
13
|
+
Wiki.new(@dir).remove_past_results
|
14
|
+
end
|
15
|
+
|
16
|
+
# Public: Removes ~/.gitnesse after all cukes are run
|
17
|
+
#
|
18
|
+
# Returns nothing
|
19
|
+
def self.teardown
|
20
|
+
Dir.chdir(@dir) do
|
21
|
+
`git push origin master`
|
22
|
+
end
|
23
|
+
|
24
|
+
FileUtils.rm_rf(@dir)
|
25
|
+
FileUtils.rm(File.absolute_path("#{Gitnesse.configuration.target_directory}/support/gitnesse_hooks.rb"))
|
26
|
+
end
|
27
|
+
|
28
|
+
# Public: Adds hooks into Cucumber
|
29
|
+
#
|
30
|
+
# Returns nothing
|
31
|
+
def self.create
|
32
|
+
hook_file = File.join(File.dirname(__FILE__), "support/hook.rb")
|
33
|
+
support_dir = File.absolute_path("#{Gitnesse.configuration.target_directory}/support")
|
34
|
+
target_file = File.join(support_dir, "gitnesse_hooks.rb")
|
35
|
+
|
36
|
+
Dir.mkdir(support_dir) unless File.directory?(support_dir)
|
37
|
+
|
38
|
+
File.write(target_file, File.read(hook_file))
|
39
|
+
end
|
40
|
+
|
41
|
+
# Public: Appends scenario results to relevant page in wiki
|
42
|
+
#
|
43
|
+
# scenario - the scenario results from Cucumber
|
44
|
+
#
|
45
|
+
# Returns nothing
|
46
|
+
def self.append_to_wiki(scenario)
|
47
|
+
Wiki.new(@dir).append_results(scenario)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/gitnesse/railtie.rb
CHANGED
data/lib/gitnesse/tasks.rake
CHANGED
@@ -4,25 +4,31 @@ namespace :gitnesse do
|
|
4
4
|
|
5
5
|
desc "Pull features from remote repository and run cucumber."
|
6
6
|
task :run => :environment do
|
7
|
-
Gitnesse.
|
7
|
+
Gitnesse::Configuration.load_using_search
|
8
8
|
Gitnesse.run
|
9
9
|
end
|
10
10
|
|
11
11
|
desc "Pull features from remote git wiki repository."
|
12
12
|
task :pull => :environment do
|
13
|
-
Gitnesse.
|
13
|
+
Gitnesse::Configuration.load_using_search
|
14
14
|
Gitnesse.pull
|
15
15
|
end
|
16
16
|
|
17
17
|
desc "Push features to remote git wiki repository."
|
18
18
|
task :push => :environment do
|
19
|
-
Gitnesse.
|
19
|
+
Gitnesse::Configuration.load_using_search
|
20
20
|
Gitnesse.push
|
21
21
|
end
|
22
22
|
|
23
|
+
desc "Push features to remote git wiki repository, run cucumber, and push results to wiki"
|
24
|
+
task :push => :environment do
|
25
|
+
Gitnesse::Configuration.load_using_search
|
26
|
+
Gitnesse.push_results
|
27
|
+
end
|
28
|
+
|
23
29
|
desc "Dump the current config info to the console."
|
24
30
|
task :info => :environment do
|
25
|
-
Gitnesse.
|
26
|
-
puts Gitnesse.
|
31
|
+
Gitnesse::Configuration.load_using_search
|
32
|
+
puts Gitnesse.configuration.to_yaml
|
27
33
|
end
|
28
|
-
end
|
34
|
+
end
|
data/lib/gitnesse/version.rb
CHANGED
@@ -0,0 +1,173 @@
|
|
1
|
+
module Gitnesse
|
2
|
+
class Wiki
|
3
|
+
attr_accessor :wiki
|
4
|
+
|
5
|
+
def initialize(dir = Dir.mktmpdir)
|
6
|
+
@wiki = Gollum::Wiki.new(dir)
|
7
|
+
@commit_info = Gitnesse.generate_commit_info
|
8
|
+
end
|
9
|
+
|
10
|
+
# Public: Loads the provided feature files into the wiki
|
11
|
+
#
|
12
|
+
# feature_files - a collection of files to search for features
|
13
|
+
# e.g. Dir.glob("./features/**/*.feature")
|
14
|
+
#
|
15
|
+
def load_feature_files(feature_files)
|
16
|
+
return if feature_files.nil?
|
17
|
+
|
18
|
+
feature_files.each do |feature_file|
|
19
|
+
feature_name = File.basename(feature_file, ".feature")
|
20
|
+
feature_content = File.read(feature_file)
|
21
|
+
wiki_page = @wiki.page(feature_name)
|
22
|
+
wiki_page ||= @wiki.page("#{feature_name}.feature")
|
23
|
+
|
24
|
+
if wiki_page
|
25
|
+
update_wiki_page(wiki_page, feature_name, feature_content)
|
26
|
+
else
|
27
|
+
create_wiki_page(feature_name, feature_content)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Public: Returns the Wiki's pages
|
33
|
+
#
|
34
|
+
# Returns an array of Wiki pages
|
35
|
+
def pages
|
36
|
+
@wiki.pages
|
37
|
+
end
|
38
|
+
|
39
|
+
# Public: Extracts gherkins from wiki page
|
40
|
+
#
|
41
|
+
# page - Wiki page to get features from
|
42
|
+
#
|
43
|
+
# Returns a hash of Cucumber features
|
44
|
+
def self.extract_features(page)
|
45
|
+
data = page.respond_to?(:raw_data) ? page.raw_data : page
|
46
|
+
features = {}
|
47
|
+
|
48
|
+
if match_result = data.match(/\u0060{3}gherkin(.+)\u0060{3}/m)
|
49
|
+
captures = match_result.captures
|
50
|
+
|
51
|
+
# create hash with feature name as key and feature text as value
|
52
|
+
captures.each do |capture|
|
53
|
+
feature_definition_at = capture.index('Feature:')
|
54
|
+
feature_text = capture[feature_definition_at,capture.size-1]
|
55
|
+
feature_lines = feature_text.split("\n")
|
56
|
+
feature_definition = feature_lines.grep(/^Feature:/).first
|
57
|
+
|
58
|
+
if feature_definition
|
59
|
+
feature_name = feature_definition.split(":").last.strip.gsub(" ","-").downcase
|
60
|
+
features[feature_name] = feature_text
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
features
|
66
|
+
end
|
67
|
+
|
68
|
+
# Public: Builds wiki page content
|
69
|
+
#
|
70
|
+
# feature_content - Content to generate the page content from
|
71
|
+
# old_page_content - old page content to replace with new page content
|
72
|
+
#
|
73
|
+
# Returns a string containing the generated page content
|
74
|
+
def build_page_content(feature_content, old_page_content = nil)
|
75
|
+
content = "```gherkin\n#{feature_content}\n```"
|
76
|
+
return content if old_page_content.nil? || old_page_content.empty?
|
77
|
+
|
78
|
+
features = Wiki.extract_features(old_page_content)
|
79
|
+
|
80
|
+
_, old_feature_content = features.shift
|
81
|
+
old_page_content.sub(old_feature_content, feature_content)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Public: Removes past Cucumber results from feature files
|
85
|
+
#
|
86
|
+
# Returns nothing
|
87
|
+
def remove_past_results
|
88
|
+
@commit_info[:message] = Gitnesse.configuration.info
|
89
|
+
features = Dir.glob("#{Gitnesse.configuration.target_directory}/*.feature")
|
90
|
+
|
91
|
+
features.each do |feature|
|
92
|
+
feature_name = File.basename(feature, ".feature")
|
93
|
+
page = @wiki.page(feature_name) || @wiki.page("#{feature_name}.feature")
|
94
|
+
|
95
|
+
if page
|
96
|
+
content = page.raw_data
|
97
|
+
content = strip_results(content)
|
98
|
+
@wiki.update_page(page, page.name, :markdown, content, @commit_info)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Public: Strips old cucumber results
|
104
|
+
#
|
105
|
+
# content - the string to remote old results from
|
106
|
+
#
|
107
|
+
# Returns a string
|
108
|
+
def strip_results(content)
|
109
|
+
if content.match(/\u0060{3}gherkin.*\u0060{3}(.*)/m)[1]
|
110
|
+
[ "FAILED", "PASSED", "PENDING", "UNDEFINED" ].each do |type|
|
111
|
+
content.gsub!(/\n*\`Last result was #{type}: .*\n*/, '')
|
112
|
+
end
|
113
|
+
end
|
114
|
+
content
|
115
|
+
end
|
116
|
+
|
117
|
+
# Public: Appends results of cucumber scenario to wiki
|
118
|
+
#
|
119
|
+
# scenario - Cucumber scenario from After hook
|
120
|
+
#
|
121
|
+
# Returns nothing
|
122
|
+
def append_results(scenario)
|
123
|
+
pages = @wiki.pages
|
124
|
+
filename = File.basename(scenario.feature.file, ".feature")
|
125
|
+
@commit_info[:message] = Gitnesse.configuration.info
|
126
|
+
|
127
|
+
pages.each do |page|
|
128
|
+
if page.name == filename || page.name == "#{filename}.feature"
|
129
|
+
if page.text_data.include? scenario.name
|
130
|
+
content = page.raw_data
|
131
|
+
string = "\n\`Last result was #{scenario.status.to_s.upcase}: #{scenario.name} (#{Time.now.to_s} - #{Gitnesse.configuration.info})\`\n"
|
132
|
+
content.gsub(string, '')
|
133
|
+
content << string
|
134
|
+
@wiki.update_page(page, page.name, :markdown, content, @commit_info)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
private
|
141
|
+
|
142
|
+
# Private: Creates a new wiki page for the provided name and content
|
143
|
+
#
|
144
|
+
# name - the name of the page to create
|
145
|
+
# content - the content the page should have
|
146
|
+
#
|
147
|
+
# Returns the newly created wiki page
|
148
|
+
def create_wiki_page(name, content)
|
149
|
+
new_page_content = build_page_content(content)
|
150
|
+
@wiki.write_page(name, :markdown, new_page_content, @commit_info)
|
151
|
+
puts " # Created Page: #{name}"
|
152
|
+
end
|
153
|
+
|
154
|
+
# Private: Updates a wiki page with the provided name and content
|
155
|
+
#
|
156
|
+
# wiki_page - the page to update
|
157
|
+
# page_name - the name of the page
|
158
|
+
# feature_content - the feature content to compare/update
|
159
|
+
#
|
160
|
+
# Returns the page
|
161
|
+
def update_wiki_page(wiki_page, page_name, feature_content)
|
162
|
+
wiki_page_content = wiki_page.raw_data
|
163
|
+
new_page_content = build_page_content(feature_content, wiki_page_content)
|
164
|
+
|
165
|
+
if new_page_content == wiki_page_content
|
166
|
+
puts " # Page #{page_name} didn't change"
|
167
|
+
else
|
168
|
+
@wiki.update_page(wiki_page, page_name, :markdown, new_page_content, @commit_info)
|
169
|
+
puts " # Updated Page: #{page_name}"
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
@@ -1,6 +1,15 @@
|
|
1
1
|
require_relative '../../test_helper'
|
2
2
|
|
3
|
-
describe Gitnesse do
|
3
|
+
describe Gitnesse::Wiki do
|
4
|
+
let(:dir) { Dir.mktmpdir }
|
5
|
+
let(:wiki) { Gitnesse::Wiki.new(dir) }
|
6
|
+
|
7
|
+
before do
|
8
|
+
Dir.chdir(dir) do
|
9
|
+
`git init`
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
4
13
|
describe ".build_page_content" do
|
5
14
|
let(:wiki_page_content) do
|
6
15
|
<<-EOS
|
@@ -35,7 +44,7 @@ Feature: Addition
|
|
35
44
|
end
|
36
45
|
|
37
46
|
describe "without existing wiki page content" do
|
38
|
-
let(:method) { lambda {
|
47
|
+
let(:method) { lambda { wiki.build_page_content(new_feature_content) } }
|
39
48
|
let(:expected_result) do
|
40
49
|
"```gherkin
|
41
50
|
Feature: Addition
|
@@ -55,7 +64,7 @@ Feature: Addition
|
|
55
64
|
end
|
56
65
|
|
57
66
|
describe "with existing wiki page content" do
|
58
|
-
let(:method) { lambda {
|
67
|
+
let(:method) { lambda { wiki.build_page_content(new_feature_content, wiki_page_content) } }
|
59
68
|
let(:expected_result) do
|
60
69
|
<<-EOS
|
61
70
|
# Addition is Awesome
|