smackdown 0.0.1.a

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7c359ca40e55cfc3d71c61a0e9dad03a1bffbe98
4
+ data.tar.gz: bd66adafbada6ee911654fcfe06883e8ee2075ac
5
+ SHA512:
6
+ metadata.gz: 7c9cdd325f82fc218614d52aee0b7c237d54f34d7756e1d3b7036dab18487862060f814ec2d077a91dfd6ff720b3676ff01ba82214217f986225c861f4467c9a
7
+ data.tar.gz: ac9be749f25cd7712cc3f33ad02b83e648f7399e2422cd04075f02ec6da603e03a454c5aa37abaec8eb09549d859f0ab5b13b567172ce72a76be76523055912d
data/lib/smackdown.rb ADDED
@@ -0,0 +1,20 @@
1
+ require 'json'
2
+ require 'rugged'
3
+
4
+ require 'smackdown/uncovered_line'
5
+ require 'smackdown/file_coverage_diff'
6
+ require 'smackdown/coverage_diff_reporter'
7
+
8
+ module Smackdown
9
+ class Tasks
10
+ if defined? Rake::DSL
11
+ include Rake::DSL
12
+
13
+ def install_tasks
14
+ import File.join(File.dirname(__FILE__), 'tasks/smackdown.rake')
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ Smackdown::Tasks.new.install_tasks if defined? Rake::DSL
@@ -0,0 +1,118 @@
1
+ module Smackdown
2
+ class CoverageDiffReporter
3
+ DEFAULT_FILTERS = %w(
4
+ ^[^\/]*$
5
+ test/
6
+ features/
7
+ spec/
8
+ autotest/
9
+ config/
10
+ db/
11
+ vendor/bundle/
12
+ script
13
+ vendor
14
+ *.rake
15
+ )
16
+
17
+ attr_reader :file_coverage_diffs
18
+
19
+ def initialize(repo_path, opts = {})
20
+ raise "Repo path does not exist: #{repo_path}" unless Dir.exist?(repo_path)
21
+
22
+ if opts[:coverage_report_path] && opts[:coverage_json]
23
+ raise "Please pass only :coverage_report_path or :coverage_json, not both."
24
+ end
25
+
26
+ @coverage_json = opts[:coverage_json] || nil
27
+
28
+ unless @coverage_json
29
+ @coverage_report_path = opts[:coverage_report_path] || File.join(repo_path, 'coverage', 'coverage.json')
30
+ end
31
+
32
+ @repo = Rugged::Repository.new(repo_path)
33
+ @report_path_prefix = opts[:report_path_prefix] || repo_path
34
+ @head = opts[:head] || 'HEAD'
35
+ @merge_base = opts[:merge_base] || 'master'
36
+ @context_lines = opts[:context_lines] || 10000
37
+ @filters = opts[:filters] || DEFAULT_FILTERS
38
+ @file_coverage_diffs = {}
39
+ end
40
+
41
+ def run
42
+ process_coverage
43
+
44
+ @diff = @repo.diff(@repo.merge_base(@merge_base, @head), @head, context_lines: @context_lines)
45
+
46
+ process_diffs
47
+ end
48
+
49
+ def completely_covered?
50
+ @file_coverage_diffs.all? do |_relative_path, file_coverage_diff|
51
+ file_coverage_diff.covered?
52
+ end
53
+ end
54
+
55
+ def report(&block)
56
+ if block_given?
57
+ report_diffs(&block)
58
+ else
59
+ default_report
60
+ end
61
+ end
62
+
63
+ private
64
+
65
+ def parse_coverage_report
66
+ uri = URI(@coverage_report_path)
67
+ if ["http", "https"].include?(uri.scheme)
68
+ file_contents = Net::HTTP.get(uri)
69
+ else
70
+ raise "Coverage report path does not exist: #{@coverage_report_path}" unless File.exist?(@coverage_report_path)
71
+ file_contents = File.read(@coverage_report_path)
72
+ end
73
+
74
+ @parsed_coverage_json = JSON.parse(file_contents)
75
+ end
76
+
77
+ def process_coverage
78
+ if @coverage_json
79
+ @parsed_coverage_json = JSON.parse(@coverage_json)
80
+ else
81
+ parse_coverage_report
82
+ end
83
+ @coverage_json_hash = Hash.new
84
+ @parsed_coverage_json["files"].each do |file_diff|
85
+ @coverage_json_hash[file_diff["filename"]] = file_diff["coverage"]
86
+ end
87
+ end
88
+
89
+ def process_diffs
90
+ @diff.patches.each do |patch|
91
+ relative_path = patch.delta.new_file[:path]
92
+
93
+ next if @filters.any?{ |filter| /^#{filter}/.match relative_path }
94
+
95
+ full_path = File.join(@report_path_prefix, relative_path)
96
+ coverage = @coverage_json_hash[full_path]
97
+
98
+ @file_coverage_diffs[relative_path] = FileCoverageDiff.new(relative_path, full_path, coverage, patch)
99
+ end
100
+ end
101
+
102
+ def report_diffs(&block)
103
+ @file_coverage_diffs.each do |_relative_path, file_coverage_diff|
104
+ yield file_coverage_diff
105
+ end
106
+ end
107
+
108
+ def default_report
109
+ if completely_covered?
110
+ "All new and modified code is covered!"
111
+ else
112
+ @file_coverage_diffs.inject("") do |output, (_path, file_coverage_diff)|
113
+ "#{output}#{file_coverage_diff.to_s}"
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,65 @@
1
+ module Smackdown
2
+ class FileCoverageDiff
3
+ attr_reader :uncovered_lines, :relative_path, :full_path
4
+
5
+ def initialize(relative_path, full_path, coverage, patch)
6
+ @relative_path = relative_path
7
+ @full_path = full_path
8
+ @coverage = coverage
9
+ @patch = patch
10
+ @uncovered_lines = []
11
+ @coverage_available = !coverage.nil?
12
+
13
+ record_coverage if @coverage_available
14
+ end
15
+
16
+ def coverage_available?
17
+ @coverage_available
18
+ end
19
+
20
+ def covered?
21
+ coverage_available? && @uncovered_lines.none?
22
+ end
23
+
24
+ def to_s
25
+ str = relative_path
26
+
27
+ if coverage_available?
28
+ if covered?
29
+ str += "\n100\% covered!"
30
+ else
31
+ uncovered_lines.each do |line|
32
+ str += "\n#{line.line_num}: #{line.line_content}"
33
+ end
34
+ end
35
+ else
36
+ str += "\nNo coverage for this file!"
37
+ end
38
+
39
+ str += "\n\n-----------------------------------------\n"
40
+
41
+ str
42
+ end
43
+
44
+ private
45
+
46
+ def record_coverage
47
+ @patch.hunks.each do |hunk|
48
+ added_lines = hunk.lines.select{ |line| line.line_origin == :addition }
49
+ added_lines.each do |line|
50
+ process_line(line)
51
+ end
52
+ end
53
+ end
54
+
55
+ def process_line(line)
56
+ line_number = line.new_lineno
57
+ single_line_hits = @coverage[line_number - 1]
58
+ if single_line_hits && single_line_hits < 1
59
+ line_content = line.content.gsub("\n", "")
60
+ @uncovered_lines << UncoveredLine.new(line_number, line_content)
61
+ end
62
+ end
63
+
64
+ end
65
+ end
@@ -0,0 +1,10 @@
1
+ module Smackdown
2
+ class UncoveredLine
3
+ attr_reader :line_num, :line_content
4
+
5
+ def initialize(line_num, line_content)
6
+ @line_num = line_num
7
+ @line_content = line_content
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ module Smackdown
2
+ VERSION = "0.0.1.a"
3
+ end
@@ -0,0 +1,8 @@
1
+ desc "Run smackdown on your current branch with the most common options"
2
+ task :smackdown do
3
+ reporter = Smackdown::CoverageDiffReporter.new(File.expand_path('.'))
4
+ reporter.run
5
+ puts reporter.report
6
+
7
+ exit(reporter.completely_covered?)
8
+ end
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: smackdown
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.a
5
+ platform: ruby
6
+ authors:
7
+ - Rob Esris
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-08-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rugged
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.19.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 0.19.0
27
+ description: Identify and report on lines of code, introduced in a branch (e.g. a
28
+ pull request) that are not covered by tests.
29
+ email:
30
+ - resris@paperlesspost.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - lib/smackdown.rb
36
+ - lib/smackdown/coverage_diff_reporter.rb
37
+ - lib/smackdown/file_coverage_diff.rb
38
+ - lib/smackdown/uncovered_line.rb
39
+ - lib/smackdown/version.rb
40
+ - lib/tasks/smackdown.rake
41
+ homepage:
42
+ licenses: []
43
+ metadata: {}
44
+ post_install_message:
45
+ rdoc_options: []
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">"
56
+ - !ruby/object:Gem::Version
57
+ version: 1.3.1
58
+ requirements: []
59
+ rubyforge_project:
60
+ rubygems_version: 2.2.2
61
+ signing_key:
62
+ specification_version: 4
63
+ summary: Identify and report on lines of code, introduced in a branch (e.g. a pull
64
+ request) that are not covered by tests.
65
+ test_files: []