takeoff 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +268 -0
- data/Rakefile +1 -0
- data/bin/takeoff +6 -0
- data/example.Launchfile +86 -0
- data/lib/takeoff/cli.rb +46 -0
- data/lib/takeoff/configuration.rb +58 -0
- data/lib/takeoff/ext/middleware_builder.rb +54 -0
- data/lib/takeoff/helpers.rb +44 -0
- data/lib/takeoff/plan/base.rb +62 -0
- data/lib/takeoff/plan/default.rb +36 -0
- data/lib/takeoff/plan/heroku.rb +41 -0
- data/lib/takeoff/stage/base.rb +17 -0
- data/lib/takeoff/stage/checkout_development_branch.rb +24 -0
- data/lib/takeoff/stage/heroku/disable_preboot.rb +37 -0
- data/lib/takeoff/stage/heroku/enable_maintenance_mode.rb +27 -0
- data/lib/takeoff/stage/heroku/migrate_database.rb +52 -0
- data/lib/takeoff/stage/heroku/precompile_and_sync_assets.rb +45 -0
- data/lib/takeoff/stage/heroku/push_to_server.rb +16 -0
- data/lib/takeoff/stage/heroku/remember_commits.rb +19 -0
- data/lib/takeoff/stage/heroku/scale_down_workers.rb +33 -0
- data/lib/takeoff/stage/heroku/verify_server_not_already_up_to_date.rb +17 -0
- data/lib/takeoff/stage/heroku/verify_staging_up_to_date.rb +28 -0
- data/lib/takeoff/stage/log.rb +28 -0
- data/lib/takeoff/stage/look_out_for_danger.rb +15 -0
- data/lib/takeoff/stage/point_checkpoint_to_development.rb +22 -0
- data/lib/takeoff/stage/push_to_github.rb +14 -0
- data/lib/takeoff/stage/stash_changes.rb +31 -0
- data/lib/takeoff/stage/verify_circle_ci_status.rb +46 -0
- data/lib/takeoff/stage/verify_github_up_to_date.rb +18 -0
- data/lib/takeoff/version.rb +3 -0
- data/lib/takeoff.rb +44 -0
- data/takeoff.gemspec +23 -0
- metadata +152 -0
@@ -0,0 +1,36 @@
|
|
1
|
+
require "takeoff/plan/base"
|
2
|
+
|
3
|
+
require "takeoff/stage/log"
|
4
|
+
require "takeoff/stage/look_out_for_danger"
|
5
|
+
require "takeoff/stage/stash_changes"
|
6
|
+
require "takeoff/stage/checkout_development_branch"
|
7
|
+
require "takeoff/stage/verify_github_up_to_date"
|
8
|
+
require "takeoff/stage/point_checkpoint_to_development"
|
9
|
+
require "takeoff/stage/push_to_github"
|
10
|
+
|
11
|
+
module Takeoff
|
12
|
+
module Plan
|
13
|
+
class Default < Base
|
14
|
+
env.merge!(
|
15
|
+
environment: "production",
|
16
|
+
github_remote: "github",
|
17
|
+
development_branch: "develop",
|
18
|
+
checkpoint_branch: "master"
|
19
|
+
)
|
20
|
+
|
21
|
+
stages do
|
22
|
+
use Stage::Log
|
23
|
+
use Stage::LookOutForDanger
|
24
|
+
|
25
|
+
use Stage::StashChanges
|
26
|
+
use Stage::CheckoutDevelopmentBranch
|
27
|
+
|
28
|
+
use Stage::VerifyGithubUpToDate
|
29
|
+
|
30
|
+
use Stage::PointCheckpointToDevelopment
|
31
|
+
|
32
|
+
use Stage::PushToGithub
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require "takeoff/plan/default"
|
2
|
+
|
3
|
+
require "takeoff/stage/heroku/remember_commits"
|
4
|
+
require "takeoff/stage/heroku/verify_server_not_already_up_to_date"
|
5
|
+
require "takeoff/stage/heroku/disable_preboot"
|
6
|
+
require "takeoff/stage/heroku/scale_down_workers"
|
7
|
+
require "takeoff/stage/heroku/enable_maintenance_mode"
|
8
|
+
require "takeoff/stage/heroku/push_to_server"
|
9
|
+
require "takeoff/stage/heroku/migrate_database"
|
10
|
+
|
11
|
+
module Takeoff
|
12
|
+
module Plan
|
13
|
+
class Heroku < Default
|
14
|
+
env.merge!(
|
15
|
+
server_remote: "heroku"
|
16
|
+
)
|
17
|
+
|
18
|
+
stages do
|
19
|
+
insert_after Stage::Log,
|
20
|
+
Stage::Heroku::RememberCommits
|
21
|
+
|
22
|
+
insert_after Stage::VerifyGithubUpToDate,
|
23
|
+
Stage::Heroku::VerifyServerNotAlreadyUpToDate
|
24
|
+
|
25
|
+
insert_after Stage::PointCheckpointToDevelopment, [
|
26
|
+
Stage::Heroku::DisablePreboot,
|
27
|
+
Stage::Heroku::ScaleDownWorkers,
|
28
|
+
Stage::Heroku::EnableMaintenanceMode,
|
29
|
+
|
30
|
+
Stage::Heroku::PushToServer,
|
31
|
+
|
32
|
+
Stage::Heroku::MigrateDatabase
|
33
|
+
]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
Takeoff.configure do
|
40
|
+
plan :heroku, Takeoff::Plan::Heroku
|
41
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "takeoff/stage/base"
|
2
|
+
|
3
|
+
module Takeoff
|
4
|
+
module Stage
|
5
|
+
class CheckoutDevelopmentBranch < Base
|
6
|
+
def call(env)
|
7
|
+
previous_branch = `git rev-parse --abbrev-ref HEAD`.strip
|
8
|
+
previous_branch = `git rev-parse --verify HEAD`.strip if previous_branch == "HEAD"
|
9
|
+
|
10
|
+
return @app.call(env) if previous_branch == env[:development_branch]
|
11
|
+
|
12
|
+
log "Checking out development branch"
|
13
|
+
execute "git checkout #{env[:development_branch]}"
|
14
|
+
|
15
|
+
begin
|
16
|
+
@app.call(env)
|
17
|
+
ensure
|
18
|
+
log "Checking out original branch '#{previous_branch}'"
|
19
|
+
execute "git checkout #{previous_branch}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "takeoff/stage/base"
|
2
|
+
|
3
|
+
module Takeoff
|
4
|
+
module Stage
|
5
|
+
module Heroku
|
6
|
+
class DisablePreboot < Base
|
7
|
+
def run?(env)
|
8
|
+
features = `heroku features --remote #{env[:server_remote]}`
|
9
|
+
preboot_line = features.split("\n").find { |feature| feature =~ /\A\[[+ ]\] preboot/ }
|
10
|
+
preboot_enabled = preboot_line.start_with?("[+]")
|
11
|
+
|
12
|
+
preboot_enabled
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
unless env[:dangerous]
|
17
|
+
log "Skipping disabling preboot because nothing dangerous is going on"
|
18
|
+
|
19
|
+
return @app.call(env)
|
20
|
+
end
|
21
|
+
|
22
|
+
return @app.call(env) unless run?(env)
|
23
|
+
|
24
|
+
log "Disabling preboot"
|
25
|
+
execute "heroku features:disable preboot --remote #{env[:server_remote]}"
|
26
|
+
|
27
|
+
begin
|
28
|
+
@app.call(env)
|
29
|
+
ensure
|
30
|
+
log "Enabling preboot"
|
31
|
+
execute "heroku features:enable preboot --remote #{env[:server_remote]}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "takeoff/stage/base"
|
2
|
+
|
3
|
+
module Takeoff
|
4
|
+
module Stage
|
5
|
+
module Heroku
|
6
|
+
class EnableMaintenanceMode < Base
|
7
|
+
def call(env)
|
8
|
+
unless env[:dangerous]
|
9
|
+
log "Skipping maintenance mode because nothing dangerous is going on"
|
10
|
+
|
11
|
+
return @app.call(env)
|
12
|
+
end
|
13
|
+
|
14
|
+
log "Enabling maintenance mode"
|
15
|
+
execute "heroku maintenance:on --remote #{env[:server_remote]}"
|
16
|
+
|
17
|
+
begin
|
18
|
+
@app.call(env)
|
19
|
+
ensure
|
20
|
+
log "Disabling maintenance mode"
|
21
|
+
execute "heroku maintenance:off --remote #{env[:server_remote]}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require "takeoff/stage/base"
|
2
|
+
|
3
|
+
module Takeoff
|
4
|
+
module Stage
|
5
|
+
module Heroku
|
6
|
+
class MigrateDatabase < Base
|
7
|
+
def self.dangerous?(env)
|
8
|
+
new(nil).dangerous?(env)
|
9
|
+
end
|
10
|
+
|
11
|
+
def dangerous?(env)
|
12
|
+
return @dangerous if defined?(@dangerous)
|
13
|
+
|
14
|
+
return @dangerous = false unless run?(env)
|
15
|
+
|
16
|
+
diff = diff(env[:deployed_commit], env[:new_commit], ["db/migrate"])
|
17
|
+
|
18
|
+
unsafe_active_record_terms = /change_column|change_table|drop_table|remove_column|remove_index|rename_column|execute/
|
19
|
+
unsafe_mongoid_terms = /renameCollection|\.drop|$rename|$set|$unset|indexes\.create|indexes\.drop/
|
20
|
+
unsafe_terms = Regexp.union(unsafe_active_record_terms, unsafe_mongoid_terms)
|
21
|
+
|
22
|
+
@dangerous = diff.split("\n").any? do |line|
|
23
|
+
line =~ unsafe_terms && line !~ /#\s*safe/i
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def run?(env)
|
28
|
+
files_have_changed?(env[:deployed_commit], env[:new_commit], ["db/migrate"])
|
29
|
+
end
|
30
|
+
|
31
|
+
def call(env)
|
32
|
+
unless run?(env)
|
33
|
+
log "Skipping database migrations"
|
34
|
+
|
35
|
+
return @app.call(env)
|
36
|
+
end
|
37
|
+
|
38
|
+
log "Running database migrations"
|
39
|
+
execute "heroku run rake db:migrate --remote #{env[:server_remote]}"
|
40
|
+
|
41
|
+
# If ActiveRecord needs to rebuild its column name cache, restart the app.
|
42
|
+
if dangerous?(env)
|
43
|
+
log "Restarting application"
|
44
|
+
execute "heroku restart --remote #{env[:server_remote]}"
|
45
|
+
end
|
46
|
+
|
47
|
+
@app.call(env)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require "takeoff/stage/base"
|
2
|
+
|
3
|
+
module Takeoff
|
4
|
+
module Stage
|
5
|
+
module Heroku
|
6
|
+
class PrecompileAndSyncAssets < Base
|
7
|
+
def run?(env)
|
8
|
+
files = %w(app/assets lib/assets vendor/asset Gemfile.lock config/initializers/assets.rb)
|
9
|
+
files_have_changed?(env[:deployed_commit], env[:new_commit], files)
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
unless run?(env)
|
14
|
+
log "Skipping precompilation of assets"
|
15
|
+
|
16
|
+
return @app.call(env)
|
17
|
+
end
|
18
|
+
|
19
|
+
begin
|
20
|
+
log "Precompiling assets"
|
21
|
+
execute "RAILS_ENV=#{env[:environment]} bundle exec rake assets:precompile"
|
22
|
+
|
23
|
+
log "Syncing assets"
|
24
|
+
execute "RAILS_ENV=#{env[:environment]} bundle exec rake assets:sync"
|
25
|
+
|
26
|
+
if file_has_changed_locally?("public/assets/manifest-#{env[:environment]}.json")
|
27
|
+
log "Committing updated asset manifests"
|
28
|
+
execute "git add public/assets/manifest-#{env[:environment]}.json"
|
29
|
+
execute "git commit -m 'Update asset manifest for #{env[:environment]}.' -m '[ci skip]'"
|
30
|
+
|
31
|
+
log "Pushing development branch to GitHub"
|
32
|
+
execute "git push github #{env[:development_branch]}:#{env[:development_branch]} --force"
|
33
|
+
end
|
34
|
+
ensure
|
35
|
+
log "Deleting precompiled assets"
|
36
|
+
execute "git ls-files -o --exclude-standard public/assets | xargs rm"
|
37
|
+
# We can't use `rm -r ./public/assets` because we still need the manifest files.
|
38
|
+
end
|
39
|
+
|
40
|
+
@app.call(env)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "takeoff/stage/base"
|
2
|
+
|
3
|
+
module Takeoff
|
4
|
+
module Stage
|
5
|
+
module Heroku
|
6
|
+
class PushToServer < Base
|
7
|
+
def call(env)
|
8
|
+
log "Pushing to server"
|
9
|
+
execute "git push #{env[:server_remote]} #{env[:checkpoint_branch]}:master --force"
|
10
|
+
|
11
|
+
@app.call(env)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "takeoff/stage/base"
|
2
|
+
|
3
|
+
module Takeoff
|
4
|
+
module Stage
|
5
|
+
module Heroku
|
6
|
+
class RememberCommits < Base
|
7
|
+
def call(env)
|
8
|
+
log "Fetching from server"
|
9
|
+
execute "git fetch #{env[:server_remote]}"
|
10
|
+
|
11
|
+
env[:deployed_commit] = latest_commit("#{env[:server_remote]}/master")
|
12
|
+
env[:new_commit] = latest_commit(env[:development_branch])
|
13
|
+
|
14
|
+
@app.call(env)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "takeoff/stage/base"
|
2
|
+
|
3
|
+
module Takeoff
|
4
|
+
module Stage
|
5
|
+
module Heroku
|
6
|
+
class ScaleDownWorkers < Base
|
7
|
+
def call(env)
|
8
|
+
unless env[:dangerous]
|
9
|
+
log "Skipping scaling down workers because nothing dangerous is going on"
|
10
|
+
|
11
|
+
return @app.call(env)
|
12
|
+
end
|
13
|
+
|
14
|
+
number_of_workers = execute(
|
15
|
+
"heroku ps --remote #{env[:server_remote]} | grep '^worker.' | wc -l | tr -d ' '"
|
16
|
+
).to_i
|
17
|
+
|
18
|
+
return @app.call(env) if number_of_workers == 0
|
19
|
+
|
20
|
+
log "Scaling down workers"
|
21
|
+
execute "heroku scale worker=0 --remote #{env[:server_remote]}"
|
22
|
+
|
23
|
+
begin
|
24
|
+
@app.call(env)
|
25
|
+
ensure
|
26
|
+
log "Scaling up workers"
|
27
|
+
execute "heroku scale worker=#{number_of_workers || 0} --remote #{env[:server_remote]}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "takeoff/stage/base"
|
2
|
+
|
3
|
+
module Takeoff
|
4
|
+
module Stage
|
5
|
+
module Heroku
|
6
|
+
class VerifyServerNotAlreadyUpToDate < Base
|
7
|
+
def call(env)
|
8
|
+
if env[:deployed_commit] == env[:new_commit]
|
9
|
+
raise "The server is already up to date."
|
10
|
+
end
|
11
|
+
|
12
|
+
@app.call(env)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "takeoff/stage/base"
|
2
|
+
|
3
|
+
module Takeoff
|
4
|
+
module Stage
|
5
|
+
module Heroku
|
6
|
+
class VerifyStagingUpToDate < Base
|
7
|
+
def call(env)
|
8
|
+
unless Takeoff.plan?("staging")
|
9
|
+
log "WARNING: Skipping verification that the staging server is up to date because a launch plan for the staging environment has not been set up"
|
10
|
+
|
11
|
+
return @app.call(env)
|
12
|
+
end
|
13
|
+
|
14
|
+
staging_takeoff = Takeoff[:staging]
|
15
|
+
|
16
|
+
log "Fetching from staging server"
|
17
|
+
execute "git fetch #{staging_takeoff.env[:server_remote]}"
|
18
|
+
|
19
|
+
unless branches_up_to_date?("#{staging_takeoff.env[:server_remote]}/master", env[:development_branch])
|
20
|
+
raise "The staging server is not up to date with branch '#{env[:development_branch]}'. Deploy to staging first."
|
21
|
+
end
|
22
|
+
|
23
|
+
@app.call(env)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "takeoff/stage/base"
|
2
|
+
|
3
|
+
module Takeoff
|
4
|
+
module Stage
|
5
|
+
class Log < Base
|
6
|
+
def call(env)
|
7
|
+
log "Ready for takeoff! Deploying to #{env[:environment]} server..."
|
8
|
+
|
9
|
+
start_time = Time.now
|
10
|
+
|
11
|
+
begin
|
12
|
+
@app.call(env)
|
13
|
+
rescue
|
14
|
+
end_time = Time.now
|
15
|
+
|
16
|
+
log "Deploying failed in #{end_time - start_time} seconds. Takeoff unsuccessful."
|
17
|
+
puts
|
18
|
+
|
19
|
+
raise
|
20
|
+
else
|
21
|
+
end_time = Time.now
|
22
|
+
|
23
|
+
log "Deploying finished in #{end_time - start_time} seconds. Takeoff successful."
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "takeoff/stage/base"
|
2
|
+
|
3
|
+
module Takeoff
|
4
|
+
module Stage
|
5
|
+
class LookOutForDanger < Base
|
6
|
+
def call(env)
|
7
|
+
env[:stages] = env[:plan].stages.middlewares
|
8
|
+
env[:dangerous_stages] = env[:stages].select { |stage| stage.respond_to?(:dangerous?) && stage.dangerous?(env) }
|
9
|
+
env[:dangerous] = env[:dangerous_stages].count > 0
|
10
|
+
|
11
|
+
@app.call(env)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "takeoff/stage/base"
|
2
|
+
|
3
|
+
module Takeoff
|
4
|
+
module Stage
|
5
|
+
class PointCheckpointToDevelopment < Base
|
6
|
+
def call(env)
|
7
|
+
return @app.call(env) if env[:development_branch] == env[:checkpoint_branch]
|
8
|
+
|
9
|
+
log "Pointing checkpoint branch to development branch"
|
10
|
+
execute "git checkout #{env[:checkpoint_branch]}"
|
11
|
+
|
12
|
+
begin
|
13
|
+
execute "git reset --hard #{env[:development_branch]}"
|
14
|
+
ensure
|
15
|
+
execute "git checkout #{env[:development_branch]}"
|
16
|
+
end
|
17
|
+
|
18
|
+
@app.call(env)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require "takeoff/stage/base"
|
2
|
+
|
3
|
+
module Takeoff
|
4
|
+
module Stage
|
5
|
+
class PushToGithub < Base
|
6
|
+
def call(env)
|
7
|
+
log "Pushing checkpoint branch to GitHub"
|
8
|
+
execute "git push github #{env[:checkpoint_branch]}:#{env[:checkpoint_branch]} --force"
|
9
|
+
|
10
|
+
@app.call(env)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "takeoff/stage/base"
|
2
|
+
|
3
|
+
module Takeoff
|
4
|
+
module Stage
|
5
|
+
class StashChanges < Base
|
6
|
+
def call(env)
|
7
|
+
status = `git status --untracked-files --short`
|
8
|
+
return @app.call(env) if status.blank?
|
9
|
+
|
10
|
+
stash_name = "Takeoff Auto-Stash: #{Time.now}"
|
11
|
+
|
12
|
+
log "Stashing uncommitted changes"
|
13
|
+
execute "git stash save -u #{Shellwords.escape(stash_name)}"
|
14
|
+
|
15
|
+
begin
|
16
|
+
@app.call(env)
|
17
|
+
ensure
|
18
|
+
log "Applying previously stashed uncommitted changes"
|
19
|
+
|
20
|
+
stashes = `git stash list`
|
21
|
+
matched_stash = stashes.split("\n").find { |stash| stash.include?(stash_name) }
|
22
|
+
label = matched_stash.match(/^([^:]+)/)
|
23
|
+
|
24
|
+
execute "git clean -fd"
|
25
|
+
execute "git stash apply #{label}"
|
26
|
+
execute "git stash drop #{label}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require "uri"
|
2
|
+
require "net/http"
|
3
|
+
require "json"
|
4
|
+
|
5
|
+
require "takeoff/stage/base"
|
6
|
+
|
7
|
+
module Takeoff
|
8
|
+
module Stage
|
9
|
+
class VerifyCircleCiStatus < Base
|
10
|
+
def call(env)
|
11
|
+
unless env[:github_repo] && ENV["GITHUB_OAUTH_TOKEN"]
|
12
|
+
log "WARNING: Skipping verification of Circle CI status because GitHub repo or OAuth token isn't set."
|
13
|
+
|
14
|
+
return @app.call(env)
|
15
|
+
end
|
16
|
+
|
17
|
+
raise "A GitHub OAuth token is required to check the Circle CI status." unless ENV["GITHUB_OAUTH_TOKEN"]
|
18
|
+
|
19
|
+
sha = latest_commit(env[:development_branch])
|
20
|
+
|
21
|
+
uri = URI.parse("https://api.github.com/repos/#{env[:github_repo]}/statuses/#{sha}")
|
22
|
+
|
23
|
+
connection = Net::HTTP.new(uri.host, uri.port)
|
24
|
+
connection.use_ssl = true
|
25
|
+
|
26
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
27
|
+
request["Authorization"] = "token #{ENV["GITHUB_OAUTH_TOKEN"]}"
|
28
|
+
response = connection.request(request)
|
29
|
+
|
30
|
+
statuses = JSON.parse(response.body)
|
31
|
+
|
32
|
+
if statuses.find { |s| s["state"] == "success" }
|
33
|
+
# Success
|
34
|
+
elsif status = statuses.find { |s| %w(failure error).include?(s["state"]) }
|
35
|
+
raise "The Circle CI tests for branch '#{env[:development_branch]}' (commit #{sha}) failed. Fix them and try again. See #{status["target_url"]}"
|
36
|
+
elsif status = statuses.find { |s| s["state"] == "pending"}
|
37
|
+
raise "The Circle CI tests for branch '#{env[:development_branch]}' (commit #{sha}) are still running. Wait for them to finish successfully. See #{status["target_url"]}"
|
38
|
+
else
|
39
|
+
raise "The Circle CI tests for branch '#{env[:development_branch]}' (commit #{sha}) have not run yet. Wait for them to start and finish successfully."
|
40
|
+
end
|
41
|
+
|
42
|
+
@app.call(env)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "takeoff/stage/base"
|
2
|
+
|
3
|
+
module Takeoff
|
4
|
+
module Stage
|
5
|
+
class VerifyGithubUpToDate < Base
|
6
|
+
def call(env)
|
7
|
+
log "Fetching from GitHub"
|
8
|
+
execute "git fetch #{env[:github_remote]}"
|
9
|
+
|
10
|
+
unless branches_up_to_date?("#{env[:github_remote]}/#{env[:development_branch]}", env[:development_branch])
|
11
|
+
raise "GitHub is not up to date on branch '#{env[:development_branch]}'. Pull and push to synchronize your changes first."
|
12
|
+
end
|
13
|
+
|
14
|
+
@app.call(env)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/takeoff.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require "active_support/core_ext"
|
2
|
+
|
3
|
+
require "takeoff/version"
|
4
|
+
require "takeoff/configuration"
|
5
|
+
|
6
|
+
require "takeoff/plan/base"
|
7
|
+
require "takeoff/plan/default"
|
8
|
+
|
9
|
+
module Takeoff
|
10
|
+
class << self
|
11
|
+
def configuration
|
12
|
+
@configuration ||= Configuration.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def configure(source = nil, source_location = nil, &block)
|
16
|
+
if source
|
17
|
+
if source_location
|
18
|
+
configuration.instance_eval(source, source_location)
|
19
|
+
else
|
20
|
+
configuration.instance_eval(source)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
if block
|
25
|
+
if block.arity == 1
|
26
|
+
block.call(configuration)
|
27
|
+
else
|
28
|
+
configuration.instance_eval(&block)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
delegate :plans, :[], :plan?, :default_plan, to: :configuration
|
34
|
+
|
35
|
+
def logger
|
36
|
+
@logger ||= Logger.new
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
configure do
|
41
|
+
plan :base, Plan::Base
|
42
|
+
plan :default, Plan::Default
|
43
|
+
end
|
44
|
+
end
|
data/takeoff.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
$:.unshift File.expand_path("../lib", __FILE__)
|
2
|
+
require "takeoff/version"
|
3
|
+
|
4
|
+
Gem::Specification.new do |spec|
|
5
|
+
spec.name = "takeoff"
|
6
|
+
spec.version = Takeoff::VERSION
|
7
|
+
spec.author = "Douwe Maan"
|
8
|
+
spec.email = "douwe@selenight.nl"
|
9
|
+
spec.summary = "Sit back, relax and let Takeoff deploy your app."
|
10
|
+
spec.description = "Takeoff is a command line tool that helps you deploy your web applications. Configure it once, and from then on Takeoff will take care of responsibly deploying your app, giving you time to get more coffee."
|
11
|
+
spec.homepage = "https://github.com/DouweM/takeoff"
|
12
|
+
spec.license = "MIT"
|
13
|
+
|
14
|
+
spec.files = `git ls-files -z`.split("\x0")
|
15
|
+
spec.executables = ["takeoff"]
|
16
|
+
spec.require_paths = ["lib"]
|
17
|
+
|
18
|
+
spec.add_dependency "activesupport"
|
19
|
+
spec.add_dependency "middleware"
|
20
|
+
spec.add_dependency "thor"
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
+
end
|