sleeping_king_studios-tasks 0.1.0.rc.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +26 -0
  3. data/DEVELOPMENT.md +50 -0
  4. data/LICENSE +22 -0
  5. data/README.md +405 -0
  6. data/lib/sleeping_king_studios/tasks.rb +27 -0
  7. data/lib/sleeping_king_studios/tasks/apps.rb +49 -0
  8. data/lib/sleeping_king_studios/tasks/apps/app_configuration.rb +68 -0
  9. data/lib/sleeping_king_studios/tasks/apps/applications_task.rb +28 -0
  10. data/lib/sleeping_king_studios/tasks/apps/bundle.rb +8 -0
  11. data/lib/sleeping_king_studios/tasks/apps/bundle/install_runner.rb +21 -0
  12. data/lib/sleeping_king_studios/tasks/apps/bundle/install_task.rb +39 -0
  13. data/lib/sleeping_king_studios/tasks/apps/bundle/update_runner.rb +21 -0
  14. data/lib/sleeping_king_studios/tasks/apps/bundle/update_task.rb +39 -0
  15. data/lib/sleeping_king_studios/tasks/apps/ci.rb +8 -0
  16. data/lib/sleeping_king_studios/tasks/apps/ci/results_reporter.rb +69 -0
  17. data/lib/sleeping_king_studios/tasks/apps/ci/rspec_task.rb +29 -0
  18. data/lib/sleeping_king_studios/tasks/apps/ci/rspec_wrapper.rb +42 -0
  19. data/lib/sleeping_king_studios/tasks/apps/ci/rubocop_task.rb +29 -0
  20. data/lib/sleeping_king_studios/tasks/apps/ci/rubocop_wrapper.rb +29 -0
  21. data/lib/sleeping_king_studios/tasks/apps/ci/simplecov_task.rb +68 -0
  22. data/lib/sleeping_king_studios/tasks/apps/ci/step_wrapper.rb +49 -0
  23. data/lib/sleeping_king_studios/tasks/apps/ci/steps_runner.rb +37 -0
  24. data/lib/sleeping_king_studios/tasks/apps/ci/steps_task.rb +92 -0
  25. data/lib/sleeping_king_studios/tasks/ci.rb +8 -0
  26. data/lib/sleeping_king_studios/tasks/ci/cucumber_parser.rb +118 -0
  27. data/lib/sleeping_king_studios/tasks/ci/cucumber_results.rb +191 -0
  28. data/lib/sleeping_king_studios/tasks/ci/cucumber_runner.rb +53 -0
  29. data/lib/sleeping_king_studios/tasks/ci/cucumber_task.rb +47 -0
  30. data/lib/sleeping_king_studios/tasks/ci/results_helpers.rb +44 -0
  31. data/lib/sleeping_king_studios/tasks/ci/rspec_each_results.rb +118 -0
  32. data/lib/sleeping_king_studios/tasks/ci/rspec_each_task.rb +156 -0
  33. data/lib/sleeping_king_studios/tasks/ci/rspec_results.rb +126 -0
  34. data/lib/sleeping_king_studios/tasks/ci/rspec_runner.rb +62 -0
  35. data/lib/sleeping_king_studios/tasks/ci/rspec_task.rb +71 -0
  36. data/lib/sleeping_king_studios/tasks/ci/rubocop_results.rb +80 -0
  37. data/lib/sleeping_king_studios/tasks/ci/rubocop_runner.rb +46 -0
  38. data/lib/sleeping_king_studios/tasks/ci/rubocop_task.rb +44 -0
  39. data/lib/sleeping_king_studios/tasks/ci/simplecov_results.rb +62 -0
  40. data/lib/sleeping_king_studios/tasks/ci/simplecov_task.rb +25 -0
  41. data/lib/sleeping_king_studios/tasks/ci/steps_runner.rb +69 -0
  42. data/lib/sleeping_king_studios/tasks/ci/steps_task.rb +93 -0
  43. data/lib/sleeping_king_studios/tasks/configuration.rb +114 -0
  44. data/lib/sleeping_king_studios/tasks/file.rb +8 -0
  45. data/lib/sleeping_king_studios/tasks/file/new_task.rb +238 -0
  46. data/lib/sleeping_king_studios/tasks/process_runner.rb +70 -0
  47. data/lib/sleeping_king_studios/tasks/task.rb +95 -0
  48. data/lib/sleeping_king_studios/tasks/task_group.rb +37 -0
  49. data/lib/sleeping_king_studios/tasks/version.rb +58 -0
  50. metadata +271 -0
