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.
@@ -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
@@ -1,2 +1,4 @@
1
1
  vendor/bundle
2
2
  /log/
3
+ /Gemfile.lock
4
+ *.gem
data/Gemfile CHANGED
@@ -1,3 +1,3 @@
1
- source :rubygems
1
+ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
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
+ }
@@ -1,7 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
-
3
2
  $: << File.expand_path('../../lib', __FILE__)
4
-
5
3
  require 'travis/artifacts'
6
-
7
- Travis::Artifacts::Cli.new(ARGV).start
4
+ exit Travis::Artifacts::Cli.new(ARGV).start
@@ -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
- exit 1
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 _upload(file)
80
- destination = File.join(target_path, file.destination)
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 = mock('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 = mock('test', :job_number => "10.1", :build_number => "10")
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 = mock('response', :status => 500)
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) { mock('bucket') }
49
- let(:bucket_files) { mock('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 = mock('bucket')
122
- bucket_files = mock('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
 
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'travis-artifacts'
3
- s.version = '0.1.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 'fog'
13
- s.add_dependency 'faraday'
14
- s.add_dependency 'faraday_middleware'
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.1.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-05-10 00:00:00.000000000 Z
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: '0'
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: '0'
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: 1.8.25
134
+ rubygems_version: 2.0.7
132
135
  signing_key:
133
- specification_version: 3
136
+ specification_version: 4
134
137
  summary: Travis build artifacts tools
135
138
  test_files:
136
139
  - spec/fixtures/files/foo/bar/baz.txt
@@ -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!