kapost_deploy 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +56 -19
- data/lib/kapost_deploy.rb +0 -1
- data/lib/kapost_deploy/heroku/app_promoter.rb +53 -0
- data/lib/kapost_deploy/heroku/app_releases.rb +36 -0
- data/lib/kapost_deploy/heroku/shell.rb +42 -0
- data/lib/kapost_deploy/identity.rb +1 -2
- data/lib/kapost_deploy/plugins/db_migrate.rb +25 -0
- data/lib/kapost_deploy/plugins/slack_after_promote.rb +19 -6
- data/lib/kapost_deploy/plugins/slack_github_diff.rb +29 -28
- data/lib/kapost_deploy/slack/notifier.rb +30 -0
- data/lib/kapost_deploy/task.rb +56 -77
- data/lib/tasks/console.rake +1 -0
- data/lib/tasks/rspec.rake +1 -0
- data/lib/tasks/rubocop.rake +1 -0
- metadata +14 -10
- data/lib/kapost_deploy/plugins/slack/notifier.rb +0 -35
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 465752e220872c86cf728e906b64fa82ff5ba691
|
4
|
+
data.tar.gz: 5592571df0b04754ce3ed7ba452d7defba8d6b3f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 34aa223ee90e83d688b15bacc6464ec20f9608ebd82b8a52e202ce4b491060c4b2fae5c8fb1090cd971f51d298e8f628158bdec4f398798cb7bfda8d1d973e58
|
7
|
+
data.tar.gz: 86b999a1120428691ae4bb0c6d660c64360e01cf21140d114275a4368c0c47d6b5b04053bff21c8f70489851a69200e5cab93665cf054bd22d18941b331a09f9
|
data/README.md
CHANGED
@@ -22,7 +22,7 @@
|
|
22
22
|
|
23
23
|
# Features
|
24
24
|
|
25
|
-
`KapostDeploy::Task.
|
25
|
+
`KapostDeploy::Task.define` creates the following rake tasks to aid in the pipeline promotion deployment of Heroku applications
|
26
26
|
|
27
27
|
[promote]
|
28
28
|
Promotes a source environment to production
|
@@ -35,11 +35,13 @@
|
|
35
35
|
|
36
36
|
Simple Example:
|
37
37
|
|
38
|
-
require
|
38
|
+
require "kapost_deploy/task"
|
39
39
|
|
40
|
-
KapostDeploy::Task.
|
41
|
-
config.app =
|
42
|
-
config.to =
|
40
|
+
KapostDeploy::Task.define do |config|
|
41
|
+
config.app = "cabbage-staging"
|
42
|
+
config.to = "cabbage-production"
|
43
|
+
config.pipeline = "cabbage"
|
44
|
+
config.heroku_api_token = "123"
|
43
45
|
|
44
46
|
config.after do
|
45
47
|
puts "It's Miller time"
|
@@ -49,26 +51,56 @@ Simple Example:
|
|
49
51
|
A slightly more complex example which will create 6 rake tasks: stage:before_stage, stage,
|
50
52
|
stage:after_stage, promote:before_promote, promote, promote:after_promote
|
51
53
|
|
52
|
-
|
53
|
-
|
54
|
-
|
54
|
+
require "kapost_deploy/task"
|
55
|
+
require "kapost_deploy/plugins/slack_after_promote"
|
56
|
+
require "kapost_deploy/plugins/slack_github_diff"
|
57
|
+
require "kapost_deploy/plugins/db_migrate"
|
58
|
+
|
59
|
+
CONFIG = {
|
60
|
+
slack_config: {
|
61
|
+
webhook_url: "https://hooks.slack.com/services/34326/FDSJFH127/68357sdhfjhHSJGFNMDngsd",
|
62
|
+
channel: "#danger",
|
63
|
+
icon_url: "http://yourcompany.s3.amazonaws.com/logo.png"
|
64
|
+
},
|
65
|
+
git_config: {
|
66
|
+
github_repo: "yourcompany/widget"
|
67
|
+
}
|
68
|
+
}.freeze
|
69
|
+
|
70
|
+
KapostDeploy::Task.define(:stage) do |config|
|
71
|
+
config.app = "cabbage-staging"
|
72
|
+
config.to = "cabbage-sandbox"
|
73
|
+
config.pipeline = "cabbage"
|
74
|
+
config.heroku_api_token = "123"
|
75
|
+
|
76
|
+
config.options = CONFIG
|
55
77
|
|
56
78
|
config.after do
|
57
79
|
sleep 60*2 wait for dynos to restart
|
58
80
|
slack.notify "The eagle has landed. [Go validate](https://testbed.sandbox.com/dashboard)!"
|
59
81
|
Launchy.open("https://testbed.sandbox.com/dashboard")
|
60
82
|
end
|
83
|
+
|
84
|
+
config.add_plugin(KapostDeploy::Plugins::DbMigrate)
|
61
85
|
end
|
62
86
|
|
63
|
-
KapostDeploy::Task.
|
64
|
-
config.app =
|
65
|
-
config.to =
|
87
|
+
KapostDeploy::Task.define do |config|
|
88
|
+
config.app = "cabbage-sandboxc"
|
89
|
+
config.to = "cabbage-production"
|
90
|
+
config.pipeline = "cabbage"
|
91
|
+
config.heroku_api_token = "123"
|
92
|
+
|
93
|
+
config.options = CONFIG
|
66
94
|
|
67
95
|
config.before do
|
68
|
-
puts
|
96
|
+
puts "Are you sure you did x, y, and z? yes/no: "
|
69
97
|
confirm = gets.strip
|
70
|
-
exit(1) unless confirm.downcase ==
|
98
|
+
exit(1) unless confirm.downcase == "yes"
|
71
99
|
end
|
100
|
+
|
101
|
+
config.add_plugin(KapostDeploy::Plugins::SlackGithubDiff)
|
102
|
+
config.add_plugin(KapostDeploy::Plugins::DbMigrate)
|
103
|
+
config.add_plugin(KapostDeploy::Plugins::SlackAfterPromote)
|
72
104
|
end
|
73
105
|
|
74
106
|
# Requirements
|
@@ -78,14 +110,19 @@ stage:after_stage, promote:before_promote, promote, promote:after_promote
|
|
78
110
|
|
79
111
|
# Configuration Options
|
80
112
|
|
113
|
+
* `pipeline`: The application pipeline to promote
|
114
|
+
* `heroku_api_token`: Your platform api token. You can retrieve this using `heroku auth:token`
|
81
115
|
* `app`: The application to be promoted
|
82
116
|
* `to`: The downstream application(s) to receive the promotion. For multiple environments, use an array.
|
83
|
-
* `
|
84
|
-
* `
|
85
|
-
|
86
|
-
* `
|
87
|
-
|
88
|
-
|
117
|
+
* `options`: An options hash containing plugin options:
|
118
|
+
* `git_config`: If using github plugins, an options hash containing the following keys:
|
119
|
+
* `github_repo`: The owner/repo string, such as `kapost/kapost_deploy`
|
120
|
+
* `slack_config`: If using slack plugins, an options hash containing the following keys:
|
121
|
+
* `webhook_url`: The webhook URL you added to your slack integrations
|
122
|
+
* `username`: The apparent username of the notifier *defaults to "webhooks bot"*
|
123
|
+
* `channel`: The channel name to post the notification to *defaults to "#general"*
|
124
|
+
* `icon_url`: A URL for the icon image *optional*
|
125
|
+
* `icon_emoji`: Emoji name to use instead of an icon *optional*
|
89
126
|
|
90
127
|
# Setup
|
91
128
|
|
data/lib/kapost_deploy.rb
CHANGED
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "platform-api"
|
3
|
+
|
4
|
+
module KapostDeploy
|
5
|
+
module Heroku
|
6
|
+
# Promotes a heroku app via Heroku Plaform API
|
7
|
+
class AppPromoter
|
8
|
+
def initialize(pipeline, token:)
|
9
|
+
self.pipeline = pipeline
|
10
|
+
self.token = token
|
11
|
+
end
|
12
|
+
|
13
|
+
def promote(from:, to:)
|
14
|
+
pipeline_id = discover_pipeline(pipeline)["id"]
|
15
|
+
from_id = discover_app(from)["id"]
|
16
|
+
to_id = discover_app(to)["id"]
|
17
|
+
|
18
|
+
promotion_data = {
|
19
|
+
pipeline: { id: pipeline_id },
|
20
|
+
source: { app: { id: from_id } },
|
21
|
+
targets: [{ app: { id: to_id } }]
|
22
|
+
}
|
23
|
+
|
24
|
+
wait_for_promotion(heroku.pipeline_promotion.create(promotion_data))
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
attr_accessor :pipeline
|
30
|
+
attr_accessor :token
|
31
|
+
|
32
|
+
def wait_for_promotion(promotion)
|
33
|
+
while promotion["status"] == "pending"
|
34
|
+
print "."
|
35
|
+
sleep 1
|
36
|
+
promotion = heroku.pipeline_promotion.info(promotion["id"])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def discover_pipeline(pipeline)
|
41
|
+
heroku.pipeline.info(pipeline)
|
42
|
+
end
|
43
|
+
|
44
|
+
def discover_app(app_name)
|
45
|
+
heroku.app.info(app_name)
|
46
|
+
end
|
47
|
+
|
48
|
+
def heroku
|
49
|
+
@heroku ||= PlatformAPI.connect(token)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "platform-api"
|
3
|
+
|
4
|
+
module KapostDeploy
|
5
|
+
module Heroku
|
6
|
+
# Promotes a heroku app via Heroku Plaform API
|
7
|
+
class AppReleases
|
8
|
+
def initialize(app, token:)
|
9
|
+
self.app = app
|
10
|
+
self.token = token
|
11
|
+
end
|
12
|
+
|
13
|
+
def latest_deploy_version
|
14
|
+
# This appears to be conventional for pipelines and standard heroku deploys and not a
|
15
|
+
# good way to get the deployed git version.
|
16
|
+
list.each do |item|
|
17
|
+
return Regexp.last_match[:sha1] if item["description"] =~ /^Deploy (?<sha1>[a-f0-9]+)$/
|
18
|
+
end
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def list
|
23
|
+
heroku.release.list(app)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
attr_accessor :app
|
29
|
+
attr_accessor :token
|
30
|
+
|
31
|
+
def heroku
|
32
|
+
@heroku ||= PlatformAPI.connect(token, default_headers: { "Range" => "version ..; order=desc" })
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "bundler"
|
3
|
+
require "English"
|
4
|
+
|
5
|
+
module KapostDeploy
|
6
|
+
module Heroku
|
7
|
+
# Wraps the heroku shell environment
|
8
|
+
# Derived from https://github.com/fastestforward/heroku_san
|
9
|
+
class Shell
|
10
|
+
def initialize(app)
|
11
|
+
self.app = app
|
12
|
+
end
|
13
|
+
|
14
|
+
def run(command)
|
15
|
+
sh("run " + command)
|
16
|
+
end
|
17
|
+
|
18
|
+
def sh(command)
|
19
|
+
preflight_check_for_cli
|
20
|
+
|
21
|
+
cmd = command.split(" ")
|
22
|
+
cmd += ["--app", app]
|
23
|
+
cmd << "--exit-code" if command =~ /^run/
|
24
|
+
|
25
|
+
show_command = cmd.join(" ")
|
26
|
+
ok = ::Bundler.with_clean_env { system "heroku", *cmd }
|
27
|
+
|
28
|
+
ok or fail "Command failed with status (#{$CHILD_STATUS.exitstatus}): [heroku #{show_command}]"
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
attr_accessor :app
|
34
|
+
|
35
|
+
def preflight_check_for_cli
|
36
|
+
if Bundler.with_clean_env { system("heroku version").nil? }
|
37
|
+
fail "The Heroku Toolbelt is required for this action. http://toolbelt.heroku.com"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "kapost_deploy/heroku/shell"
|
3
|
+
|
4
|
+
module KapostDeploy
|
5
|
+
module Plugins
|
6
|
+
# After-promotion task to run rake db:migrate
|
7
|
+
class DbMigrate
|
8
|
+
def initialize(config,
|
9
|
+
shell: KapostDeploy::Heroku::Shell.new(config.to))
|
10
|
+
self.shell = shell
|
11
|
+
end
|
12
|
+
|
13
|
+
def before
|
14
|
+
end
|
15
|
+
|
16
|
+
def after
|
17
|
+
shell.run("rake db:migrate")
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
attr_accessor :shell
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -1,11 +1,13 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "kapost_deploy/slack/notifier"
|
2
3
|
|
3
4
|
module KapostDeploy
|
4
5
|
module Plugins
|
5
6
|
# After-promotion plugin to notify via slack after a promotion is complete with an
|
6
7
|
# optional message.
|
7
8
|
class SlackAfterPromote
|
8
|
-
def initialize(config,
|
9
|
+
def initialize(config,
|
10
|
+
notifier: KapostDeploy::Slack::Notifier.new(config.options.fetch(:slack_config, nil)))
|
9
11
|
self.config = config
|
10
12
|
self.notifier = notifier
|
11
13
|
end
|
@@ -16,18 +18,29 @@ module KapostDeploy
|
|
16
18
|
def after
|
17
19
|
return unless notifier.configured?
|
18
20
|
|
19
|
-
|
20
|
-
addl = "\n#{addl}" unless addl.empty?
|
21
|
-
|
22
|
-
message = "#{identity} promoted *#{config.app}* to *#{config.to.join(",")}*#{addl}"
|
21
|
+
message = "#{identity} promoted *#{config.app}* to *#{config.to}*#{additional_message}"
|
23
22
|
notifier.notify(message)
|
24
23
|
end
|
25
24
|
|
26
25
|
private
|
27
26
|
|
27
|
+
def additional_message
|
28
|
+
slack_config = config.options.fetch(:slack_config)
|
29
|
+
addl = ""
|
30
|
+
addl = slack_config.fetch(:additional_message, "") unless slack_config.nil?
|
31
|
+
addl = "\n#{addl}" unless addl.empty?
|
32
|
+
addl
|
33
|
+
end
|
34
|
+
|
35
|
+
def identity
|
36
|
+
@identity ||= `whoami`.chomp
|
37
|
+
end
|
38
|
+
|
28
39
|
attr_accessor :notifier
|
29
40
|
|
30
41
|
attr_accessor :config
|
42
|
+
|
43
|
+
attr_accessor :slack_config
|
31
44
|
end
|
32
45
|
end
|
33
46
|
end
|
@@ -1,24 +1,31 @@
|
|
1
|
-
|
2
|
-
require "
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "kapost_deploy/slack/notifier"
|
3
|
+
require "kapost_deploy/heroku/app_releases"
|
3
4
|
|
4
5
|
module KapostDeploy
|
5
6
|
module Plugins
|
6
7
|
# Before-promotion plugin to notify slack with a github comparison warning
|
7
8
|
class SlackGithubDiff
|
8
|
-
def initialize(config,
|
9
|
-
|
9
|
+
def initialize(config,
|
10
|
+
notifier: KapostDeploy::Slack::Notifier.new(config.options.fetch(:slack_config, nil)),
|
11
|
+
behind_releases: KapostDeploy::Heroku::AppReleases.new(config.to, token: config.heroku_api_token),
|
12
|
+
ahead_releases: KapostDeploy::Heroku::AppReleases.new(config.app, token: config.heroku_api_token))
|
13
|
+
|
10
14
|
self.ahead_app = config.app
|
11
|
-
self.
|
15
|
+
self.behind_app = config.to
|
16
|
+
self.git_config = config.options.fetch(:git_config, nil)
|
12
17
|
self.notifier = notifier
|
18
|
+
self.behind_releases = behind_releases
|
19
|
+
self.ahead_releases = ahead_releases
|
13
20
|
end
|
14
21
|
|
15
22
|
def before
|
16
23
|
return unless configured?
|
17
24
|
|
18
|
-
|
19
|
-
|
25
|
+
msg = "#{identity} is promoting <#{github_compare_url}|#{ahead_sha1}>"\
|
26
|
+
" from *#{ahead_app}* to *#{behind_app}*"
|
20
27
|
|
21
|
-
notifier.notify(
|
28
|
+
notifier.notify(msg)
|
22
29
|
end
|
23
30
|
|
24
31
|
def after
|
@@ -26,37 +33,31 @@ module KapostDeploy
|
|
26
33
|
|
27
34
|
private
|
28
35
|
|
29
|
-
def behind_sha1
|
30
|
-
@behind_sha1 ||= heroku_head_sha1(behind_app)
|
31
|
-
end
|
32
|
-
|
33
|
-
def ahead_sha1
|
34
|
-
@ahead_sha1 ||= heroku_head_sha1(ahead_app)
|
35
|
-
end
|
36
|
-
|
37
36
|
attr_accessor :notifier
|
38
|
-
attr_accessor :
|
39
|
-
attr_accessor :
|
37
|
+
attr_accessor :git_config
|
38
|
+
attr_accessor :behind_releases
|
39
|
+
attr_accessor :ahead_releases
|
40
40
|
attr_accessor :ahead_app
|
41
|
+
attr_accessor :behind_app
|
41
42
|
|
42
|
-
def
|
43
|
-
|
43
|
+
def behind_sha1
|
44
|
+
@behind_sha1 ||= behind_releases.latest_deploy_version
|
44
45
|
end
|
45
46
|
|
46
|
-
def
|
47
|
-
|
47
|
+
def ahead_sha1
|
48
|
+
@ahead_sha1 ||= ahead_releases.latest_deploy_version
|
48
49
|
end
|
49
50
|
|
50
|
-
def
|
51
|
-
|
51
|
+
def identity
|
52
|
+
@identity ||= `whoami`.chomp
|
52
53
|
end
|
53
54
|
|
54
|
-
def
|
55
|
-
|
55
|
+
def configured?
|
56
|
+
!git_config.nil? && notifier.configured?
|
56
57
|
end
|
57
58
|
|
58
|
-
def
|
59
|
-
|
59
|
+
def github_compare_url
|
60
|
+
"https://github.com/#{git_config[:github_repo]}/compare/#{behind_sha1}...#{ahead_sha1}"
|
60
61
|
end
|
61
62
|
end
|
62
63
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "slack-notify"
|
3
|
+
|
4
|
+
module KapostDeploy
|
5
|
+
module Slack
|
6
|
+
# Wrapper for slack-notify gem
|
7
|
+
class Notifier
|
8
|
+
def initialize(slack_config)
|
9
|
+
self.slack_config = slack_config
|
10
|
+
end
|
11
|
+
|
12
|
+
def notify(message)
|
13
|
+
return unless configured?
|
14
|
+
slack.notify(message)
|
15
|
+
end
|
16
|
+
|
17
|
+
def configured?
|
18
|
+
!slack_config.nil?
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def slack
|
24
|
+
@slack ||= SlackNotify::Client.new(slack_config)
|
25
|
+
end
|
26
|
+
|
27
|
+
attr_accessor :slack_config
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/kapost_deploy/task.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require "rake"
|
2
3
|
require "rake/tasklib"
|
3
|
-
require "
|
4
|
+
require "kapost_deploy/heroku/app_promoter"
|
4
5
|
|
5
6
|
module KapostDeploy
|
6
7
|
##
|
@@ -8,7 +9,9 @@ module KapostDeploy
|
|
8
9
|
#
|
9
10
|
# require 'kapost_deploy/task'
|
10
11
|
#
|
11
|
-
# KapostDeploy::Task.
|
12
|
+
# KapostDeploy::Task.define do |config|
|
13
|
+
# config.pipeline = 'cabbage'
|
14
|
+
# config.heroku_api_token = ENV.fetch('HEROKU_API_TOKEN')
|
12
15
|
# config.app = 'cabbage-democ'
|
13
16
|
# config.to = 'cabbage-prodc'
|
14
17
|
#
|
@@ -17,48 +20,27 @@ module KapostDeploy
|
|
17
20
|
# end
|
18
21
|
# end
|
19
22
|
#
|
20
|
-
# A slightly more complex example which will create 6 rake tasks: before_stage, stage,
|
21
|
-
# after_stage, before_promote, promote, after_promote
|
22
|
-
#
|
23
|
-
# KapostDeploy::Task.new(:stage) do |config|
|
24
|
-
# config.app = 'cabbage-stagingc'
|
25
|
-
# config.to = %w[cabbage-sandboxc cabbage-democ]
|
26
|
-
#
|
27
|
-
# config.after do
|
28
|
-
# sleep 60*2 # wait for dynos to restart
|
29
|
-
# notifier.ping "The eagle has landed. [Go validate](https://testbed.sandbox.com/dashboard)!"
|
30
|
-
# Launchy.open("https://testbed.sandbox.com/dashboard")
|
31
|
-
# end
|
32
|
-
# end
|
33
|
-
#
|
34
|
-
# KapostDeploy::Task.new(:promote) do |config|
|
35
|
-
# config.app = 'cabbage-sandbox1c'
|
36
|
-
# config.to = 'cabbage-prodc'
|
37
|
-
#
|
38
|
-
# config.before do
|
39
|
-
# puts 'Are you sure you did x, y, and z? yes/no: '
|
40
|
-
# confirm = gets.strip
|
41
|
-
# exit(1) unless confirm.downcase == 'yes'
|
42
|
-
# end
|
43
|
-
# end
|
44
23
|
class Task < Rake::TaskLib
|
45
24
|
attr_accessor :app
|
46
25
|
|
47
|
-
|
26
|
+
attr_accessor :to
|
27
|
+
|
28
|
+
attr_accessor :pipeline
|
29
|
+
|
30
|
+
attr_accessor :heroku_api_token
|
48
31
|
|
49
32
|
attr_accessor :name
|
50
33
|
|
51
|
-
attr_accessor :
|
34
|
+
attr_accessor :options
|
52
35
|
|
53
|
-
def
|
54
|
-
|
55
|
-
@name = name
|
56
|
-
@shell = shell
|
36
|
+
def self.define(name = :promote) # :yield: self
|
37
|
+
instance = new(name)
|
57
38
|
|
58
|
-
yield
|
39
|
+
yield instance if block_given?
|
59
40
|
|
60
|
-
validate
|
61
|
-
define
|
41
|
+
instance.validate
|
42
|
+
instance.define
|
43
|
+
instance
|
62
44
|
end
|
63
45
|
|
64
46
|
def before(&block)
|
@@ -69,81 +51,78 @@ module KapostDeploy
|
|
69
51
|
@after = block
|
70
52
|
end
|
71
53
|
|
72
|
-
def
|
73
|
-
|
54
|
+
def add_plugin(plugin)
|
55
|
+
plugins << plugin
|
74
56
|
end
|
75
57
|
|
76
58
|
def defaults
|
77
59
|
@name = :promote
|
60
|
+
@pipeline = nil
|
61
|
+
@heroku_api_token = nil
|
78
62
|
@app = nil
|
79
|
-
@
|
80
|
-
@to = []
|
63
|
+
@to = nil
|
81
64
|
@before = -> {}
|
82
65
|
@after = -> {}
|
66
|
+
@plugins = []
|
67
|
+
@options = {}
|
83
68
|
end
|
84
69
|
|
85
70
|
def validate
|
71
|
+
fail "No 'heroku_api_token' configured."\
|
72
|
+
"Set config.heroku_api_token to your API secret token" if heroku_api_token.nil?
|
73
|
+
fail "No 'pipeline' configured. Set config.pipeline to the name of your pipeline" if pipeline.nil?
|
86
74
|
fail "No 'app' configured. Set config.app to the application to be promoted" if app.nil?
|
87
|
-
fail "No 'to' configured. Set config.to to the downstream application
|
75
|
+
fail "No 'to' configured. Set config.to to the downstream application to be promoted to" if to.nil?
|
88
76
|
end
|
89
77
|
|
90
78
|
def define
|
91
79
|
define_hooks
|
92
80
|
|
93
|
-
desc "Promote #{app} to #{to
|
81
|
+
desc "Promote #{app} to #{to}"
|
94
82
|
task name.to_s do
|
95
|
-
|
96
|
-
@before.call
|
97
|
-
promote
|
98
|
-
notify_slack
|
99
|
-
@after.call
|
83
|
+
promote_with_hooks
|
100
84
|
end
|
101
85
|
end
|
102
86
|
|
103
87
|
private
|
104
88
|
|
105
|
-
def
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
def pipelines_installed?
|
110
|
-
`heroku plugins` =~ /^heroku-pipelines@/
|
89
|
+
def initialize(name)
|
90
|
+
defaults
|
91
|
+
self.name = name
|
111
92
|
end
|
112
93
|
|
113
|
-
|
114
|
-
namespace :"#{name}" do
|
115
|
-
desc "Perform after-#{name} tasks"
|
116
|
-
task :"after_#{name}" do
|
117
|
-
@after.call
|
118
|
-
end
|
94
|
+
attr_accessor :plugins
|
119
95
|
|
120
|
-
|
121
|
-
|
122
|
-
@before.call
|
123
|
-
end
|
124
|
-
end
|
96
|
+
def promoter
|
97
|
+
@promoter ||= KapostDeploy::Heroku::AppPromoter.new(pipeline, token: heroku_api_token)
|
125
98
|
end
|
126
99
|
|
127
|
-
def
|
128
|
-
|
100
|
+
def promote_with_hooks
|
101
|
+
Rake.application[:"#{name}:before_#{name}"].execute
|
102
|
+
promoter.promote(from: app, to: to)
|
103
|
+
Rake.application[:"#{name}:after_#{name}"].execute
|
129
104
|
end
|
130
105
|
|
131
|
-
def
|
132
|
-
|
133
|
-
|
134
|
-
addl = slack_config.fetch(:additional_message, "")
|
135
|
-
addl = "\n#{addl}" unless addl.empty?
|
136
|
-
|
137
|
-
message = "#{identity} promoted *#{app}* to *#{to.join(",")}*#{addl}"
|
138
|
-
slack.notify(message)
|
106
|
+
def shell(command)
|
107
|
+
@shell.call(command)
|
139
108
|
end
|
140
109
|
|
141
|
-
def
|
142
|
-
|
110
|
+
def define_hooks
|
111
|
+
namespace :"#{name}" do
|
112
|
+
define_hook(:before)
|
113
|
+
define_hook(:after)
|
114
|
+
end
|
143
115
|
end
|
144
116
|
|
145
|
-
def
|
146
|
-
|
117
|
+
def define_hook(kind)
|
118
|
+
desc "Perform #{kind}-#{name} tasks"
|
119
|
+
task :"#{kind}_#{name}" do
|
120
|
+
instance_variable_get(:"@#{kind}").call
|
121
|
+
plugins.each do |p|
|
122
|
+
plugin = p.new(self)
|
123
|
+
plugin.send(kind) if plugin.respond_to?(kind)
|
124
|
+
end
|
125
|
+
end
|
147
126
|
end
|
148
127
|
end
|
149
128
|
end
|
data/lib/tasks/console.rake
CHANGED
data/lib/tasks/rspec.rake
CHANGED
data/lib/tasks/rubocop.rake
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kapost_deploy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brandon Croft
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-05-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -25,31 +25,31 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '10.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: platform-api
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 0.6.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 0.6.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: slack-notify
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: 0.4.1
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: 0.4.1
|
55
55
|
- !ruby/object:Gem::Dependency
|
@@ -272,10 +272,14 @@ extra_rdoc_files:
|
|
272
272
|
files:
|
273
273
|
- README.md
|
274
274
|
- lib/kapost_deploy.rb
|
275
|
+
- lib/kapost_deploy/heroku/app_promoter.rb
|
276
|
+
- lib/kapost_deploy/heroku/app_releases.rb
|
277
|
+
- lib/kapost_deploy/heroku/shell.rb
|
275
278
|
- lib/kapost_deploy/identity.rb
|
276
|
-
- lib/kapost_deploy/plugins/
|
279
|
+
- lib/kapost_deploy/plugins/db_migrate.rb
|
277
280
|
- lib/kapost_deploy/plugins/slack_after_promote.rb
|
278
281
|
- lib/kapost_deploy/plugins/slack_github_diff.rb
|
282
|
+
- lib/kapost_deploy/slack/notifier.rb
|
279
283
|
- lib/kapost_deploy/task.rb
|
280
284
|
- lib/tasks/console.rake
|
281
285
|
- lib/tasks/rspec.rake
|
@@ -1,35 +0,0 @@
|
|
1
|
-
require "slack-notify"
|
2
|
-
|
3
|
-
module KapostDeploy
|
4
|
-
module Plugins
|
5
|
-
module Slack
|
6
|
-
# Wrapper for slack-notify gem
|
7
|
-
class Notifier
|
8
|
-
def initialize(slack_config)
|
9
|
-
self.slack_config = slack_config
|
10
|
-
end
|
11
|
-
|
12
|
-
def notify_slack(message)
|
13
|
-
return unless configured?
|
14
|
-
slack.notify(message)
|
15
|
-
end
|
16
|
-
|
17
|
-
def identity
|
18
|
-
@identity ||= `whoami`.chomp
|
19
|
-
end
|
20
|
-
|
21
|
-
def configured?
|
22
|
-
!slack_config.nil?
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
def slack
|
28
|
-
@slack ||= SlackNotify::Client.new(slack_config)
|
29
|
-
end
|
30
|
-
|
31
|
-
attr_accessor :slack_config
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|