osbro-git-deploy 0.5.5
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +18 -0
- data/README.markdown +86 -0
- data/bin/git-deploy +3 -0
- data/lib/git_deploy.rb +110 -0
- data/lib/git_deploy/configuration.rb +81 -0
- data/lib/git_deploy/generator.rb +28 -0
- data/lib/git_deploy/ssh_methods.rb +99 -0
- data/lib/git_deploy/templates/after_push.sh +17 -0
- data/lib/git_deploy/templates/before_restart.rb +39 -0
- data/lib/git_deploy/templates/restart.sh +3 -0
- data/lib/hooks/post-receive.sh +53 -0
- metadata +119 -0
data/LICENSE
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Copyright (c) 2009 Mislav Marohnić
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
4
|
+
this software and associated documentation files (the "Software"), to deal in
|
5
|
+
the Software without restriction, including without limitation the rights to
|
6
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
7
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
8
|
+
subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
15
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
16
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
18
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
Easy git deployment
|
2
|
+
===================
|
3
|
+
|
4
|
+
Straightforward, [Heroku][]-style, push-based deployment. Your deploys will look like this:
|
5
|
+
|
6
|
+
$ git push production master
|
7
|
+
|
8
|
+
To get started, install the "git-deploy" gem.
|
9
|
+
|
10
|
+
$ gem install git-deploy
|
11
|
+
|
12
|
+
|
13
|
+
What application frameworks/languages are supported?
|
14
|
+
----------------------------------------------------
|
15
|
+
|
16
|
+
Regardless of the fact that this tool is mostly written in Ruby, git-deploy can be useful for any kind of code that needs deploying on a remote server. The default scripts are suited for Ruby web apps, but can be edited to accommodate other frameworks.
|
17
|
+
|
18
|
+
Your deployment is customized with per-project callback scripts which can be written in any language.
|
19
|
+
|
20
|
+
The assumption is that you're deploying to a single host to which you connect over SSH using public/private key authentication.
|
21
|
+
|
22
|
+
|
23
|
+
Setup steps
|
24
|
+
-----------
|
25
|
+
|
26
|
+
1. Create a git remote for where you'll push the code on your server. The name of this remote in the examples is "production", but it can be whatever you wish ("online", "website", or other).
|
27
|
+
|
28
|
+
$ git remote add production user@example.com:/path/to/myapp
|
29
|
+
|
30
|
+
The "/path/to/myapp" is the directory where your code will reside. It doesn't have to exist; it will be created for you during this setup.
|
31
|
+
|
32
|
+
2. Run the setup task:
|
33
|
+
|
34
|
+
$ git deploy setup -r production
|
35
|
+
|
36
|
+
This will initialize the remote git repository in the target directory ("/path/to/myapp" in the above example) and install the remote git hooks.
|
37
|
+
|
38
|
+
3. Run the init task:
|
39
|
+
|
40
|
+
$ git deploy init
|
41
|
+
|
42
|
+
This generates default deploy callback scripts in the "deploy/" directory. You must check them in version control. They are going to be executed on the server on each deploy.
|
43
|
+
|
44
|
+
4. Push the code.
|
45
|
+
|
46
|
+
$ git push production master
|
47
|
+
|
48
|
+
3. Login to your server and manually perform necessary one-time administrative operations. This might include:
|
49
|
+
* set up the Apache/nginx virtual host for this application;
|
50
|
+
* check your "config/database.yml" and create the production database.
|
51
|
+
|
52
|
+
|
53
|
+
Deployment
|
54
|
+
----------
|
55
|
+
|
56
|
+
If you've set your app correctly, visiting "http://example.com" in your browser should show it up and running.
|
57
|
+
|
58
|
+
Now, subsequent deployments are done simply by pushing to the branch that is currently checked out on the remote:
|
59
|
+
|
60
|
+
$ git push production master
|
61
|
+
|
62
|
+
Because the deployments are done with git, not everyone on the team had to install git-deploy. Just the person who was doing the setup.
|
63
|
+
|
64
|
+
Deployments are logged to "log/deploy.log" in your application.
|
65
|
+
|
66
|
+
On every deploy, the "deploy/after_push" script performs the following:
|
67
|
+
|
68
|
+
1. updates git submodules (if there are any);
|
69
|
+
2. runs `bundle install --deployment` if there is a Gemfile;
|
70
|
+
3. runs `rake db:migrate` if new migrations have been added;
|
71
|
+
4. clears cached CSS/JS assets in "public/stylesheets" and "public/javascripts";
|
72
|
+
5. restarts the web application.
|
73
|
+
|
74
|
+
You can customize all of this by editing scripts in the "deploy/" directory of your app.
|
75
|
+
|
76
|
+
How it works
|
77
|
+
------------
|
78
|
+
|
79
|
+
The "setup" task installed a "post-receive" hook in the remote git repository. This is how your working copy on the server is kept up to date. This hook, after checking out latest code, asynchronously dispatches to "deploy/after_push" script in your application. This script executes on the server and also calls "deploy/before_restart", "restart", and "after_restart" callbacks if they are present.
|
80
|
+
|
81
|
+
These scripts are ordinary unix executable files. The ones which are generated for you are written in shell script and Ruby.
|
82
|
+
|
83
|
+
It's worth remembering that "after_push" is done **asynchronously from your git push**. This is because migrating the database and updating submodules might take a long time and you don't want to wait for all that during a git push. But, this means that when the push is done, the server has *not yet restarted*. You might need to wait a few seconds or a minute.
|
84
|
+
|
85
|
+
|
86
|
+
[heroku]: http://heroku.com/
|
data/bin/git-deploy
ADDED
data/lib/git_deploy.rb
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'net/ssh'
|
3
|
+
require 'net/scp'
|
4
|
+
|
5
|
+
class GitDeploy < Thor
|
6
|
+
LOCAL_DIR = File.expand_path('..', __FILE__)
|
7
|
+
|
8
|
+
require 'git_deploy/configuration'
|
9
|
+
require 'git_deploy/ssh_methods'
|
10
|
+
include Configuration
|
11
|
+
include SSHMethods
|
12
|
+
|
13
|
+
class_option :remote, :aliases => '-r', :type => :string, :default => 'origin'
|
14
|
+
class_option :noop, :aliases => '-n', :type => :boolean, :default => false
|
15
|
+
class_option :env, :aliases => '-e', :type => :string, :default => 'production'
|
16
|
+
|
17
|
+
desc "init", "Generates deployment customization scripts for your app"
|
18
|
+
def init
|
19
|
+
require 'git_deploy/generator'
|
20
|
+
Generator::start([])
|
21
|
+
end
|
22
|
+
|
23
|
+
desc "setup", "Create the remote git repository and install push hooks for it"
|
24
|
+
method_option :shared, :aliases => '-g', :type => :boolean, :default => true
|
25
|
+
method_option :sudo, :aliases => '-s', :type => :boolean, :default => false
|
26
|
+
def setup
|
27
|
+
sudo = options.sudo? ? "#{sudo_cmd} " : ''
|
28
|
+
|
29
|
+
unless run_test("test -x #{deploy_to}")
|
30
|
+
run ["#{sudo}mkdir -p #{deploy_to}"] do |cmd|
|
31
|
+
cmd << "#{sudo}chown $USER #{deploy_to}" if options.sudo?
|
32
|
+
cmd
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
run [] do |cmd|
|
37
|
+
cmd << "chmod g+ws #{deploy_to}" if options.shared?
|
38
|
+
cmd << "cd #{deploy_to}"
|
39
|
+
cmd << "git init #{options.shared? ? '--shared' : ''}"
|
40
|
+
cmd << "sed -i'' -e 's/master/#{branch}/' .git/HEAD" unless branch == 'master'
|
41
|
+
cmd << "git config --bool receive.denyNonFastForwards false" if options.shared?
|
42
|
+
cmd << "git config receive.denyCurrentBranch ignore"
|
43
|
+
end
|
44
|
+
|
45
|
+
invoke :hooks
|
46
|
+
end
|
47
|
+
|
48
|
+
desc "hooks", "Installs git hooks to the remote repository"
|
49
|
+
def hooks
|
50
|
+
hooks_dir = File.join(LOCAL_DIR, 'hooks')
|
51
|
+
remote_dir = "#{deploy_to}/.git/hooks"
|
52
|
+
scp_upload "#{hooks_dir}/post-receive.sh" => "#{remote_dir}/post-receive"
|
53
|
+
run "sed -i'' -e 's/production/#{options[:env]}/' #{remote_dir}/post-receive" unless options[:env] == 'production'
|
54
|
+
run "chmod +x #{remote_dir}/post-receive"
|
55
|
+
end
|
56
|
+
|
57
|
+
desc "restart", "Restarts the application on the server"
|
58
|
+
def restart
|
59
|
+
run "cd #{deploy_to} && deploy/restart | tee -a log/deploy.log"
|
60
|
+
end
|
61
|
+
|
62
|
+
desc "rollback", "Rolls back the checkout to before the last push"
|
63
|
+
def rollback
|
64
|
+
run "cd #{deploy_to} && git reset --hard ORIG_HEAD"
|
65
|
+
invoke :restart
|
66
|
+
end
|
67
|
+
|
68
|
+
desc "tag", "Checkout the tag <tag>"
|
69
|
+
def tag(tag)
|
70
|
+
run "cd #{deploy_to} && git reset --hard && git checkout #{tag}"
|
71
|
+
restart
|
72
|
+
end
|
73
|
+
|
74
|
+
desc "reset", "Bring the remote up to date with the current branch"
|
75
|
+
def reset
|
76
|
+
run "cd #{deploy_to} && git reset --hard && git checkout master"
|
77
|
+
restart
|
78
|
+
end
|
79
|
+
|
80
|
+
desc "log", "Shows the last part of the deploy log on the server"
|
81
|
+
method_option :tail, :aliases => '-t', :type => :boolean, :default => false
|
82
|
+
method_option :lines, :aliases => '-l', :type => :numeric, :default => 20
|
83
|
+
def log(n = nil)
|
84
|
+
tail_args = options.tail? ? '-f' : "-n#{n || options.lines}"
|
85
|
+
run "tail #{tail_args} #{deploy_to}/log/deploy.log"
|
86
|
+
end
|
87
|
+
|
88
|
+
desc "upload <files>", "Copy local files to the remote app"
|
89
|
+
def upload(*files)
|
90
|
+
files = files.map { |f| Dir[f.strip] }.flatten
|
91
|
+
abort "Error: Specify at least one file to upload" if files.empty?
|
92
|
+
|
93
|
+
scp_upload files.inject({}) { |all, file|
|
94
|
+
all[file] = File.join(deploy_to, file)
|
95
|
+
all
|
96
|
+
}
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
__END__
|
101
|
+
Multiple hosts:
|
102
|
+
# deploy:
|
103
|
+
invoke :code
|
104
|
+
command = ["cd #{deploy_to}"]
|
105
|
+
command << ".git/hooks/post-reset `cat .git/ORIG_HEAD` HEAD 2>&1 | tee -a log/deploy.log"
|
106
|
+
|
107
|
+
# code:
|
108
|
+
command = ["cd #{deploy_to}"]
|
109
|
+
command << source.scm('fetch', remote, "+refs/heads/#{branch}:refs/remotes/origin/#{branch}")
|
110
|
+
command << source.scm('reset', '--hard', "origin/#{branch}")
|
@@ -0,0 +1,81 @@
|
|
1
|
+
class GitDeploy
|
2
|
+
module Configuration
|
3
|
+
private
|
4
|
+
|
5
|
+
def host
|
6
|
+
extract_host_and_user unless defined? @host
|
7
|
+
@host
|
8
|
+
end
|
9
|
+
|
10
|
+
def remote_user
|
11
|
+
extract_host_and_user unless defined? @user
|
12
|
+
@user
|
13
|
+
end
|
14
|
+
|
15
|
+
def extract_host_and_user
|
16
|
+
info = remote_url.split(':').first.split('@')
|
17
|
+
if info.size < 2
|
18
|
+
@user, @host = `whoami`.chomp, info.first
|
19
|
+
else
|
20
|
+
@user, @host = *info
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def deploy_to
|
25
|
+
@deploy_to ||= remote_url.split(':').last
|
26
|
+
end
|
27
|
+
|
28
|
+
def branch
|
29
|
+
'master'
|
30
|
+
end
|
31
|
+
|
32
|
+
def git_config
|
33
|
+
@git_config ||= Hash.new do |cache, cmd|
|
34
|
+
git = ENV['GIT'] || 'git'
|
35
|
+
out = `#{git} #{cmd}`
|
36
|
+
if $?.success? then cache[cmd] = out.chomp
|
37
|
+
else cache[cmd] = nil
|
38
|
+
end
|
39
|
+
cache[cmd]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def remote_urls(remote)
|
44
|
+
git_config["config --get-all remote.#{remote}.url"].to_s.split("\n")
|
45
|
+
end
|
46
|
+
|
47
|
+
def remote_url(remote = options[:remote])
|
48
|
+
@remote_url ||= {}
|
49
|
+
@remote_url[remote] ||= begin
|
50
|
+
url = remote_urls(remote).first
|
51
|
+
if url.nil?
|
52
|
+
abort "Error: Remote url not found for remote #{remote.inspect}"
|
53
|
+
elsif url =~ /\bgithub\.com\b/
|
54
|
+
abort "Error: Remote url for #{remote.inspect} points to GitHub. Can't deploy there!"
|
55
|
+
end
|
56
|
+
url
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def current_branch
|
61
|
+
git_config['symbolic-ref -q HEAD']
|
62
|
+
end
|
63
|
+
|
64
|
+
def tracked_branch
|
65
|
+
branch = current_branch && tracked_for(current_branch)
|
66
|
+
normalize_branch(branch) if branch
|
67
|
+
end
|
68
|
+
|
69
|
+
def normalize_branch(branch)
|
70
|
+
branch.sub('refs/heads/', '')
|
71
|
+
end
|
72
|
+
|
73
|
+
def remote_for(branch)
|
74
|
+
git_config['config branch.%s.remote' % normalize_branch(branch)]
|
75
|
+
end
|
76
|
+
|
77
|
+
def tracked_for(branch)
|
78
|
+
git_config['config branch.%s.merge' % normalize_branch(branch)]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'thor/group'
|
2
|
+
|
3
|
+
class GitDeploy::Generator < Thor::Group
|
4
|
+
include Thor::Actions
|
5
|
+
|
6
|
+
def self.source_root
|
7
|
+
File.expand_path('../templates', __FILE__)
|
8
|
+
end
|
9
|
+
|
10
|
+
def copy_main_hook
|
11
|
+
copy_hook 'after_push.sh', 'deploy/after_push'
|
12
|
+
end
|
13
|
+
|
14
|
+
def copy_restart_hook
|
15
|
+
copy_hook 'restart.sh', 'deploy/restart'
|
16
|
+
end
|
17
|
+
|
18
|
+
def copy_restart_callbacks
|
19
|
+
copy_hook 'before_restart.rb', 'deploy/before_restart'
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def copy_hook(template, destination)
|
25
|
+
copy_file template, destination
|
26
|
+
chmod destination, 0744 unless File.executable? destination
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
class GitDeploy
|
2
|
+
module SSHMethods
|
3
|
+
private
|
4
|
+
|
5
|
+
def sudo_cmd
|
6
|
+
"sudo -p 'sudo password: '"
|
7
|
+
end
|
8
|
+
|
9
|
+
def system(*args)
|
10
|
+
puts "[local] $ " + args.join(' ').gsub(' && ', " && \\\n ")
|
11
|
+
super unless options.noop?
|
12
|
+
end
|
13
|
+
|
14
|
+
def run(cmd = nil)
|
15
|
+
cmd = yield(cmd) if block_given?
|
16
|
+
cmd = cmd.join(' && ') if Array === cmd
|
17
|
+
puts "[#{options[:remote]}] $ " + cmd.gsub(' && ', " && \\\n ")
|
18
|
+
|
19
|
+
unless options.noop?
|
20
|
+
status, output = ssh_exec cmd do |ch, stream, data|
|
21
|
+
case stream
|
22
|
+
when :stdout then $stdout.print data
|
23
|
+
when :stderr then $stderr.print data
|
24
|
+
end
|
25
|
+
ch.send_data(askpass) if data =~ /^sudo password: /
|
26
|
+
end
|
27
|
+
output
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def run_test(cmd)
|
32
|
+
status, output = ssh_exec(cmd) { }
|
33
|
+
status == 0
|
34
|
+
end
|
35
|
+
|
36
|
+
def ssh_exec(cmd, &block)
|
37
|
+
status = nil
|
38
|
+
output = ''
|
39
|
+
|
40
|
+
channel = ssh_connection.open_channel do |chan|
|
41
|
+
chan.exec(cmd) do |ch, success|
|
42
|
+
raise "command failed: #{cmd.inspect}" unless success
|
43
|
+
# ch.request_pty
|
44
|
+
|
45
|
+
ch.on_data do |c, data|
|
46
|
+
output << data
|
47
|
+
yield(c, :stdout, data)
|
48
|
+
end
|
49
|
+
|
50
|
+
ch.on_extended_data do |c, type, data|
|
51
|
+
output << data
|
52
|
+
yield(c, :stderr, data)
|
53
|
+
end
|
54
|
+
|
55
|
+
ch.on_request "exit-status" do |ch, data|
|
56
|
+
status = data.read_long
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
channel.wait
|
62
|
+
[status, output]
|
63
|
+
end
|
64
|
+
|
65
|
+
# TODO: use Highline for cross-platform support
|
66
|
+
def askpass
|
67
|
+
tty_state = `stty -g`
|
68
|
+
system 'stty raw -echo -icanon isig' if $?.success?
|
69
|
+
pass = ''
|
70
|
+
while char = $stdin.getbyte and not (char == 13 or char == 10)
|
71
|
+
if char == 127 or char == 8
|
72
|
+
pass[-1,1] = '' unless pass.empty?
|
73
|
+
else
|
74
|
+
pass << char.chr
|
75
|
+
end
|
76
|
+
end
|
77
|
+
pass
|
78
|
+
ensure
|
79
|
+
system "stty #{tty_state}" unless tty_state.empty?
|
80
|
+
end
|
81
|
+
|
82
|
+
def scp_upload(files)
|
83
|
+
channels = []
|
84
|
+
files.each do |local, remote|
|
85
|
+
puts "FILE: [local] #{local.sub(LOCAL_DIR + '/', '')} -> [#{options[:remote]}] #{remote}"
|
86
|
+
channels << ssh_connection.scp.upload(local, remote) unless options.noop?
|
87
|
+
end
|
88
|
+
channels.each { |c| c.wait }
|
89
|
+
end
|
90
|
+
|
91
|
+
def ssh_connection
|
92
|
+
@ssh ||= begin
|
93
|
+
ssh = Net::SSH.start(host, remote_user)
|
94
|
+
at_exit { ssh.close }
|
95
|
+
ssh
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
set -e
|
3
|
+
oldrev=$1
|
4
|
+
newrev=$2
|
5
|
+
|
6
|
+
run() {
|
7
|
+
[ -x $1 ] && $1 $oldrev $newrev
|
8
|
+
}
|
9
|
+
|
10
|
+
echo files changed: $(git diff $oldrev $newrev --diff-filter=ACDMR --name-only | wc -l)
|
11
|
+
|
12
|
+
umask 002
|
13
|
+
|
14
|
+
git submodule init && git submodule sync && git submodule update
|
15
|
+
|
16
|
+
run deploy/before_restart
|
17
|
+
run deploy/restart && run deploy/after_restart
|
@@ -0,0 +1,39 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
oldrev, newrev = ARGV
|
3
|
+
|
4
|
+
def run(cmd)
|
5
|
+
exit($?.exitstatus) unless system "umask 002 && #{cmd}"
|
6
|
+
end
|
7
|
+
|
8
|
+
RAILS_ENV = ENV['RAILS_ENV'] || 'production'
|
9
|
+
use_bundler = File.file? 'Gemfile'
|
10
|
+
rake_cmd = use_bundler ? 'bundle exec rake' : 'rake'
|
11
|
+
|
12
|
+
if use_bundler
|
13
|
+
bundler_args = ['--deployment']
|
14
|
+
BUNDLE_WITHOUT = ENV['BUNDLE_WITHOUT'] || 'development:test'
|
15
|
+
bundler_args << '--without' << BUNDLE_WITHOUT unless BUNDLE_WITHOUT.empty?
|
16
|
+
|
17
|
+
# update gem bundle
|
18
|
+
run "bundle install #{bundler_args.join(' ')}"
|
19
|
+
end
|
20
|
+
|
21
|
+
if File.file? 'Rakefile'
|
22
|
+
tasks = []
|
23
|
+
|
24
|
+
num_migrations = `git diff #{oldrev} #{newrev} --diff-filter=A --name-only -z db/migrate`.split("\0").size
|
25
|
+
# run migrations if new ones have been added
|
26
|
+
tasks << "db:migrate" if num_migrations > 0
|
27
|
+
|
28
|
+
# precompile assets
|
29
|
+
changed_assets = `git diff #{oldrev} #{newrev} --name-only -z app/assets`.split("\0")
|
30
|
+
tasks << "assets:precompile" if changed_assets.size > 0
|
31
|
+
|
32
|
+
run "#{rake_cmd} #{tasks.join(' ')} RAILS_ENV=#{RAILS_ENV}" if tasks.any?
|
33
|
+
end
|
34
|
+
|
35
|
+
# clear cached assets (unversioned/ignored files)
|
36
|
+
run "git clean -x -f -- public/stylesheets public/javascripts"
|
37
|
+
|
38
|
+
# clean unversioned files from vendor/plugins (e.g. old submodules)
|
39
|
+
run "git clean -d -f -- vendor/plugins"
|
@@ -0,0 +1,53 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
if [ "$GIT_DIR" = "." ]; then
|
3
|
+
# The script has been called as a hook; chdir to the working copy
|
4
|
+
cd ..
|
5
|
+
GIT_DIR=.git
|
6
|
+
export GIT_DIR
|
7
|
+
fi
|
8
|
+
|
9
|
+
# try to obtain the usual system PATH
|
10
|
+
if [ -f /etc/profile ]; then
|
11
|
+
PATH=$(source /etc/profile; echo $PATH)
|
12
|
+
export PATH
|
13
|
+
fi
|
14
|
+
|
15
|
+
# get the current branch
|
16
|
+
head="$(git symbolic-ref HEAD)"
|
17
|
+
# abort if we're on a detached head
|
18
|
+
[ "$?" != "0" ] && exit 1
|
19
|
+
|
20
|
+
# read the STDIN to detect if this push changed the current branch
|
21
|
+
while read oldrev newrev refname
|
22
|
+
do
|
23
|
+
[ "$refname" = "$head" ] && break
|
24
|
+
done
|
25
|
+
# abort if there's no update, or in case the branch is deleted
|
26
|
+
[ -z "${newrev//0}" ] && exit
|
27
|
+
|
28
|
+
export RAILS_ENV=production
|
29
|
+
export RACK_ENV=production
|
30
|
+
|
31
|
+
# check out the latest code into the working copy
|
32
|
+
umask 002
|
33
|
+
git reset --hard
|
34
|
+
|
35
|
+
logfile=log/deploy.log
|
36
|
+
restart=tmp/restart.txt
|
37
|
+
|
38
|
+
if [ -z "${oldrev//0}" ]; then
|
39
|
+
# this is the first push; this branch was just created
|
40
|
+
mkdir -p log tmp
|
41
|
+
chmod 0775 log tmp
|
42
|
+
touch $logfile $restart
|
43
|
+
chmod 0664 $logfile $restart
|
44
|
+
|
45
|
+
# init submodules
|
46
|
+
git submodule update --init | tee -a $logfile
|
47
|
+
else
|
48
|
+
# log timestamp
|
49
|
+
echo ==== $(date) ==== >> $logfile
|
50
|
+
|
51
|
+
# execute the deploy hook in background
|
52
|
+
[ -x deploy/after_push ] && nohup deploy/after_push $oldrev $newrev 1>>$logfile 2>>$logfile &
|
53
|
+
fi
|
metadata
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: osbro-git-deploy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 1
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 5
|
9
|
+
- 5
|
10
|
+
version: 0.5.5
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- "Mislav Marohni\xC4\x87"
|
14
|
+
- Simon Brook
|
15
|
+
autorequire:
|
16
|
+
bindir: bin
|
17
|
+
cert_chain: []
|
18
|
+
|
19
|
+
date: 2012-06-26 00:00:00 +01:00
|
20
|
+
default_executable:
|
21
|
+
dependencies:
|
22
|
+
- !ruby/object:Gem::Dependency
|
23
|
+
name: thor
|
24
|
+
prerelease: false
|
25
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ">="
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
hash: 3
|
31
|
+
segments:
|
32
|
+
- 0
|
33
|
+
version: "0"
|
34
|
+
type: :runtime
|
35
|
+
version_requirements: *id001
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: net-ssh
|
38
|
+
prerelease: false
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
hash: 3
|
45
|
+
segments:
|
46
|
+
- 0
|
47
|
+
version: "0"
|
48
|
+
type: :runtime
|
49
|
+
version_requirements: *id002
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
name: net-scp
|
52
|
+
prerelease: false
|
53
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
hash: 3
|
59
|
+
segments:
|
60
|
+
- 0
|
61
|
+
version: "0"
|
62
|
+
type: :runtime
|
63
|
+
version_requirements: *id003
|
64
|
+
description: A tool to install useful git hooks on your remote repository to enable push-based, Heroku-like deployment on your host.
|
65
|
+
email: simon@obdev.co.uk
|
66
|
+
executables:
|
67
|
+
- git-deploy
|
68
|
+
extensions: []
|
69
|
+
|
70
|
+
extra_rdoc_files: []
|
71
|
+
|
72
|
+
files:
|
73
|
+
- bin/git-deploy
|
74
|
+
- lib/git_deploy/configuration.rb
|
75
|
+
- lib/git_deploy/generator.rb
|
76
|
+
- lib/git_deploy/ssh_methods.rb
|
77
|
+
- lib/git_deploy/templates/after_push.sh
|
78
|
+
- lib/git_deploy/templates/before_restart.rb
|
79
|
+
- lib/git_deploy/templates/restart.sh
|
80
|
+
- lib/git_deploy.rb
|
81
|
+
- lib/hooks/post-receive.sh
|
82
|
+
- README.markdown
|
83
|
+
- LICENSE
|
84
|
+
has_rdoc: true
|
85
|
+
homepage: https://github.com/osbornebrook/git-deploy
|
86
|
+
licenses: []
|
87
|
+
|
88
|
+
post_install_message:
|
89
|
+
rdoc_options: []
|
90
|
+
|
91
|
+
require_paths:
|
92
|
+
- lib
|
93
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
hash: 3
|
99
|
+
segments:
|
100
|
+
- 0
|
101
|
+
version: "0"
|
102
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
+
none: false
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
hash: 3
|
108
|
+
segments:
|
109
|
+
- 0
|
110
|
+
version: "0"
|
111
|
+
requirements: []
|
112
|
+
|
113
|
+
rubyforge_project:
|
114
|
+
rubygems_version: 1.3.7
|
115
|
+
signing_key:
|
116
|
+
specification_version: 3
|
117
|
+
summary: Simple git push-based application deployment
|
118
|
+
test_files: []
|
119
|
+
|