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.
@@ -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!