travis-artifacts 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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!
|