sleeping_king_studios-tasks 0.1.0.rc.0 → 0.3.0

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.
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