sleeping_king_studios-tasks 0.1.0.rc.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +12 -0
  3. data/DEVELOPMENT.md +9 -4
  4. data/README.md +4 -2
  5. data/lib/sleeping_king_studios/tasks/apps/bundle/tasks.thor +15 -0
  6. data/lib/sleeping_king_studios/tasks/apps/ci/rspec_task.rb +1 -1
  7. data/lib/sleeping_king_studios/tasks/apps/ci/rubocop_task.rb +1 -1
  8. data/lib/sleeping_king_studios/tasks/apps/ci/tasks.thor +20 -0
  9. data/lib/sleeping_king_studios/tasks/ci/cucumber_parser.rb +4 -3
  10. data/lib/sleeping_king_studios/tasks/ci/cucumber_results.rb +2 -2
  11. data/lib/sleeping_king_studios/tasks/ci/cucumber_task.rb +1 -1
  12. data/lib/sleeping_king_studios/tasks/ci/eslint_results.rb +112 -0
  13. data/lib/sleeping_king_studios/tasks/ci/eslint_runner.rb +51 -0
  14. data/lib/sleeping_king_studios/tasks/ci/eslint_task.rb +32 -0
  15. data/lib/sleeping_king_studios/tasks/ci/jest_results.rb +106 -0
  16. data/lib/sleeping_king_studios/tasks/ci/jest_runner.rb +51 -0
  17. data/lib/sleeping_king_studios/tasks/ci/jest_task.rb +43 -0
  18. data/lib/sleeping_king_studios/tasks/ci/rspec_each_task.rb +18 -2
  19. data/lib/sleeping_king_studios/tasks/ci/rspec_task.rb +12 -2
  20. data/lib/sleeping_king_studios/tasks/ci/rubocop_task.rb +1 -1
  21. data/lib/sleeping_king_studios/tasks/ci/tasks.thor +24 -0
  22. data/lib/sleeping_king_studios/tasks/configuration.rb +25 -4
  23. data/lib/sleeping_king_studios/tasks/file/new_task.rb +14 -12
  24. data/lib/sleeping_king_studios/tasks/file/tasks.thor +13 -0
  25. data/lib/sleeping_king_studios/tasks/file/templates/rspec.erb +13 -0
  26. data/lib/sleeping_king_studios/tasks/file/templates/ruby.erb +28 -0
  27. data/lib/sleeping_king_studios/tasks/process_runner.rb +14 -4
  28. data/lib/sleeping_king_studios/tasks/version.rb +3 -3
  29. data/lib/sleeping_king_studios/tools/toolbox/configuration.rb +280 -0
  30. metadata +32 -28
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ require 'sleeping_king_studios/tasks/ci'
6
+ require 'sleeping_king_studios/tasks/process_runner'
7
+
8
+ module SleepingKingStudios::Tasks::Ci
9
+ # Service object to run Jest as an external process with the specified
10
+ # parameters.
11
+ class JestRunner < SleepingKingStudios::Tasks::ProcessRunner
12
+ def call env: {}, files: [], options: [], report: true
13
+ report = 'tmp/ci/jest.json' if report && !report.is_a?(String)
14
+ command =
15
+ build_command(
16
+ :env => env,
17
+ :files => files,
18
+ :options => options,
19
+ :report => report
20
+ )
21
+
22
+ stream_process(command)
23
+
24
+ report ? load_report(:report => report) : {}
25
+ end
26
+
27
+ private
28
+
29
+ def base_command
30
+ 'yarn jest'
31
+ end
32
+
33
+ def build_options files:, options:, report:, **_kwargs
34
+ options += ['--json', "--outputFile=#{report}"] if report
35
+
36
+ super :files => files, :options => options
37
+ end
38
+
39
+ def load_report report:
40
+ raw = File.read report
41
+
42
+ return {} if raw.empty?
43
+
44
+ JSON.parse raw
45
+ rescue
46
+ # :nocov:
47
+ {}
48
+ # :nocov:
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'sleeping_king_studios/tasks/ci'
4
+ require 'sleeping_king_studios/tasks/ci/jest_results'
5
+ require 'sleeping_king_studios/tasks/ci/jest_runner'
6
+
7
+ module SleepingKingStudios::Tasks::Ci
8
+ # Defines a Thor task for running the full Jest (JavaScript) test suite.
9
+ class JestTask < SleepingKingStudios::Tasks::Task
10
+ def self.description
11
+ 'Runs the Jest test suite.'
12
+ end
13
+
14
+ def self.task_name
15
+ 'jest'
16
+ end
17
+
18
+ option :verbose,
19
+ :type => :boolean,
20
+ :desc => 'Output individual test results.'
21
+
22
+ def call *files
23
+ results = jest_runner.call(:files => files)
24
+
25
+ JestResults.new(results)
26
+ end
27
+
28
+ private
29
+
30
+ def default_verbose
31
+ SleepingKingStudios::Tasks.configuration.ci.jest.
32
+ fetch(:verbose, false)
33
+ end
34
+
35
+ def jest_runner
36
+ env = options.fetch('__env__', {})
37
+ opts = %w[--color]
38
+ opts << "--verbose=#{options.fetch('verbose', default_verbose)}"
39
+
40
+ JestRunner.new(:env => env, :options => opts)
41
+ end
42
+ end
43
+ end
@@ -21,6 +21,9 @@ module SleepingKingStudios::Tasks::Ci
21
21
  'rspec_each'
