rspec-tracer 0.7.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +198 -236
- data/lib/rspec_tracer/configuration.rb +12 -23
- data/lib/rspec_tracer/remote_cache/aws.rb +178 -0
- data/lib/rspec_tracer/remote_cache/cache.rb +36 -144
- data/lib/rspec_tracer/remote_cache/repo.rb +175 -0
- data/lib/rspec_tracer/remote_cache/validator.rb +52 -0
- data/lib/rspec_tracer/version.rb +1 -1
- metadata +6 -4
- data/lib/rspec_tracer/remote_cache/git.rb +0 -113
@@ -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
|
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
|
28
|
-
|
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
|
46
|
-
|
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
|
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
|
64
|
-
|
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
|
-
|
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,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 '
|
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
|
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
|
-
@
|
18
|
-
@
|
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
|
-
|
27
|
-
puts 'S3 URI is not configured'
|
28
|
-
|
29
|
-
return
|
30
|
-
end
|
18
|
+
return unless cache_ref?
|
31
19
|
|
32
|
-
|
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 "
|
23
|
+
puts "Error: #{e.message}"
|
24
|
+
puts e.backtrace.first(5).join("\n")
|
45
25
|
end
|
46
26
|
|
47
27
|
def upload
|
48
|
-
|
49
|
-
|
28
|
+
@aws.upload_file(@repo.branch_ref, 'last_run.json')
|
29
|
+
@aws.upload_dir(@repo.branch_ref, last_run_id)
|
50
30
|
|
51
|
-
|
52
|
-
end
|
31
|
+
file_name = File.join(RSpecTracer.cache_path, 'branch_refs.json')
|
53
32
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
puts "
|
58
|
-
|
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
|
65
|
-
|
66
|
-
@test_suites = ENV['TEST_SUITES']
|
42
|
+
def cache_ref?
|
43
|
+
cache_validator = RSpecTracer::RemoteCache::Validator.new
|
67
44
|
|
68
|
-
|
69
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
57
|
+
true
|
58
|
+
end
|
130
59
|
|
131
|
-
|
132
|
-
|
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
|
-
|
63
|
+
puts "Failed to find object #{@repo.branch_ref} commit timestamp" unless $CHILD_STATUS.success?
|
140
64
|
|
141
|
-
|
142
|
-
end
|
65
|
+
ref_list = @repo.branch_refs.merge(@repo.branch_ref => branch_ref_time.to_i)
|
143
66
|
|
144
|
-
|
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
|
-
|
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
|