oyencov 0.0.1.pre

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 829c5d959c386d08c7d81c836251104461d0875fc4fb6e04d1963cd32301235b
4
+ data.tar.gz: 4f14f7447a5278cc84b89d7c6bcd9d4fa97c6ea3f12f4d898e89b042a5de880d
5
+ SHA512:
6
+ metadata.gz: 11a0471aae67aa816d1840f1882eaa206be0ad339ab40fae872567985579a8e84dbae85573b5466083450849b33c30e9ee7a136c48d7ad08d1976849ce46290f
7
+ data.tar.gz: f896668dcbdf7deb0cb392da50f410fca1a0361f20181844fd99753df1ebd83ea3d5d870a9e3790cce60debe8fef09b88430a58149b40ac016c95c7244a3c23e
data/bin/oyencov ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ unless File.exist?('./Gemfile')
4
+ abort 'Please run oyencov from the root of the project.'
5
+ end
6
+
7
+ require 'rubygems'
8
+ begin
9
+ require 'bundler'
10
+ Bundler.setup
11
+ rescue StandardError
12
+ end
13
+
14
+ here = File.expand_path(File.dirname __FILE__)
15
+ $LOAD_PATH << "#{here}/../lib"
16
+
17
+ require "oyencov/cli"
18
+ OyenCov::CLI.start(ARGV)
@@ -0,0 +1,53 @@
1
+ require "faraday"
2
+ require "singleton"
3
+
4
+ module OyenCov
5
+ class APIConnection < Faraday::Connection
6
+ include Singleton
7
+
8
+ def initialize
9
+ super({
10
+ url: (ENV["OYENCOV_API_URL"] || "https://telemetry-api.oyencov.com"),
11
+ headers: {
12
+ "Authorization" => "Bearer #{ENV["OYENCOV_API_KEY"]}",
13
+ "Content-Type" => "application/json",
14
+ "User-Agent" => "oyencov-ruby 0.0.1"
15
+ }
16
+ }) do |f|
17
+ f.request :json
18
+ f.response :json
19
+ end
20
+ end
21
+
22
+ # Used in `background.rb` to determine whether to start background
23
+ def get_data_submission_clearance
24
+ attempts = 3
25
+ begin
26
+ response = get("/v1/data_submission_clearance")
27
+ rescue Faraday::Error => e
28
+ if ENV["OYENCOV_DEBUG"]
29
+ warn(e)
30
+ end
31
+
32
+ if attempts > 0
33
+ attempts -= 1
34
+ sleep(5)
35
+ retry
36
+ end
37
+ nil
38
+ end
39
+
40
+ response
41
+ end
42
+
43
+ def post_runtime_report(body)
44
+ post("/v1/runtime_reports", body)
45
+ rescue Faraday::Error
46
+ false
47
+ end
48
+
49
+ def post_test_report(body)
50
+ post("/v1/test_reports", body)
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,81 @@
1
+ require "securerandom"
2
+ require "singleton"
3
+ require_relative "api_connection"
4
+ require_relative "coverage_peek_delta"
5
+
6
+ # Bootstrap the thread that starts Coverage module data collection.
7
+ #
8
+ # Every 60 secs or so:
9
+ # 1. Get the coverage peek_result delta
10
+ # 2. Parse source code and determine which method being run
11
+ # 3. Get controller actions' hits
12
+ # 4. Call the reporter
13
+ #
14
+ # Most of the codes here are inspired by danmayer's coverband gem.
15
+ #
16
+ module OyenCov
17
+ class Background
18
+ @loop_interval = 60 # seconds, can be set from server
19
+ @semaphore = Mutex.new
20
+ @thread = nil
21
+ @reporter = nil
22
+ @api_conn = OyenCov::APIConnection.instance
23
+ @config = OyenCov.config
24
+
25
+ def self.start
26
+ puts "Hello #{Rails.env}"
27
+
28
+ # Start `Coverage` as soon as possible before other codes are loaded
29
+ CoveragePeekDelta.start
30
+
31
+ @thread = Thread.new {
32
+ # Check with backend to get parameters
33
+ sleep(3)
34
+ clearance = @api_conn.get_data_submission_clearance
35
+
36
+ if clearance.nil?
37
+ puts "Unable to obtain oyencov submission clearance. Stopping OyenCov background thread."
38
+ Thread.stop
39
+ end
40
+
41
+ if ENV["OYENCOV_DEBUG"]
42
+ puts(clearance.body)
43
+ end
44
+
45
+ @config.mode == "production" && loop do
46
+ sleep(@loop_interval + 3 - rand(6))
47
+ new_method_hits = CoveragePeekDelta.snapshot_delta
48
+ new_controller_hits = ControllerTracking.snapshot_and_reset!
49
+
50
+ puts new_method_hits
51
+
52
+ runtime_report = {
53
+ git_commit_sha: @config.release,
54
+ controller_action_hits: new_controller_hits,
55
+ method_hits: new_method_hits
56
+ }
57
+ response = @api_conn.post_runtime_report(runtime_report)
58
+
59
+ if response && response.body["status"] == "ok"
60
+ puts "[OyenOnsen] POST runtime_report ok."
61
+ else
62
+ warn "[OyenOnsen] POST runtime_report failed. Stopping background thread."
63
+ Thread.stop
64
+ end
65
+ end # loop
66
+ }
67
+
68
+ @thread.run
69
+
70
+ nil
71
+ end
72
+
73
+ # If production/staging etc, we can exit without further processing.
74
+ # For `test`, persist controller report.
75
+ def self.stop
76
+ @thread.stop
77
+ end
78
+
79
+ private_class_method
80
+ end
81
+ end
@@ -0,0 +1,97 @@
1
+ require "thor"
2
+ require_relative "./api_connection"
3
+ require_relative "./test_report_merger"
4
+ require_relative "./simplecov_resultset_translator"
5
+
6
+ # Bootstrapped from `bin/oyencov`
7
+ #
8
+ #
9
+ module OyenCov
10
+ class CLI < Thor
11
+ desc "translate_simplecov coverage/.resultset.json", "err"
12
+ long_desc <<~TEXT
13
+ If you have parallel test jobs, this command is to be run right after
14
+ finishing the tests, and before artifacts are uploaded.
15
+
16
+ Assumes the --coverage-dir path contains both the simplecov .resultset.json,
17
+ and the oyencov-resultset.json. It parses the .resultset.json file
18
+ generated by simplecov, and append the translated information into the
19
+ pre-existing oyencov-resultset.json.
20
+ TEXT
21
+ # option :coverage_dir, default: "coverage"
22
+ option :simplecov_json_path, default: "coverage/.resultset.json"
23
+ option :oyencov_json_path, default: "coverage/oyencov-resultset.json"
24
+ option :dry_run, type: :boolean, default: false
25
+ def translate_simplecov
26
+ oyencov_json_path = Dir.pwd + "/" + options[:oyencov_json_path]
27
+ simplecov_json_path = Dir.pwd + "/" + options[:simplecov_json_path]
28
+
29
+ # Find existing resultset files
30
+ if File.exist?(oyencov_json_path)
31
+ oyencov_json = File.read(oyencov_json_path)
32
+ else
33
+ warn("Could not find existing oyencov-resultset.json at #{oyencov_json_path}")
34
+ exit(1)
35
+ end
36
+
37
+ warn "Starting to translate simplecov"
38
+
39
+ if File.exist?(simplecov_json_path)
40
+ simplecov_translated_json = OyenCov::SimplecovResultsetTranslator.translate(simplecov_json_path)
41
+ else
42
+ warn("Could not find existing simplecov's .resultset.json at #{simplecov_json_path}")
43
+ exit(1)
44
+ end
45
+
46
+ warn "AFTER translate simplecov"
47
+
48
+ # Attempt merging
49
+ oyencov_resultset = JSON.parse(oyencov_json)
50
+ oyencov_resultset = oyencov_resultset.merge("method_hits" => simplecov_translated_json)
51
+
52
+ # Persist, or dry run stdout?
53
+ new_oyencov_resultset_json = JSON.pretty_generate(oyencov_resultset)
54
+ if options[:dry_run]
55
+ puts new_oyencov_resultset_json
56
+ else
57
+ File.write(oyencov_json_path, new_oyencov_resultset_json)
58
+ end
59
+ end
60
+
61
+ desc "submit tmp/coverage-jsons-*/oyencov-resultset.json",
62
+ "submits the oyencov resultsets data"
63
+ option :files, type: :array, required: true
64
+ option :git_commit_sha, required: true
65
+ option :token
66
+ def submit
67
+ resultset_files = options[:files]
68
+ ENV["OYENCOV_DEBUG"] && if resultset_files.any?
69
+ puts "Found #{resultset_files.join(", ")}"
70
+ else
71
+ puts "No resultset files found"
72
+ exit 1
73
+ end
74
+
75
+ collated_report = OyenCov::TestReportMerger
76
+ .collate_job_reports(options[:files])
77
+ .merge({
78
+ "git_commit_sha" => options[:git_commit_sha]
79
+ })
80
+
81
+ # puts JSON.pretty_generate(collated_report)
82
+
83
+ # Add metadaata
84
+
85
+ ENV["OYENCOV_API_KEY"] ||= options[:token]
86
+ unless ENV["OYENCOV_API_KEY"]
87
+ warn "API token not set. Unable to submit."
88
+ exit(1)
89
+ end
90
+
91
+ connection = OyenCov::APIConnection.instance
92
+ post_response = connection.post_test_report(collated_report)
93
+
94
+ puts post_response.body
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,62 @@
1
+ # We encourage configuring OyenOnsen through environment variables.
2
+ #
3
+ # But some can be set through config/ if they are meant to be uniform across environments.
4
+ module OyenCov
5
+ class Configuration
6
+ ENV_PARAMETERS = %w[
7
+ API_KEY
8
+ API_URL
9
+ MODE
10
+ RELEASE
11
+ TEST_REPORTING_DIR
12
+ TEST_RESULTSET_PATH
13
+ PROGRAM_NAME
14
+ ]
15
+
16
+ attr :api_key, :api_url, :mode, :including_file_paths, :excluding_file_paths, :release, :test_reporting_dir, :test_resultset_path, :program_name
17
+
18
+ def initialize
19
+ reset_to_defaults
20
+ ENV_PARAMETERS.each do |key|
21
+ if (envvar_value = ENV["OYENONSEN_#{key}"])
22
+ instance_variable_set(
23
+ :"@#{key.downcase}", envvar_value
24
+ )
25
+ end
26
+ end
27
+ end
28
+
29
+ def reset_to_defaults
30
+ @api_key = nil
31
+ @api_url = "https://telemetry-api.oyencov.com"
32
+ @mode = ENV["RAILS_ENV"]
33
+ @including_file_paths = %w[app lib]
34
+ @excluding_file_paths = []
35
+ @release = suggest_release
36
+ @test_reporting_dir = "coverage/"
37
+ @test_resultset_path = "coverage/oyencov-resultset.json"
38
+ end
39
+
40
+ private
41
+
42
+ # Lots of ideas came from sentry-ruby, thanks to nate berkopec.
43
+ def suggest_release
44
+ release = `git rev-parse HEAD ||:`.strip
45
+
46
+ if release == "" || release.nil?
47
+ [".source_version", "REVISION"].each do |version_clue|
48
+ if File.exist?(Rails.root.join(version_clue))
49
+ release = File.read(Rails.root.join(version_clue)).strip
50
+ return release
51
+ end
52
+ end
53
+ end
54
+
55
+ release
56
+ end
57
+
58
+ # We need to know if this is rails, sidekiq, rake task etc
59
+ def suggest_program_name
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,22 @@
1
+ # This module is merely the container data structure.
2
+ #
3
+ # The ACTUAL code that tracks controller is in `railtie.rb`
4
+ module OyenCov
5
+ module ControllerTracking
6
+ @hits = {}
7
+
8
+ def self.bump(controller_action_name)
9
+ if @hits[controller_action_name]
10
+ @hits[controller_action_name] += 1
11
+ else
12
+ @hits[controller_action_name] = 1
13
+ end
14
+ end
15
+
16
+ def self.snapshot_and_reset!
17
+ current_hits = @hits
18
+ @hits = {}
19
+ current_hits
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,83 @@
1
+ require "coverage"
2
+ require_relative "method_range_parser"
3
+
4
+ # `CoveragePeekDelta` utility is meant to take...
5
+ #
6
+ # This class won't be governing the state, that will be handled by `OyenCov::Background`. However this will help strip the project path from the hash keys for cleaner reporting.
7
+ module OyenCov
8
+ module CoveragePeekDelta
9
+ PWD = Dir.pwd
10
+
11
+ @@previous_method_hits = {}
12
+
13
+ # We go a bit softer here. If there are other libraries starting
14
+ # coverage then don't throw exception.
15
+ def self.start
16
+ reset!
17
+
18
+ unless Coverage.running?
19
+ Coverage.start
20
+ end
21
+ end
22
+
23
+ # 1. Filter only the keys with PWD.
24
+ # 2. `transform_keys` and remove the PWD
25
+ # 3. Use MRP to get the impt lines.
26
+ #
27
+ # @return [Hash] Method name => line num executions diff from last time
28
+ def self.snapshot_delta
29
+ current_peek = Coverage.peek_result
30
+
31
+ if ENV["OYENONSEN_DEBUG"]
32
+ $stdout.puts "current_peek size = #{current_peek.size}, keys like: #{current_peek.keys[0, 3]}"
33
+ end
34
+
35
+ # Filter into project
36
+ filtered = current_peek.select do |k, _|
37
+ /^#{PWD}/o.match?(k)
38
+ end.transform_keys do |k|
39
+ k.gsub(/#{PWD}\//o, "")
40
+ end
41
+
42
+ if ENV["OYENONSEN_DEBUG"]
43
+ $stdout.puts "filtered size = #{filtered.size}, keys like: #{filtered.keys[0, 3]}"
44
+ end
45
+
46
+ # Filter inside project to just the paths
47
+ filtered = filtered.select do |k, _|
48
+ /^(app|lib)/.match?(k)
49
+ end
50
+
51
+ if ENV["OYENONSEN_DEBUG"]
52
+ $stdout.puts "filtered size = #{filtered.size}, keys like: #{filtered.keys[0, 3]}"
53
+ end
54
+
55
+ # Find the method ranges, set
56
+ current_method_hits = {}
57
+ filtered.each_pair do |fpath, line_hits|
58
+ MethodRangeParser[fpath]&.each_pair do |method_name, line_num|
59
+ # puts [method_name, line_num, line_hits[line_num]]
60
+ next if line_num.nil? || line_hits[line_num].nil?
61
+ current_method_hits[method_name] = line_hits[line_num]
62
+ end
63
+ end
64
+
65
+ # Compare and delta
66
+ new_method_hits = {}
67
+ current_method_hits.each_pair do |method_name, counter|
68
+ if counter.nil?; puts method_name; end
69
+ new_hits = counter - (@@previous_method_hits[method_name] || 0)
70
+ if new_hits > 0
71
+ new_method_hits[method_name] = new_hits
72
+ end
73
+ end
74
+
75
+ @@previous_method_hits = current_method_hits
76
+ new_method_hits
77
+ end
78
+
79
+ def self.reset!
80
+ @@previous_method_hits = {}
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,101 @@
1
+ require "parser/current"
2
+
3
+ # This module helps scanning source code files and get the definition line
4
+ # ranges, so we can count how many times a method has been executed.
5
+ module OyenCov
6
+ class MethodRangeParser < Hash
7
+ @@parsed_files = {}
8
+
9
+ def self.parsed_files
10
+ @@parsed_files
11
+ end
12
+
13
+ # Check cache
14
+ def self.[](filepath)
15
+ @filepath = filepath
16
+ @@parsed_files[@filepath] ||= parse_file(@filepath)
17
+ end
18
+
19
+ private
20
+
21
+ # Considerations:
22
+ # - Some .rb files do not have valid syntax, we can rescue them. However parser
23
+ # stills stderr
24
+ #
25
+ # @return [Hash<String, >] Hash of methods to their children starting line count. The line count can be used to read how often the method is executed from `Coverage.peek_result`
26
+ private_class_method def self.parse_file(filepath)
27
+ traverse_ast(Parser::CurrentRuby.parse(File.read(filepath)))
28
+ .to_h
29
+ .select do |k, v|
30
+ /\.|\#/.match?(k)
31
+ end.transform_keys do |k|
32
+ k.gsub(/^::/, "")
33
+ end
34
+ rescue Parser::SyntaxError
35
+ {}
36
+ end
37
+
38
+ private_class_method def self.declaration_name(node)
39
+ case node.type
40
+ when :begin then ""
41
+ when :defs then ".#{node.children[1]}"
42
+ when :def then "##{node.children[0]}"
43
+ when :class, :module # traverse
44
+ current_name_constant_node = node.children[0]
45
+ full_constant_name = ""
46
+ until current_name_constant_node.children[0].nil?
47
+ full_constant_name = "::#{current_name_constant_node.children[1]}#{full_constant_name}"
48
+ current_name_constant_node = current_name_constant_node.children[0]
49
+ end
50
+ "::#{current_name_constant_node.children[1]}#{full_constant_name}"
51
+ else "Unsupported AST node type: #{node.type}"
52
+ end
53
+ end
54
+
55
+ # @return [Integer]
56
+ private_class_method def self.definition_line_num(node)
57
+ definition_lines = node.children.find do |i|
58
+ Parser::AST::Node === i && i.type == :begin
59
+ end || node.children[-1]
60
+
61
+ if definition_lines.nil?
62
+ nil
63
+ else
64
+ definition_lines.loc.first_line
65
+ end
66
+ end
67
+
68
+ # this be recursion
69
+ # return array of ["node_type/namespace::nam#node_name" => [startline, endline]
70
+ private_class_method def self.traverse_ast(node)
71
+ unless Parser::AST::Node === node
72
+ return nil
73
+ end
74
+
75
+ unless %i[begin module class defs def].include?(node.type)
76
+ return nil
77
+ end
78
+
79
+ node_children = node.children.find do |i|
80
+ Parser::AST::Node === i && i.type == :begin
81
+ end&.children || [node.children[-1]]
82
+
83
+ ownself_name = declaration_name(node)
84
+ ownself_range = definition_line_num(node)
85
+
86
+ children_name_range = []
87
+
88
+ node_children&.each do |cnode|
89
+ if Array === traverse_ast(cnode)
90
+ children_name_range += traverse_ast(cnode)
91
+ end
92
+ end
93
+
94
+ children_name_range.map! do |cnode|
95
+ ["#{ownself_name}#{cnode[0]}", cnode[1]]
96
+ end
97
+
98
+ [[ownself_name, ownself_range]] + children_name_range
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,26 @@
1
+ require_relative "background"
2
+ require_relative "controller_tracking"
3
+ require_relative "test_reporting"
4
+
5
+ module OyenCov
6
+ class Railtie < Rails::Railtie
7
+ initializer "oyencov.configure" do
8
+ # puts "lib/oyencov/railtie.rb initializer oyencov.configure"
9
+ OyenCov::Background.start
10
+ end
11
+
12
+ config.after_initialize do
13
+ # puts "lib/oyencov/railtie.rb config.after_initialize"
14
+ ActiveSupport::Notifications.subscribe("start_processing.action_controller") do |name, start, finish, id, payload|
15
+ # puts(payload)
16
+ ControllerTracking.bump("#{payload[:controller]}##{payload[:action]}")
17
+ end
18
+
19
+ if OyenCov.config.mode == "test"
20
+ at_exit do
21
+ OyenCov::TestReporting.persist_controller_actions!
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,54 @@
1
+ require_relative "./method_range_parser"
2
+ require_relative "./test_report_merger"
3
+
4
+ # This is meant to be run at the end of the fan-out jobs, and the output
5
+ # artefacts are meant to be persisted for the next job in the workflow.
6
+ #
7
+ # It's possible the full codebase isn't pulled in the final summarising
8
+ # job. User can opt to just `gem install oyencov` and do the collation
9
+ # and submission with just the gem.
10
+ #
11
+ # The code should be similar to `CoveragePeekDelta`.
12
+ #
13
+ # A simplecov .resultset.json file looks like this:
14
+ #
15
+ # ```
16
+ # $test_tool (e.g. Minitest, RSpec) # can disregard
17
+ # "coverage" # constant string
18
+ # $rb_filepath # root relative paths
19
+ # [null, 1, 2, null, ...] # raw `Coverage.result` output
20
+ # ```
21
+ #
22
+ module OyenCov
23
+ module SimplecovResultsetTranslator
24
+ PWD = Dir.pwd
25
+
26
+ # @param [String] Root-relative path to the .resultset.json
27
+ # @return [String] JSON file
28
+ def self.translate(resultset_json_path, persist: false)
29
+ # Open up the JSON
30
+ resultset = JSON.parse(File.read(resultset_json_path))
31
+
32
+ # binding.irb
33
+
34
+ # Loop through all the files
35
+ # Set {"method" => runs, ...}
36
+ all_methods_hits = resultset[resultset.keys[0]]["coverage"].each_pair.map do |file_path, file_attr|
37
+ # file_path = file_path.gsub(/#{PWD}\//o, "")
38
+ line_hits = file_attr["lines"]
39
+ methods_hits = MethodRangeParser[file_path]&.each_pair&.map do |method_name, line_num|
40
+ next if line_num.nil? || line_hits[line_num].nil?
41
+ [method_name, line_hits[line_num]]
42
+ end&.compact.to_h
43
+ # methods_hits
44
+ end.reduce(:merge)
45
+
46
+ # Persist to existing oyencov report?
47
+ if persist
48
+ OyenCov::TestReportMerger.create_or_append!(method_hits: all_methods_hits)
49
+ end
50
+
51
+ all_methods_hits
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,71 @@
1
+ require "json"
2
+
3
+ # Currently Oyencov only tracks
4
+ #
5
+ # Simplecov report collation is not handled here.
6
+ module OyenCov
7
+ module TestReportMerger
8
+ def self.create_or_append!(hash_to_merge)
9
+ resultset_path = OyenCov.config.test_resultset_path
10
+
11
+ # Load
12
+ hash_content = if File.exist?(resultset_path)
13
+ JSON.parse(File.read(resultset_path))
14
+ else
15
+ {}
16
+ end
17
+
18
+ hash_content.merge!(hash_to_merge)
19
+
20
+ # Persist
21
+ File.write(resultset_path, JSON.generate(hash_content))
22
+ end
23
+
24
+ # @param [String]
25
+ # @param [String]
26
+ # @return [Hash]
27
+ def self.collate_job_reports(filepath_glob, save_to = nil)
28
+ # Read and parse their JSONs
29
+ job_reports_files = Dir.glob(filepath_glob)
30
+ # binding.irb
31
+ return if job_reports_files.count == 0
32
+
33
+ job_reports = job_reports_files.map do |f|
34
+ JSON.parse(File.read(f))
35
+ end
36
+
37
+ # Add them up
38
+ collated_report = job_reports.reduce({
39
+ "controller_action_hits" => {},
40
+ "method_hits" => {}
41
+ }) do |i, j|
42
+ ij = {}
43
+ i.keys.each do |metric|
44
+ unless j[metric]
45
+ ij[metric] = i[metric]
46
+ next
47
+ end
48
+
49
+ case metric
50
+ when "controller_action_hits", "method_hits"
51
+ ij[metric] = add_hashes(i[metric], j[metric])
52
+ end
53
+ end
54
+
55
+ ij
56
+ end
57
+
58
+ # Persist to filesystem as JSON
59
+ if !!save_to
60
+ end
61
+
62
+ collated_report
63
+ end
64
+
65
+ private_class_method def self.add_hashes(i, j)
66
+ (i.keys | j.keys).map do |key|
67
+ [key, (i[key] || 0) + (j[key] || 0)]
68
+ end.to_h
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,28 @@
1
+ require "securerandom"
2
+
3
+ # For use in CI only, one-off export
4
+ #
5
+ module OyenCov
6
+ class TestReporting
7
+ def self.persist_controller_actions!
8
+ controller_action_hits = OyenCov::ControllerTracking.snapshot_and_reset!
9
+
10
+ # Persist report file
11
+ test_report_dir = File.expand_path(OyenCov.config.test_reporting_dir)
12
+ FileUtils.mkdir_p(test_report_dir)
13
+ test_report_path = OyenCov.config.test_resultset_path
14
+
15
+ report_content = {
16
+ controller_action_hits:
17
+ }
18
+
19
+ report_content_json = JSON.generate(report_content)
20
+
21
+ File.open(test_report_path, "w+") do |f|
22
+ f.puts(report_content_json)
23
+ end
24
+
25
+ puts "[OyenCov] Saved to #{test_report_path}"
26
+ end
27
+ end
28
+ end
data/lib/oyencov.rb ADDED
@@ -0,0 +1,15 @@
1
+ require_relative "oyencov/configuration"
2
+ require_relative "oyencov/simplecov_resultset_translator"
3
+
4
+ # For now, support only Rails. We bootstrap from Railtie.
5
+ module OyenCov
6
+ VERSION = "0.0.1.pre"
7
+
8
+ def self.config
9
+ @config ||= OyenCov::Configuration.new
10
+ end
11
+
12
+ if defined?(Rails::Railtie) && ENV["OYENONSEN_API_KEY"]
13
+ require_relative "oyencov/railtie"
14
+ end
15
+ end
metadata ADDED
@@ -0,0 +1,160 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: oyencov
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.pre
5
+ platform: ruby
6
+ authors:
7
+ - Anonoz Chong
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-08-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: mocha
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: standard
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: faraday
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: parser
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '2'
90
+ - - "<"
91
+ - !ruby/object:Gem::Version
92
+ version: '4.0'
93
+ type: :runtime
94
+ prerelease: false
95
+ version_requirements: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '2'
100
+ - - "<"
101
+ - !ruby/object:Gem::Version
102
+ version: '4.0'
103
+ - !ruby/object:Gem::Dependency
104
+ name: thor
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ type: :runtime
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ description: Runtime and test reporters.
118
+ email: anonoz@oyencov.com
119
+ executables:
120
+ - oyencov
121
+ extensions: []
122
+ extra_rdoc_files: []
123
+ files:
124
+ - bin/oyencov
125
+ - lib/oyencov.rb
126
+ - lib/oyencov/api_connection.rb
127
+ - lib/oyencov/background.rb
128
+ - lib/oyencov/cli.rb
129
+ - lib/oyencov/configuration.rb
130
+ - lib/oyencov/controller_tracking.rb
131
+ - lib/oyencov/coverage_peek_delta.rb
132
+ - lib/oyencov/method_range_parser.rb
133
+ - lib/oyencov/railtie.rb
134
+ - lib/oyencov/simplecov_resultset_translator.rb
135
+ - lib/oyencov/test_report_merger.rb
136
+ - lib/oyencov/test_reporting.rb
137
+ homepage: https://www.oyencov.com
138
+ licenses:
139
+ - MIT
140
+ metadata: {}
141
+ post_install_message:
142
+ rdoc_options: []
143
+ require_paths:
144
+ - lib
145
+ required_ruby_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: 3.1.0
150
+ required_rubygems_version: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - ">"
153
+ - !ruby/object:Gem::Version
154
+ version: 1.3.1
155
+ requirements: []
156
+ rubygems_version: 3.3.7
157
+ signing_key:
158
+ specification_version: 4
159
+ summary: Client-side telemetry
160
+ test_files: []