22
22
  end # class method task_name
23
23
 
24
+ option :format,
25
+ :type => :string,
26
+ :desc => 'The RSpec formatter to use. Defaults to the configuration.'
24
27
  option :quiet,
25
28
  :aliases => '-q',
26
29
  :type => :boolean,
@@ -73,8 +76,13 @@ module SleepingKingStudios::Tasks::Ci
73
76
  } # end results
74
77
  end # method build_totals
75
78
 
79
+ def default_format
80
+ SleepingKingStudios::Tasks.configuration.ci.rspec_each.
81
+ fetch(:format, :documentation)
82
+ end # method default_format
83
+
76
84
  def files_list groups
77
- groups = %w(spec) if groups.empty?
85
+ groups = %w[spec] if groups.empty?
78
86
 
79
87
  groups.map do |group_or_file|
80
88
  if File.extname(group_or_file).empty?
@@ -132,7 +140,15 @@ module SleepingKingStudios::Tasks::Ci
132
140
  end # method rspec_runner
133
141
 
134
142
  def run_file file
135
- results = rspec_runner.call(:files => [file])
143
+ opts = []
144
+ format = options.fetch('format', default_format)
145
+
146
+ if format && !quiet?
147
+ opts = %w[--color --tty]
148
+ opts << "--format=#{format}"
149
+ end # if
150
+
151
+ results = rspec_runner.call(:files => [file], :options => opts)
136
152
  results = RSpecResults.new(results)
137
153
 
138
154
  say "#{set_color results_state(results), results_color(results)} #{file}"
@@ -18,6 +18,9 @@ module SleepingKingStudios::Tasks::Ci
18
18
  option :coverage,
19
19
  :type => :boolean,
20
20
  :desc => 'Enable or disable coverage with SimpleCov, if available.'
21
+ option :format,
22
+ :type => :string,
23
+ :desc => 'The RSpec formatter to use. Defaults to the configuration.'
21
24
  option :gemfile,
22
25
  :type => :string,
23
26
  :desc => 'The Gemfile used to run the specs.',
@@ -41,6 +44,11 @@ module SleepingKingStudios::Tasks::Ci
41
44
 
42
45
  private
43
46
 
47
+ def default_format
48
+ SleepingKingStudios::Tasks.configuration.ci.rspec.
49
+ fetch(:format, :documentation)
50
+ end # method default_format
51
+
44
52
  def default_gemfile
45
53
  File.join(Dir.pwd, 'Gemfile')
46
54
  end # method default_gemfile
@@ -62,8 +70,10 @@ module SleepingKingStudios::Tasks::Ci
62
70
  env[:bundle_gemfile] = gemfile if gemfile
63
71
  env[:coverage] = false unless coverage
64
72
 
