guard-cucumber 1.4.1 → 1.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +3 -3
- data/lib/guard/cucumber.rb +61 -44
- data/lib/guard/cucumber.rb.orig +143 -0
- data/lib/guard/cucumber/focuser.rb +14 -13
- data/lib/guard/cucumber/focuser.rb.orig +81 -0
- data/lib/guard/cucumber/inspector.rb +19 -9
- data/lib/guard/cucumber/inspector.rb.orig +77 -0
- data/lib/guard/cucumber/notification_formatter.rb +30 -26
- data/lib/guard/cucumber/notification_formatter.rb.orig +124 -0
- data/lib/guard/cucumber/runner.rb +50 -23
- data/lib/guard/cucumber/runner.rb.orig +86 -0
- data/lib/guard/cucumber/templates/Guardfile +6 -3
- data/lib/guard/cucumber/templates/Guardfile.orig +5 -0
- data/lib/guard/cucumber/version.rb +1 -1
- data/lib/guard/cucumber/version.rb.orig +6 -0
- metadata +18 -12
- data/lib/guard/cucumber/version.rbc +0 -203
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 446cce06cfc0d77430a6b6c7e3ce31b76325ca71
|
4
|
+
data.tar.gz: 9544582765bbb7025dfadb2a88bd3b8114e6ed45
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6ab8153c6cdcd1090baca18e1d1ef3a35ee609b6459fcd7c0ada3b6828d0a44963b5af0de79268641b29e11901ea3cb3f68a2130325d6bdbe13f8123e36f3025
|
7
|
+
data.tar.gz: e7cb7a1c69c3b507eb65f068ee642a778cd6ba3c1d92c1c0f7944e0f3974c3334126ede5c758c2182d61822d1d237fbba9c66d9f37e28c0c361ab7620b1978e4
|
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Guard::Cucumber allows you to automatically run Cucumber features when files are modified.
|
4
4
|
|
5
|
-
Tested on MRI Ruby 1.
|
5
|
+
Tested on MRI Ruby 1.9.3, 2.0.0, 2.1.0 and the latest versions of JRuby.
|
6
6
|
|
7
7
|
If you have any questions please join us on our [Google group](http://groups.google.com/group/guard-dev) or on `#guard` (irc.freenode.net).
|
8
8
|
|
@@ -131,7 +131,7 @@ Since guard-cucumber version 0.3.2, the default `:cli` options are:
|
|
131
131
|
:cli => '--no-profile --color --format progress --strict'
|
132
132
|
```
|
133
133
|
|
134
|
-
This default configuration has been chosen to avoid strange behavior when mixing configurations
|
134
|
+
This default configuration has been chosen to avoid strange behavior when mixing configurations from
|
135
135
|
the cucumber.yml default profile with the guard-cucumber `:cli` option.
|
136
136
|
|
137
137
|
You can safely remove `config/cucumber.yml`, since all configuration is done in the `Guardfile`.
|
@@ -226,7 +226,7 @@ For questions please join us in our [Google group](http://groups.google.com/grou
|
|
226
226
|
|
227
227
|
## Author
|
228
228
|
|
229
|
-
Developed by Michael Kessler, sponsored by [
|
229
|
+
Developed by Michael Kessler, sponsored by [FlinkFinger](http://www.flinkfinger.com).
|
230
230
|
|
231
231
|
If you like Guard::Cucumber, you can watch the repository at [GitHub](https://github.com/netzpirat/guard-cucumber)
|
232
232
|
and follow [@netzpirat](https://twitter.com/#!/netzpirat) on Twitter for project updates.
|
data/lib/guard/cucumber.rb
CHANGED
@@ -1,18 +1,16 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
1
|
+
require "guard"
|
2
|
+
require "guard/plugin"
|
3
|
+
require "cucumber"
|
4
|
+
require "guard/cucumber/version"
|
5
5
|
|
6
6
|
module Guard
|
7
|
-
|
8
7
|
# The Cucumber guard that gets notifications about the following
|
9
8
|
# Guard events: `start`, `stop`, `reload`, `run_all` and `run_on_change`.
|
10
9
|
#
|
11
|
-
class Cucumber <
|
12
|
-
|
13
|
-
autoload :
|
14
|
-
autoload :
|
15
|
-
autoload :Focuser, 'guard/cucumber/focuser'
|
10
|
+
class Cucumber < Plugin
|
11
|
+
autoload :Runner, "guard/cucumber/runner"
|
12
|
+
autoload :Inspector, "guard/cucumber/inspector"
|
13
|
+
autoload :Focuser, "guard/cucumber/focuser"
|
16
14
|
|
17
15
|
attr_accessor :last_failed, :failed_path
|
18
16
|
|
@@ -21,25 +19,31 @@ module Guard
|
|
21
19
|
# @param [Array<Guard::Watcher>] watchers the watchers in the Guard block
|
22
20
|
# @param [Hash] options the options for the Guard
|
23
21
|
# @option options [String] :cli any arbitrary Cucumber CLI arguments
|
24
|
-
# @option options [Array<String>] :feature_sets a list of non-standard
|
22
|
+
# @option options [Array<String>] :feature_sets a list of non-standard
|
23
|
+
# feature directory/ies
|
25
24
|
# @option options [Boolean] :bundler use bundler or not
|
26
|
-
# @option options [Array<String>] :rvm a list of rvm version to use for the
|
25
|
+
# @option options [Array<String>] :rvm a list of rvm version to use for the
|
26
|
+
# test
|
27
27
|
# @option options [Boolean] :notification show notifications
|
28
|
-
# @option options [Boolean] :all_after_pass run all features after changed
|
28
|
+
# @option options [Boolean] :all_after_pass run all features after changed
|
29
|
+
# features pass
|
29
30
|
# @option options [Boolean] :all_on_start run all the features at startup
|
30
|
-
# @option options [Boolean] :keep_failed Keep failed features until they
|
31
|
-
#
|
32
|
-
# @option options [Boolean] :
|
31
|
+
# @option options [Boolean] :keep_failed Keep failed features until they
|
32
|
+
# pass
|
33
|
+
# @option options [Boolean] :run_all run override any option when running
|
34
|
+
# all specs
|
35
|
+
# @option options [Boolean] :change_format use a different cucumber format
|
36
|
+
# when running individual features
|
33
37
|
#
|
34
|
-
def initialize(
|
35
|
-
super
|
38
|
+
def initialize(options = {})
|
39
|
+
super(options)
|
36
40
|
|
37
41
|
@options = {
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
42
|
+
all_after_pass: true,
|
43
|
+
all_on_start: true,
|
44
|
+
keep_failed: true,
|
45
|
+
cli: "--no-profile --color --format progress --strict",
|
46
|
+
feature_sets: ["features"]
|
43
47
|
}.update(options)
|
44
48
|
|
45
49
|
@last_failed = false
|
@@ -59,7 +63,9 @@ module Guard
|
|
59
63
|
# @raise [:task_has_failed] when stop has failed
|
60
64
|
#
|
61
65
|
def run_all
|
62
|
-
|
66
|
+
opts = options.merge(options[:run_all] || {})
|
67
|
+
opts.merge!(message: "Running all features")
|
68
|
+
passed = Runner.run(options[:feature_sets], opts)
|
63
69
|
|
64
70
|
if passed
|
65
71
|
@failed_paths = []
|
@@ -87,23 +93,17 @@ module Guard
|
|
87
93
|
#
|
88
94
|
def run_on_modifications(paths)
|
89
95
|
paths += @failed_paths if @options[:keep_failed]
|
90
|
-
paths
|
91
|
-
options = @options[:change_format] ? change_format(@options[:change_format]) : @options
|
92
|
-
passed = Runner.run(paths, paths.include?('features') ? options.merge({ :message => 'Running all features' }) : options)
|
96
|
+
paths = Inspector.clean(paths, options[:feature_sets])
|
93
97
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
# run all the specs if the changed specs failed, like autotest
|
98
|
-
run_all if @last_failed && @options[:all_after_pass]
|
99
|
-
else
|
100
|
-
# remember failed paths for the next change
|
101
|
-
@failed_paths += read_failed_features if @options[:keep_failed]
|
102
|
-
# track whether the changed feature failed for the next change
|
103
|
-
@last_failed = true
|
98
|
+
options = @options
|
99
|
+
if @options[:change_format]
|
100
|
+
options = change_format(@options[:change_format])
|
104
101
|
end
|
105
102
|
|
106
|
-
|
103
|
+
msg = "Running all features"
|
104
|
+
options.merge!(message: msg) if paths.include?("features")
|
105
|
+
|
106
|
+
_run(paths, options)
|
107
107
|
end
|
108
108
|
|
109
109
|
private
|
@@ -116,9 +116,9 @@ module Guard
|
|
116
116
|
def read_failed_features
|
117
117
|
failed = []
|
118
118
|
|
119
|
-
if File.exist?(
|
120
|
-
failed = File.open(
|
121
|
-
File.delete(
|
119
|
+
if File.exist?("rerun.txt")
|
120
|
+
failed = File.open("rerun.txt") { |file| file.read.split(" ") }
|
121
|
+
File.delete("rerun.txt")
|
122
122
|
end
|
123
123
|
|
124
124
|
failed
|
@@ -130,14 +130,31 @@ module Guard
|
|
130
130
|
# @return [Hash] the new options
|
131
131
|
#
|
132
132
|
def change_format(format)
|
133
|
-
cli_parts = @options[:cli].split(
|
133
|
+
cli_parts = @options[:cli].split(" ")
|
134
134
|
cli_parts.each_with_index do |part, index|
|
135
|
-
if part ==
|
135
|
+
if part == "--format" && cli_parts[index + 2] != "--out"
|
136
136
|
cli_parts[index + 1] = format
|
137
137
|
end
|
138
138
|
end
|
139
|
-
@options.merge(:
|
139
|
+
@options.merge(cli: cli_parts.join(" "))
|
140
140
|
end
|
141
141
|
|
142
|
+
private
|
143
|
+
|
144
|
+
def _run(paths, options)
|
145
|
+
if Runner.run(paths, options)
|
146
|
+
# clean failed paths memory
|
147
|
+
@failed_paths -= paths if @options[:keep_failed]
|
148
|
+
# run all the specs if the changed specs failed, like autotest
|
149
|
+
run_all if @last_failed && @options[:all_after_pass]
|
150
|
+
return
|
151
|
+
end
|
152
|
+
|
153
|
+
# remember failed paths for the next change
|
154
|
+
@failed_paths += read_failed_features if @options[:keep_failed]
|
155
|
+
# track whether the changed feature failed for the next change
|
156
|
+
@last_failed = true
|
157
|
+
throw :task_has_failed
|
158
|
+
end
|
142
159
|
end
|
143
160
|
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
require 'guard'
|
2
|
+
require 'guard/guard'
|
3
|
+
require 'cucumber'
|
4
|
+
require 'guard/cucumber/version'
|
5
|
+
|
6
|
+
module Guard
|
7
|
+
|
8
|
+
# The Cucumber guard that gets notifications about the following
|
9
|
+
# Guard events: `start`, `stop`, `reload`, `run_all` and `run_on_change`.
|
10
|
+
#
|
11
|
+
class Cucumber < Guard
|
12
|
+
|
13
|
+
autoload :Runner, 'guard/cucumber/runner'
|
14
|
+
autoload :Inspector, 'guard/cucumber/inspector'
|
15
|
+
autoload :Focuser, 'guard/cucumber/focuser'
|
16
|
+
|
17
|
+
attr_accessor :last_failed, :failed_path
|
18
|
+
|
19
|
+
# Initialize Guard::Cucumber.
|
20
|
+
#
|
21
|
+
# @param [Array<Guard::Watcher>] watchers the watchers in the Guard block
|
22
|
+
# @param [Hash] options the options for the Guard
|
23
|
+
# @option options [String] :cli any arbitrary Cucumber CLI arguments
|
24
|
+
# @option options [Array<String>] :feature_sets a list of non-standard feature directory/ies
|
25
|
+
# @option options [Boolean] :bundler use bundler or not
|
26
|
+
# @option options [Array<String>] :rvm a list of rvm version to use for the test
|
27
|
+
# @option options [Boolean] :notification show notifications
|
28
|
+
# @option options [Boolean] :all_after_pass run all features after changed features pass
|
29
|
+
# @option options [Boolean] :all_on_start run all the features at startup
|
30
|
+
# @option options [Boolean] :keep_failed Keep failed features until they pass
|
31
|
+
# @option options [Boolean] :run_all run override any option when running all specs
|
32
|
+
# @option options [Boolean] :change_format use a different cucumber format when running individual features
|
33
|
+
#
|
34
|
+
def initialize(watchers = [], options = { })
|
35
|
+
super
|
36
|
+
|
37
|
+
@options = {
|
38
|
+
:all_after_pass => true,
|
39
|
+
:all_on_start => true,
|
40
|
+
:keep_failed => true,
|
41
|
+
:cli => '--no-profile --color --format progress --strict',
|
42
|
+
:feature_sets => ['features']
|
43
|
+
}.update(options)
|
44
|
+
|
45
|
+
@last_failed = false
|
46
|
+
@failed_paths = []
|
47
|
+
end
|
48
|
+
|
49
|
+
# Gets called once when Guard starts.
|
50
|
+
#
|
51
|
+
# @raise [:task_has_failed] when stop has failed
|
52
|
+
#
|
53
|
+
def start
|
54
|
+
run_all if @options[:all_on_start]
|
55
|
+
end
|
56
|
+
|
57
|
+
# Gets called when all specs should be run.
|
58
|
+
#
|
59
|
+
# @raise [:task_has_failed] when stop has failed
|
60
|
+
#
|
61
|
+
def run_all
|
62
|
+
passed = Runner.run(options[:feature_sets], options.merge(options[:run_all] || { }).merge(:message => 'Running all features'))
|
63
|
+
|
64
|
+
if passed
|
65
|
+
@failed_paths = []
|
66
|
+
else
|
67
|
+
@failed_paths = read_failed_features if @options[:keep_failed]
|
68
|
+
end
|
69
|
+
|
70
|
+
@last_failed = !passed
|
71
|
+
|
72
|
+
throw :task_has_failed unless passed
|
73
|
+
end
|
74
|
+
|
75
|
+
# Gets called when the Guard should reload itself.
|
76
|
+
#
|
77
|
+
# @raise [:task_has_failed] when stop has failed
|
78
|
+
#
|
79
|
+
def reload
|
80
|
+
@failed_paths = []
|
81
|
+
end
|
82
|
+
|
83
|
+
# Gets called when watched paths and files have changes.
|
84
|
+
#
|
85
|
+
# @param [Array<String>] paths the changed paths and files
|
86
|
+
# @raise [:task_has_failed] when stop has failed
|
87
|
+
#
|
88
|
+
def run_on_modifications(paths)
|
89
|
+
paths += @failed_paths if @options[:keep_failed]
|
90
|
+
paths = Inspector.clean(paths, options[:feature_sets])
|
91
|
+
options = @options[:change_format] ? change_format(@options[:change_format]) : @options
|
92
|
+
passed = Runner.run(paths, paths.include?('features') ? options.merge({ :message => 'Running all features' }) : options)
|
93
|
+
|
94
|
+
if passed
|
95
|
+
# clean failed paths memory
|
96
|
+
@failed_paths -= paths if @options[:keep_failed]
|
97
|
+
# run all the specs if the changed specs failed, like autotest
|
98
|
+
run_all if @last_failed && @options[:all_after_pass]
|
99
|
+
else
|
100
|
+
# remember failed paths for the next change
|
101
|
+
@failed_paths += read_failed_features if @options[:keep_failed]
|
102
|
+
# track whether the changed feature failed for the next change
|
103
|
+
@last_failed = true
|
104
|
+
end
|
105
|
+
|
106
|
+
throw :task_has_failed unless passed
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
# Read the failed features that from `rerun.txt`
|
112
|
+
#
|
113
|
+
# @see Guard::Cucumber::NotificationFormatter#write_rerun_features
|
114
|
+
# @return [Array<String>] the list of features
|
115
|
+
#
|
116
|
+
def read_failed_features
|
117
|
+
failed = []
|
118
|
+
|
119
|
+
if File.exist?('rerun.txt')
|
120
|
+
failed = File.open('rerun.txt') { |file| file.read.split(' ') }
|
121
|
+
File.delete('rerun.txt')
|
122
|
+
end
|
123
|
+
|
124
|
+
failed
|
125
|
+
end
|
126
|
+
|
127
|
+
# Change the `--format` cli option.
|
128
|
+
#
|
129
|
+
# @param [String] format the new format
|
130
|
+
# @return [Hash] the new options
|
131
|
+
#
|
132
|
+
def change_format(format)
|
133
|
+
cli_parts = @options[:cli].split(' ')
|
134
|
+
cli_parts.each_with_index do |part, index|
|
135
|
+
if part == '--format' && cli_parts[index + 2] != '--out'
|
136
|
+
cli_parts[index + 1] = format
|
137
|
+
end
|
138
|
+
end
|
139
|
+
@options.merge(:cli => cli_parts.join(' '))
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
module Guard
|
2
2
|
class Cucumber
|
3
|
-
|
4
3
|
# The Cucumber focuser updates cucumber feature paths to
|
5
4
|
# focus on sections tagged with a provided focus_tag.
|
6
5
|
#
|
@@ -18,7 +17,6 @@ module Guard
|
|
18
17
|
#
|
19
18
|
module Focuser
|
20
19
|
class << self
|
21
|
-
|
22
20
|
# Focus the supplied paths using the provided focus tag.
|
23
21
|
#
|
24
22
|
# @param [Array<String>] paths the locations of the feature files
|
@@ -31,12 +29,12 @@ module Guard
|
|
31
29
|
paths.inject([]) do |updated_paths, path|
|
32
30
|
focused_line_numbers = scan_path_for_focus_tag(path, focus_tag)
|
33
31
|
|
34
|
-
|
32
|
+
if focused_line_numbers.empty?
|
33
|
+
updated_paths << path
|
34
|
+
else
|
35
35
|
updated_paths << append_line_numbers_to_path(
|
36
36
|
focused_line_numbers, path
|
37
37
|
)
|
38
|
-
else
|
39
|
-
updated_paths << path
|
40
38
|
end
|
41
39
|
|
42
40
|
updated_paths
|
@@ -48,14 +46,15 @@ module Guard
|
|
48
46
|
#
|
49
47
|
# @param [String] path the file path to search
|
50
48
|
# @param [String] focus_tag the focus tag to look for in each path
|
51
|
-
# @return [Array<Integer>] the line numbers that include the focus tag
|
49
|
+
# @return [Array<Integer>] the line numbers that include the focus tag
|
50
|
+
# in path
|
52
51
|
#
|
53
52
|
def scan_path_for_focus_tag(path, focus_tag)
|
54
|
-
return [] if File.directory?(path) || path.include?(
|
53
|
+
return [] if File.directory?(path) || path.include?(":")
|
55
54
|
|
56
55
|
line_numbers = []
|
57
56
|
|
58
|
-
File.open(path,
|
57
|
+
File.open(path, "r") do |file|
|
59
58
|
while (line = file.gets)
|
60
59
|
if line.include?(focus_tag)
|
61
60
|
line_numbers << file.lineno
|
@@ -68,16 +67,18 @@ module Guard
|
|
68
67
|
|
69
68
|
# Appends the line numbers to the path
|
70
69
|
#
|
71
|
-
# @param [Array<Integer>] line_numbers the line numbers to append to
|
72
|
-
#
|
73
|
-
# @
|
70
|
+
# @param [Array<Integer>] line_numbers the line numbers to append to
|
71
|
+
# the path
|
72
|
+
# @param [String] path the path that will receive the appended line
|
73
|
+
# numbers
|
74
|
+
# @return [String] the string containing the path appended with the
|
75
|
+
# line number
|
74
76
|
#
|
75
77
|
def append_line_numbers_to_path(line_numbers, path)
|
76
|
-
line_numbers.each { |num| path +=
|
78
|
+
line_numbers.each { |num| path += ":" + num.to_s }
|
77
79
|
|
78
80
|
path
|
79
81
|
end
|
80
|
-
|
81
82
|
end
|
82
83
|
end
|
83
84
|
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Guard
|
2
|
+
class Cucumber
|
3
|
+
# The Cucumber focuser updates cucumber feature paths to
|
4
|
+
# focus on sections tagged with a provided focus_tag.
|
5
|
+
#
|
6
|
+
# For example, if the `foo.feature` file has the provided focus tag
|
7
|
+
# `@bar` on line 8, then the path will be updated using the cucumber
|
8
|
+
# syntax for focusing on a section:
|
9
|
+
#
|
10
|
+
# foo.feature:8
|
11
|
+
#
|
12
|
+
# If '@bar' is found on lines 8 and 16, the path is updated as follows:
|
13
|
+
#
|
14
|
+
# foo.feature:8:16
|
15
|
+
#
|
16
|
+
# The path is not updated if it does not contain the focus tag.
|
17
|
+
#
|
18
|
+
module Focuser
|
19
|
+
class << self
|
20
|
+
# Focus the supplied paths using the provided focus tag.
|
21
|
+
#
|
22
|
+
# @param [Array<String>] paths the locations of the feature files
|
23
|
+
# @param [String] focus_tag the focus tag to look for in each path
|
24
|
+
# @return [Array<String>] the updated paths
|
25
|
+
#
|
26
|
+
def focus(paths, focus_tag)
|
27
|
+
return false if paths.empty?
|
28
|
+
|
29
|
+
paths.inject([]) do |updated_paths, path|
|
30
|
+
focused_line_numbers = scan_path_for_focus_tag(path, focus_tag)
|
31
|
+
|
32
|
+
unless focused_line_numbers.empty?
|
33
|
+
updated_paths << append_line_numbers_to_path(
|
34
|
+
focused_line_numbers, path
|
35
|
+
)
|
36
|
+
else
|
37
|
+
updated_paths << path
|
38
|
+
end
|
39
|
+
|
40
|
+
updated_paths
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Checks to see if the file at path contains the focus tag
|
45
|
+
# It will return an empty array if the path is a directory.
|
46
|
+
#
|
47
|
+
# @param [String] path the file path to search
|
48
|
+
# @param [String] focus_tag the focus tag to look for in each path
|
49
|
+
# @return [Array<Integer>] the line numbers that include the focus tag in path
|
50
|
+
#
|
51
|
+
def scan_path_for_focus_tag(path, focus_tag)
|
52
|
+
return [] if File.directory?(path) || path.include?(":")
|
53
|
+
|
54
|
+
line_numbers = []
|
55
|
+
|
56
|
+
File.open(path, "r") do |file|
|
57
|
+
while (line = file.gets)
|
58
|
+
if line.include?(focus_tag)
|
59
|
+
line_numbers << file.lineno
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
line_numbers
|
65
|
+
end
|
66
|
+
|
67
|
+
# Appends the line numbers to the path
|
68
|
+
#
|
69
|
+
# @param [Array<Integer>] line_numbers the line numbers to append to the path
|
70
|
+
# @param [String] path the path that will receive the appended line numbers
|
71
|
+
# @return [String] the string containing the path appended with the line number
|
72
|
+
#
|
73
|
+
def append_line_numbers_to_path(line_numbers, path)
|
74
|
+
line_numbers.each { |num| path += ":" + num.to_s }
|
75
|
+
|
76
|
+
path
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|