pipely 0.6.2 → 0.7.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 +4 -4
- data/lib/pipely/deploy/bootstrap.rb +115 -0
- data/lib/pipely/deploy/client.rb +2 -0
- data/lib/pipely/tasks.rb +1 -0
- data/lib/pipely/tasks/upload_pipeline_as_gem.rb +81 -0
- data/lib/pipely/tasks/upload_steps.rb +7 -6
- data/lib/pipely/version.rb +1 -1
- data/spec/fixtures/vcr_cassettes/build_and_upload_gems.yml +47 -0
- data/spec/lib/pipely/deploy/bootstrap_spec.rb +86 -0
- data/spec/spec_helper.rb +23 -1
- metadata +50 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ffc556ad3308b03b691185eb21f4ee10f26592f9
|
4
|
+
data.tar.gz: caf8a2a7b8c63c281979bde1ad75f75bdc0f963f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3b6a6b168162ec377f29e5f416a956fa90c3a1d7a21c462f5104d0ebf8db11d340e95b90ddbaf6a5de74f21673cb15084e2a99eb156d200b69acc54d6243bd06
|
7
|
+
data.tar.gz: 7b659bdb5a01ebe0b4306a3a8c8ec7c426df709e3e56df95a50c1f7134fa3c7d5235efd887b187d1ebbf1c545c2d57d50c33bcb6fa4599a167e6b5930271eda6
|
@@ -0,0 +1,115 @@
|
|
1
|
+
module Pipely
|
2
|
+
module Deploy
|
3
|
+
|
4
|
+
# Helps bootstrap a pipeline
|
5
|
+
class Bootstrap
|
6
|
+
|
7
|
+
attr_reader :bucket_name
|
8
|
+
attr_reader :s3_gems_path
|
9
|
+
attr_reader :project_spec
|
10
|
+
attr_reader :gem_files
|
11
|
+
|
12
|
+
def initialize(s3_bucket, s3_gems_path)
|
13
|
+
@s3_bucket = s3_bucket
|
14
|
+
@bucket_name = s3_bucket.name
|
15
|
+
@s3_gems_path = s3_gems_path
|
16
|
+
end
|
17
|
+
|
18
|
+
# Builds the project's gem from gemspec, uploads the gem to s3, and
|
19
|
+
# uploads all the gem dependences to S3
|
20
|
+
def build_and_upload_gems
|
21
|
+
|
22
|
+
# placeholder, name will be nil if a gemspec is not defined
|
23
|
+
project_gem_name = nil
|
24
|
+
|
25
|
+
gem_spec = Dir.glob("*.gemspec").first
|
26
|
+
if gem_spec
|
27
|
+
|
28
|
+
# Build pipeline gem
|
29
|
+
@project_spec = Gem::Specification::load(gem_spec)
|
30
|
+
# build the gem
|
31
|
+
project_gem_file =
|
32
|
+
`gem build ./#{gem_spec}`.scan(
|
33
|
+
/File:(.+.gem)$/).flatten.first.strip
|
34
|
+
project_gem_name = @project_spec.name
|
35
|
+
upload_gem(project_gem_file)
|
36
|
+
end
|
37
|
+
|
38
|
+
@gem_files = upload_gems_from_bundler(project_gem_name)
|
39
|
+
|
40
|
+
# project gem has to be loaded last
|
41
|
+
@gem_files << project_gem_file if @project_spec
|
42
|
+
end
|
43
|
+
|
44
|
+
def context
|
45
|
+
BootstrapContext.new(
|
46
|
+
@gem_files.map{ |file|
|
47
|
+
File.join("s3://", @s3_bucket.name, gem_s3_path(file) )
|
48
|
+
} )
|
49
|
+
end
|
50
|
+
|
51
|
+
def gem_s3_path(gem_file)
|
52
|
+
filename = File.basename(gem_file)
|
53
|
+
File.join(@s3_gems_path, filename)
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def s3_gem_exists?( gem_file )
|
59
|
+
!@s3_bucket.objects[gem_s3_path(gem_file)].nil?
|
60
|
+
end
|
61
|
+
|
62
|
+
def upload_gem( gem_file )
|
63
|
+
puts "uploading #{gem_file} to #{gem_s3_path(gem_file)}"
|
64
|
+
@s3_bucket.objects[gem_s3_path(gem_file)].write(File.open(gem_file))
|
65
|
+
end
|
66
|
+
|
67
|
+
def upload_gems_from_bundler(project_gem_name)
|
68
|
+
gem_files = []
|
69
|
+
Bundler.definition.specs_for([:default]).each do |spec|
|
70
|
+
# Exclude project from gem deps
|
71
|
+
unless spec.name == project_gem_name
|
72
|
+
gem_file = spec.cache_file
|
73
|
+
|
74
|
+
# XXX: Some gems do not exist in the cache, e.g. json. Looks the
|
75
|
+
# gem is already packaged with the ruby dist
|
76
|
+
if File.exists? gem_file
|
77
|
+
gem_files << gem_file
|
78
|
+
|
79
|
+
# only upload gem if it doesnt exist already
|
80
|
+
unless s3_gem_exists?( gem_file )
|
81
|
+
upload_gem(gem_file)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
gem_files
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# Context passed to the erb templates
|
92
|
+
class BootstrapContext
|
93
|
+
attr_reader :gem_files
|
94
|
+
|
95
|
+
def initialize(gem_files)
|
96
|
+
@gem_files = gem_files
|
97
|
+
end
|
98
|
+
|
99
|
+
def install_gems_script
|
100
|
+
script = ""
|
101
|
+
|
102
|
+
@gem_files.each do |gem_file|
|
103
|
+
filename = File.basename(gem_file)
|
104
|
+
script << %Q[
|
105
|
+
# #{filename}
|
106
|
+
hadoop fs -copyToLocal #{gem_file} /home/hadoop/#{filename}
|
107
|
+
gem install --local /home/hadoop/#{filename} --no-ri --no-rdoc
|
108
|
+
]
|
109
|
+
end
|
110
|
+
|
111
|
+
script
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
data/lib/pipely/deploy/client.rb
CHANGED
data/lib/pipely/tasks.rb
CHANGED
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'aws'
|
3
|
+
require 'pipely/deploy/bootstrap'
|
4
|
+
|
5
|
+
module Pipely
|
6
|
+
module Tasks
|
7
|
+
class UploadPipelineAsGem < ::Rake::TaskLib
|
8
|
+
include ::Rake::DSL if defined?(::Rake::DSL)
|
9
|
+
|
10
|
+
# Name of this rake task
|
11
|
+
attr_accessor :name
|
12
|
+
|
13
|
+
attr_accessor :bucket_name
|
14
|
+
attr_accessor :s3_steps_path
|
15
|
+
attr_accessor :s3_gems_path
|
16
|
+
attr_accessor :config
|
17
|
+
|
18
|
+
def initialize(*args, &task_block)
|
19
|
+
setup_ivars(args)
|
20
|
+
|
21
|
+
task name, *args do |_, task_args|
|
22
|
+
RakeFileUtils.send(:verbose, verbose) do
|
23
|
+
if task_block
|
24
|
+
task_block.call(*[self, task_args].slice(0, task_block.arity))
|
25
|
+
end
|
26
|
+
|
27
|
+
run_task verbose
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
Rake::Task["upload_steps"].enhance [name]
|
32
|
+
end
|
33
|
+
|
34
|
+
def setup_ivars(args)
|
35
|
+
@name = args.shift || 'deploy:upload_pipeline_as_gem'
|
36
|
+
@verbose = true
|
37
|
+
end
|
38
|
+
|
39
|
+
def run_task(verbose)
|
40
|
+
context = build_bootstrap_context
|
41
|
+
|
42
|
+
Dir.glob("templates/*.erb").each do |erb_file|
|
43
|
+
upload_filename = File.basename(erb_file).sub( /\.erb$/, '' )
|
44
|
+
|
45
|
+
# Exclude the pipeline.json
|
46
|
+
if upload_filename == 'pipeline.json'
|
47
|
+
next
|
48
|
+
end
|
49
|
+
|
50
|
+
template_erb = Erubis::Eruby.new( File.read(erb_file) )
|
51
|
+
upload_to_s3( upload_filename, template_erb.result(context) )
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
def s3_bucket
|
57
|
+
s3 = AWS::S3.new
|
58
|
+
s3.buckets[@bucket_name]
|
59
|
+
end
|
60
|
+
|
61
|
+
def build_bootstrap_context
|
62
|
+
bootstrap_helper =
|
63
|
+
Pipely::Deploy::Bootstrap.new(s3_bucket, @s3_gems_path)
|
64
|
+
bootstrap_helper.build_and_upload_gems
|
65
|
+
|
66
|
+
# erb context
|
67
|
+
{
|
68
|
+
bootstrap: bootstrap_helper.context,
|
69
|
+
config: config
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
def upload_to_s3( upload_filename, body )
|
74
|
+
|
75
|
+
s3_dest = File.join(@s3_steps_path, upload_filename)
|
76
|
+
puts "uploading #{s3_dest}" if verbose
|
77
|
+
s3_bucket.objects[s3_dest].write(body)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'rake'
|
2
2
|
require 'rake/tasklib'
|
3
|
-
require 'fog'
|
4
3
|
|
5
4
|
module Pipely
|
6
5
|
module Tasks
|
@@ -57,11 +56,11 @@ module Pipely
|
|
57
56
|
end
|
58
57
|
|
59
58
|
def run_task(verbose)
|
60
|
-
with_bucket do |
|
59
|
+
with_bucket do |bucket|
|
61
60
|
step_files.each do |file_name|
|
62
61
|
dest = file_name.sub(/^#{local_path}/, s3_path)
|
63
62
|
puts "uploading #{dest}" if verbose
|
64
|
-
|
63
|
+
bucket.objects[dest].write(File.read(file_name))
|
65
64
|
end
|
66
65
|
end
|
67
66
|
end
|
@@ -69,9 +68,11 @@ module Pipely
|
|
69
68
|
private
|
70
69
|
|
71
70
|
def with_bucket
|
72
|
-
|
73
|
-
|
74
|
-
|
71
|
+
s3 = AWS::S3.new
|
72
|
+
bucket = s3.buckets[s3_bucket_name]
|
73
|
+
|
74
|
+
if bucket.exists?
|
75
|
+
yield(bucket)
|
75
76
|
else
|
76
77
|
raise "Couldn't find S3 bucket '#{s3_bucket_name}'"
|
77
78
|
end
|
data/lib/pipely/version.rb
CHANGED
@@ -0,0 +1,47 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: put
|
5
|
+
uri: https://a-test-bucket.s3.amazonaws.com/test_path/gems/pipely-0.7.0.gem
|
6
|
+
body:
|
7
|
+
encoding: UTF-8
|
8
|
+
string: !binary |-
|
9
|
+
bWV0YWRhdGEuZ3oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
10
|
+
headers:
|
11
|
+
Content-Type:
|
12
|
+
- ''
|
13
|
+
Accept-Encoding:
|
14
|
+
- ''
|
15
|
+
Content-Length:
|
16
|
+
- '21504'
|
17
|
+
User-Agent:
|
18
|
+
- aws-sdk-ruby/1.50.0 ruby/2.0.0 x86_64-darwin13.3.0
|
19
|
+
Date:
|
20
|
+
- Wed, 10 Sep 2014 00:58:35 GMT
|
21
|
+
Authorization:
|
22
|
+
- AWS 123
|
23
|
+
Accept:
|
24
|
+
- '*/*'
|
25
|
+
response:
|
26
|
+
status:
|
27
|
+
code: 200
|
28
|
+
message: OK
|
29
|
+
headers:
|
30
|
+
X-Amz-Id-2:
|
31
|
+
- 123
|
32
|
+
X-Amz-Request-Id:
|
33
|
+
- 123
|
34
|
+
Date:
|
35
|
+
- Wed, 10 Sep 2014 00:58:36 GMT
|
36
|
+
Etag:
|
37
|
+
- '"123"'
|
38
|
+
Content-Length:
|
39
|
+
- '0'
|
40
|
+
Server:
|
41
|
+
- AmazonS3
|
42
|
+
body:
|
43
|
+
encoding: UTF-8
|
44
|
+
string: ''
|
45
|
+
http_version:
|
46
|
+
recorded_at: Wed, 10 Sep 2014 00:58:35 GMT
|
47
|
+
recorded_with: VCR 2.9.2
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# Copyright Swipely, Inc. All rights reserved.
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'pipely/deploy/bootstrap'
|
5
|
+
require 'fog'
|
6
|
+
require 'fileutils'
|
7
|
+
|
8
|
+
module Pipely
|
9
|
+
describe Deploy::Bootstrap do
|
10
|
+
subject { described_class.new(s3_bucket, 'test_path/gems') }
|
11
|
+
let(:s3_bucket) do
|
12
|
+
s3 = AWS::S3.new
|
13
|
+
s3.buckets['a-test-bucket']
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should have bucket name" do
|
17
|
+
expect(subject.bucket_name).to eql 'a-test-bucket'
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should have a s3 gems path" do
|
21
|
+
expect(subject.s3_gems_path).to eql 'test_path/gems'
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#build_and_upload_gems" do
|
25
|
+
let(:build_and_upload_gems) do
|
26
|
+
VCR.use_cassette('build_and_upload_gems') do
|
27
|
+
subject.build_and_upload_gems
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should create project gem" do
|
32
|
+
build_and_upload_gems
|
33
|
+
|
34
|
+
expect(File).to exist(subject.project_spec.file_name)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should upload gems" do
|
38
|
+
specs = Bundler.definition.specs_for([:default])
|
39
|
+
|
40
|
+
gems = specs.map(&:file_name).reject do |g|
|
41
|
+
# Ignore bundler, since it could be a system installed gem (travis)
|
42
|
+
# without a cache file
|
43
|
+
g.match(/^json-\d+\.\d+\.\d+\.gem$/) or
|
44
|
+
g.match(/^bundler-\d+\.\d+\.\d+\.gem$/)
|
45
|
+
end
|
46
|
+
|
47
|
+
objects = double(:objects)
|
48
|
+
s3_object = double('s3_object', write: nil)
|
49
|
+
|
50
|
+
allow(objects).to receive(:[]) { s3_object }
|
51
|
+
|
52
|
+
gems.each do |gem|
|
53
|
+
expect(objects).to receive(:[]).with(subject.gem_s3_path(gem))
|
54
|
+
end
|
55
|
+
|
56
|
+
expect(s3_bucket).to(receive(:objects)).
|
57
|
+
at_least(gems.size).times.
|
58
|
+
at_most(gems.size + 1).times. # allow for Bundler
|
59
|
+
and_return(objects)
|
60
|
+
|
61
|
+
build_and_upload_gems
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#context" do
|
66
|
+
let(:context) { subject.context}
|
67
|
+
|
68
|
+
before do
|
69
|
+
VCR.use_cassette('build_and_upload_gems') do
|
70
|
+
subject.build_and_upload_gems
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should have gem_files" do
|
75
|
+
expect(context.gem_files).to_not be_nil
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should be an s3 url" do
|
79
|
+
expect(context.gem_files.first).to(
|
80
|
+
match( /^s3:\/\/#{subject.bucket_name}\/#{subject.s3_gems_path}/ )
|
81
|
+
)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,9 +1,31 @@
|
|
1
1
|
require 'timecop'
|
2
|
+
require 'aws-sdk'
|
2
3
|
require 'fog'
|
4
|
+
require 'rspec'
|
5
|
+
require 'vcr'
|
6
|
+
|
7
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
|
8
|
+
|
9
|
+
AWS.config(
|
10
|
+
access_key_id: "xxx",
|
11
|
+
secret_access_key: "xxx"
|
12
|
+
)
|
3
13
|
|
4
14
|
Fog.credentials = {
|
5
15
|
aws_access_key_id: "xxx",
|
6
16
|
aws_secret_access_key: "xxx"
|
7
17
|
}
|
8
18
|
|
9
|
-
|
19
|
+
VCR.configure do |c|
|
20
|
+
c.allow_http_connections_when_no_cassette = true
|
21
|
+
c.cassette_library_dir = 'spec/fixtures/vcr_cassettes'
|
22
|
+
c.hook_into :webmock
|
23
|
+
end
|
24
|
+
|
25
|
+
class WebMock::StubSocket
|
26
|
+
attr_accessor :continue_timeout, :read_timeout
|
27
|
+
|
28
|
+
def closed?
|
29
|
+
true
|
30
|
+
end
|
31
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pipely
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Gillooly
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-09-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ruby-graphviz
|
@@ -122,6 +122,20 @@ dependencies:
|
|
122
122
|
- - ">="
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: erubis
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
125
139
|
- !ruby/object:Gem::Dependency
|
126
140
|
name: rspec
|
127
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -164,6 +178,34 @@ dependencies:
|
|
164
178
|
- - ">="
|
165
179
|
- !ruby/object:Gem::Version
|
166
180
|
version: '0'
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: vcr
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - ">="
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '0'
|
188
|
+
type: :development
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - ">="
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '0'
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: webmock
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - ">="
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '0'
|
202
|
+
type: :development
|
203
|
+
prerelease: false
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - ">="
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '0'
|
167
209
|
description:
|
168
210
|
email:
|
169
211
|
- matt@swipely.com
|
@@ -192,6 +234,7 @@ files:
|
|
192
234
|
- lib/pipely/definition.rb
|
193
235
|
- lib/pipely/dependency.rb
|
194
236
|
- lib/pipely/deploy.rb
|
237
|
+
- lib/pipely/deploy/bootstrap.rb
|
195
238
|
- lib/pipely/deploy/client.rb
|
196
239
|
- lib/pipely/fog_client.rb
|
197
240
|
- lib/pipely/graph_builder.rb
|
@@ -205,8 +248,10 @@ files:
|
|
205
248
|
- lib/pipely/tasks/definition.rb
|
206
249
|
- lib/pipely/tasks/deploy.rb
|
207
250
|
- lib/pipely/tasks/graph.rb
|
251
|
+
- lib/pipely/tasks/upload_pipeline_as_gem.rb
|
208
252
|
- lib/pipely/tasks/upload_steps.rb
|
209
253
|
- lib/pipely/version.rb
|
254
|
+
- spec/fixtures/vcr_cassettes/build_and_upload_gems.yml
|
210
255
|
- spec/lib/pipely/build/daily_scheduler_spec.rb
|
211
256
|
- spec/lib/pipely/build/right_now_scheduler_spec.rb
|
212
257
|
- spec/lib/pipely/build/s3_path_builder_spec.rb
|
@@ -215,6 +260,7 @@ files:
|
|
215
260
|
- spec/lib/pipely/component_spec.rb
|
216
261
|
- spec/lib/pipely/definition_spec.rb
|
217
262
|
- spec/lib/pipely/dependency_spec.rb
|
263
|
+
- spec/lib/pipely/deploy/bootstrap_spec.rb
|
218
264
|
- spec/lib/pipely/deploy/client_spec.rb
|
219
265
|
- spec/lib/pipely/graph_builder_spec.rb
|
220
266
|
- spec/lib/pipely/reference_list_spec.rb
|
@@ -245,6 +291,7 @@ signing_key:
|
|
245
291
|
specification_version: 4
|
246
292
|
summary: Generate dependency graphs from pipeline definitions.
|
247
293
|
test_files:
|
294
|
+
- spec/fixtures/vcr_cassettes/build_and_upload_gems.yml
|
248
295
|
- spec/lib/pipely/build/daily_scheduler_spec.rb
|
249
296
|
- spec/lib/pipely/build/right_now_scheduler_spec.rb
|
250
297
|
- spec/lib/pipely/build/s3_path_builder_spec.rb
|
@@ -253,6 +300,7 @@ test_files:
|
|
253
300
|
- spec/lib/pipely/component_spec.rb
|
254
301
|
- spec/lib/pipely/definition_spec.rb
|
255
302
|
- spec/lib/pipely/dependency_spec.rb
|
303
|
+
- spec/lib/pipely/deploy/bootstrap_spec.rb
|
256
304
|
- spec/lib/pipely/deploy/client_spec.rb
|
257
305
|
- spec/lib/pipely/graph_builder_spec.rb
|
258
306
|
- spec/lib/pipely/reference_list_spec.rb
|