travis-artifacts 0.0.1
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.
- data/.gitignore +2 -0
- data/.rspec +1 -0
- data/.travis.yml +6 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +52 -0
- data/bin/travis-artifacts +8 -0
- data/lib/travis/artifacts.rb +25 -0
- data/lib/travis/artifacts/artifact.rb +17 -0
- data/lib/travis/artifacts/cli.rb +93 -0
- data/lib/travis/artifacts/logger.rb +17 -0
- data/lib/travis/artifacts/path.rb +15 -0
- data/lib/travis/artifacts/test.rb +27 -0
- data/lib/travis/artifacts/uploader.rb +109 -0
- data/lib/travis/client.rb +47 -0
- data/lib/travis/client_spec.rb +4 -0
- data/script/console +11 -0
- data/spec/fixtures/files/foo/bar/baz.txt +0 -0
- data/spec/fixtures/files/logs/bar.log +0 -0
- data/spec/fixtures/files/logs/foo.log +0 -0
- data/spec/fixtures/files/output.txt +0 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/travis/artifacts/artifact_spec.rb +6 -0
- data/spec/travis/artifacts/cli_spec.rb +65 -0
- data/spec/travis/artifacts/uploader_spec.rb +137 -0
- data/travis-artifacts.gemspec +22 -0
- metadata +142 -0
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
travis-artifacts (0.0.1)
|
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!
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Travis
|
2
|
+
autoload :Client, 'travis/client'
|
3
|
+
|
4
|
+
module Artifacts
|
5
|
+
autoload :Cli, 'travis/artifacts/cli'
|
6
|
+
autoload :Uploader, 'travis/artifacts/uploader'
|
7
|
+
autoload :Artifact, 'travis/artifacts/artifact'
|
8
|
+
autoload :Path, 'travis/artifacts/path'
|
9
|
+
autoload :Logger, 'travis/artifacts/logger'
|
10
|
+
autoload :Test, 'travis/artifacts/test'
|
11
|
+
autoload :ConfigParser, 'travis/artifacts/config_parser'
|
12
|
+
autoload :Prefix, 'travis/artifacts/prefix'
|
13
|
+
|
14
|
+
def self.aws_config
|
15
|
+
{ :aws_access_key_id => ENV['ARTIFACTS_AWS_ACCESS_KEY_ID'],
|
16
|
+
:aws_secret_access_key => ENV['ARTIFACTS_AWS_SECRET_ACCESS_KEY'],
|
17
|
+
:region => ENV['ARTIFACTS_AWS_REGION'] || 'us-east-1'
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.bucket_name
|
22
|
+
ENV['ARTIFACTS_S3_BUCKET']
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'mime/types'
|
2
|
+
|
3
|
+
module Travis::Artifacts
|
4
|
+
class Artifact < Struct.new(:source, :destination)
|
5
|
+
def content_type
|
6
|
+
if MIME::Types.type_for(source).any?
|
7
|
+
MIME::Types.type_for(source).first.content_type
|
8
|
+
else
|
9
|
+
'application/octet-stream'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def read
|
14
|
+
File.read(source)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module Travis::Artifacts
|
4
|
+
class Cli
|
5
|
+
attr_reader :options, :argv, :paths
|
6
|
+
attr_accessor :command, :client
|
7
|
+
|
8
|
+
VALID_COMMANDS = ['upload']
|
9
|
+
|
10
|
+
def initialize(argv = nil)
|
11
|
+
@argv = argv || ARGV
|
12
|
+
@options = { :paths => [] }
|
13
|
+
@paths = []
|
14
|
+
@client = Travis::Client.new
|
15
|
+
end
|
16
|
+
|
17
|
+
# I would like to use option parser for now, to keep
|
18
|
+
# the code super simple and without too much external
|
19
|
+
# dependencies, if it grows too much, I may change it
|
20
|
+
def start
|
21
|
+
parse!
|
22
|
+
create_paths
|
23
|
+
|
24
|
+
execute_command
|
25
|
+
end
|
26
|
+
|
27
|
+
def root
|
28
|
+
options[:root] || Dir.pwd
|
29
|
+
end
|
30
|
+
|
31
|
+
def upload
|
32
|
+
Uploader.new(paths, options[:target_path]).upload
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def execute_command
|
38
|
+
if VALID_COMMANDS.include? command
|
39
|
+
send(command)
|
40
|
+
else
|
41
|
+
STDERR.puts 'Could not find command'
|
42
|
+
exit 1
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def fetch_paths
|
47
|
+
options[:paths]
|
48
|
+
end
|
49
|
+
|
50
|
+
def create_paths
|
51
|
+
fetch_paths.each do |path|
|
52
|
+
from, to = path.split(':')
|
53
|
+
paths << Path.new(from, to, root)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def parse!
|
58
|
+
self.command = argv[0]
|
59
|
+
parser.parse! argv
|
60
|
+
end
|
61
|
+
|
62
|
+
def parser
|
63
|
+
@opt_parser ||= begin
|
64
|
+
options = self.options
|
65
|
+
|
66
|
+
OptionParser.new do |opt|
|
67
|
+
opt.banner = 'Usage: travis-uploader COMMAND [OPTIONS]'
|
68
|
+
opt.separator ''
|
69
|
+
opt.separator 'Commands'
|
70
|
+
opt.separator ' upload: upload files to server'
|
71
|
+
opt.separator ''
|
72
|
+
opt.separator 'Options'
|
73
|
+
|
74
|
+
opt.on('--path PATH','path(s) to upload to a server') do |path|
|
75
|
+
options[:paths] << path
|
76
|
+
end
|
77
|
+
|
78
|
+
opt.on('--target-path TARGET_PATH', 'path to upload files to') do |target_path|
|
79
|
+
options[:target_path] = target_path
|
80
|
+
end
|
81
|
+
|
82
|
+
opt.on('--root ROOT', 'root directory for relative paths') do |root|
|
83
|
+
options[:root] = root
|
84
|
+
end
|
85
|
+
|
86
|
+
opt.on('-h','--help','help') do
|
87
|
+
puts @opt_parser
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Travis::Artifacts
|
4
|
+
module Logger
|
5
|
+
class << self
|
6
|
+
attr_accessor :output
|
7
|
+
end
|
8
|
+
self.output = STDOUT
|
9
|
+
|
10
|
+
|
11
|
+
attr_reader :logger
|
12
|
+
|
13
|
+
def logger
|
14
|
+
@logger ||= ::Logger.new(Travis::Artifacts::Logger.output)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Travis::Artifacts
|
2
|
+
class Test
|
3
|
+
def success?
|
4
|
+
ENV['TRAVIS_TEST_RESULT'].to_i == 0
|
5
|
+
end
|
6
|
+
|
7
|
+
def failure?
|
8
|
+
!success?
|
9
|
+
end
|
10
|
+
|
11
|
+
def build_number
|
12
|
+
ENV['TRAVIS_BUILD_NUMBER']
|
13
|
+
end
|
14
|
+
|
15
|
+
def build_id
|
16
|
+
ENV['TRAVIS_BUILD_ID']
|
17
|
+
end
|
18
|
+
|
19
|
+
def job_number
|
20
|
+
ENV['TRAVIS_JOB_NUMBER']
|
21
|
+
end
|
22
|
+
|
23
|
+
def job_id
|
24
|
+
ENV['TRAVIS_JOB_ID']
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'find'
|
2
|
+
require 'fog'
|
3
|
+
|
4
|
+
module Travis::Artifacts
|
5
|
+
class Uploader
|
6
|
+
include Travis::Artifacts::Logger
|
7
|
+
|
8
|
+
attr_reader :paths, :target_path
|
9
|
+
|
10
|
+
def initialize(paths, target_path = nil)
|
11
|
+
@paths = paths
|
12
|
+
@test = Test.new
|
13
|
+
@target_path = target_path || "artifacts/#{@test.build_number}/#{@test.job_number}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def upload
|
17
|
+
files.each do |file|
|
18
|
+
upload_file(file)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def files
|
23
|
+
files = []
|
24
|
+
|
25
|
+
paths.each do |artifact_path|
|
26
|
+
to = artifact_path.to
|
27
|
+
from = artifact_path.from
|
28
|
+
root = artifact_path.root
|
29
|
+
|
30
|
+
if artifact_path.directory?
|
31
|
+
root = File.join(root, from)
|
32
|
+
root << '/' unless root =~ /\/$/
|
33
|
+
end
|
34
|
+
|
35
|
+
Find.find(artifact_path.fullpath) do |path|
|
36
|
+
next unless File.file? path
|
37
|
+
|
38
|
+
relative = path.sub(/#{root}\/?/, '')
|
39
|
+
|
40
|
+
destination = if to
|
41
|
+
artifact_path.directory? ? File.join(to, relative) : to
|
42
|
+
else
|
43
|
+
relative
|
44
|
+
end
|
45
|
+
|
46
|
+
files << Artifact.new(path, destination)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
files
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
def upload_file(file)
|
55
|
+
retries = 0
|
56
|
+
|
57
|
+
begin
|
58
|
+
_upload(file)
|
59
|
+
rescue StandardError => e
|
60
|
+
if retries < 2
|
61
|
+
logger.info "Attempt to upload failed, retrying"
|
62
|
+
retries += 1
|
63
|
+
retry
|
64
|
+
else
|
65
|
+
if e.respond_to?(:request)
|
66
|
+
# we don't want to display sensitive data, make the error message simpler
|
67
|
+
request = e.request
|
68
|
+
response = e.response
|
69
|
+
raise e
|
70
|
+
raise e.class.new("Expected(#{request[:expects].inspect}) <=> Actual(#{response.status})")
|
71
|
+
else
|
72
|
+
raise
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def _upload(file)
|
79
|
+
destination = File.join(target_path, file.destination)
|
80
|
+
|
81
|
+
logger.info "Uploading file #{file.source} to #{destination}"
|
82
|
+
|
83
|
+
bucket.files.create({
|
84
|
+
:key => destination,
|
85
|
+
:public => true,
|
86
|
+
:body => file.read,
|
87
|
+
:content_type => file.content_type,
|
88
|
+
:metadata => { "Cache-Control" => 'public, max-age=315360000'}
|
89
|
+
})
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def job_id
|
95
|
+
test.job_id
|
96
|
+
end
|
97
|
+
|
98
|
+
def bucket
|
99
|
+
@bucket ||= s3.directories.get(Travis::Artifacts.bucket_name)
|
100
|
+
end
|
101
|
+
|
102
|
+
def s3
|
103
|
+
@s3 ||= begin
|
104
|
+
config = { :provider => 'AWS' }.merge Travis::Artifacts.aws_config
|
105
|
+
Fog::Storage.new(config)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'faraday_middleware'
|
3
|
+
|
4
|
+
module Travis
|
5
|
+
class Client
|
6
|
+
attr_reader :connection
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@connection = create_connection
|
10
|
+
end
|
11
|
+
|
12
|
+
# TODO: this needs to be fixed before going too far, returning body without
|
13
|
+
# ability to inspect response or returning nil on any failure are not
|
14
|
+
# the best ways to deal with API client
|
15
|
+
def fetch_config(job_id)
|
16
|
+
response = get("/jobs/#{job_id}")
|
17
|
+
if (200..299).include?(response.status)
|
18
|
+
response.body['job']['config']
|
19
|
+
else
|
20
|
+
# TODO: I should probably raise here
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
http_methods = [:get, :post, :put, :patch, :delete, :head]
|
28
|
+
http_methods.each do |method|
|
29
|
+
|
30
|
+
define_method(method) do |*args, &block|
|
31
|
+
path, params, headers = *args
|
32
|
+
connection.send(method, path, params, headers, &block)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def create_connection
|
37
|
+
# TODO: support for pro
|
38
|
+
Faraday.new(:url => 'https://api.travis-ci.org') do |faraday|
|
39
|
+
faraday.response :json, :content_type => /\bjson$/
|
40
|
+
|
41
|
+
faraday.adapter :net_http
|
42
|
+
end.tap do |connection|
|
43
|
+
connection.headers['Accept'] = 'application/vnd.travis-ci.2+json'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/script/console
ADDED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Travis::Artifacts
|
4
|
+
describe Cli do
|
5
|
+
let(:cli) { described_class.new(argv) }
|
6
|
+
|
7
|
+
|
8
|
+
context 'with multiple paths' do
|
9
|
+
before { cli.stub(:upload) }
|
10
|
+
let(:argv) { ['upload', '--path', 'path/to/foo', '--path', 'path/to/bar:bar'] }
|
11
|
+
|
12
|
+
before { cli.start }
|
13
|
+
|
14
|
+
it 'parses them' do
|
15
|
+
cli.options[:paths].should == ['path/to/foo', 'path/to/bar:bar']
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'adds paths to paths array' do
|
19
|
+
cli.paths.map { |p| [p.from, p.to] }.should == [['path/to/foo', nil], ['path/to/bar', 'bar']]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'upload' do
|
24
|
+
let(:argv) { ['upload', '--path', 'foo', '--target-path', 'bar'] }
|
25
|
+
it 'calls Uploader with given paths and target_path' do
|
26
|
+
uploader = mock('uploader')
|
27
|
+
Uploader.should_receive(:new).with([Path.new('foo', nil, Dir.pwd)], 'bar').and_return(uploader)
|
28
|
+
uploader.should_receive(:upload)
|
29
|
+
|
30
|
+
cli.start
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '#root' do
|
35
|
+
before { cli.stub(:upload) }
|
36
|
+
before { cli.start }
|
37
|
+
|
38
|
+
context 'with root passed as an argument' do
|
39
|
+
let(:argv) { ['upload', '--root', 'foo'] }
|
40
|
+
it 'returns passed value' do
|
41
|
+
cli.root.should == 'foo'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'without root passed as an argument' do
|
46
|
+
before { cli.stub(:upload) }
|
47
|
+
let(:argv) { ['upload'] }
|
48
|
+
it 'returns cwd' do
|
49
|
+
cli.root.should == Dir.pwd
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'with a command' do
|
55
|
+
before { cli.stub(:upload) }
|
56
|
+
let(:argv) { ['upload'] }
|
57
|
+
|
58
|
+
before { cli.start }
|
59
|
+
|
60
|
+
it 'saves it' do
|
61
|
+
cli.command.should == 'upload'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Travis::Artifacts
|
4
|
+
describe Uploader do
|
5
|
+
let(:uploader) { Uploader.new(paths, 'artifacts/1') }
|
6
|
+
let(:paths) { [] }
|
7
|
+
|
8
|
+
context 'without given target_path' do
|
9
|
+
let(:uploader) { Uploader.new(paths, nil) }
|
10
|
+
|
11
|
+
it 'sets a default' do
|
12
|
+
test = mock('test', :job_number => "10.1", :build_number => "10")
|
13
|
+
Test.stub(:new => test)
|
14
|
+
|
15
|
+
uploader.target_path.should == 'artifacts/10/10.1'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#upload_file' do
|
20
|
+
it 'retries 3 times before giving up' do
|
21
|
+
file = Artifact.new('source/file.png', 'destination/file.png')
|
22
|
+
|
23
|
+
uploader.should_receive(:_upload).exactly(3).times.and_raise(StandardError)
|
24
|
+
|
25
|
+
expect {
|
26
|
+
uploader.upload_file(file)
|
27
|
+
}.to raise_error(StandardError)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'simplifies excon error to not show request data' do
|
31
|
+
file = Artifact.new('source/file.png', 'destination/file.png')
|
32
|
+
|
33
|
+
request = { :expects => 200 }
|
34
|
+
response = mock('response', :status => 500)
|
35
|
+
error_class = Class.new(Excon::Errors::HTTPStatusError)
|
36
|
+
my_error = error_class.new('message', request, response)
|
37
|
+
uploader.should_receive(:_upload).exactly(4).times.and_raise(my_error)
|
38
|
+
|
39
|
+
expect {
|
40
|
+
uploader.upload_file(file)
|
41
|
+
}.to raise_error { |e|
|
42
|
+
e.message.should == 'Expected(200) <=> Actual(500)'
|
43
|
+
}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '#upload' do
|
48
|
+
it 'uploads file to S3' do
|
49
|
+
files = [
|
50
|
+
Artifact.new('source/path.png', 'destination/path.png')
|
51
|
+
]
|
52
|
+
files[0].stub(:read => 'contents')
|
53
|
+
uploader.stub(:files => files)
|
54
|
+
|
55
|
+
bucket = mock('bucker')
|
56
|
+
bucket_files = mock('bucket_files')
|
57
|
+
uploader.stub(:bucket => bucket)
|
58
|
+
bucket.stub(:files => bucket_files)
|
59
|
+
|
60
|
+
bucket_files.should_receive(:create).with({
|
61
|
+
:key => 'artifacts/1/destination/path.png',
|
62
|
+
:public => true,
|
63
|
+
:body => 'contents',
|
64
|
+
:content_type => 'image/png',
|
65
|
+
:metadata => {'Cache-Control' => 'public, max-age=315360000'}
|
66
|
+
|
67
|
+
})
|
68
|
+
|
69
|
+
uploader.upload
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe '#files' do
|
74
|
+
let(:root) { File.expand_path('../../../fixtures', __FILE__) }
|
75
|
+
|
76
|
+
context 'with nested files from root' do
|
77
|
+
let(:paths) { [Path.new('.', nil, root)] }
|
78
|
+
|
79
|
+
it 'resolves paths into files to upload' do
|
80
|
+
files = [
|
81
|
+
'files/foo/bar/baz.txt',
|
82
|
+
'files/logs/bar.log',
|
83
|
+
'files/logs/foo.log',
|
84
|
+
'files/output.txt'
|
85
|
+
]
|
86
|
+
files.map! { |file| Artifact.new(File.join(root, '.', file), file) }
|
87
|
+
|
88
|
+
uploader.files.sort_by { |o| o.source }.should == files.sort_by { |o| o.source }
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'with destination path and directory' do
|
93
|
+
let(:paths) { [Path.new('files/logs', 'logs', root)] }
|
94
|
+
|
95
|
+
it 'resolves paths into files to upload' do
|
96
|
+
files = [
|
97
|
+
'logs/bar.log',
|
98
|
+
'logs/foo.log'
|
99
|
+
]
|
100
|
+
files.map! { |file| Artifact.new(File.join(root, 'files', file), "#{file}") }
|
101
|
+
|
102
|
+
uploader.files.sort_by { |o| o.source }.should == files.sort_by { |o| o.source }
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context 'with individual files' do
|
107
|
+
let(:paths) {
|
108
|
+
[Path.new('files/logs/bar.log', nil, root),
|
109
|
+
Path.new('files/logs/foo.log', 'new/location/foo.log', root)]
|
110
|
+
|
111
|
+
}
|
112
|
+
|
113
|
+
it 'resolves paths into files to upload' do
|
114
|
+
file1 = 'files/logs/bar.log'
|
115
|
+
file2 = 'files/logs/foo.log'
|
116
|
+
|
117
|
+
files = [
|
118
|
+
Artifact.new(File.join(root, file1), 'files/logs/bar.log'),
|
119
|
+
Artifact.new(File.join(root, file2), 'new/location/foo.log')
|
120
|
+
]
|
121
|
+
|
122
|
+
uploader.files.should == files
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context 'with multilevel directory and to' do
|
127
|
+
let(:paths) {
|
128
|
+
[Path.new('files/foo', 'foo1', root)]
|
129
|
+
}
|
130
|
+
|
131
|
+
it 'resolves paths into files to upload' do
|
132
|
+
uploader.files.should == [Artifact.new(File.join(root, 'files/foo/bar/baz.txt'), 'foo1/bar/baz.txt')]
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'travis-artifacts'
|
3
|
+
s.version = '0.0.1'
|
4
|
+
|
5
|
+
s.description = 'Travis build artifacts tools'
|
6
|
+
s.summary = s.description
|
7
|
+
|
8
|
+
s.homepage = 'https://github.com/travis-ci/travis-artifacts'
|
9
|
+
s.authors = ['admin@travis-ci.org']
|
10
|
+
s.email = 'admin@travis-ci.org'
|
11
|
+
|
12
|
+
s.add_dependency 'fog'
|
13
|
+
s.add_dependency 'faraday'
|
14
|
+
s.add_dependency 'faraday_middleware'
|
15
|
+
|
16
|
+
s.add_development_dependency 'rspec'
|
17
|
+
|
18
|
+
s.files = `git ls-files`.split($/)
|
19
|
+
s.executables = s.files.grep(/^bin/).map{|f| File.basename(f) }
|
20
|
+
s.test_files = s.files.grep(/^spec/)
|
21
|
+
s.require_paths = ['lib']
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: travis-artifacts
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- admin@travis-ci.org
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-11-30 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: fog
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: faraday
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: faraday_middleware
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rspec
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
description: Travis build artifacts tools
|
79
|
+
email: admin@travis-ci.org
|
80
|
+
executables:
|
81
|
+
- travis-artifacts
|
82
|
+
extensions: []
|
83
|
+
extra_rdoc_files: []
|
84
|
+
files:
|
85
|
+
- .gitignore
|
86
|
+
- .rspec
|
87
|
+
- .travis.yml
|
88
|
+
- Gemfile
|
89
|
+
- Gemfile.lock
|
90
|
+
- bin/travis-artifacts
|
91
|
+
- lib/travis/artifacts.rb
|
92
|
+
- lib/travis/artifacts/artifact.rb
|
93
|
+
- lib/travis/artifacts/cli.rb
|
94
|
+
- lib/travis/artifacts/logger.rb
|
95
|
+
- lib/travis/artifacts/path.rb
|
96
|
+
- lib/travis/artifacts/test.rb
|
97
|
+
- lib/travis/artifacts/uploader.rb
|
98
|
+
- lib/travis/client.rb
|
99
|
+
- lib/travis/client_spec.rb
|
100
|
+
- script/console
|
101
|
+
- spec/fixtures/files/foo/bar/baz.txt
|
102
|
+
- spec/fixtures/files/logs/bar.log
|
103
|
+
- spec/fixtures/files/logs/foo.log
|
104
|
+
- spec/fixtures/files/output.txt
|
105
|
+
- spec/spec_helper.rb
|
106
|
+
- spec/travis/artifacts/artifact_spec.rb
|
107
|
+
- spec/travis/artifacts/cli_spec.rb
|
108
|
+
- spec/travis/artifacts/uploader_spec.rb
|
109
|
+
- travis-artifacts.gemspec
|
110
|
+
homepage: https://github.com/travis-ci/travis-artifacts
|
111
|
+
licenses: []
|
112
|
+
post_install_message:
|
113
|
+
rdoc_options: []
|
114
|
+
require_paths:
|
115
|
+
- lib
|
116
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
117
|
+
none: false
|
118
|
+
requirements:
|
119
|
+
- - ! '>='
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
|
+
none: false
|
124
|
+
requirements:
|
125
|
+
- - ! '>='
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: '0'
|
128
|
+
requirements: []
|
129
|
+
rubyforge_project:
|
130
|
+
rubygems_version: 1.8.24
|
131
|
+
signing_key:
|
132
|
+
specification_version: 3
|
133
|
+
summary: Travis build artifacts tools
|
134
|
+
test_files:
|
135
|
+
- spec/fixtures/files/foo/bar/baz.txt
|
136
|
+
- spec/fixtures/files/logs/bar.log
|
137
|
+
- spec/fixtures/files/logs/foo.log
|
138
|
+
- spec/fixtures/files/output.txt
|
139
|
+
- spec/spec_helper.rb
|
140
|
+
- spec/travis/artifacts/artifact_spec.rb
|
141
|
+
- spec/travis/artifacts/cli_spec.rb
|
142
|
+
- spec/travis/artifacts/uploader_spec.rb
|