travis-artifacts 0.1.0 → 0.2.0
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 +7 -0
- data/.gitignore +2 -0
- data/Gemfile +1 -1
- data/README.md +26 -0
- data/bin/travis-artifacts +1 -4
- data/lib/travis/artifacts/cli.rb +6 -1
- data/lib/travis/artifacts/uploader.rb +17 -3
- data/spec/travis/artifacts/cli_spec.rb +49 -1
- data/spec/travis/artifacts/uploader_spec.rb +61 -9
- data/travis-artifacts.gemspec +5 -4
- metadata +35 -32
- data/Gemfile.lock +0 -52
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6f1e65f3bfb2d7b4a648352fd2ea57c6320d8ee1
|
4
|
+
data.tar.gz: f5e6ef0dc3118f5a47bd4816d35fb66b48212c83
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: da865e2b1fb54254ddf5ba80b1c1e38f9a55e6adfae5e64bd1d8a11fe8c7f654bca2c3bcea81c701b088a673b417657a8f2a5534fe29b6dc395e579dd694f0ad
|
7
|
+
data.tar.gz: d80ba3a8d339b3ba3de30e7c21ecca50ba5600eca933f27cf054b058da17078cf0072cb2e61f4c35f03fd05282fd1a0ce86d2475cffd532d771c6302d1bf0f37
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -6,3 +6,29 @@ easily upload them to Amazon S3.
|
|
6
6
|
See the Travis blog for more:
|
7
7
|
|
8
8
|
http://about.travis-ci.org/blog/2012-12-18-travis-artifacts/
|
9
|
+
|
10
|
+
## The minimum AWS policy needed for the gem to work
|
11
|
+
|
12
|
+
{
|
13
|
+
"Statement": [
|
14
|
+
{
|
15
|
+
"Action": [
|
16
|
+
"s3:ListBucket"
|
17
|
+
],
|
18
|
+
"Effect": "Allow",
|
19
|
+
"Resource": [
|
20
|
+
"arn:aws:s3:::your-bucket"
|
21
|
+
]
|
22
|
+
},
|
23
|
+
{
|
24
|
+
"Action": [
|
25
|
+
"s3:PutObject",
|
26
|
+
"s3:PutObjectAcl"
|
27
|
+
],
|
28
|
+
"Effect": "Allow",
|
29
|
+
"Resource": [
|
30
|
+
"arn:aws:s3:::your-bucket/*"
|
31
|
+
]
|
32
|
+
}
|
33
|
+
]
|
34
|
+
}
|
data/bin/travis-artifacts
CHANGED
data/lib/travis/artifacts/cli.rb
CHANGED
@@ -37,9 +37,10 @@ module Travis::Artifacts
|
|
37
37
|
def execute_command
|
38
38
|
if VALID_COMMANDS.include? command
|
39
39
|
send(command)
|
40
|
+
return 0
|
40
41
|
else
|
41
42
|
STDERR.puts 'Could not find command'
|
42
|
-
|
43
|
+
return 1
|
43
44
|
end
|
44
45
|
end
|
45
46
|
|
@@ -79,6 +80,10 @@ module Travis::Artifacts
|
|
79
80
|
options[:target_path] = target_path
|
80
81
|
end
|
81
82
|
|
83
|
+
opt.on('--clone-path CLONE_PATH', 'path to clone uploaded files to') do |clone_path|
|
84
|
+
options[:clone_path] = clone_path
|
85
|
+
end
|
86
|
+
|
82
87
|
opt.on('--root ROOT', 'root directory for relative paths') do |root|
|
83
88
|
options[:root] = root
|
84
89
|
end
|
@@ -5,13 +5,14 @@ module Travis::Artifacts
|
|
5
5
|
class Uploader
|
6
6
|
include Travis::Artifacts::Logger
|
7
7
|
|
8
|
-
attr_reader :paths, :target_path
|
8
|
+
attr_reader :paths, :target_path, :clone_path
|
9
9
|
|
10
10
|
def initialize(paths, options = {})
|
11
11
|
@paths = paths
|
12
12
|
@test = Test.new
|
13
13
|
@public = ! (options[:private]||false)
|
14
14
|
@target_path = options[:target_path] || "artifacts/#{@test.build_number}/#{@test.job_number}"
|
15
|
+
@clone_path = options[:clone_path]
|
15
16
|
@cache_control = !@public ? 'private' : options[:cache_control] || 'public, max-age=315360000'
|
16
17
|
end
|
17
18
|
|
@@ -76,9 +77,21 @@ module Travis::Artifacts
|
|
76
77
|
end
|
77
78
|
end
|
78
79
|
|
79
|
-
def
|
80
|
-
|
80
|
+
def _clone(s3_source_path, filename)
|
81
|
+
clone_destination = File.join(clone_path, filename).sub(/^\//, '')
|
82
|
+
logger.info "Cloning to #{clone_destination}, public: #{@public}"
|
83
|
+
|
84
|
+
bucket.files.create({
|
85
|
+
:key => clone_destination,
|
86
|
+
:public => @public,
|
87
|
+
:body => '',
|
88
|
+
:metadata => { 'etag'=>'', 'x-amz-copy-source' => "#{Travis::Artifacts.bucket_name}/#{s3_source_path}" }
|
89
|
+
})
|
90
|
+
end
|
91
|
+
|
81
92
|
|
93
|
+
def _upload(file)
|
94
|
+
destination = File.join(target_path, file.destination).sub(/^\//, '')
|
82
95
|
logger.info "Uploading file #{file.source} to #{destination}, public: #{@public}"
|
83
96
|
|
84
97
|
bucket.files.create({
|
@@ -88,6 +101,7 @@ module Travis::Artifacts
|
|
88
101
|
:content_type => file.content_type,
|
89
102
|
:metadata => { "Cache-Control" => @cache_control }
|
90
103
|
})
|
104
|
+
_clone(destination, file.destination) unless clone_path.nil?
|
91
105
|
end
|
92
106
|
|
93
107
|
private
|
@@ -26,7 +26,7 @@ module Travis::Artifacts
|
|
26
26
|
end
|
27
27
|
|
28
28
|
it 'calls Uploader with given paths, target_path, and cache_control' do
|
29
|
-
uploader =
|
29
|
+
uploader = double('uploader')
|
30
30
|
Uploader.should_receive(:new).with([Path.new('foo', nil, Dir.pwd)], \
|
31
31
|
{:paths=>["foo"], :private=>false, :target_path=>"bar",
|
32
32
|
:cache_control=>'public, max-age=3600'}\
|
@@ -35,6 +35,19 @@ module Travis::Artifacts
|
|
35
35
|
|
36
36
|
cli.start
|
37
37
|
end
|
38
|
+
|
39
|
+
context 'with clone path specified' do
|
40
|
+
let(:argv) do
|
41
|
+
['upload', '--path', 'foo', '--target-path', 'bar', '--cache-control', 'public, max-age=3600', "--clone-path", 'baz']
|
42
|
+
end
|
43
|
+
|
44
|
+
it "calls Uploader with the clone-path in addition to other parameters" do
|
45
|
+
Uploader.should_receive(:new).with(anything, hash_including(:clone_path => 'baz')).and_return double('uploader').as_null_object
|
46
|
+
|
47
|
+
cli.start
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
38
51
|
end
|
39
52
|
|
40
53
|
describe '#root' do
|
@@ -67,5 +80,40 @@ module Travis::Artifacts
|
|
67
80
|
cli.command.should == 'upload'
|
68
81
|
end
|
69
82
|
end
|
83
|
+
|
84
|
+
context 'with a valid command' do
|
85
|
+
let(:argv) { ['upload'] }
|
86
|
+
let(:retcode) { cli.start }
|
87
|
+
before { cli.stub(:upload) }
|
88
|
+
|
89
|
+
it 'returns 0' do
|
90
|
+
retcode.should == 0
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'with an invalid command' do
|
95
|
+
let(:argv) { ['derf'] }
|
96
|
+
let(:retcode) { cli.start }
|
97
|
+
|
98
|
+
it 'returns 1' do
|
99
|
+
STDERR.stub(:puts)
|
100
|
+
retcode.should == 1
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'tells us about it' do
|
104
|
+
STDERR.should_receive(:puts).with(/Could not find command/)
|
105
|
+
cli.start
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context 'with an internal error' do
|
110
|
+
let(:argv) { ['upload'] }
|
111
|
+
let(:custom_error) { Class.new(Exception) }
|
112
|
+
before { cli.stub(:upload) { raise custom_error } }
|
113
|
+
|
114
|
+
it 'allows it to bubble up' do
|
115
|
+
expect { cli.start }.to raise_error(custom_error)
|
116
|
+
end
|
117
|
+
end
|
70
118
|
end
|
71
119
|
end
|
@@ -9,13 +9,21 @@ module Travis::Artifacts
|
|
9
9
|
let(:uploader) { Uploader.new(paths) }
|
10
10
|
|
11
11
|
it 'sets a default' do
|
12
|
-
test =
|
12
|
+
test = double('test', :job_number => "10.1", :build_number => "10")
|
13
13
|
Test.stub(:new => test)
|
14
14
|
|
15
15
|
uploader.target_path.should == 'artifacts/10/10.1'
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
+
context 'when given an empty string as target_path' do
|
20
|
+
let(:uploader) { Uploader.new(paths, {:target_path => ''}) }
|
21
|
+
|
22
|
+
it 'leaves it alone' do
|
23
|
+
uploader.target_path.should == ''
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
19
27
|
describe '#upload_file' do
|
20
28
|
it 'retries 3 times before giving up' do
|
21
29
|
file = Artifact.new('source/file.png', 'destination/file.png')
|
@@ -31,7 +39,7 @@ module Travis::Artifacts
|
|
31
39
|
file = Artifact.new('source/file.png', 'destination/file.png')
|
32
40
|
|
33
41
|
request = { :expects => 200 }
|
34
|
-
response =
|
42
|
+
response = double('response', :status => 500)
|
35
43
|
error_class = Class.new(Excon::Errors::HTTPStatusError)
|
36
44
|
my_error = error_class.new('message', request, response)
|
37
45
|
uploader.should_receive(:_upload).exactly(3).times.and_raise(my_error)
|
@@ -45,13 +53,11 @@ module Travis::Artifacts
|
|
45
53
|
end
|
46
54
|
|
47
55
|
describe '#upload' do
|
48
|
-
let(:bucket) {
|
49
|
-
let(:bucket_files) {
|
56
|
+
let(:bucket) { double('bucket') }
|
57
|
+
let(:bucket_files) { double('bucket_files') }
|
58
|
+
let(:files) { [Artifact.new('source/path.png', 'destination/path.png')] }
|
50
59
|
|
51
60
|
before do
|
52
|
-
files = [
|
53
|
-
Artifact.new('source/path.png', 'destination/path.png')
|
54
|
-
]
|
55
61
|
files[0].stub(:read => 'contents')
|
56
62
|
uploader.stub(:files => files)
|
57
63
|
|
@@ -72,6 +78,23 @@ module Travis::Artifacts
|
|
72
78
|
uploader.upload
|
73
79
|
end
|
74
80
|
|
81
|
+
context 'with a top-level destination and empty string as target_path' do
|
82
|
+
let(:uploader) { Uploader.new(paths, {:target_path => ''}) }
|
83
|
+
let(:files) { [Artifact.new('source/path.png', 'path.png')] }
|
84
|
+
|
85
|
+
it 'uploads file to the root of the S3 bucket' do
|
86
|
+
bucket_files.should_receive(:create).with({
|
87
|
+
:key => 'path.png',
|
88
|
+
:public => true,
|
89
|
+
:body => 'contents',
|
90
|
+
:content_type => 'image/png',
|
91
|
+
:metadata => {'Cache-Control' => 'public, max-age=315360000'}
|
92
|
+
})
|
93
|
+
|
94
|
+
uploader.upload
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
75
98
|
context 'with private set to true' do
|
76
99
|
let(:uploader) do
|
77
100
|
Uploader.new(paths, {
|
@@ -95,6 +118,35 @@ module Travis::Artifacts
|
|
95
118
|
end
|
96
119
|
end
|
97
120
|
|
121
|
+
context 'with a clone path specified' do
|
122
|
+
let(:uploader) do
|
123
|
+
Uploader.new(paths, {
|
124
|
+
:target_path =>'artifacts/1',
|
125
|
+
:clone_path => 'artifacts/latest'
|
126
|
+
})
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'uploads file to S3 and clones it to a second remote location' do
|
130
|
+
|
131
|
+
bucket_files.should_receive(:create).with({
|
132
|
+
:key => 'artifacts/1/destination/path.png',
|
133
|
+
:public => true,
|
134
|
+
:body => 'contents',
|
135
|
+
:content_type => 'image/png',
|
136
|
+
:metadata => {'Cache-Control' => 'public, max-age=315360000'}
|
137
|
+
})
|
138
|
+
|
139
|
+
bucket_files.should_receive(:create).with({
|
140
|
+
:key => 'artifacts/latest/destination/path.png',
|
141
|
+
:public => true,
|
142
|
+
:body => '',
|
143
|
+
:metadata => { 'etag'=>'', 'x-amz-copy-source' => '/artifacts/1/destination/path.png' }
|
144
|
+
})
|
145
|
+
|
146
|
+
uploader.upload
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
98
150
|
context 'with a custom cache control option' do
|
99
151
|
let(:custom_cache_control) do
|
100
152
|
[
|
@@ -118,8 +170,8 @@ module Travis::Artifacts
|
|
118
170
|
files[0].stub(:read => 'contents')
|
119
171
|
uploader.stub(:files => files)
|
120
172
|
|
121
|
-
bucket =
|
122
|
-
bucket_files =
|
173
|
+
bucket = double('bucket')
|
174
|
+
bucket_files = double('bucket_files')
|
123
175
|
uploader.stub(:bucket => bucket)
|
124
176
|
bucket.stub(:files => bucket_files)
|
125
177
|
|
data/travis-artifacts.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'travis-artifacts'
|
3
|
-
s.version = '0.
|
3
|
+
s.version = '0.2.0'
|
4
4
|
|
5
5
|
s.description = 'Travis build artifacts tools'
|
6
6
|
s.summary = s.description
|
@@ -9,9 +9,10 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.authors = ['admin@travis-ci.org']
|
10
10
|
s.email = 'admin@travis-ci.org'
|
11
11
|
|
12
|
-
s.add_dependency '
|
13
|
-
s.add_dependency '
|
14
|
-
s.add_dependency '
|
12
|
+
s.add_dependency 'nokogiri', '1.5.10'
|
13
|
+
s.add_dependency 'fog', '~> 1.7'
|
14
|
+
s.add_dependency 'faraday', '~> 0.8'
|
15
|
+
s.add_dependency 'faraday_middleware', '~> 0.9'
|
15
16
|
|
16
17
|
s.add_development_dependency 'rspec'
|
17
18
|
|
metadata
CHANGED
@@ -1,78 +1,83 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: travis-artifacts
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.2.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- admin@travis-ci.org
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-
|
11
|
+
date: 2013-09-23 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: nokogiri
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.5.10
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.5.10
|
14
27
|
- !ruby/object:Gem::Dependency
|
15
28
|
name: fog
|
16
29
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
30
|
requirements:
|
19
|
-
- -
|
31
|
+
- - ~>
|
20
32
|
- !ruby/object:Gem::Version
|
21
|
-
version: '
|
33
|
+
version: '1.7'
|
22
34
|
type: :runtime
|
23
35
|
prerelease: false
|
24
36
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
37
|
requirements:
|
27
|
-
- -
|
38
|
+
- - ~>
|
28
39
|
- !ruby/object:Gem::Version
|
29
|
-
version: '
|
40
|
+
version: '1.7'
|
30
41
|
- !ruby/object:Gem::Dependency
|
31
42
|
name: faraday
|
32
43
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
44
|
requirements:
|
35
|
-
- -
|
45
|
+
- - ~>
|
36
46
|
- !ruby/object:Gem::Version
|
37
|
-
version: '0'
|
47
|
+
version: '0.8'
|
38
48
|
type: :runtime
|
39
49
|
prerelease: false
|
40
50
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
51
|
requirements:
|
43
|
-
- -
|
52
|
+
- - ~>
|
44
53
|
- !ruby/object:Gem::Version
|
45
|
-
version: '0'
|
54
|
+
version: '0.8'
|
46
55
|
- !ruby/object:Gem::Dependency
|
47
56
|
name: faraday_middleware
|
48
57
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
58
|
requirements:
|
51
|
-
- -
|
59
|
+
- - ~>
|
52
60
|
- !ruby/object:Gem::Version
|
53
|
-
version: '0'
|
61
|
+
version: '0.9'
|
54
62
|
type: :runtime
|
55
63
|
prerelease: false
|
56
64
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
65
|
requirements:
|
59
|
-
- -
|
66
|
+
- - ~>
|
60
67
|
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
68
|
+
version: '0.9'
|
62
69
|
- !ruby/object:Gem::Dependency
|
63
70
|
name: rspec
|
64
71
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
72
|
requirements:
|
67
|
-
- -
|
73
|
+
- - '>='
|
68
74
|
- !ruby/object:Gem::Version
|
69
75
|
version: '0'
|
70
76
|
type: :development
|
71
77
|
prerelease: false
|
72
78
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
79
|
requirements:
|
75
|
-
- -
|
80
|
+
- - '>='
|
76
81
|
- !ruby/object:Gem::Version
|
77
82
|
version: '0'
|
78
83
|
description: Travis build artifacts tools
|
@@ -86,7 +91,6 @@ files:
|
|
86
91
|
- .rspec
|
87
92
|
- .travis.yml
|
88
93
|
- Gemfile
|
89
|
-
- Gemfile.lock
|
90
94
|
- README.md
|
91
95
|
- bin/travis-artifacts
|
92
96
|
- lib/travis/artifacts.rb
|
@@ -110,27 +114,26 @@ files:
|
|
110
114
|
- travis-artifacts.gemspec
|
111
115
|
homepage: https://github.com/travis-ci/travis-artifacts
|
112
116
|
licenses: []
|
117
|
+
metadata: {}
|
113
118
|
post_install_message:
|
114
119
|
rdoc_options: []
|
115
120
|
require_paths:
|
116
121
|
- lib
|
117
122
|
required_ruby_version: !ruby/object:Gem::Requirement
|
118
|
-
none: false
|
119
123
|
requirements:
|
120
|
-
- -
|
124
|
+
- - '>='
|
121
125
|
- !ruby/object:Gem::Version
|
122
126
|
version: '0'
|
123
127
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
124
|
-
none: false
|
125
128
|
requirements:
|
126
|
-
- -
|
129
|
+
- - '>='
|
127
130
|
- !ruby/object:Gem::Version
|
128
131
|
version: '0'
|
129
132
|
requirements: []
|
130
133
|
rubyforge_project:
|
131
|
-
rubygems_version:
|
134
|
+
rubygems_version: 2.0.7
|
132
135
|
signing_key:
|
133
|
-
specification_version:
|
136
|
+
specification_version: 4
|
134
137
|
summary: Travis build artifacts tools
|
135
138
|
test_files:
|
136
139
|
- spec/fixtures/files/foo/bar/baz.txt
|
data/Gemfile.lock
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
travis-artifacts (0.1.0)
|
5
|
-
faraday
|
6
|
-
faraday_middleware
|
7
|
-
fog
|
8
|
-
|
9
|
-
GEM
|
10
|
-
remote: http://rubygems.org/
|
11
|
-
specs:
|
12
|
-
builder (3.1.4)
|
13
|
-
diff-lcs (1.1.3)
|
14
|
-
excon (0.16.8)
|
15
|
-
faraday (0.8.4)
|
16
|
-
multipart-post (~> 1.1)
|
17
|
-
faraday_middleware (0.9.0)
|
18
|
-
faraday (>= 0.7.4, < 0.9)
|
19
|
-
fog (1.7.0)
|
20
|
-
builder
|
21
|
-
excon (~> 0.14)
|
22
|
-
formatador (~> 0.2.0)
|
23
|
-
mime-types
|
24
|
-
multi_json (~> 1.0)
|
25
|
-
net-scp (~> 1.0.4)
|
26
|
-
net-ssh (>= 2.1.3)
|
27
|
-
nokogiri (~> 1.5.0)
|
28
|
-
ruby-hmac
|
29
|
-
formatador (0.2.4)
|
30
|
-
mime-types (1.19)
|
31
|
-
multi_json (1.3.7)
|
32
|
-
multipart-post (1.1.5)
|
33
|
-
net-scp (1.0.4)
|
34
|
-
net-ssh (>= 1.99.1)
|
35
|
-
net-ssh (2.6.1)
|
36
|
-
nokogiri (1.5.5)
|
37
|
-
rspec (2.12.0)
|
38
|
-
rspec-core (~> 2.12.0)
|
39
|
-
rspec-expectations (~> 2.12.0)
|
40
|
-
rspec-mocks (~> 2.12.0)
|
41
|
-
rspec-core (2.12.0)
|
42
|
-
rspec-expectations (2.12.0)
|
43
|
-
diff-lcs (~> 1.1.3)
|
44
|
-
rspec-mocks (2.12.0)
|
45
|
-
ruby-hmac (0.4.0)
|
46
|
-
|
47
|
-
PLATFORMS
|
48
|
-
ruby
|
49
|
-
|
50
|
-
DEPENDENCIES
|
51
|
-
rspec
|
52
|
-
travis-artifacts!
|