65
- opts = %w(--color --tty)
66
- opts << '--format=documentation' unless quiet?
73
+ format = options.fetch('format', default_format)
74
+
75
+ opts = %w[--color --tty]
76
+ opts << "--format=#{format}" unless quiet?
67
77
 
68
78
  RSpecRunner.new(:env => env, :options => opts)
69
79
  end # method rspec_runner
@@ -35,7 +35,7 @@ module SleepingKingStudios::Tasks::Ci
35
35
  private
36
36
 
37
37
  def rubocop_runner
38
- opts = %w(--color)
38
+ opts = %w[--color]
39
39
  opts << '--format=progress' unless quiet?
40
40
 
41
41
  RuboCopRunner.new(:options => opts)
@@ -0,0 +1,24 @@
1
+ # lib/sleeping_king_studios/tasks/ci/tasks.thor
2
+
3
+ require 'sleeping_king_studios/tasks/ci/cucumber_task'
4
+ require 'sleeping_king_studios/tasks/ci/eslint_task'
5
+ require 'sleeping_king_studios/tasks/ci/jest_task'
6
+ require 'sleeping_king_studios/tasks/ci/rspec_task'
7
+ require 'sleeping_king_studios/tasks/ci/rspec_each_task'
8
+ require 'sleeping_king_studios/tasks/ci/rubocop_task'
9
+ require 'sleeping_king_studios/tasks/ci/steps_task'
10
+
11
+ module SleepingKingStudios::Tasks::Ci
12
+ # Thor integration for continuous integration tasks.
13
+ class Tasks < SleepingKingStudios::Tasks::TaskGroup
14
+ namespace :ci
15
+
16
+ task SleepingKingStudios::Tasks::Ci::CucumberTask
17
+ task SleepingKingStudios::Tasks::Ci::EslintTask
18
+ task SleepingKingStudios::Tasks::Ci::JestTask
19
+ task SleepingKingStudios::Tasks::Ci::RSpecTask
20
+ task SleepingKingStudios::Tasks::Ci::RSpecEachTask
21
+ task SleepingKingStudios::Tasks::Ci::RuboCopTask
22
+ task SleepingKingStudios::Tasks::Ci::StepsTask
23
+ end # class
24
+ end # module
@@ -5,6 +5,8 @@ require 'sleeping_king_studios/tools/toolbox/configuration'
5
5
  require 'sleeping_king_studios/tasks'
6
6
 
7
7
  module SleepingKingStudios::Tasks
8
+ # rubocop:disable Metrics/ClassLength
9
+
8
10
  # Task configuration options, grouped by namespace.
9
11
  class Configuration < SleepingKingStudios::Tools::Toolbox::Configuration
10
12
  # rubocop:disable Metrics/BlockLength
@@ -32,7 +34,7 @@ module SleepingKingStudios::Tasks
32
34
  :global => true
33
35
  } # end rspec
34
36
 
35
- option :steps, :default => %i(rspec rubocop simplecov)
37
+ option :steps, :default => %i[rspec rubocop simplecov]
36
38
 
37
39
  define_method :steps_with_options do
38
40
  steps.each.with_object({}) do |step, hsh|
@@ -55,18 +57,36 @@ module SleepingKingStudios::Tasks
55
57
  :default_files => ['step_definitions', 'step_definitions.rb']
56
58
  } # end cucumber
57
59
 
60
+ option :eslint, :default =>
61
+ {
62
+ :class => 'SleepingKingStudios::Tasks::Ci::EslintTask',
63
+ :default_files => '"**/*.js"',
64
+ :require => 'sleeping_king_studios/tasks/ci/eslint_task',
65
+ :title => 'ESLint'
66
+ }
67
+
68
+ option :jest, :default =>
69
+ {
70
+ :class => 'SleepingKingStudios::Tasks::Ci::JestTask',
71
+ :require => 'sleeping_king_studios/tasks/ci/jest_task',
72
+ :title => 'Jest',
73
+ :verbose => false
74
+ }
75
+
58
76
  option :rspec, :default =>
59
77
  {
60
78
  :require => 'sleeping_king_studios/tasks/ci/rspec_task',
61
79
  :class => 'SleepingKingStudios::Tasks::Ci::RSpecTask',
62
- :title => 'RSpec'
80
+ :title => 'RSpec',
81
+ :format => 'documentation'
63
82
  } # end rspec
64
83
 
65
84
  option :rspec_each, :default =>
66
85
  {
67
86
  :require => 'sleeping_king_studios/tasks/ci/rspec_each_task',
68
87
  :class => 'SleepingKingStudios::Tasks::Ci::RSpecEachTask',
69
- :title => 'RSpec (Each)'
88
+ :title => 'RSpec (Each)',
89
+ :format => nil
70
90
  } # end rspec
71
91
 
72
92
  option :rubocop, :default =>
@@ -83,7 +103,7 @@ module SleepingKingStudios::Tasks
83
103
  :title => 'SimpleCov'
84
104
  } # end rspec
85
105
 
86
- option :steps, :default => %i(rspec rubocop simplecov)
106
+ option :steps, :default => %i[rspec rubocop simplecov]
87
107
 
88
108
  define_method :steps_with_options do
89
109
  steps.each.with_object({}) do |step, hsh|
@@ -111,4 +131,5 @@ module SleepingKingStudios::Tasks
111
131
  option :template_paths, :default => [default_template_path]
112
132
  end # namespace
113
133
  end # class
134
+ # rubocop:enable Metrics/ClassLength
114
135
  end # module
@@ -11,6 +11,8 @@ module SleepingKingStudios::Tasks::File
11
11
 
12
12
  # Thor task for generating a new Ruby source file.
13
13
  class NewTask < SleepingKingStudios::Tasks::Task
14
+ class MissingTemplateError < StandardError; end
15
+
14
16
  def self.description
15
17
  'Creates a Ruby source file and corresponding spec file.'
16
18
  end # class method description
@@ -56,8 +58,8 @@ module SleepingKingStudios::Tasks::File
56
58
 
57
59
  return unless prompt_confirmation
58
60
 
59
- create_source_file
60
- create_spec_file
61
+ create_source_file unless dry_run?
62
+ create_spec_file unless dry_run?
61
63
 
62
64
  say 'Complete!', :green
63
65
  end # method file_name
@@ -78,10 +80,16 @@ module SleepingKingStudios::Tasks::File
78
80
  raise "file already exists at #{file_path}" unless force?
79
81
  end # method check_for_existing_file
80
82
 
83
+ def create_directories *directory_names
84
+ directory_path = directory_names.compact.join(File::SEPARATOR)
85
+
86
+ FileUtils.mkdir_p directory_path unless directory_path.empty?
87
+ end # method create_directories
88
+
81
89
  def create_source_file
82
90
  create_directories directory, *relative_path
83
91
 
84
- File.write file_path, rendered_source unless dry_run?
92
+ File.write file_path, rendered_source
85
93
  end # method create_file
86
94
 
87
95
  def create_spec_file
@@ -91,15 +99,9 @@ module SleepingKingStudios::Tasks::File
91
99
 
92
100
  create_directories 'spec', *relative_path
93
101
 
94
- File.write spec_path, rendered_spec unless dry_run?
102
+ File.write spec_path, rendered_spec
95
103
  end # method create_spec_file
96
104
 
97
- def create_directories *directory_names
98
- return if dry_run?
99
-
100
- FileUtils.mkdir_p directory_names.compact.join(File::SEPARATOR)
101
- end # method create_directories
102
-
103
105
  def find_template name
104
106
  template_paths.each do |template_dir|
105
107
  template_path = File.expand_path(File.join template_dir, name)
@@ -109,7 +111,7 @@ module SleepingKingStudios::Tasks::File
109
111
  return File.read(template_path)
110
112
  end # each
111
113
 
112
- nil
114
+ raise MissingTemplateError, "No template found for \"#{name}\""
113
115
  end # method find_template
114
116
 
115
117
  def preview
@@ -218,7 +220,7 @@ module SleepingKingStudios::Tasks::File
218
220
  end # method split_file_path
219
221
 
220
222
  def split_relative_path fragments
