codeclimate-test-reporter 0.0.5 → 0.0.6

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.
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'codeclimate-test-reporter'
5
+ require 'tmpdir'
6
+
7
+ if ENV["CODECLIMATE_REPO_TOKEN"]
8
+ tmpdir = Dir.tmpdir
9
+ puts "Searching #{tmpdir} for files to POST."
10
+ coverage_report_files = Dir.glob("#{tmpdir}/codeclimate-test-coverage-*")
11
+ if coverage_report_files.size > 0
12
+ puts "Found: "
13
+ puts coverage_report_files.join("\n")
14
+ client = CodeClimate::TestReporter::Client.new
15
+ print "Sending reports to #{client.host}..."
16
+ client.batch_post_results(coverage_report_files)
17
+ puts "done."
18
+ else
19
+ puts "No files found to POST."
20
+ end
21
+ else
22
+ $stderr.puts "Cannot batch post - environment variable CODECLIMATE_REPO_TOKEN must be set."
23
+ exit(1)
24
+ end
@@ -0,0 +1,20 @@
1
+ module CodeClimate
2
+ module TestReporter
3
+ VERSION = "0.0.6"
4
+
5
+ def self.start
6
+ if run?
7
+ require "simplecov"
8
+ ::SimpleCov.add_filter 'vendor'
9
+ ::SimpleCov.formatter = Formatter
10
+ ::SimpleCov.start("test_frameworks")
11
+ else
12
+ puts("Not reporting to Code Climate because ENV['CODECLIMATE_REPO_TOKEN'] is not set.")
13
+ end
14
+ end
15
+
16
+ def self.run?
17
+ !!ENV["CODECLIMATE_REPO_TOKEN"]
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,80 @@
1
+ require "json"
2
+ require "uri"
3
+ require "net/https"
4
+
5
+ module CodeClimate
6
+ module TestReporter
7
+
8
+ class Client
9
+
10
+ def host
11
+ ENV["CODECLIMATE_API_HOST"] ||
12
+ "https://codeclimate.com"
13
+ end
14
+
15
+ def batch_post_results(files)
16
+ uri = URI.parse("#{host}/test_reports/batch")
17
+ http = http_client(uri)
18
+
19
+ boundary = SecureRandom.uuid
20
+ post_body = []
21
+ post_body << "--#{boundary}\r\n"
22
+ post_body << "Content-Disposition: form-data; name=\"repo_token\"\r\n"
23
+ post_body << "\r\n"
24
+ post_body << ENV["CODECLIMATE_REPO_TOKEN"]
25
+ files.each_with_index do |file, index|
26
+ post_body << "\r\n--#{boundary}\r\n"
27
+ post_body << "Content-Disposition: form-data; name=\"coverage_reports[#{index}]\"; filename=\"#{File.basename(file)}\"\r\n"
28
+ post_body << "Content-Type: application/json\r\n"
29
+ post_body << "\r\n"
30
+ post_body << File.read(file)
31
+ end
32
+ post_body << "\r\n--#{boundary}--\r\n"
33
+ request = Net::HTTP::Post.new(uri.request_uri)
34
+ request.body = post_body.join
35
+ request["Content-Type"] = "multipart/form-data, boundary=#{boundary}"
36
+ response = http.request(request)
37
+
38
+ if response.code.to_i >= 200 && response.code.to_i < 300
39
+ response
40
+ else
41
+ raise "HTTP Error: #{response.code}"
42
+ end
43
+ end
44
+
45
+ def post_results(result)
46
+ uri = URI.parse("#{host}/test_reports")
47
+ http = http_client(uri)
48
+
49
+ request = Net::HTTP::Post.new(uri.path)
50
+ request["Content-Type"] = "application/json"
51
+ request.body = result.to_json
52
+
53
+ response = http.request(request)
54
+
55
+ if response.code.to_i >= 200 && response.code.to_i < 300
56
+ response
57
+ else
58
+ raise "HTTP Error: #{response.code}"
59
+ end
60
+ end
61
+
62
+ private
63
+
64
+ def http_client(uri)
65
+ Net::HTTP.new(uri.host, uri.port).tap do |http|
66
+ if uri.scheme == "https"
67
+ http.use_ssl = true
68
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
69
+ http.ca_file = File.expand_path('../../config/cacert.pem', __FILE__)
70
+ http.verify_depth = 5
71
+ end
72
+ http.open_timeout = 5 # in seconds
73
+ http.read_timeout = 5 # in seconds
74
+ end
75
+ end
76
+
77
+ end
78
+
79
+ end
80
+ end
@@ -0,0 +1,151 @@
1
+ require "tmpdir"
2
+ require "securerandom"
3
+ require "json"
4
+ require "digest/sha1"
5
+
6
+ module CodeClimate
7
+ module TestReporter
8
+ class Formatter
9
+ def format(result)
10
+ print "Coverage = #{result.covered_percent.round(2)}%."
11
+
12
+ payload = to_payload(result)
13
+ if tddium? || ENV["TO_FILE"]
14
+ file_path = File.join(Dir.tmpdir, "codeclimate-test-coverage-#{SecureRandom.uuid}.json")
15
+ print "Coverage results saved to #{file_path}..."
16
+ File.open(file_path, "w") { |file| file.write(payload.to_json) }
17
+ else
18
+ client = Client.new
19
+ print "Sending report to #{client.host}... "
20
+ client.post_results(payload)
21
+ end
22
+
23
+ puts "done."
24
+ true
25
+ rescue => ex
26
+ puts "\nCode Climate encountered an exception: #{ex.class}"
27
+ puts ex.message
28
+ ex.backtrace.each do |line|
29
+ puts line
30
+ end
31
+ false
32
+ end
33
+
34
+ def partial?
35
+ tddium?
36
+ end
37
+
38
+ def to_payload(result)
39
+ totals = Hash.new(0)
40
+ source_files = result.files.map do |file|
41
+ totals[:total] += file.lines.count
42
+ totals[:covered] += file.covered_lines.count
43
+ totals[:missed] += file.missed_lines.count
44
+
45
+ {
46
+ name: short_filename(file.filename),
47
+ blob_id: calculate_blob_id(file.filename),
48
+ coverage: file.coverage.to_json,
49
+ covered_percent: file.covered_percent.round(2),
50
+ covered_strength: file.covered_strength.round(2),
51
+ line_counts: {
52
+ total: file.lines.count,
53
+ covered: file.covered_lines.count,
54
+ missed: file.missed_lines.count
55
+ }
56
+ }
57
+ end
58
+
59
+ {
60
+ repo_token: ENV["CODECLIMATE_REPO_TOKEN"],
61
+ source_files: source_files,
62
+ run_at: result.created_at,
63
+ covered_percent: result.covered_percent.round(2),
64
+ covered_strength: result.covered_strength.round(2),
65
+ line_counts: totals,
66
+ partial: partial?,
67
+ git: {
68
+ head: `git log -1 --pretty=format:'%H'`,
69
+ committed_at: committed_at,
70
+ branch: git_branch,
71
+ },
72
+ environment: {
73
+ test_framework: result.command_name.downcase,
74
+ pwd: Dir.pwd,
75
+ rails_root: (Rails.root.to_s rescue nil),
76
+ simplecov_root: ::SimpleCov.root,
77
+ gem_version: VERSION
78
+ },
79
+ ci_service: ci_service_data
80
+ }
81
+ end
82
+
83
+ def ci_service_data
84
+ if ENV['TRAVIS']
85
+ {
86
+ name: "travis-ci",
87
+ branch: ENV['TRAVIS_BRANCH'],
88
+ build_identifier: ENV['TRAVIS_JOB_ID'],
89
+ pull_request: ENV['TRAVIS_PULL_REQUEST']
90
+ }
91
+ elsif ENV['CIRCLECI']
92
+ {
93
+ name: "circlci",
94
+ build_identifier: ENV['CIRCLE_BUILD_NUM'],
95
+ branch: ENV['CIRCLE_BRANCH'],
96
+ commit_sha: ENV['CIRCLE_SHA1']
97
+ }
98
+ elsif ENV['SEMAPHORE']
99
+ {
100
+ name: "semaphore",
101
+ branch: ENV['BRANCH_NAME'],
102
+ build_identifier: ENV['SEMAPHORE_BUILD_NUMBER']
103
+ }
104
+ elsif ENV['JENKINS_URL']
105
+ {
106
+ name: "jenkins",
107
+ build_identifier: ENV['BUILD_NUMBER'],
108
+ build_url: ENV['BUILD_URL'],
109
+ branch: ENV['GIT_BRANCH'],
110
+ commit_sha: ENV['GIT_COMMIT']
111
+ }
112
+ elsif ENV['TDDIUM']
113
+ {
114
+ name: "tddium",
115
+ build_identifier: ENV['TDDIUM_SESSION_ID'],
116
+ worker_id: ENV['TDDIUM_TID']
117
+ }
118
+ else
119
+ {}
120
+ end
121
+ end
122
+
123
+ def calculate_blob_id(path)
124
+ content = File.open(path, "rb").read
125
+ header = "blob #{content.length}\0"
126
+ store = header + content
127
+ Digest::SHA1.hexdigest(store)
128
+ end
129
+
130
+ def short_filename(filename)
131
+ return filename unless ::SimpleCov.root
132
+ filename.gsub(::SimpleCov.root, '.').gsub(/^\.\//, '')
133
+ end
134
+
135
+ def committed_at
136
+ committed_at = `git log -1 --pretty=format:'%ct'`
137
+ committed_at.to_i.zero? ? nil : committed_at.to_i
138
+ end
139
+
140
+ def git_branch
141
+ branch = `git branch`.split("\n").delete_if { |i| i[0] != "*" }
142
+ branch = [branch].flatten.first
143
+ branch ? branch.gsub("* ","") : nil
144
+ end
145
+
146
+ def tddium?
147
+ ci_service_data && ci_service_data[:name] == "tddium"
148
+ end
149
+ end
150
+ end
151
+ end
@@ -1,175 +1,3 @@
1
- require "json"
2
- require "digest/sha1"
3
- require "net/https"
4
- require "uri"
5
-
6
- module CodeClimate
7
- class TestReporter
8
- VERSION = "0.0.5"
9
-
10
- class API
11
- def self.host
12
- ENV["CODECLIMATE_API_HOST"] ||
13
- "https://codeclimate.com"
14
- end
15
-
16
- def self.post_results(result)
17
- uri = URI.parse("#{host}/test_reports")
18
- http = Net::HTTP.new(uri.host, uri.port)
19
-
20
- if uri.scheme == "https"
21
- http.use_ssl = true
22
- http.verify_mode = OpenSSL::SSL::VERIFY_PEER
23
- http.ca_file = File.expand_path('../../config/cacert.pem', __FILE__)
24
- http.verify_depth = 5
25
- end
26
-
27
- http.open_timeout = 5 # in seconds
28
- http.read_timeout = 5 # in seconds
29
-
30
- request = Net::HTTP::Post.new(uri.path)
31
- request["Content-Type"] = "application/json"
32
- request.body = result.to_json
33
-
34
- response = http.request(request)
35
-
36
- if response.code.to_i >= 200 && response.code.to_i < 300
37
- response
38
- else
39
- raise "HTTP Error: #{response.code}"
40
- end
41
- end
42
- end
43
-
44
- class Formatter
45
- def format(result)
46
- totals = Hash.new(0)
47
-
48
- source_files = result.files.map do |file|
49
- totals[:total] += file.lines.count
50
- totals[:covered] += file.covered_lines.count
51
- totals[:missed] += file.missed_lines.count
52
-
53
- {
54
- name: short_filename(file.filename),
55
- blob_id: calculate_blob_id(file.filename),
56
- coverage: file.coverage.to_json,
57
- covered_percent: file.covered_percent.round(2),
58
- covered_strength: file.covered_strength.round(2),
59
- line_counts: {
60
- total: file.lines.count,
61
- covered: file.covered_lines.count,
62
- missed: file.missed_lines.count
63
- }
64
- }
65
- end
66
-
67
- print "Coverage = #{result.covered_percent.round(2)}%. Sending report to #{API.host}... "
68
-
69
- API.post_results({
70
- repo_token: ENV["CODECLIMATE_REPO_TOKEN"],
71
- source_files: source_files,
72
- run_at: result.created_at,
73
- covered_percent: result.covered_percent.round(2),
74
- covered_strength: result.covered_strength.round(2),
75
- line_counts: totals,
76
- git: {
77
- head: `git log -1 --pretty=format:'%H'`,
78
- committed_at: committed_at,
79
- branch: git_branch,
80
- },
81
- environment: {
82
- test_framework: result.command_name.downcase,
83
- pwd: Dir.pwd,
84
- rails_root: (Rails.root.to_s rescue nil),
85
- simplecov_root: ::SimpleCov.root,
86
- gem_version: VERSION
87
- },
88
- ci_service: ci_service_data
89
- })
90
-
91
- puts "done."
92
- true
93
- rescue => ex
94
- puts "\nCode Climate encountered an exception: #{ex.class}"
95
- puts ex.message
96
- ex.backtrace.each do |line|
97
- puts line
98
- end
99
- false
100
- end
101
-
102
- def ci_service_data
103
- if ENV['TRAVIS']
104
- {
105
- name: "travis-ci",
106
- branch: ENV['TRAVIS_BRANCH'],
107
- build_identifier: ENV['TRAVIS_JOB_ID'],
108
- pull_request: ENV['TRAVIS_PULL_REQUEST']
109
- }
110
- elsif ENV['CIRCLECI']
111
- {
112
- name: "circlci",
113
- build_identifier: ENV['CIRCLE_BUILD_NUM'],
114
- branch: ENV['CIRCLE_BRANCH'],
115
- commit_sha: ENV['CIRCLE_SHA1']
116
- }
117
- elsif ENV['SEMAPHORE']
118
- {
119
- name: "semaphore",
120
- branch: ENV['BRANCH_NAME'],
121
- build_identifier: ENV['SEMAPHORE_BUILD_NUMBER']
122
- }
123
- elsif ENV['JENKINS_URL']
124
- {
125
- name: "jenkins",
126
- build_identifier: ENV['BUILD_NUMBER'],
127
- build_url: ENV['BUILD_URL'],
128
- branch: ENV['GIT_BRANCH'],
129
- commit_sha: ENV['GIT_COMMIT']
130
- }
131
- else
132
- {}
133
- end
134
- end
135
-
136
- def calculate_blob_id(path)
137
- content = File.open(path, "rb").read
138
- header = "blob #{content.length}\0"
139
- store = header + content
140
- Digest::SHA1.hexdigest(store)
141
- end
142
-
143
- def short_filename(filename)
144
- return filename unless ::SimpleCov.root
145
- filename.gsub(::SimpleCov.root, '.').gsub(/^\.\//, '')
146
- end
147
-
148
- def committed_at
149
- committed_at = `git log -1 --pretty=format:'%ct'`
150
- committed_at.to_i.zero? ? nil : committed_at.to_i
151
- end
152
-
153
- def git_branch
154
- branch = `git branch`.split("\n").delete_if { |i| i[0] != "*" }
155
- branch = [branch].flatten.first
156
- branch ? branch.gsub("* ","") : nil
157
- end
158
- end
159
-
160
- def self.start
161
- if run?
162
- require "simplecov"
163
- ::SimpleCov.add_filter 'vendor'
164
- ::SimpleCov.formatter = Formatter
165
- ::SimpleCov.start("test_frameworks")
166
- else
167
- puts("Not reporting to Code Climate because ENV['CODECLIMATE_REPO_TOKEN'] is not set.")
168
- end
169
- end
170
-
171
- def self.run?
172
- !!ENV["CODECLIMATE_REPO_TOKEN"]
173
- end
174
- end
175
- end
1
+ require 'code_climate/test_reporter'
2
+ require "code_climate/test_reporter/client"
3
+ require "code_climate/test_reporter/formatter"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: codeclimate-test-reporter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-07-28 00:00:00.000000000 Z
12
+ date: 2013-09-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: simplecov
@@ -69,7 +69,8 @@ description: Collects test coverage data from your Ruby test suite and sends it
69
69
  Code Climate's hosted, automated code review service. Based on SimpleCov.
70
70
  email:
71
71
  - bryan@brynary.com
72
- executables: []
72
+ executables:
73
+ - cc-tddium-post-worker
73
74
  extensions: []
74
75
  extra_rdoc_files: []
75
76
  files:
@@ -78,8 +79,12 @@ files:
78
79
  - LICENSE.txt
79
80
  - README.md
80
81
  - Rakefile
82
+ - bin/cc-tddium-post-worker
81
83
  - codeclimate-test-reporter.gemspec
82
84
  - config/cacert.pem
85
+ - lib/code_climate/test_reporter.rb
86
+ - lib/code_climate/test_reporter/client.rb
87
+ - lib/code_climate/test_reporter/formatter.rb
83
88
  - lib/codeclimate-test-reporter.rb
84
89
  - spec/spec_helper.rb
85
90
  homepage: ''
@@ -108,3 +113,4 @@ specification_version: 3
108
113
  summary: Uploads Ruby test coverage data to Code Climate.
109
114
  test_files:
110
115
  - spec/spec_helper.rb
116
+ has_rdoc: