rspec-tracer 0.6.2 → 0.9.1

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.
@@ -14,21 +14,18 @@ module RSpecTracer
14
14
  return @root if defined?(@root) && root.nil?
15
15
 
16
16
  @cache_path = nil
17
+ @report_path = nil
18
+ @coverage_path = nil
19
+
17
20
  @root = File.expand_path(root || Dir.getwd)
18
21
  end
19
22
 
20
- def project_name(proj_name = nil)
21
- return @project_name if defined?(@project_name) && proj_name.nil?
22
-
23
- @project_name = proj_name if proj_name.is_a?(String)
23
+ def project_name
24
24
  @project_name ||= File.basename(root).capitalize
25
25
  end
26
26
 
27
- def cache_dir(dir = nil)
28
- return @cache_dir if defined?(@cache_dir) && dir.nil?
29
-
30
- @cache_path = nil
31
- @cache_dir = dir || DEFAULT_CACHE_DIR
27
+ def cache_dir
28
+ @cache_dir ||= (ENV['RSPEC_TRACER_CACHE_DIR'] || DEFAULT_CACHE_DIR)
32
29
  end
33
30
 
34
31
  def cache_path
@@ -42,15 +39,12 @@ module RSpecTracer
42
39
  end
43
40
  end
44
41
 
45
- def report_dir(dir = nil)
46
- return @report_dir if defined?(@report_dir) && dir.nil?
47
-
48
- @report_path = nil
49
- @report_dir = dir || DEFAULT_REPORT_DIR
42
+ def report_dir
43
+ @report_dir ||= (ENV['RSPEC_TRACER_REPORT_DIR'] || DEFAULT_REPORT_DIR)
50
44
  end
51
45
 
52
46
  def report_path
53
- @report_path || begin
47
+ @report_path ||= begin
54
48
  report_path = File.expand_path(report_dir, root)
55
49
  report_path = File.join(report_path, ENV['TEST_SUITE_ID'].to_s)
56
50
 
@@ -60,11 +54,8 @@ module RSpecTracer
60
54
  end
61
55
  end
62
56
 
63
- def coverage_dir(dir = nil)
64
- return @coverage_dir if defined?(@coverage_dir) && dir.nil?
65
-
66
- @coverage_path = nil
67
- @coverage_dir = dir || DEFAULT_COVERAGE_DIR
57
+ def coverage_dir
58
+ @coverage_dir ||= (ENV['RSPEC_TRACER_COVERAGE_DIR'] || DEFAULT_COVERAGE_DIR)
68
59
  end
69
60
 
70
61
  def coverage_path
@@ -103,9 +94,7 @@ module RSpecTracer
103
94
  end
104
95
 
105
96
  def verbose?
106
- return @verbose if defined?(@verbose)
107
-
108
- @verbose = ENV.fetch('RSPEC_TRACER_VERBOSE', 'false') == 'true'
97
+ @verbose ||= (ENV.fetch('RSPEC_TRACER_VERBOSE', 'false') == 'true')
109
98
  end
110
99
 
111
100
  def configure(&block)
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :assets do
4
+ desc 'Compiles all assets'
5
+ task :precompile do
6
+ require 'sprockets'
7
+
8
+ assets = Sprockets::Environment.new do |env|
9
+ env.append_path 'assets/javascripts'
10
+ env.append_path 'assets/stylesheets'
11
+ env.js_compressor = :uglifier
12
+ env.css_compressor = :yui
13
+ end
14
+
15
+ assets['application.js'].write_to('public/application.js')
16
+ assets['application.css'].write_to('public/application.css')
17
+ end
18
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :rspec_tracer do
4
+ namespace :remote_cache do
5
+ desc 'Download cache'
6
+ task :download do
7
+ unless system('git', 'rev-parse', 'HEAD', out: File::NULL, err: File::NULL)
8
+ puts 'Not a git repository'
9
+
10
+ exit
11
+ end
12
+
13
+ require 'rspec_tracer'
14
+
15
+ RSpecTracer::RemoteCache::Cache.new.download
16
+ end
17
+
18
+ desc 'Upload cache'
19
+ task :upload do
20
+ unless system('git', 'rev-parse', 'HEAD', out: File::NULL, err: File::NULL)
21
+ puts 'Not a git repository'
22
+
23
+ exit
24
+ end
25
+
26
+ unless ENV.fetch('CI', 'false') == 'true' || ENV.fetch('RSPEC_TRACER_UPLOAD_LOCAL_CACHE', 'false') == 'true'
27
+ puts 'Skipping upload from local development environment'
28
+ puts 'Use RSPEC_TRACER_UPLOAD_LOCAL_CACHE=true to upload local cache'
29
+
30
+ exit
31
+ end
32
+
33
+ require 'rspec_tracer'
34
+
35
+ RSpecTracer::RemoteCache::Cache.new.upload
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,178 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RSpecTracer
4
+ module RemoteCache
5
+ class Aws
6
+ class AwsError < StandardError; end
7
+
8
+ def initialize
9
+ @s3_bucket, @s3_path = setup_s3
10
+ @aws_cli = setup_aws_cli
11
+ end
12
+
13
+ def branch_refs?(branch_name)
14
+ key = "#{@s3_path}/branch-refs/#{branch_name}/branch_refs.json"
15
+
16
+ system(
17
+ @aws_cli,
18
+ 's3api',
19
+ 'head-object',
20
+ '--bucket',
21
+ @s3_bucket,
22
+ '--key',
23
+ key,
24
+ out: File::NULL,
25
+ err: File::NULL
26
+ )
27
+ end
28
+
29
+ def download_branch_refs(branch_name, file_name)
30
+ key = "#{@s3_path}/branch-refs/#{branch_name}/branch_refs.json"
31
+
32
+ system(
33
+ @aws_cli,
34
+ 's3api',
35
+ 'get-object',
36
+ '--bucket',
37
+ @s3_bucket,
38
+ '--key',
39
+ key,
40
+ file_name,
41
+ out: File::NULL,
42
+ err: File::NULL
43
+ )
44
+ end
45
+
46
+ def upload_branch_refs(branch_name, file_name)
47
+ remote_path = "s3://#{@s3_bucket}/#{@s3_path}/branch-refs/#{branch_name}/branch_refs.json"
48
+
49
+ raise AwsError, "Failed to upload branch refs for #{branch_name} branch" unless system(
50
+ @aws_cli,
51
+ 's3',
52
+ 'cp',
53
+ file_name,
54
+ remote_path,
55
+ out: File::NULL,
56
+ err: File::NULL
57
+ )
58
+
59
+ puts "Uploaded branch refs for #{branch_name} branch to #{remote_path}"
60
+ end
61
+
62
+ def cache_files_list(ref)
63
+ prefix = "s3://#{@s3_bucket}/#{@s3_path}/#{ref}/"
64
+
65
+ `#{@aws_cli} s3 ls #{prefix} --recursive`.chomp.split("\n")
66
+ end
67
+
68
+ def download_file(ref, file_name)
69
+ remote_path = File.join(s3_dir(ref), file_name)
70
+ local_path = File.join(RSpecTracer.cache_path, file_name)
71
+
72
+ raise AwsError, "Failed to download file #{remote_path}" unless system(
73
+ @aws_cli,
74
+ 's3',
75
+ 'cp',
76
+ remote_path,
77
+ local_path,
78
+ out: File::NULL,
79
+ err: File::NULL
80
+ )
81
+
82
+ puts "Downloaded file #{remote_path} to #{local_path}"
83
+ end
84
+
85
+ def download_dir(ref, run_id)
86
+ remote_dir = s3_dir(ref, run_id)
87
+ local_dir = File.join(RSpecTracer.cache_path, run_id)
88
+
89
+ raise AwsError, "Failed to download files from #{remote_dir}" unless system(
90
+ @aws_cli,
91
+ 's3',
92
+ 'cp',
93
+ remote_dir,
94
+ local_dir,
95
+ '--recursive',
96
+ out: File::NULL,
97
+ err: File::NULL
98
+ )
99
+
100
+ puts "Downloaded cache files from #{remote_dir} to #{local_dir}"
101
+ rescue AwsError => e
102
+ FileUtils.rm_rf(local_dir)
103
+
104
+ raise e
105
+ end
106
+
107
+ def upload_file(ref, file_name)
108
+ remote_path = File.join(s3_dir(ref), file_name)
109
+ local_path = File.join(RSpecTracer.cache_path, file_name)
110
+
111
+ raise AwsError, "Failed to upload file #{local_path}" unless system(
112
+ @aws_cli,
113
+ 's3',
114
+ 'cp',
115
+ local_path,
116
+ remote_path,
117
+ out: File::NULL,
118
+ err: File::NULL
119
+ )
120
+
121
+ puts "Uploaded file #{local_path} to #{remote_path}"
122
+ end
123
+
124
+ def upload_dir(ref, run_id)
125
+ remote_dir = s3_dir(ref, run_id)
126
+ local_dir = File.join(RSpecTracer.cache_path, run_id)
127
+
128
+ raise AwsError, "Failed to download files from #{local_dir}" unless system(
129
+ @aws_cli,
130
+ 's3',
131
+ 'cp',
132
+ local_dir,
133
+ remote_dir,
134
+ '--recursive',
135
+ out: File::NULL,
136
+ err: File::NULL
137
+ )
138
+
139
+ puts "Uploaded files from #{local_dir} to #{remote_dir}"
140
+ end
141
+
142
+ private
143
+
144
+ def setup_s3
145
+ s3_uri = ENV['RSPEC_TRACER_S3_URI']
146
+
147
+ raise AwsError, 'RSPEC_TRACER_S3_URI environment variable is not set' if s3_uri.nil?
148
+
149
+ uri_parts = s3_uri[4..-1].split('/')
150
+
151
+ raise AwsError, "Invalid S3 URI #{s3_uri}" unless uri_parts.length >= 3 && uri_parts.first.empty?
152
+
153
+ [
154
+ uri_parts[1],
155
+ uri_parts[2..-1].join('/')
156
+ ]
157
+ end
158
+
159
+ def setup_aws_cli
160
+ if ENV.fetch('LOCAL_AWS', 'false') == 'true'
161
+ 'awslocal'
162
+ else
163
+ 'aws'
164
+ end
165
+ end
166
+
167
+ def s3_dir(ref, run_id = nil)
168
+ test_suite_id = ENV['TEST_SUITE_ID']
169
+
170
+ if test_suite_id.nil?
171
+ "s3://#{@s3_bucket}/#{@s3_path}/#{ref}/#{run_id}/".sub(%r{/+$}, '/')
172
+ else
173
+ "s3://#{@s3_bucket}/#{@s3_path}/#{ref}/#{test_suite_id}/#{run_id}/".sub(%r{/+$}, '/')
174
+ end
175
+ end
176
+ end
177
+ end
178
+ end
@@ -1,186 +1,78 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'git'
3
+ require_relative 'aws'
4
+ require_relative 'repo'
5
+ require_relative 'validator'
4
6
 
5
7
  module RSpecTracer
6
8
  module RemoteCache
7
9
  class Cache
8
- class CacheDownloadError < StandardError; end
9
-
10
- class CacheUploadError < StandardError; end
11
-
12
- class LocalCacheNotFoundError < StandardError; end
13
-
14
- CACHE_FILES_PER_TEST_SUITE = 8
10
+ class CacheError < StandardError; end
15
11
 
16
12
  def initialize
17
- @s3_uri = ENV['RSPEC_TRACER_S3_URI']
18
- @aws_s3 = if ENV.fetch('LOCAL_AWS', 'false') == 'true'
19
- 'awslocal'
20
- else
21
- 'aws'
22
- end
13
+ @aws = RSpecTracer::RemoteCache::Aws.new
14
+ @repo = RSpecTracer::RemoteCache::Repo.new(@aws)
23
15
  end
24
16
 
25
17
  def download
26
- if @s3_uri.nil?
27
- puts 'S3 URI is not configured'
28
-
29
- return
30
- end
18
+ return unless cache_ref?
31
19
 
32
- prepare_for_download
33
-
34
- if @cache_sha.nil?
35
- puts 'Could not find a suitable cache sha to download'
36
-
37
- return
38
- end
39
-
40
- download_files
41
-
42
- puts "Downloaded cache from #{@download_prefix} to #{@download_path}"
20
+ @aws.download_file(@cache_sha, 'last_run.json')
21
+ @aws.download_dir(@cache_sha, last_run_id)
43
22
  rescue StandardError => e
44
- puts "Errored: #{e.message}"
23
+ puts "Error: #{e.message}"
24
+ puts e.backtrace.first(5).join("\n")
45
25
  end
46
26
 
47
27
  def upload
48
- if @s3_uri.nil?
49
- puts 'S3 URI is not configured'
28
+ @aws.upload_file(@repo.branch_ref, 'last_run.json')
29
+ @aws.upload_dir(@repo.branch_ref, last_run_id)
50
30
 
51
- return
52
- end
31
+ file_name = File.join(RSpecTracer.cache_path, 'branch_refs.json')
53
32
 
54
- prepare_for_upload
55
- upload_files
56
-
57
- puts "Uploaded cache from #{@upload_path} to #{@upload_prefix}"
58
- rescue CacheUploadError => e
59
- puts "Errored: #{e.message}"
33
+ write_branch_refs(file_name)
34
+ @aws.upload_branch_refs(@repo.branch_name, file_name)
35
+ rescue StandardError => e
36
+ puts "Error: #{e.message}"
37
+ puts e.backtrace.first(5).join("\n")
60
38
  end
61
39
 
62
40
  private
63
41
 
64
- def prepare_for_download
65
- @test_suite_id = ENV['TEST_SUITE_ID']
66
- @test_suites = ENV['TEST_SUITES']
42
+ def cache_ref?
43
+ cache_validator = RSpecTracer::RemoteCache::Validator.new
67
44
 
68
- if @test_suite_id.nil? ^ @test_suites.nil?
69
- raise(
70
- CacheDownloadError,
71
- 'Both the enviornment variables TEST_SUITE_ID and TEST_SUITES are not set'
72
- )
73
- end
74
-
75
- @git = RSpecTracer::RemoteCache::Git.new
76
- @git.prepare_for_download
45
+ @cache_sha = @repo.cache_refs.each_key.detect do |ref|
46
+ puts "Validating ref #{ref}"
77
47
 
78
- generate_cached_files_count_and_regex
79
-
80
- @cache_sha = nearest_cache_sha
81
- end
82
-
83
- def generate_cached_files_count_and_regex
84
- if @test_suites.nil?
85
- @last_run_files_count = 1
86
- @last_run_files_regex = '/%<ref>s/last_run.json$'
87
- @cached_files_count = CACHE_FILES_PER_TEST_SUITE
88
- @cached_files_regex = '/%<ref>s/[0-9a-f]{32}/.+.json'
89
- else
90
- @test_suites = @test_suites.to_i
91
- @test_suites_regex = (1..@test_suites).to_a.join('|')
92
-
93
- @last_run_files_count = @test_suites
94
- @last_run_files_regex = "/%<ref>s/(#{@test_suites_regex})/last_run.json$"
95
- @cached_files_count = CACHE_FILES_PER_TEST_SUITE * @test_suites.to_i
96
- @cached_files_regex = "/%<ref>s/(#{@test_suites_regex})/[0-9a-f]{32}/.+.json$"
48
+ cache_validator.valid?(ref, @aws.cache_files_list(ref))
97
49
  end
98
- end
99
-
100
- def nearest_cache_sha
101
- @git.ref_list.detect do |ref|
102
- prefix = "#{@s3_uri}/#{ref}/"
103
-
104
- puts "Testing prefix #{prefix}"
105
-
106
- objects = `#{@aws_s3} s3 ls #{prefix} --recursive`.chomp.split("\n")
107
50
 
108
- last_run_regex = Regexp.new(format(@last_run_files_regex, ref: ref))
109
-
110
- next if objects.count { |object| object.match?(last_run_regex) } != @last_run_files_count
111
-
112
- cache_regex = Regexp.new(format(@cached_files_regex, ref: ref))
51
+ if @cache_sha.nil?
52
+ puts 'Could not find a suitable cache sha to download'
113
53
 
114
- objects.count { |object| object.match?(cache_regex) } == @cached_files_count
54
+ return false
115
55
  end
116
- end
117
-
118
- def download_files
119
- @download_prefix = "#{@s3_uri}/#{@cache_sha}/#{@test_suite_id}/".sub(%r{/+$}, '/')
120
- @download_path = RSpecTracer.cache_path
121
-
122
- raise CacheDownloadError, 'Failed to download cache files' unless system(
123
- @aws_s3, 's3', 'cp',
124
- File.join(@download_prefix, 'last_run.json'),
125
- @download_path,
126
- out: File::NULL, err: File::NULL
127
- )
128
56
 
129
- @run_id = last_run_id
57
+ true
58
+ end
130
59
 
131
- return if system(
132
- @aws_s3, 's3', 'cp',
133
- File.join(@download_prefix, @run_id),
134
- File.join(@download_path, @run_id),
135
- '--recursive',
136
- out: File::NULL, err: File::NULL
137
- )
60
+ def write_branch_refs(file_name)
61
+ branch_ref_time = `git show --no-patch --format="%ct" #{@repo.branch_ref}`.chomp
138
62
 
139
- FileUtils.rm_rf(@download_path)
63
+ puts "Failed to find object #{@repo.branch_ref} commit timestamp" unless $CHILD_STATUS.success?
140
64
 
141
- raise CacheDownloadError, 'Failed to download cache files'
142
- end
65
+ ref_list = @repo.branch_refs.merge(@repo.branch_ref => branch_ref_time.to_i)
143
66
 
144
- def prepare_for_upload
145
- @git = RSpecTracer::RemoteCache::Git.new
146
- @test_suite_id = ENV['TEST_SUITE_ID']
147
- @upload_prefix = if @test_suite_id.nil?
148
- "#{@s3_uri}/#{@git.branch_ref}/"
149
- else
150
- "#{@s3_uri}/#{@git.branch_ref}/#{@test_suite_id}/"
151
- end
152
-
153
- @upload_path = RSpecTracer.cache_path
154
- @run_id = last_run_id
155
- end
156
-
157
- def upload_files
158
- return if system(
159
- @aws_s3, 's3', 'cp',
160
- File.join(@upload_path, 'last_run.json'),
161
- @upload_prefix,
162
- out: File::NULL, err: File::NULL
163
- ) && system(
164
- @aws_s3, 's3', 'cp',
165
- File.join(@upload_path, @run_id),
166
- File.join(@upload_prefix, @run_id),
167
- '--recursive',
168
- out: File::NULL, err: File::NULL
169
- )
170
-
171
- raise CacheUploadError, 'Failed to upload cache files'
67
+ File.write(file_name, JSON.pretty_generate(ref_list))
172
68
  end
173
69
 
174
70
  def last_run_id
175
71
  file_name = File.join(RSpecTracer.cache_path, 'last_run.json')
176
72
 
177
- return unless File.file?(file_name)
178
-
179
- run_id = JSON.parse(File.read(file_name))['run_id']
180
-
181
- raise LocalCacheNotFoundError, 'Could not find any local cache to upload' if run_id.nil?
73
+ raise CacheError, 'Could not find any local cache to upload' unless File.file?(file_name)
182
74
 
183
- run_id
75
+ JSON.parse(File.read(file_name))['run_id']
184
76
  end
185
77
  end
186
78
  end