221
- if %w(app apps lib spec tmp vendor).include?(fragments.first)
223
+ if %w[app apps lib spec tmp vendor].include?(fragments.first)
222
224
  @directory = fragments.shift
223
225
  end # if
224
226
 
@@ -0,0 +1,13 @@
1
+ # lib/sleeping_king_studios/tasks/file/tasks.thor
2
+
3
+ require 'sleeping_king_studios/tasks/file'
4
+ require 'sleeping_king_studios/tasks/file/new_task'
5
+
6
+ module SleepingKingStudios::Tasks::File
7
+ # Thor integration for file tasks.
8
+ class Tasks < SleepingKingStudios::Tasks::TaskGroup
9
+ namespace :file
10
+
11
+ task SleepingKingStudios::Tasks::File::NewTask
12
+ end # class
13
+ end # module
@@ -0,0 +1,13 @@
1
+ <%# lib/sleeping_king_studios/tasks/file/templates/ruby.rspec %>
2
+ <% require 'sleeping_king_studios/tools' %>
3
+ <% tools = SleepingKingStudios::Tools::Toolbelt.new %>
4
+ <% full_path = [*relative_path, file_name.sub(/_spec\z/, '')] %>
5
+ require '<%= full_path.join('/') %>'
6
+
7
+ <%
8
+ qualified_module =
9
+ full_path.map { |rel| tools.string.camelize(rel) }.join('::')
10
+ %>
11
+ RSpec.describe <%= qualified_module %> do
12
+ pending
13
+ end
@@ -0,0 +1,28 @@
1
+ <%# lib/sleeping_king_studios/tasks/file/templates/ruby.erb %>
2
+ <% require 'sleeping_king_studios/tools' %>
3
+ <% tools = SleepingKingStudios::Tools::Toolbelt.new %>
4
+ <% if relative_path.empty? %>
5
+ <% if defined?(superclass) %>
6
+ class <%= tools.string.camelize file_name %> < <%= superclass %>
7
+
8
+ end
9
+ <% else %>
10
+ module <%= tools.string.camelize file_name %>
11
+
12
+ end
13
+ <% end %>
14
+ <% else %>
15
+ require '<%= relative_path.join('/') %>'
16
+
17
+ module <%= relative_path.map { |rel| tools.string.camelize(rel) }.join('::') %>
18
+ <% if defined?(superclass) %>
19
+ class <%= tools.string.camelize file_name %> < <%= superclass %>
20
+
21
+ end
22
+ <% else %>
23
+ module <%= tools.string.camelize file_name %>
24
+
25
+ end
26
+ <% end %>
27
+ end
28
+ <% end %>
@@ -29,8 +29,8 @@ module SleepingKingStudios::Tasks
29
29
  end # method base_command
30
30
 
31
31
  def build_command **kwargs
32
- env = build_environment(kwargs)
33
- opts = build_options(kwargs)
32
+ env = build_environment(**kwargs)
33
+ opts = build_options(**kwargs)
34
34
 
35
35
  "#{env} #{base_command} #{opts}".strip
36
36
  end # method build_command
@@ -52,7 +52,7 @@ module SleepingKingStudios::Tasks
52
52
  end # method build_options
53
53
 
54
54
  def stream_process command
55
- Bundler.with_clean_env do
55
+ unbundled_env do
56
56
  IO.popen(command) do |io|
57
57
  loop do
58
58
  char = io.getc
@@ -60,11 +60,21 @@ module SleepingKingStudios::Tasks
60
60
  char ? print(char) : break
61
61
  end # loop
62
62
  end # popen
63
- end # with_clean_env
63
+ end # with_unbundled_env
64
64
  end # method stream_process
65
65
 
66
66
  def tools
67
67
  SleepingKingStudios::Tools::Toolbelt.new
68
68
  end # method tools
69
+
70
+ def unbundled_env
71
+ # :nocov:
72
+ if Bundler.respond_to?(:with_unbundled_env)
73
+ Bundler.with_unbundled_env { yield }
74
+ else
75
+ Bundler.with_clean_env { yield }
76
+ end
77
+ # :nocov:
78
+ end
69
79
  end # class
70
80
  end # module