sunraise 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +0 -0
- data/bin/sunraise +26 -0
- data/lib/config.rb +97 -0
- data/lib/deployer.rb +197 -0
- data/sunraise.example +12 -0
- data/sunraise.gemspec +26 -0
- metadata +80 -0
data/README.md
ADDED
File without changes
|
data/bin/sunraise
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'rainbow'
|
5
|
+
|
6
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'config')
|
7
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'deployer')
|
8
|
+
|
9
|
+
include SunRaise::PubConf
|
10
|
+
|
11
|
+
|
12
|
+
if File.expand_path(__FILE__) == File.expand_path(File.join(Dir.pwd, 'sunraise'))
|
13
|
+
puts "Run it from you app folder, containing sunraise file with deploy instructions"
|
14
|
+
exit
|
15
|
+
end
|
16
|
+
|
17
|
+
unless File.file?(File.join Dir.pwd, 'sunraise')
|
18
|
+
puts "No sunraise file found at #{Dir.pwd}"
|
19
|
+
exit
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
at_exit { SunRaise::Deployer.new.go! }
|
24
|
+
|
25
|
+
|
26
|
+
load File.join Dir.pwd, 'sunraise'
|
data/lib/config.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require 'optparse'
|
3
|
+
|
4
|
+
module SunRaise
|
5
|
+
# configurator class
|
6
|
+
class Config
|
7
|
+
|
8
|
+
include Singleton
|
9
|
+
attr_accessor :conf, :callbacks
|
10
|
+
|
11
|
+
class << self
|
12
|
+
attr_accessor :config_methods
|
13
|
+
end
|
14
|
+
|
15
|
+
@config_methods = [
|
16
|
+
:remote_host,
|
17
|
+
:remote_user,
|
18
|
+
:deploy_to,
|
19
|
+
:then_link_to,
|
20
|
+
:git_url,
|
21
|
+
:shared_dirs,
|
22
|
+
:linked_dirs,
|
23
|
+
:local_project_path,
|
24
|
+
:verbose,
|
25
|
+
:force,
|
26
|
+
:release,
|
27
|
+
:remake,
|
28
|
+
:test_rails_app,
|
29
|
+
:auto_migrate,
|
30
|
+
:help,
|
31
|
+
:destroy
|
32
|
+
]
|
33
|
+
|
34
|
+
@config_methods.each do |method_name|
|
35
|
+
define_method method_name do |value|
|
36
|
+
value.strip! if value.class == String
|
37
|
+
@conf[method_name] = value
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def initialize
|
42
|
+
@callbacks = {:after => ''}
|
43
|
+
@conf = {
|
44
|
+
:verbose => false,
|
45
|
+
:local_project_path => '.',
|
46
|
+
:release => true,
|
47
|
+
:test_rails_app => true,
|
48
|
+
:auto_migrate => true,
|
49
|
+
:help => false
|
50
|
+
}
|
51
|
+
|
52
|
+
cl_options
|
53
|
+
end
|
54
|
+
|
55
|
+
def cl_options
|
56
|
+
OptionParser.new do |opts|
|
57
|
+
opts.on("-v", "--[no-]verbose", "Run verbosely") do |verbose|
|
58
|
+
@conf[:verbose] = verbose
|
59
|
+
end
|
60
|
+
|
61
|
+
opts.on("-f", "--[no-]force", "Deploy even there are no new commits") do |force|
|
62
|
+
@conf[:force] = force
|
63
|
+
end
|
64
|
+
|
65
|
+
opts.on("-n", "--no-reelase", "Do not replace 'current' dir and start test server") do |no_release|
|
66
|
+
@conf[:release] = !no_release
|
67
|
+
end
|
68
|
+
|
69
|
+
opts.on("--remake", "Delete current deploy and make initial deploy") do |remake|
|
70
|
+
@conf[:remake] = remake
|
71
|
+
end
|
72
|
+
|
73
|
+
opts.on("-d", "--destroy", "Delete current deploy and make initial deploy") do |destroy|
|
74
|
+
@conf[:destroy] = destroy
|
75
|
+
end
|
76
|
+
|
77
|
+
opts.on("-h", "--help", "Show this help") do |help|
|
78
|
+
@conf[:help] = true
|
79
|
+
puts opts
|
80
|
+
end
|
81
|
+
end.parse!
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
module PubConf
|
87
|
+
SunRaise::Config.config_methods.each do |method_name|
|
88
|
+
define_method method_name do |value|
|
89
|
+
SunRaise::Config.instance.send method_name, value
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def after_deploy &block
|
94
|
+
SunRaise::Config.instance.callbacks[:after] = block
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
data/lib/deployer.rb
ADDED
@@ -0,0 +1,197 @@
|
|
1
|
+
begin
|
2
|
+
require 'rubygems'
|
3
|
+
gem 'net-ssh', ">= 2.0.10"
|
4
|
+
rescue LoadError, NameError
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'net/ssh'
|
8
|
+
|
9
|
+
module SunRaise
|
10
|
+
# working horse
|
11
|
+
class Deployer
|
12
|
+
|
13
|
+
def go!
|
14
|
+
return if conf[:help]
|
15
|
+
return destroy_existen! if conf[:destroy]
|
16
|
+
if !conf[:remake] && initiated?
|
17
|
+
update
|
18
|
+
else
|
19
|
+
init_deploy
|
20
|
+
end
|
21
|
+
|
22
|
+
callbacks :after
|
23
|
+
|
24
|
+
puts "SSH OUT: \n" + @ssh_out.join("\n") if conf[:verbose]
|
25
|
+
end
|
26
|
+
|
27
|
+
def init_deploy
|
28
|
+
destroy_existen! if conf[:remake]
|
29
|
+
log_ok "initial deploy.."
|
30
|
+
ssh_exec [
|
31
|
+
"mkdir -p #{deploy_path}",
|
32
|
+
"cd #{deploy_path}",
|
33
|
+
"mkdir -p log shared tmp",
|
34
|
+
"git clone #{conf[:git_url]} current"
|
35
|
+
]
|
36
|
+
log_ok "Created dir and cloned repo"
|
37
|
+
|
38
|
+
test_rails_app! 'current' if conf[:test_rails_app]
|
39
|
+
auto_migrate! 'current' if conf[:auto_migrate]
|
40
|
+
|
41
|
+
log_ok "Made new dirs and cloned repo"
|
42
|
+
make_links 'current'
|
43
|
+
end
|
44
|
+
|
45
|
+
def update
|
46
|
+
|
47
|
+
last_commit = ssh_exec ["cd #{current_path}", "git log -1 --pretty=format:\"%H\""]
|
48
|
+
last_repo_commit = (`cd #{conf[:local_project_path]} && git ls-remote #{conf[:git_url]}`).split("\t").first
|
49
|
+
|
50
|
+
if !conf[:force] && last_commit.strip == last_repo_commit.strip
|
51
|
+
log_ok "Nothing to update"
|
52
|
+
return
|
53
|
+
end
|
54
|
+
|
55
|
+
new_commits = (`cd #{conf[:local_project_path]} && git log #{last_commit}..HEAD --pretty=format:"%s"`).split("\n")
|
56
|
+
|
57
|
+
log_ok "New commits: \n #{new_commits.join "\n "}"
|
58
|
+
@new_dir = "pre_release"
|
59
|
+
|
60
|
+
ssh_exec [
|
61
|
+
"cd #{deploy_path}",
|
62
|
+
"rm #{@new_dir} .git_temp previous2 current2 -rf", # if previous deploy was crashed
|
63
|
+
"mv current/.git .git_temp", # moving repo dir
|
64
|
+
"cp current #{@new_dir}", # clone sitedir without .git
|
65
|
+
"mv .git_temp #{@new_dir}/.git", # move git in pre_release folder
|
66
|
+
"cd #{@new_dir}",
|
67
|
+
"git pull origin master"
|
68
|
+
]
|
69
|
+
log_ok "Forked, git updated"
|
70
|
+
|
71
|
+
make_links @new_dir
|
72
|
+
|
73
|
+
test_rails_app! @new_dir if conf[:test_rails_app]
|
74
|
+
auto_migrate! @new_dir if conf[:auto_migrate]
|
75
|
+
|
76
|
+
release! if conf[:release]
|
77
|
+
end
|
78
|
+
|
79
|
+
def release!
|
80
|
+
ssh_exec [
|
81
|
+
"cd #{deploy_path}", # folder magic :) old current => previous, pre_release => current
|
82
|
+
"mv current current2",
|
83
|
+
"mv #{@new_dir} current",
|
84
|
+
"if [ -d previous ]; then mv previous previous2 -f; fi",
|
85
|
+
"mv current2 previous"
|
86
|
+
]
|
87
|
+
log_ok "Released!"
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
def ssh_exec command
|
92
|
+
command = command.join " && " if command.is_a? Array
|
93
|
+
puts ">>>>".color(:cyan) + " #{command}" if conf[:verbose]
|
94
|
+
@ssh_ist ||= Net::SSH.start conf[:remote_host], conf[:remote_user]
|
95
|
+
@ssh_out ||= []
|
96
|
+
@ssh_out << @ssh_ist.exec!(command)
|
97
|
+
@ssh_out.last
|
98
|
+
end
|
99
|
+
|
100
|
+
def make_links dist_dir
|
101
|
+
links = []
|
102
|
+
conf[:shared_dirs].each do |dir|
|
103
|
+
links << "rm #{dir} -rf"
|
104
|
+
links << "mkdir ../shared/#{dir} -p"
|
105
|
+
links << "ln -s ../shared/#{dir} #{dir}"
|
106
|
+
end
|
107
|
+
|
108
|
+
conf[:linked_dirs].each do |dir|
|
109
|
+
links << "rm #{dir} -rf"
|
110
|
+
links << "mkdir ../#{dir} -p"
|
111
|
+
links << "ln -s ../#{dir} #{dir}"
|
112
|
+
end
|
113
|
+
|
114
|
+
ssh_exec ["cd #{File.join deploy_path, dist_dir}"] + links
|
115
|
+
@ssh_out.each {|m| puts m}
|
116
|
+
log_ok "Made links"
|
117
|
+
end
|
118
|
+
|
119
|
+
def initiated?
|
120
|
+
ssh_exec "cd #{current_path}"
|
121
|
+
last_msg = @ssh_out.pop
|
122
|
+
!(last_msg && last_msg =~ /No such file or directory/)
|
123
|
+
end
|
124
|
+
|
125
|
+
def destroy_existen!
|
126
|
+
log_ok "Removing existen deploy dir"
|
127
|
+
ssh_exec "rm #{deploy_path} -rf"
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_rails_app! dir
|
131
|
+
@app_about ||= rails_app_about dir
|
132
|
+
if !@app_about.index('Application root')
|
133
|
+
if !@app_about.index('Database schema version')
|
134
|
+
log_error "Rails app test fail"
|
135
|
+
else
|
136
|
+
log_error "Rails app test: Database didn't configurated"
|
137
|
+
end
|
138
|
+
puts @app_about
|
139
|
+
log_error "Deploy aborted, use " + "ssh #{conf[:remote_user]}@#{conf[:remote_host]}".italic + " to fix it"
|
140
|
+
exit
|
141
|
+
else
|
142
|
+
log_ok "Rails app successfully tested"
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def auto_migrate! dir
|
147
|
+
@app_about ||= rails_app_about dir
|
148
|
+
matches = @app_about.match(/Database schema version\s+ ([0-9]+)/)
|
149
|
+
remote_magration_version = matches && matches.size > 0 && matches[1] || 0
|
150
|
+
local_about = `#{File.join conf[:local_project_path], 'script', 'about'}`
|
151
|
+
local_migration_version = local_about.match(/Database schema version\s+ ([0-9]+)/)[1]
|
152
|
+
if remote_magration_version == local_migration_version
|
153
|
+
msg_ok "No new migrations"
|
154
|
+
else
|
155
|
+
log_ok "Rinning rake db:migrate"
|
156
|
+
puts ssh_exec ["cd #{File.join deploy_path, dir}", "rake db:migrate RAILS_ENV=production"] # run migrations
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def rails_app_about dir
|
161
|
+
ssh_exec "RAILS_ENV=production " + File.join(deploy_path, dir, 'script', 'about') # run script/about
|
162
|
+
end
|
163
|
+
|
164
|
+
def conf
|
165
|
+
SunRaise::Config.instance.conf
|
166
|
+
end
|
167
|
+
|
168
|
+
def callbacks name
|
169
|
+
c = SunRaise::Config.instance.callbacks
|
170
|
+
|
171
|
+
if c[name].class == Proc
|
172
|
+
instance_eval &c[name]
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def current_path
|
177
|
+
File.join conf[:deploy_to], 'current'
|
178
|
+
end
|
179
|
+
|
180
|
+
def deploy_path
|
181
|
+
conf[:deploy_to]
|
182
|
+
end
|
183
|
+
|
184
|
+
def app_path
|
185
|
+
File.join deploy_path, (conf[:release] ? 'current' : 'pre_release' )
|
186
|
+
end
|
187
|
+
|
188
|
+
def log_ok msg
|
189
|
+
puts ":: ".color(:green) + "#{msg}".bright
|
190
|
+
end
|
191
|
+
|
192
|
+
def log_error msg
|
193
|
+
puts "!! ".bright.color(:red) + "#{msg}".bright
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|
197
|
+
end
|
data/sunraise.example
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
remote_host 'twews.com'
|
2
|
+
remote_user 'root'
|
3
|
+
|
4
|
+
git_url 'git://github.com/Paxa/sunraise_test_app.git'
|
5
|
+
|
6
|
+
deploy_to '/tmp/deploy/suntest'
|
7
|
+
then_link_to '/tmp/www/suntest'
|
8
|
+
|
9
|
+
shared_dirs ['lib']
|
10
|
+
linked_dirs ['logs', 'tmp']
|
11
|
+
|
12
|
+
local_project_path "/home/paxa/Dropbox/sunraise/test/suntest"
|
data/sunraise.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "sunraise"
|
3
|
+
s.version = "0.1.1"
|
4
|
+
s.summary = "Super-fast and simple rails deployment."
|
5
|
+
s.description = "Super-fast and simple rails deployment"
|
6
|
+
s.author = "Pavel Evstigneev"
|
7
|
+
s.email = "pavel.evst@gmail.com"
|
8
|
+
s.homepage = "http://github.com/Paxa/sunraise"
|
9
|
+
s.has_rdoc = false
|
10
|
+
s.executables = ["sunraise"]
|
11
|
+
s.rubyforge_project = "sunraise"
|
12
|
+
s.files = [ "bin/sunraise", "lib/config.rb", "lib/deployer.rb", "README.md", "sunraise.gemspec", 'sunraise.example']
|
13
|
+
|
14
|
+
if s.respond_to? :specification_version then
|
15
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
16
|
+
s.specification_version = 3
|
17
|
+
|
18
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
19
|
+
s.add_development_dependency(%q<rainbow>, [">= 1.0.4"])
|
20
|
+
else
|
21
|
+
s.add_dependency(%q<rainbow>, [">= 1.0.4"])
|
22
|
+
end
|
23
|
+
else
|
24
|
+
s.add_dependency(%q<rainbow>, [">= 1.0.4"])
|
25
|
+
end
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sunraise
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 1
|
9
|
+
version: 0.1.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Pavel Evstigneev
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-03-09 00:00:00 +03:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: rainbow
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 1
|
29
|
+
- 0
|
30
|
+
- 4
|
31
|
+
version: 1.0.4
|
32
|
+
type: :development
|
33
|
+
version_requirements: *id001
|
34
|
+
description: Super-fast and simple rails deployment
|
35
|
+
email: pavel.evst@gmail.com
|
36
|
+
executables:
|
37
|
+
- sunraise
|
38
|
+
extensions: []
|
39
|
+
|
40
|
+
extra_rdoc_files: []
|
41
|
+
|
42
|
+
files:
|
43
|
+
- bin/sunraise
|
44
|
+
- lib/config.rb
|
45
|
+
- lib/deployer.rb
|
46
|
+
- README.md
|
47
|
+
- sunraise.gemspec
|
48
|
+
- sunraise.example
|
49
|
+
has_rdoc: true
|
50
|
+
homepage: http://github.com/Paxa/sunraise
|
51
|
+
licenses: []
|
52
|
+
|
53
|
+
post_install_message:
|
54
|
+
rdoc_options: []
|
55
|
+
|
56
|
+
require_paths:
|
57
|
+
- lib
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
version: "0"
|
65
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
segments:
|
70
|
+
- 0
|
71
|
+
version: "0"
|
72
|
+
requirements: []
|
73
|
+
|
74
|
+
rubyforge_project: sunraise
|
75
|
+
rubygems_version: 1.3.6
|
76
|
+
signing_key:
|
77
|
+
specification_version: 3
|
78
|
+
summary: Super-fast and simple rails deployment.
|
79
|
+
test_files: []
|
80
|
+
|