class Spoom::Cli::Coverage

Constants

DATA_DIR

Public Instance Methods

bundle_install(path, sha) click to toggle source
# File lib/spoom/cli/coverage.rb, line 183
def bundle_install(path, sha)
  opts = {}
  opts[:chdir] = path
  out, status = Open3.capture2e("bundle install", opts)
  unless status.success?
    say_error("Can't run `bundle install` for commit `#{sha}`. Skipping snapshot")
    say_error(out, status: nil)
    return false
  end
  true
end
message_no_data(file) click to toggle source
# File lib/spoom/cli/coverage.rb, line 195
        def message_no_data(file)
          say_error("No snapshot files found in `#{file}`")
          say_error(<<~ERR, status: nil)

            If you already generated snapshot files under another directory use #{blue('spoom coverage report PATH')}.

            To generate snapshot files run #{blue('spoom coverage timeline --save-dir spoom_data')}.
          ERR
        end
open(file = "spoom_report.html") click to toggle source
# File lib/spoom/cli/coverage.rb, line 159
      def open(file = "spoom_report.html")
        unless File.exist?(file)
          say_error("No report file to open `#{file}`")
          say_error(<<~ERR, status: nil)

            If you already generated a report under another name use #{blue('spoom coverage open PATH')}.

            To generate a report run #{blue('spoom coverage report')}.
          ERR
          exit(1)
        end

        exec("open #{file}")
      end
parse_time(string, option) click to toggle source
# File lib/spoom/cli/coverage.rb, line 175
def parse_time(string, option)
  return nil unless string
  Time.parse(string)
rescue ArgumentError
  say_error("Invalid date `#{string}` for option `#{option}` (expected format `YYYY-MM-DD`)")
  exit(1)
end
report() click to toggle source
# File lib/spoom/cli/coverage.rb, line 128
def report
  in_sorbet_project!

  data_dir = options[:data]
  files = Dir.glob("#{data_dir}/*.json")
  if files.empty?
    message_no_data(data_dir)
    exit(1)
  end

  snapshots = files.sort.map do |file|
    json = File.read(file)
    Spoom::Coverage::Snapshot.from_json(json)
  end.filter(&:commit_timestamp).sort_by!(&:commit_timestamp)

  palette = Spoom::Coverage::D3::ColorPalette.new(
    ignore: options[:color_ignore],
    false: options[:color_false],
    true: options[:color_true],
    strict: options[:color_strict],
    strong: options[:color_strong]
  )

  report = Spoom::Coverage.report(snapshots, palette: palette, path: exec_path)
  file = options[:file]
  File.write(file, report.html)
  say("Report generated under `#{file}`")
  say("\nUse `spoom coverage open` to open it.")
end
snapshot() click to toggle source
# File lib/spoom/cli/coverage.rb, line 20
def snapshot
  in_sorbet_project!
  path = exec_path
  sorbet = options[:sorbet]

  snapshot = Spoom::Coverage.snapshot(path: path, rbi: options[:rbi], sorbet_bin: sorbet)
  snapshot.print

  save_dir = options[:save]
  return unless save_dir
  FileUtils.mkdir_p(save_dir)
  file = "#{save_dir}/#{snapshot.commit_sha || snapshot.timestamp}.json"
  File.write(file, snapshot.to_json)
  say("\nSnapshot data saved under `#{file}`")
end
timeline() click to toggle source
# File lib/spoom/cli/coverage.rb, line 42
      def timeline
        in_sorbet_project!
        path = exec_path
        sorbet = options[:sorbet]

        ref_before = Spoom::Git.current_branch
        ref_before = Spoom::Git.last_commit(path: path) unless ref_before
        unless ref_before
          say_error("Not in a git repository")
          say_error("\nSpoom needs to checkout into your previous commits to build the timeline.", status: nil)
          exit(1)
        end

        unless Spoom::Git.workdir_clean?(path: path)
          say_error("Uncommited changes")
          say_error(<<~ERR, status: nil)

            Spoom needs to checkout into your previous commits to build the timeline."

            Please `git commit` or `git stash` your changes then try again
          ERR
          exit(1)
        end

        save_dir = options[:save]
        FileUtils.mkdir_p(save_dir) if save_dir

        from = parse_time(options[:from], "--from")
        to = parse_time(options[:to], "--to")

        unless from
          intro_sha = Spoom::Git.sorbet_intro_commit(path: path)
          intro_sha = T.must(intro_sha) # we know it's in there since in_sorbet_project!
          from = Spoom::Git.commit_time(intro_sha, path: path)
        end

        timeline = Spoom::Timeline.new(from, to, path: path)
        ticks = timeline.ticks

        if ticks.empty?
          say_error("No commits to replay, try different `--from` and `--to` options")
          exit(1)
        end

        ticks.each_with_index do |sha, i|
          date = Spoom::Git.commit_time(sha, path: path)
          say("Analyzing commit `#{sha}` - #{date&.strftime('%F')} (#{i + 1} / #{ticks.size})")

          Spoom::Git.checkout(sha, path: path)

          snapshot = T.let(nil, T.nilable(Spoom::Coverage::Snapshot))
          if options[:bundle_install]
            Bundler.with_unbundled_env do
              next unless bundle_install(path, sha)
              snapshot = Spoom::Coverage.snapshot(path: path, sorbet_bin: sorbet)
            end
          else
            snapshot = Spoom::Coverage.snapshot(path: path, sorbet_bin: sorbet)
          end
          next unless snapshot

          snapshot.print(indent_level: 2)
          say("\n")

          next unless save_dir
          file = "#{save_dir}/#{sha}.json"
          File.write(file, snapshot.to_json)
          say("  Snapshot data saved under `#{file}`\n\n")
        end
        Spoom::Git.checkout(ref_before, path: path)
      end