pipely 0.6.2 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 74943132df56cd3648e12d5f45fb4761fb4bc3d2
4
- data.tar.gz: bee0d005acd89ba86f703090877350f667120e3f
3
+ metadata.gz: ffc556ad3308b03b691185eb21f4ee10f26592f9
4
+ data.tar.gz: caf8a2a7b8c63c281979bde1ad75f75bdc0f963f
5
5
  SHA512:
6
- metadata.gz: 1e98b2c4ea1c5042b70b8a56f87b11a45211444f9b7d7fbae84bf27ddea676f11d1d51a06315599581743e62674618d818ae2c896ca8be3fda01999cfc02185c
7
- data.tar.gz: 69f416836edc06e0a24b8fea78ad1568b7a1ecea873e63ad58a7d598c0e50126067bc33ff0ea7eed7879a89ffe4b69d43fd6ddfcb890a0f8eda3e95ee4f90e3f
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
@@ -61,6 +61,8 @@ module Pipely
61
61
  @log.warn(error)
62
62
  end
63
63
  end
64
+
65
+ created_pipeline_id
64
66
  end
65
67
 
66
68
  def existing_pipelines(pipeline_name)
@@ -1,5 +1,6 @@
1
1
  require 'pipely/tasks/upload_steps'
2
2
  require 'pipely/tasks/deploy'
3
+ require 'pipely/tasks/upload_pipeline_as_gem'
3
4
  require 'pipely/tasks/graph'
4
5
  require 'pipely/tasks/definition'
5
6
 
@@ -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 |directory|
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
- directory.files.create(key: dest, body: File.read(file_name))
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
- storage = Fog::Storage.new({ provider: 'AWS' })
73
- if directory = storage.directories.detect{ |d| d.key == s3_bucket_name }
74
- yield(directory)
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
@@ -1,3 +1,3 @@
1
1
  module Pipely
2
- VERSION = "0.6.2" unless defined?(::Pipely::VERSION)
2
+ VERSION = "0.7.0" unless defined?(::Pipely::VERSION)
3
3
  end
@@ -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
@@ -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
- $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
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.6.2
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-08-01 00:00:00.000000000 Z
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