Module: SimpleCov::CLI::Watch

Extended by:
CommandHelpers, Watch
Included in:
Watch
Defined in:
lib/simplecov/cli/watch.rb,
lib/simplecov/cli/watch/poller.rb,
lib/simplecov/cli/watch/session.rb,
lib/simplecov/cli/watch/narrator.rb,
lib/simplecov/cli/watch/test_plan.rb,
lib/simplecov/cli/watch/live_report.rb

Overview

simplecov watch <command...>: the coverage inner loop. Serves the report the way serve does, polls the tracked files for saves, re-runs the given command on change, and pushes a reload to the open tab over server-sent events when the report regenerates. With a track_tests recording in the report, a save re-runs only the tests that touch the changed files, by the same selection walk simplecov affected uses.

Defined Under Namespace

Modules: TestPlan Classes: LiveReport, Narrator, Poller, Session

Constant Summary

Constants included from CommandHelpers

CommandHelpers::STATS_ROW_FORMAT

Instance Method Summary collapse

Methods included from CommandHelpers

build_parser, command_name, common_options, error, error_nil, on_help, one?, parse_common, quiet_option, recorded_contexts, stats_row

Instance Method Details

#bind(opts, stderr) ⇒ Object



73
74
75
76
77
# File 'lib/simplecov/cli/watch.rb', line 73

def bind(opts, stderr)
  (_ = TCPServer).new(opts.fetch(:host), opts.fetch(:port)) #: TCPServer
rescue SystemCallError, SocketError => e
  error_nil(stderr, "cannot bind to #{opts.fetch(:host)}:#{opts.fetch(:port)} (#{e})")
end

#launch_browser(server, stderr) ⇒ Object

Fire-and-forget through the same platform opener simplecov open uses, detached so the session never waits on a browser. A platform with no known opener notes the URL instead of failing the watch.



48
49
50
51
52
53
54
55
56
# File 'lib/simplecov/cli/watch.rb', line 48

def launch_browser(server, stderr)
  url = "http://#{Serve.url_host(server.addr.fetch(3))}:#{server.addr.fetch(1)}/"
  opener = Open.browser_opener
  unless opener
    return stderr.puts("simplecov watch: no known browser opener for this platform, open it yourself: #{url}")
  end

  Process.detach(spawn(*opener, url, out: File::NULL, err: File::NULL))
end

#parse(args) ⇒ Object

order rather than parse stops at the first positional, so the runner command keeps its own flags: simplecov watch bundle exec rspec --seed 1 passes --seed through untouched.



61
62
63
64
65
66
67
68
69
70
71
# File 'lib/simplecov/cli/watch.rb', line 61

def parse(args)
  opts = {port: 0, host: "127.0.0.1", interval: 0.5, open: false} #: Hash[Symbol, untyped]
  rest =
    build_parser do |parser|
      parser.on("--port N", Integer) { |v| opts[:port] = v }
      parser.on("--host HOST") { |v| opts[:host] = v }
      parser.on("--interval SECONDS", Float) { |v| opts[:interval] = v }
      parser.on("--open") { opts[:open] = true }
    end.order(args)
  [opts, rest]
end

#run(args, stdout:, stderr:) ⇒ Object



27
28
29
30
31
32
33
34
35
36
# File 'lib/simplecov/cli/watch.rb', line 27

def run(args, stdout:, stderr:, **)
  opts, command = parse(args)
  return error(stderr, "missing command to run (e.g. `simplecov watch bundle exec rspec`)") if command.empty?

  Serve.require_socket
  server = bind(opts, stderr)
  return 1 unless server

  serve_session(server, command, opts, stdout, stderr)
end

#serve_session(server, command, opts, stdout, stderr) ⇒ Object



38
39
40
41
42
43
# File 'lib/simplecov/cli/watch.rb', line 38

def serve_session(server, command, opts, stdout, stderr)
  launch_browser(server, stderr) if opts.fetch(:open)
  session_for(command, opts, stdout, stderr).run(server)
ensure
  server.close
end

#session_for(command, opts, stdout, stderr) ⇒ Object



79
80
81
82
# File 'lib/simplecov/cli/watch.rb', line 79

def session_for(command, opts, stdout, stderr)
  Session.new(command: command, dir: CLI.coverage_dir,
    interval: opts.fetch(:interval), stdout: stdout, stderr: stderr)
end