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 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