@@ -0,0 +1,53 @@
1
+ # lib/sleeping_king_studios/tasks/ci/cucumber_runner.rb
2
+
3
+ require 'json'
4
+
5
+ require 'sleeping_king_studios/tasks/ci'
6
+ require 'sleeping_king_studios/tasks/ci/cucumber_parser'
7
+ require 'sleeping_king_studios/tasks/process_runner'
8
+
9
+ module SleepingKingStudios::Tasks::Ci
10
+ # Service object to run Cucumber as an external process with the specified
11
+ # parameters.
12
+ class CucumberRunner < SleepingKingStudios::Tasks::ProcessRunner
13
+ def call env: {}, files: [], options: [], report: true
14
+ report = 'tmp/ci/cucumber.json' if report && !report.is_a?(String)
15
+ command =
16
+ build_command(
17
+ :env => env,
18
+ :files => files,
19
+ :options => options,
20
+ :report => report
21
+ ) # end build_command
22
+
23
+ stream_process(command)
24
+
25
+ report ? load_report(:report => report) : {}
26
+ end # method call
27
+
28
+ private
29
+
30
+ def base_command
31
+ 'bundle exec cucumber'
32
+ end # method base_command
33
+
34
+ def build_options files:, options:, report:, **_kwargs
35
+ options += ['--format=json', "--out=#{report}"] if report
36
+
37
+ super :files => files, :options => options
38
+ end # method build_options
39
+
40
+ def load_report report:
41
+ raw = File.read report
42
+
43
+ return {} if raw.empty?
44
+
45
+ json = JSON.parse raw
46
+ parser = SleepingKingStudios::Tasks::Ci::CucumberParser
47
+
48
+ parser.parse(json)
49
+ rescue
50
+ {}
51
+ end # method load_report
52
+ end # class
53
+ end # module
@@ -0,0 +1,47 @@
1
+ # lib/sleeping_king_studios/tasks/ci/cucumber_task.rb
2
+
3
+ require 'sleeping_king_studios/tasks/ci'
4
+ require 'sleeping_king_studios/tasks/ci/cucumber_results'
5
+ require 'sleeping_king_studios/tasks/ci/cucumber_runner'
6
+
7
+ module SleepingKingStudios::Tasks::Ci
8
+ # Defines a Thor task for running the full RSpec test suite.
9
+ class CucumberTask < SleepingKingStudios::Tasks::Task
10
+ def self.description
11
+ 'Runs the Cucumber feature suite.'
12
+ end # class method description
13
+
14
+ option :quiet,
15
+ :aliases => '-q',
16
+ :type => :boolean,
17
+ :default => false,
18
+ :desc => 'Do not write spec results to STDOUT.'
19
+ option :raw,
20
+ :aliases => '-r',
21
+ :type => :boolean,
22
+ :default => false,
23
+ :desc => 'Return a Hash instead of a results object.'
24
+
25
+ def call *files
26
+ files += default_files unless files.empty?
27
+
28
+ results = cucumber_runner.call(:files => files)
29
+
30
+ raw? ? results : CucumberResults.new(results)
31
+ end # method call
32
+
33
+ private
34
+
35
+ def cucumber_runner
36
+ opts = %w(--color)
37
+ opts << '--format=pretty' unless quiet?
38
+
39
+ CucumberRunner.new(:options => opts)
40
+ end # method cucumber_runner
41
+
42
+ def default_files
43
+ SleepingKingStudios::Tasks.configuration.ci.cucumber.
44
+ fetch('default_files', [])
45
+ end # method default_files
46
+ end # class
47
+ end # module
@@ -0,0 +1,44 @@
1
+ # lib/sleeping_king_studios/tasks/ci/results_helpers.rb
2
+
3
+ require 'sleeping_king_studios/tasks/ci'
4
+
5
+ module SleepingKingStudios::Tasks::Ci
6
+ # Helper methods for reporting CI results.
7
+ module ResultsHelpers
8
+ private
9
+
10
+ # Returns a terminal color corresponding to the state of the results object.
11
+ #
12
+ # @param results [Object] The results object.
13
+ #
14
+ # @return [Symbol] The terminal color.
15
+ def results_color results
16
+ if results.failing?
17
+ :red
18
+ elsif results.respond_to?(:errored?) && results.errored?
19
+ :red
20
+ elsif results.pending? || results.empty?
21
+ :yellow
22
+ else
23
+ :green
24
+ end # if-elsif-else
25
+ end # method set_results_color
26
+
27
+ # Returns a state string for the results object.
28
+ #
29
+ # @param results [Object] The results object.
30
+ #
31
+ # @return [String] The results state.
32
+ def results_state results
33
+ if results.respond_to?(:errored?) && results.errored?
34
+ 'Errored'
35
+ elsif results.failing?
36
+ 'Failing'
37
+ elsif results.pending? || results.empty?
38
+ 'Pending'
39
+ else
40
+ 'Passing'
41
+ end # if-elsif-else
42
+ end # method results_state
43
+ end # module
44
+ end # module
@@ -0,0 +1,118 @@
1
+ # lib/sleeping_king_studios/tasks/ci/rspec_each_results.rb
2
+
3
+ require 'sleeping_king_studios/tasks/ci'
4
+
5
+ module SleepingKingStudios::Tasks::Ci
6
+ # Encapsulates the results of an RSpecEach call.
7
+ class RSpecEachResults
8
+ # @param results [Hash] The raw results of the RSpecEach call.
9
+ def initialize results
10
+ @results = results
11
+ end # constructor
12
+
13
+ # @param other [RSpecEachResults] The other results object to compare.
14
+ #
15
+ # @return [Boolean] True if the results are equal, otherwise false.
16
+ def == other
17
+ if other.is_a?(Hash)
18
+ empty? ? other.empty? : to_h == other
19
+ elsif other.is_a?(RSpecEachResults)
20
+ to_h == other.to_h
21
+ else
22
+ false
23
+ end # if-elsif-else
24
+ end # method ==
25
+
26
+ # @return [Float] The duration value.
27
+ def duration
28
+ @results.fetch('duration', 0.0)
29
+ end # method duration
30
+
31
+ # @return [Boolean] True if there are no files, otherwise false.
32
+ def empty?
33
+ file_count.zero?
34
+ end # method empty?
35
+
36
+ # @return [Boolean] True if there are any errored files, otherwise false.
37
+ def errored?
38
+ !errored_count.zero?
39
+ end # method errored?
40
+
41
+ # @return [Integer] The number of errored files.
42
+ def errored_count
43
+ errored_files.count
44
+ end # method errored_count
45
+
46
+ # @return [Array] The list of errored file names.
47
+ def errored_files
48
+ @results.fetch('errored_files', [])
49
+ end # method errored_files
50
+
51
+ # @return [Boolean] True if there are any failing files, otherwise false.
52
+ def failing?
53
+ !failure_count.zero?
54
+ end # method failing?
55
+
56
+ # @return [Array] The list of failing file names.
57
+ def failing_files
58
+ @results.fetch('failing_files', [])
59
+ end # method failing_files
60
+
61
+ # @return [Integer] The number of failing files.
62
+ def failure_count
63
+ failing_files.count
64
+ end # method failing_files
65
+
66
+ # @return [Integer] The total file count.
67
+ def file_count
68
+ @results.fetch('file_count', 0)
69
+ end # method file_count
70
+
71
+ # @return [Boolean] True if there are any pending files, otherwise false.
72
+ def pending?
73
+ !pending_count.zero?
74
+ end # method pending?
75
+
76
+ # @return [Integer] The number of pending files.
77
+ def pending_count
78
+ pending_files.count
79
+ end # method pending_count
80
+
81
+ # @return [Array] The list of pending file names.
82
+ def pending_files
83
+ @results.fetch('pending_files', [])
84
+ end # method pending_files
85
+
86
+ def pluralize count, singular, plural = nil
87
+ "#{count} #{tools.integer.pluralize count, singular, plural}"
88
+ end # method pluralize
89
+
90
+ # @return [Hash] The hash representation of the results.
91
+ def to_h
92
+ {
93
+ 'failing_files' => failing_files,
94
+ 'pending_files' => pending_files,
95
+ 'errored_files' => errored_files,
96
+ 'file_count' => file_count,
97
+ 'duration' => duration
98
+ } # end hash
99
+ end # method to_h
100
+
101
+ # @return [String] The string representation of the results.
102
+ def to_s
103
+ str = "#{file_count} files"
104
+
105
+ str << ', ' << pluralize(failure_count, 'failure')
106
+
107
+ str << ", #{pending_count} pending" if pending?
108
+
109
+ str << ", #{errored_count} errored" if errored?
110
+
111
+ str << " in #{duration.round(2)} seconds"
112
+ end # method to_s
113
+
114
+ def tools
115
+ SleepingKingStudios::Tools::Toolbelt.instance
116
+ end # method tools
117
+ end # class
118
+ end # module
@@ -0,0 +1,156 @@
1
+ # lib/sleeping_king_studios/tasks/ci/rspec_each_task.rb
2
+
3
+ require 'sleeping_king_studios/tasks/ci'
4
+ require 'sleeping_king_studios/tasks/ci/results_helpers'
5
+ require 'sleeping_king_studios/tasks/ci/rspec_each_results'
6
+ require 'sleeping_king_studios/tasks/ci/rspec_results'
7
+ require 'sleeping_king_studios/tasks/ci/rspec_runner'
8
+
9
+ module SleepingKingStudios::Tasks::Ci
10
+ # rubocop:disable Metrics/ClassLength
11
+
12
+ # Defines a Thor task for running the full RSpec test suite.
13
+ class RSpecEachTask < SleepingKingStudios::Tasks::Task
14
+ include SleepingKingStudios::Tasks::Ci::ResultsHelpers
15
+
16
+ def self.description
17
+ 'Runs each spec file as an individual RSpec process.'
18
+ end # class method description
19
+
20
+ def self.task_name
21
+ 'rspec_each'
22
+ end # class method task_name
23
+
24
+ option :quiet,
25
+ :aliases => '-q',
26
+ :type => :boolean,
27
+ :default => false,
28
+ :desc => 'Do not write spec results to STDOUT.'
29
+ option :raw,
30
+ :aliases => '-r',
31
+ :type => :boolean,
32
+ :default => false,
33
+ :desc => 'Return a Hash instead of a results object.'
34
+
35
+ def call *groups
36
+ mute! if quiet?
37
+
38
+ files = files_list(groups)
39
+
40
+ say "Running #{files.count} spec files..."
41
+ say "\n"
42
+
43
+ results = run_files(files)
44
+
45
+ report_pending results
46
+ report_failing results
47
+ report_errored results
48
+ report_totals results
49
+
50
+ raw? ? results.to_h : results
51
+ end # method call
52
+
53
+ private
54
+
55
+ def aggregate_results file, results, totals
56
+ if results.errored?
57
+ totals['errored_files'] << file
58
+ elsif results.failing?
59
+ totals['failing_files'] << file
60
+ elsif results.pending?
61
+ totals['pending_files'] << file
62
+ end # if-else
63
+
64
+ totals['file_count'] += 1
65
+ end # method aggregate_results
66
+
67
+ def build_totals
68
+ {
69
+ 'pending_files' => [],
70
+ 'failing_files' => [],
71
+ 'errored_files' => [],
72
+ 'file_count' => 0
73
+ } # end results
74
+ end # method build_totals
75
+
76
+ def files_list groups
77
+ groups = %w(spec) if groups.empty?
78
+
79
+ groups.map do |group_or_file|
80
+ if File.extname(group_or_file).empty?
81
+ Dir[File.join group_or_file, pattern]
82
+ else
83
+ [group_or_file]
84
+ end # if-else
85
+ end. # map
86
+ flatten.
87
+ uniq
88
+ end # method files_list
89
+
90
+ def pattern
91
+ '**{,/*/**}/*_spec.rb'
92
+ end # method pattern
93
+
94
+ def report_errored results
95
+ return unless results.errored?
96
+
97
+ say "\nErrored:\n\n"
98
+
99
+ results.errored_files.each { |file| say " #{file}", :red }
100
+ end # report_pending
101
+
102
+ def report_failing results
103
+ return unless results.failing?
104
+
105
+ say "\nFailures:\n\n"
106
+
107
+ results.failing_files.each { |file| say " #{file}", :red }
108
+ end # report_pending
109
+
110
+ def report_pending results
111
+ return unless results.pending?
112
+
113
+ say "\nPending:\n\n"
114
+
115
+ results.pending_files.each { |file| say " #{file}", :yellow }
116
+ end # report_pending
117
+
118
+ def report_totals results
119
+ say "\nFinished in #{results.duration.round(2)} seconds"
120
+
121
+ if results.failing? || results.errored?
122
+ say results.to_s, :red
123
+ elsif results.pending? || results.empty?
124
+ say results.to_s, :yellow
125
+ else
126
+ say results.to_s, :green
127
+ end # if-elsif-else
128
+ end # method report_totals
129
+
130
+ def rspec_runner
131
+ RSpecRunner.new(:env => { :coverage => false })
132
+ end # method rspec_runner
133
+
134
+ def run_file file
135
+ results = rspec_runner.call(:files => [file])
136
+ results = RSpecResults.new(results)
137
+
138
+ say "#{set_color results_state(results), results_color(results)} #{file}"
139
+
140
+ results
141
+ end # method run_file
142
+
143
+ def run_files files
144
+ start = Time.now
145
+ totals = build_totals
146
+
147
+ files.each { |file| aggregate_results(file, run_file(file), totals) }
148
+
149
+ totals['duration'] = Time.now - start
150
+
151
+ RSpecEachResults.new(totals)
152
+ end # method run_files
153
+ end # class
154
+
155
+ # rubocop:enable Metrics/ClassLength
156
+ end # module
@@ -0,0 +1,126 @@
1
+ # lib/sleeping_king_studios/tasks/ci/rspec_results.rb
2
+
3
+ require 'sleeping_king_studios/tasks/ci'
4
+
5
+ module SleepingKingStudios::Tasks::Ci
6
+ # Encapsulates the results of an RSpec call.
7
+ class RSpecResults
8
+ # @param results [Hash] The raw results of the RSpec call.
9
+ def initialize results
10
+ @results = results
11
+ end # constructor
12
+
13
+ # @param other [RSpecResults] The other results object to compare.
14
+ #
15
+ # @return [Boolean] True if the results are equal, otherwise false.
16
+ def == other
17
+ if other.is_a?(Hash)
18
+ empty? ? other.empty? : to_h == other
19
+ elsif other.is_a?(RSpecResults)
20
+ to_h == other.to_h
21
+ else
22
+ false
23
+ end # if-elsif-else
24
+ end # method ==
25
+
26
+ # @return [Float] The duration value.
27
+ def duration
28
+ @results.fetch('duration', 0.0)
29
+ end # method duration
30
+
31
+ # @return [Boolean] True if there are no examples, otherwise false.
32
+ def empty?
33
+ example_count.zero?
34
+ end # method empty?
35
+
36
+ # @return [Boolean] True if there are no results or if errors occurred
37
+ # outside of examples, otherwise false.
38
+ def errored?
39
+ @results.empty? || !error_count.zero?
40
+ end # method errored?
41
+
42
+ # @return [Integer] The number of errors that occurred outside of examples.
43
+ def error_count
44
+ @results.fetch('error_count', 0)
45
+ end # method error_count
46
+
47
+ # @return [Integer] The total number of examples.
48
+ def example_count
49
+ @results.fetch('example_count', 0)
50
+ end # method example_count
51
+
52
+ # @return [Boolean] True if there are any failing examples, otherwise false.
53
+ def failing?
54
+ !failure_count.zero?
55
+ end # method failing?
56
+
57
+ # @return [Integer] The number of failing examples.
58
+ def failure_count
59
+ @results.fetch('failure_count', 0)
60
+ end # method failure_count
61
+
62
+ # Adds the given result values and returns a new results object with the
63
+ # sums.
64
+ #
65
+ # @param other [RSpecResults] The results to add.
66
+ #
67
+ # @return [RSpecResults] The total results.
68
+ def merge other
69
+ self.class.new(
70
+ 'duration' => duration + other.duration,
71
+ 'example_count' => example_count + other.example_count,
72
+ 'failure_count' => failure_count + other.failure_count,
73
+ 'pending_count' => pending_count + other.pending_count
74
+ ) # end new
75
+ end # method merge
76
+
77
+ # @return [Boolean] True if there are any pending examples, otherwise false.
78
+ def pending?
79
+ !pending_count.zero?
80
+ end # method pending?
81
+
82
+ # @return [Intger] The number of pending examples.
83
+ def pending_count
84
+ @results.fetch('pending_count', 0)
85
+ end # method pending_count
86
+
87
+ def pluralize count, singular, plural = nil
88
+ "#{count} #{tools.integer.pluralize count, singular, plural}"
89
+ end # method pluralize
90
+
91
+ # @return [Hash] The hash representation of the results.
92
+ def to_h
93
+ {
94
+ 'duration' => duration,
95
+ 'example_count' => example_count,
96
+ 'failure_count' => failure_count,
97
+ 'pending_count' => pending_count,
98
+ 'error_count' => error_count
99
+ } # end hash
100
+ end # method to_h
101
+
102
+ # rubocop:disable Metrics/AbcSize
103
+
104
+ # @return [String] The string representation of the results.
105
+ def to_s
106
+ str = pluralize(example_count, 'example')
107
+
108
+ str << ', ' << pluralize(failure_count, 'failure')
109
+
110
+ str << ', ' << pending_count.to_s << ' pending' if pending?
111
+
112
+ if error_count.zero?
113
+ str << " in #{duration.round(2)} seconds"
114
+ else
115
+ str << ', ' << pluralize(error_count, 'error') <<
116
+ ' occurred outside of examples'
117
+ end # if-else
118
+ end # method to_s
119
+
120
+ # rubocop:enable Metrics/AbcSize
121
+
122
+ def tools
123
+ SleepingKingStudios::Tools::Toolbelt.instance
124
+ end # method tools
125
+ end # class
126
+ end # module