simplecov-s3 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ .DS_Store
2
+ *.gem
3
+ .bundle
4
+ Gemfile.lock
5
+ EYIntegratedGemfile.lock
6
+ pkg/*
7
+ .rvmrc
8
+ coverage
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --format documentation --colour
data/.travis.yml ADDED
@@ -0,0 +1,24 @@
1
+ ---
2
+ git:
3
+ depth: 1
4
+
5
+ notifications:
6
+ email: false
7
+ webhooks:
8
+ urls:
9
+ - https://ensemble.engineyard.com/travis
10
+ on_success: always
11
+ on_failure: always
12
+ on_start: true
13
+
14
+ before_script:
15
+ - echo "--profile --color" > '.rspec' # Report slowest ten tests, make it pretty
16
+
17
+ script: bundle exec rake
18
+
19
+ env:
20
+ global:
21
+ - RUBY_GC_MALLOC_LIMIT=1000000000
22
+ - RUBY_HEAP_SLOTS_GROWTH_FACTOR=1.25
23
+ - RUBY_HEAP_MIN_SLOTS=800000
24
+ - RUBY_FREE_MIN=600000
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ group :test do
6
+ gem 'rake'
7
+ gem 'pry'
8
+ end
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2013 Engine Yard
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,87 @@
1
+ # Simplecov-S3
2
+
3
+ Sample Usage:
4
+
5
+ config/environment.rb
6
+
7
+ require File.expand_path('../application', __FILE__)
8
+
9
+ if Rails.env.test?
10
+ require File.expand_path("../../spec/coverage_helper", __FILE__)
11
+ end
12
+
13
+ coverage_helper.rb
14
+
15
+ unless ENV["SKIP_COVERAGE"]
16
+ require 'simplecov'
17
+ SimpleCov.start(:rails)
18
+ SimpleCov.formatter = SimpleCov::Formatter::HTMLFormatter
19
+ SimpleCov.at_exit do
20
+ SimpleCov.result.format!
21
+ end
22
+ SimpleCov.command_name("HAX#{Time.now.to_i}")
23
+ SimpleCov.merge_timeout 86400
24
+ end
25
+
26
+ Rakefile
27
+
28
+ task :coverage do
29
+ build_units = YAML.load_file(File.expand_path("../build_units.yml",__FILE__)).size
30
+ require File.expand_path("../spec/coverage_helper", __FILE__)
31
+ cov = SimpleCov::S3.new(
32
+ :fog => {
33
+ :provider => 'AWS',
34
+ :aws_access_key_id => "XXXXXX",
35
+ :aws_secret_access_key => "XXXXXXXXXXXXX",
36
+ :region => "us-east-1",
37
+ },
38
+ :project_name => ENV["TRAVIS_REPO_SLUG"],
39
+ :build_id => ENV["TRAVIS_BUILD_ID"],
40
+ :job_id => ENV["TRAVIS_JOB_ID"],
41
+ :build_unit => ENV["BUILD_UNIT"],
42
+ :build_units => build_units,
43
+ :bucket_name => "somebucket",
44
+ :public_url_base => "http://somebucket.s3-website-us-east-1.amazonaws.com/",
45
+ :assets_url => "http://somebucket.s3-website-us-east-1.amazonaws.com/assets",
46
+ :shared_secret => "XXXXXXXXXXXX", #used so build units can find each other, and for covereage postback
47
+ :postback_url => "https://bot.example.org/coverage",
48
+ )
49
+ cov.push_partial(:debug => true)
50
+ cov.pull_merge_and_push_full
51
+ end
52
+
53
+ Sample S3 Bucket policy to allow the "<user>" user of from the Amazon Account ID "<awsaccount>" access to read/write from the "<bucket>" bucket, while the public is allowed read-only:
54
+
55
+ {
56
+ "Version": "2008-10-17",
57
+ "Id": "Policy123456",
58
+ "Statement": [
59
+ {
60
+ "Sid": "Stmt11111",
61
+ "Effect": "Allow",
62
+ "Principal": {
63
+ "AWS": "arn:aws:iam::<awsaccount>:user/<user>"
64
+ },
65
+ "Action": "s3:*",
66
+ "Resource": "arn:aws:s3:::<bucket>"
67
+ },
68
+ {
69
+ "Sid": "Stmt222222",
70
+ "Effect": "Allow",
71
+ "Principal": {
72
+ "AWS": "arn:aws:iam::<awsaccount>:user/<user>"
73
+ },
74
+ "Action": "s3:*",
75
+ "Resource": "arn:aws:s3:::<bucket>/*"
76
+ },
77
+ {
78
+ "Sid": "Stmt33333",
79
+ "Effect": "Allow",
80
+ "Principal": {
81
+ "AWS": "*"
82
+ },
83
+ "Action": "s3:GetObject",
84
+ "Resource": "arn:aws:s3:::<bucket>/*"
85
+ }
86
+ ]
87
+ }
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'rspec/core/rake_task'
2
+
3
+ desc 'Default: run specs.'
4
+ task :default => :spec
5
+
6
+ desc "Run specs"
7
+ RSpec::Core::RakeTask.new do |t|
8
+ # Put spec opts in a file named .rspec in root
9
+ end
@@ -0,0 +1,141 @@
1
+ require 'digest'
2
+ require 'securerandom'
3
+ require 'excon'
4
+ require 'fog'
5
+ require 'simplecov'
6
+ require 'json'
7
+
8
+ module SimpleCov
9
+ class S3
10
+
11
+ def self.ensured(task_to_invoke, &block)
12
+ Rake::Task[task_to_invoke].invoke
13
+ ensure
14
+ begin
15
+ yield
16
+ rescue => e
17
+ puts e.inspect
18
+ puts e.backtrace
19
+ end
20
+ end
21
+
22
+ class Formatter < SimpleCov::Formatter::HTMLFormatter
23
+ #an ugly partial-copy from: https://github.com/colszowka/simplecov-html/blob/master/lib/simplecov-html.rb
24
+ def format(result)
25
+ template('layout').result(binding)
26
+ end
27
+ end
28
+
29
+ def initialize(opts)
30
+ @connection = Fog::Storage.new(opts[:fog])
31
+ @public_url_base = opts[:public_url_base]
32
+ @shared_secret = opts[:shared_secret]
33
+ @assets_url = opts[:assets_url]
34
+ @bucket_name = opts[:bucket_name]
35
+ @build_units = opts[:build_units]
36
+ @postback_url = opts[:postback_url]
37
+ @build_unit = opts[:build_unit]
38
+ @build_id = opts[:build_id]
39
+ @job_id = opts[:job_id]
40
+ @project_name = opts[:project_name]
41
+ end
42
+
43
+ def push_partial(opts = {})
44
+ begin
45
+ result = SimpleCov::ResultMerger.merged_result
46
+ data_to_push = result.original_result.merge("BUILD_UNIT" => @build_unit).to_json
47
+ put_file("#{@project_name}-#{commit_time}-coverageJSON/#{hashed_build_id}/#{@job_id}", data_to_push)
48
+ rescue => e
49
+ puts e.inspect
50
+ puts e.backtrace
51
+ puts "SOMEHTING WENT WRONG, PUSHING EMPTY COVERAGE FILE"
52
+ put_file("#{@project_name}-#{commit_time}-coverageJSON/#{hashed_build_id}/#{@job_id}", {}.to_json)
53
+ end
54
+ if opts[:debug]
55
+ debug_folder = "#{@project_name}-#{Time.now.to_i}-coverageDEBUG/#{hashed_build_id}-#{@job_id}"
56
+ push_coverage_to(debug_folder, gen_body(result))
57
+ end
58
+ end
59
+
60
+ def pull_merge_and_push_full
61
+ if(json_files.size < @build_units)
62
+ puts "Expected to see #{@build_units} files"
63
+ puts "currently only #{json_files.size}"
64
+ require 'pp'
65
+ pp json_files.map(&:key)
66
+ puts "Assuming some other build unit will be the last to exit, and merge/post full coverage"
67
+ return false
68
+ end
69
+ puts "Coverage combined from #{json_files.size} units"
70
+ results = []
71
+ included_units = []
72
+ json_files.each do |f|
73
+ parsed = JSON.parse(f.body)
74
+ included_units << parsed.delete("BUILD_UNIT")
75
+ results << SimpleCov::Result.new(parsed)
76
+ end
77
+ puts "Included units: #{included_units.sort_by(&:to_s).inspect}"
78
+ merged = {}
79
+ results.each do |result|
80
+ merged = result.original_result.merge_resultset(merged)
81
+ end
82
+ result = SimpleCov::Result.new(merged)
83
+ push_coverage_to("#{@project_name}-#{Time.now.to_i}-coverageRESULT/#{SecureRandom.urlsafe_base64(33)}", gen_body(result), result.covered_percent, @postback_url)
84
+ end
85
+
86
+ def push_full
87
+ result = SimpleCov::ResultMerger.merged_result
88
+ push_coverage_to("#{@project_name}-#{Time.now.to_i}-coverageRESULT/#{SecureRandom.urlsafe_base64(33)}", gen_body(result), result.covered_percent, @postback_url)
89
+ end
90
+
91
+ private
92
+
93
+ def put_file(path, data)
94
+ puts "Putting to #{path} data size #{data.size}"
95
+ @connection.directories.get(@bucket_name).files.create(:key => path, :body => data, :content_type => "text/html")
96
+ end
97
+
98
+ def json_files
99
+ expected_dir = "#{@project_name}-#{commit_time}-coverageJSON/#{hashed_build_id}/"
100
+ @connection.directories.get(@bucket_name, :prefix => expected_dir).files
101
+ end
102
+
103
+ def gen_body(result)
104
+ Formatter.new.format(result).gsub("./assets",@assets_url)
105
+ end
106
+
107
+ def push_coverage_to(folder, data, covered_percent = nil, postback_url = false)
108
+ coverage_url = "#{@public_url_base}#{folder}"
109
+ puts "Pushing full coverage to #{coverage_url}"
110
+ put_file("#{folder}/index.html", data)
111
+ if postback_url
112
+ puts "Postback coverage_url to #{postback_url}"
113
+ coverage_percentage = "#{covered_percent.round(2)}"
114
+ travis_id = @build_id
115
+ signature = Digest::SHA1.hexdigest([coverage_url, coverage_percentage, travis_id, @shared_secret].join("."))
116
+ post_params = {
117
+ 'coverage_url' => coverage_url,
118
+ 'coverage_percentage' => coverage_percentage,
119
+ 'travis_id' => travis_id,
120
+ 'signature' => signature,
121
+ }
122
+ puts "post params: " + post_params.inspect
123
+ result = Excon.post(postback_url,
124
+ :body => URI.encode_www_form(post_params),
125
+ :headers => { "Content-Type" => "application/x-www-form-urlencoded" })
126
+ puts result.inspect
127
+ end
128
+ end
129
+
130
+ def commit_time
131
+ @commit_time ||= DateTime.parse(`git show | grep Date`.gsub("Date:","").strip).strftime("%s")
132
+ end
133
+
134
+ def hashed_build_id
135
+ @hashed_build_id ||= begin
136
+ Digest::SHA1.hexdigest(@build_id + @shared_secret)
137
+ end
138
+ end
139
+
140
+ end
141
+ end
@@ -0,0 +1,5 @@
1
+ module SimpleCov
2
+ class S3
3
+ VERSION = "0.1.1"
4
+ end
5
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "simplecov-s3/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "simplecov-s3"
7
+ s.version = SimpleCov::S3::VERSION
8
+ s.authors = ["Jacob"]
9
+ s.email = ["jacob@engineyard.com"]
10
+ s.homepage = "https://github.com/engineyard/simplecov-s3"
11
+ s.summary = %q{Merge simplecov outputs using S3 as shared storage (and publish the results as html to S3)}
12
+ s.description = %q{Merge simplecov outputs using S3 as shared storage (and publish the results as html to S3) (works best with travis)}
13
+
14
+ s.files = (`git ls-files`.split("\n") - `git ls-files -- fake`.split("\n"))
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ["lib"]
18
+
19
+ s.add_development_dependency 'rspec'
20
+ s.add_dependency "fog"
21
+ s.add_dependency 'simplecov'
22
+ end
data/spec/a_spec.rb ADDED
@@ -0,0 +1,44 @@
1
+ require 'simplecov-s3'
2
+ require 'rspec'
3
+ require 'pry'
4
+
5
+ describe SimpleCov::S3 do
6
+
7
+ it "is just barely tested" do
8
+ Fog.mock!
9
+ def Excon.post(*args)
10
+ puts "Mocked!"
11
+ end
12
+ #TODO: generate some coverage data via SimpleCov.start ?
13
+ fog_opts = {
14
+ :provider => 'AWS',
15
+ :aws_access_key_id => "XXXXXX",
16
+ :aws_secret_access_key => "XXXXXXXXXXXXX",
17
+ :region => "us-east-1",
18
+ }
19
+ s3conn = Fog::Storage.new(fog_opts)
20
+ s3conn.directories.create(:key => "somebucket")
21
+ cov_opts = {
22
+ :fog => fog_opts,
23
+ :project_name => "ey/simplecov-s3", #ENV["TRAVIS_REPO_SLUG"],
24
+ :build_id => "123", #ENV["TRAVIS_BUILD_ID"],
25
+ :job_id => "456", #ENV["TRAVIS_JOB_ID"],
26
+ :build_unit => "5", #ENV["BUILD_UNIT"],
27
+ :build_units => 2,
28
+ :bucket_name => "somebucket",
29
+ :public_url_base => "http://somebucket.s3-website-us-east-1.amazonaws.com/",
30
+ :assets_url => "http://somebucket.s3-website-us-east-1.amazonaws.com/assets",
31
+ :shared_secret => "XXXXXXXXXXXX", #used so build units can find each other, and for covereage postback
32
+ :postback_url => "https://bot.example.org/coverage",
33
+ }
34
+ cov = SimpleCov::S3.new(cov_opts)
35
+ cov.push_partial(:debug => true)
36
+ cov.pull_merge_and_push_full
37
+ cov2 = SimpleCov::S3.new(cov_opts.merge(:job_id => "457", :build_unit => "6"))
38
+ cov2.push_partial(:debug => true)
39
+ cov2.pull_merge_and_push_full
40
+ cov2.push_full
41
+ #TODO: assert on the resulting contents of S3?
42
+ end
43
+
44
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simplecov-s3
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jacob
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-08-07 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: fog
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: simplecov
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: Merge simplecov outputs using S3 as shared storage (and publish the results
63
+ as html to S3) (works best with travis)
64
+ email:
65
+ - jacob@engineyard.com
66
+ executables: []
67
+ extensions: []
68
+ extra_rdoc_files: []
69
+ files:
70
+ - .gitignore
71
+ - .rspec
72
+ - .travis.yml
73
+ - Gemfile
74
+ - LICENSE
75
+ - README.md
76
+ - Rakefile
77
+ - lib/simplecov-s3.rb
78
+ - lib/simplecov-s3/version.rb
79
+ - simplecov-s3.gemspec
80
+ - spec/a_spec.rb
81
+ homepage: https://github.com/engineyard/simplecov-s3
82
+ licenses: []
83
+ post_install_message:
84
+ rdoc_options: []
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ! '>='
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ requirements: []
100
+ rubyforge_project:
101
+ rubygems_version: 1.8.25
102
+ signing_key:
103
+ specification_version: 3
104
+ summary: Merge simplecov outputs using S3 as shared storage (and publish the results
105
+ as html to S3)
106
+ test_files:
107
+ - spec/a_spec.rb
108
+ has_rdoc: