g5_sibling_deployer_engine 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +19 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +13 -0
  5. data/Gemfile +6 -0
  6. data/Guardfile +24 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +130 -0
  9. data/Rakefile +2 -0
  10. data/app/controllers/siblings/application_controller.rb +2 -0
  11. data/app/controllers/siblings/deploys_controller.rb +5 -0
  12. data/app/controllers/siblings/instructions_controller.rb +5 -0
  13. data/app/controllers/siblings_controller.rb +14 -0
  14. data/app/controllers/webhooks_controller.rb +6 -0
  15. data/app/models/sibling/deploy.rb +59 -0
  16. data/app/models/sibling/instruction.rb +60 -0
  17. data/app/models/sibling.rb +56 -0
  18. data/app/views/siblings/_nav.html.erb +5 -0
  19. data/app/views/siblings/deploys/index.html.erb +15 -0
  20. data/app/views/siblings/index.html.erb +16 -0
  21. data/app/views/siblings/instructions/index.html.erb +13 -0
  22. data/app/workers/sibling_consumer.rb +15 -0
  23. data/app/workers/sibling_deployer.rb +40 -0
  24. data/app/workers/sibling_instruction_consumer.rb +15 -0
  25. data/config/initializers/github_heroku_deployer.rb +7 -0
  26. data/config/initializers/resque.rb +12 -0
  27. data/config/initializers/table_cloth.rb +3 -0
  28. data/config/routes.rb +12 -0
  29. data/db/migrate/001_create_siblings.rb +14 -0
  30. data/db/migrate/002_create_sibling_deploys.rb +15 -0
  31. data/db/migrate/003_create_sibling_instructions.rb +11 -0
  32. data/g5_sibling_deployer_engine.gemspec +34 -0
  33. data/lib/g5_sibling_deployer_engine/engine.rb +4 -0
  34. data/lib/g5_sibling_deployer_engine/version.rb +3 -0
  35. data/lib/g5_sibling_deployer_engine.rb +12 -0
  36. data/lib/tasks/g5_sibling_deployer_engine_tasks.rake +16 -0
  37. data/lib/tasks/resque.rake +8 -0
  38. data/main_app_v2.html +38 -0
  39. data/spec/controllers/siblings/deploys_controller_spec.rb +12 -0
  40. data/spec/controllers/siblings/instructions_controller_spec.rb +12 -0
  41. data/spec/controllers/siblings_controller_spec.rb +28 -0
  42. data/spec/controllers/webhooks_controller_spec.rb +13 -0
  43. data/spec/dummy/README.rdoc +261 -0
  44. data/spec/dummy/Rakefile +7 -0
  45. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  46. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  47. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  48. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  49. data/spec/dummy/app/mailers/.gitkeep +0 -0
  50. data/spec/dummy/app/models/.gitkeep +0 -0
  51. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  52. data/spec/dummy/config/application.rb +65 -0
  53. data/spec/dummy/config/boot.rb +10 -0
  54. data/spec/dummy/config/database.yml +25 -0
  55. data/spec/dummy/config/environment.rb +5 -0
  56. data/spec/dummy/config/environments/development.rb +37 -0
  57. data/spec/dummy/config/environments/production.rb +67 -0
  58. data/spec/dummy/config/environments/test.rb +37 -0
  59. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  60. data/spec/dummy/config/initializers/inflections.rb +15 -0
  61. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  62. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  63. data/spec/dummy/config/initializers/session_store.rb +8 -0
  64. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  65. data/spec/dummy/config/locales/en.yml +5 -0
  66. data/spec/dummy/config/routes.rb +58 -0
  67. data/spec/dummy/config.ru +4 -0
  68. data/spec/dummy/db/development.sqlite3 +0 -0
  69. data/spec/dummy/db/schema.rb +47 -0
  70. data/spec/dummy/db/test.sqlite3 +0 -0
  71. data/spec/dummy/lib/assets/.gitkeep +0 -0
  72. data/spec/dummy/log/.gitkeep +0 -0
  73. data/spec/dummy/public/404.html +26 -0
  74. data/spec/dummy/public/422.html +26 -0
  75. data/spec/dummy/public/500.html +25 -0
  76. data/spec/dummy/public/favicon.ico +0 -0
  77. data/spec/dummy/script/rails +6 -0
  78. data/spec/lib/g5_sibling_deployer_engine_spec.rb +8 -0
  79. data/spec/models/sibling/deploy_spec.rb +61 -0
  80. data/spec/models/sibling/instruction_spec.rb +63 -0
  81. data/spec/models/sibling_spec.rb +73 -0
  82. data/spec/routing/routes_spec.rb +31 -0
  83. data/spec/spec_helper.rb +42 -0
  84. data/spec/support/g5-configurator-app.html +98 -0
  85. data/spec/support/g5-configurator-entries.html +387 -0
  86. data/spec/support/instructions.html +51 -0
  87. data/spec/support/main_app.html +87 -0
  88. data/spec/workers/sibling_consumer_spec.rb +21 -0
  89. data/spec/workers/sibling_deployer_spec.rb +45 -0
  90. data/spec/workers/sibling_instruction_consumer_spec.rb +15 -0
  91. metadata +352 -0
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NGZlNTEwM2NlNTRkOGYwMjA3MWJiMDAwNzg2MTEzYzA0ZTRmMjBlZQ==
5
+ data.tar.gz: !binary |-
6
+ MzkyY2IxYThmMjJhNGU4YjAyMDAxNjU0N2Q5YmNkMWEwNTU2ZWJkNg==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ NWY5NDE0ZDYyZDQzMzFhNGE3ZWRmY2JlNWRiYmM2MzMwZDFiMzUyMWQ1MDYz
10
+ YTJjZWEyMDY2NjExOTBjMDhmODg0NjUxYjQ5ZWVlZjQxZTk0ZDg3YjJlNjZi
11
+ MjZjNTU0NDhlYjRlMzkyY2M4ZjQ1NzAyZmYzMDQxN2RiZmMzNWU=
12
+ data.tar.gz: !binary |-
13
+ NjUyMGIzODAyYjA3OWY5MjA1MDFhY2E3YmUyMjY5NDAyZTdkYWJmNjFhNzFi
14
+ NzIzNWNlOTIyMjE3MDg2M2MwMDVlMjYxNDI5YjhjNzc2M2FiMmNmOGY4ODgz
15
+ Njc2NDMwYzY2MjVlZTM3MWJlZjA4NTYzNjZlYWUxYzhlYTI2NDU=
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+
19
+ spec/dummy/log/*
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format doc
data/.travis.yml ADDED
@@ -0,0 +1,13 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ script:
5
+ - bundle exec rspec
6
+ notifications:
7
+ campfire:
8
+ rooms:
9
+ secure: H6dWBB9lw65AwG951x+jNzj7nMI0FAHN/W1ZzQ+93hPW1mUHm3EK028JsEROSqNG1dMG4dm+UB1MPds4wtHWJNBjkcQO5qglCxWkWwUADcTMSkmAL7OcY59LkfXPa+Eqw1dGnhDZqA7EQuFWXIXnbV/EazadvpHHucbNzipDJrw=
10
+ template:
11
+ - "%{repository}#%{build_number} %{message} (%{branch} - %{commit} : %{author}) Change view : %{compare_url} Build details : %{build_url}"
12
+ on_success: change
13
+ on_failure: always
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in g5_sibiling_deployer_engine.gemspec
4
+ gemspec
5
+
6
+ gem "codeclimate-test-reporter", group: :test, require: nil
data/Guardfile ADDED
@@ -0,0 +1,24 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec' do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+
9
+ # Rails example
10
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
11
+ watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
12
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
13
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
14
+ watch('config/routes.rb') { "spec/routing" }
15
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
16
+
17
+ # Capybara request specs
18
+ watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
19
+
20
+ # Turnip features and steps
21
+ watch(%r{^spec/acceptance/(.+)\.feature$})
22
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
23
+ end
24
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 G5
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,130 @@
1
+ # G5 Sibling Deployer Engine
2
+
3
+ [![Build Status](https://travis-ci.org/G5/g5_sibling_deployer_engine.png?branch=master)](https://travis-ci.org/G5/g5_sibling_deployer_engine)
4
+ [![Code Climate](https://codeclimate.com/repos/531273cf6956803c53001d6f/badges/1f71ed4b6e818344987e/gpa.png)](https://codeclimate.com/repos/531273cf6956803c53001d6f/feed)
5
+
6
+ Provides models, views, controllers, routes, and rake tasks for deploying Sibling Apps.
7
+
8
+
9
+ ## Current Version
10
+
11
+ 0.2.6
12
+
13
+
14
+ ## Requirements
15
+
16
+ * ["rails"](http://rubygems.org/gems/rails)
17
+ * ["table_cloth"](http://rubygems.org/gems/table_cloth)
18
+ * ["state_machine"](http://rubygems.org/gems/state_machine)
19
+ * ["heroku_resque_autoscaler"](http://rubygems.org/gems/heroku_resque_autoscaler)
20
+ * ["github_heroku_deployer"](http://rubygems.org/gems/github_heroku_deployer)
21
+ * ["microformats2"](http://rubygems.org/gems/microformats2)
22
+
23
+
24
+ ## Installation
25
+
26
+ Add these lines to your application's Gemfile.
27
+
28
+ ```ruby
29
+ gem "g5_sibling_deployer_engine"
30
+ ```
31
+
32
+
33
+ ## Usage
34
+
35
+ Export environment variables:
36
+ ```bash
37
+ export MAIN_APP_UID=http://g5-configurator.herokuapp.com/apps/1
38
+ ```
39
+
40
+ Run migrations:
41
+ ```bash
42
+ rake railties:install:migrations
43
+ rake db:migrate
44
+ ```
45
+
46
+ Seed database:
47
+ ```bash
48
+ rake sibling:consume
49
+ rake sibling:instruction:consume
50
+ ```
51
+
52
+ You get these routes and views for free:
53
+ ```bash
54
+ deploy_sibling POST /siblings/:id/deploy(.:format) siblings#deploy
55
+ siblings GET /siblings(.:format) siblings#index
56
+ siblings_instructions GET /siblings/instructions(.:format) siblings/instructions#index
57
+ siblings_deploys GET /siblings/deploys(.:format) siblings/deploys#index
58
+ g5_configurator_webhook POST /webhooks/g5-configurator(.:format) webhooks#g5_configurator
59
+ ```
60
+
61
+ You get these rake tasks:
62
+ ```bash
63
+ rake sibling:consume # seeds siblings
64
+ rake sibling:deploy # deploys all siblings
65
+ rake sibling:instruction:consume # consumes instruction feed
66
+ ```
67
+
68
+
69
+ ## Authors
70
+
71
+ * Jessica Lynn Suttles / [@jlsuttles](https://github.com/jlsuttles)
72
+ * Bookis Smuin / [@bookis](https://github.com/bookis)
73
+ * Michael Mitchell / [@variousred](https://github.com/variousred)
74
+
75
+
76
+ ## Contributing
77
+
78
+ 2. Get it running
79
+ 3. Create your feature branch (`git checkout -b my-new-feature`)
80
+ 4. Write your code and **specs**
81
+ 5. Commit your changes (`git commit -am 'Add some feature'`)
82
+ 6. Push to the branch (`git push origin my-new-feature`)
83
+ 7. Create new Pull Request
84
+
85
+ If you find bugs, have feature requests or questions, please
86
+ [file an issue](https://github.com/G5/g5_sibling_deployer_engine/issues).
87
+
88
+
89
+ ## Specs
90
+
91
+ Run once.
92
+ ```bash
93
+ $ rspec spec
94
+ ```
95
+
96
+ Keep then running.
97
+ ```bash
98
+ $ guard
99
+ ```
100
+
101
+ Coverage.
102
+ ```bash
103
+ $ rspec spec
104
+ $ open coverage/index.html
105
+ ```
106
+
107
+
108
+ ## License
109
+
110
+ Copyright (c) 2013 G5
111
+
112
+ MIT License
113
+
114
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
115
+ this software and associated documentation files (the "Software"), to deal in
116
+ the Software without restriction, including without limitation the rights to
117
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
118
+ of the Software, and to permit persons to whom the Software is furnished to do
119
+ so, subject to the following conditions:
120
+
121
+ The above copyright notice and this permission notice shall be included in all
122
+ copies or substantial portions of the Software.
123
+
124
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
125
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
126
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
127
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
128
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
129
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
130
+ SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,2 @@
1
+ class Siblings::ApplicationController < ApplicationController
2
+ end
@@ -0,0 +1,5 @@
1
+ class Siblings::DeploysController < Siblings::ApplicationController
2
+ def index
3
+ @siblings_deploys = Sibling::Deploy.order("created_at DESC")
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class Siblings::InstructionsController < Siblings::ApplicationController
2
+ def index
3
+ @siblings_instructions = Sibling::Instruction.order("created_at DESC")
4
+ end
5
+ end
@@ -0,0 +1,14 @@
1
+ class SiblingsController < ApplicationController
2
+ def index
3
+ @siblings = Sibling.all
4
+ end
5
+
6
+ def deploy
7
+ @sibling = Sibling.find(params[:id])
8
+ if @sibling.deploy
9
+ redirect_to siblings_deploys_path, notice: "Deploy has been queued."
10
+ else
11
+ redirect_to siblings_deploys_path, alert: "Something went wrong. Deploy has not been queued."
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,6 @@
1
+ class WebhooksController < ApplicationController
2
+ def g5_configurator
3
+ Sibling::Instruction.async_consume_feed
4
+ render json: {}, status: :ok
5
+ end
6
+ end
@@ -0,0 +1,59 @@
1
+ class Sibling::Deploy < ActiveRecord::Base
2
+ attr_accessible :sibling_id, :instruction_id, :manual, :state
3
+ attr_accessible :git_repo, :heroku_repo, :heroku_app_name
4
+
5
+ belongs_to :sibling
6
+ belongs_to :instruction
7
+
8
+ validates :sibling_id, presence: true
9
+ validates :manual, inclusion: { in: [true, false] }
10
+ validates :git_repo, presence: true
11
+ validates :heroku_repo, presence: true
12
+ validates :heroku_app_name, presence: true
13
+
14
+ after_create :async_deploy
15
+
16
+ state_machine :initial => :new do
17
+ event :queue do
18
+ transition any => :queued
19
+ end
20
+ event :start do
21
+ transition any => :deploying
22
+ end
23
+ event :fail do
24
+ transition any => :failed
25
+ end
26
+ event :succeed do
27
+ transition any => :succeeded
28
+ end
29
+ end
30
+
31
+ scope :manual, where(manual: true)
32
+ scope :automatic, where(manual: false)
33
+
34
+ def deploy
35
+ start!
36
+
37
+ GithubHerokuDeployer.deploy(deployer_options)
38
+ GithubHerokuDeployer.heroku_run("rake db:migrate", deployer_options)
39
+
40
+ succeed!
41
+ rescue StandardError => e
42
+ fail!
43
+ raise e
44
+ end
45
+
46
+ def deployer_options
47
+ { github_repo: git_repo,
48
+ heroku_repo: heroku_repo,
49
+ heroku_app_name: heroku_app_name }
50
+ end
51
+
52
+ def async_deploy
53
+ queue!
54
+ Resque.enqueue(SiblingDeployer, self.id)
55
+ rescue StandardError => e
56
+ fail!
57
+ raise e
58
+ end
59
+ end
@@ -0,0 +1,60 @@
1
+ require 'open-uri'
2
+
3
+ class Sibling::Instruction < ActiveRecord::Base
4
+
5
+ attr_accessible :uid, :name, :published_at
6
+
7
+ has_many :deploys
8
+ has_many :siblings, through: :deploys
9
+
10
+ validates :uid, uniqueness: true
11
+ validates :name, presence: true
12
+ validates :published_at, presence: true
13
+
14
+ after_save :deploy
15
+
16
+ class << self
17
+ def feed_url
18
+ ENV["G5_CONFIGURATOR_FEED_URL"]
19
+ end
20
+
21
+ def feed
22
+ Microformats2.parse(feed_url)
23
+ end
24
+
25
+ def consume_feed
26
+ feed.entries.map do |hentry|
27
+ find_or_create_from_hentry(hentry) if targets_me?(hentry)
28
+ end.compact
29
+ rescue OpenURI::HTTPError => e
30
+ raise e unless /304 Not Modified/ =~ e.message
31
+ end
32
+
33
+ def async_consume_feed
34
+ Resque.enqueue(SiblingInstructionConsumer)
35
+ end
36
+
37
+ def targets_me?(hentry)
38
+ targets = instruction(hentry).g5_targets.map { |t| t.format.uid.to_s }
39
+ targets && targets.include?(Sibling.main_app_uid)
40
+ end
41
+
42
+ def instruction(hentry)
43
+ Microformats2.parse(hentry.content.to_s).card
44
+ end
45
+
46
+ def find_or_create_from_hentry(hentry)
47
+ find_or_create_by_uid(hentry.uid.to_s) do |instruction|
48
+ hcard = instruction(hentry)
49
+ instruction.name = hcard.name.to_s
50
+ instruction.published_at = hentry.updated.value
51
+ end
52
+ end
53
+ end # class << self
54
+
55
+ private
56
+
57
+ def deploy
58
+ Sibling.deploy_all(true, self.id)
59
+ end
60
+ end
@@ -0,0 +1,56 @@
1
+ class Sibling < ActiveRecord::Base
2
+ attr_accessible :uid, :name, :git_repo, :heroku_repo, :heroku_app_name
3
+
4
+ has_many :deploys
5
+ has_many :instructions, through: :deploys
6
+
7
+ validates :uid, presence: true, uniqueness: true
8
+ validates :name, presence: true
9
+ validates :git_repo, presence: true
10
+ validates :heroku_repo, presence: true
11
+ validates :heroku_app_name, presence: true
12
+
13
+ class << self
14
+ def main_app_uid
15
+ ENV["MAIN_APP_UID"]
16
+ end
17
+
18
+ def main_app_hcard
19
+ Microformats2.parse(main_app_uid).card
20
+ end
21
+
22
+ def consume_main_app_hcard
23
+ main_app_hcard.g5_siblings.map do |sibling|
24
+ find_or_create_from_hcard(sibling.format)
25
+ end.compact if main_app_hcard
26
+ rescue OpenURI::HTTPError, "304 Not Modified"
27
+ end
28
+
29
+ def async_consume
30
+ Resque.enqueue(SiblingConsumer)
31
+ end
32
+
33
+ def find_or_create_from_hcard(hcard)
34
+ find_or_create_by_uid(hcard.uid.to_s) do |sibling|
35
+ sibling.name = hcard.name.to_s
36
+ sibling.git_repo = hcard.g5_git_repo.to_s
37
+ sibling.heroku_repo = hcard.g5_heroku_repo.to_s
38
+ sibling.heroku_app_name = hcard.g5_heroku_app_name.to_s
39
+ end
40
+ end
41
+
42
+ def deploy_all(manual=true, instruction_id=nil)
43
+ all.each { |sibling| sibling.deploy(instruction_id) }
44
+ end
45
+ end
46
+
47
+ def deploy(instruction_id=nil)
48
+ self.deploys.create!(
49
+ instruction_id: instruction_id,
50
+ manual: !instruction_id,
51
+ git_repo: git_repo,
52
+ heroku_repo: heroku_repo,
53
+ heroku_app_name: heroku_app_name
54
+ )
55
+ end
56
+ end