git-deployer 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.textile ADDED
@@ -0,0 +1,78 @@
1
+ h1. About
2
+
3
+ This is simple and flexible deployment solution based on Git post-receive hook.
4
+
5
+ * You don't have to install anything on your server
6
+ * It works with whichever thinkable solution, Rails, Merb, "Rango":http://github.com/botanicus/rango, Sinatra or even Django or static pages, it just doesn't matter!
7
+ * Deployment to more servers is supported.
8
+
9
+ h1. Usage
10
+
11
+ * Run @gem install git-deployer --development@
12
+ * Add following lines to your file with "Nake":http://github.com/botanicus/nake tasks (I'll refer this file as @tasks.rb@):
13
+
14
+ <pre>
15
+ begin
16
+ load "git-deployer.nake"
17
+ Task["deployer:setup"].config[:servers] = {
18
+ server1: {
19
+ user: "www",
20
+ host: "127.0.0.1",
21
+ repo: "/var/sources/deploy-test.git",
22
+ path: "/var/www/deploy-test"
23
+ }
24
+ }
25
+ rescue LoadError
26
+ warn "You have to install git-deployer gem if you want to deploy to remote servers!"
27
+ end
28
+ </pre>
29
+
30
+ * Install hooks via @./tasks.rb deployer:install@
31
+ * Edit @hooks/clone@ and @hooks/update@
32
+ * Install @post-receive@ hook and create necessary directories via @./tasks.rb deployer:install@
33
+ * Push your changes via @git push origin master@
34
+
35
+ That's it. When you run @git push origin master@ for the first time, it should found that given branch isn't cloned yet, so it should
36
+
37
+ h1. Available tasks
38
+
39
+ h3. Task @deployer:install@
40
+
41
+ This task will copy @hooks/clone@ and @hooks/update@ hooks to your project. This step is mandatory.
42
+
43
+ h3. Task @deployer:setup@
44
+
45
+ It can take one or more optional arguments with
46
+ It takes the same arguments resp. configuration options as @deployer:compile_hook@ task
47
+
48
+ h3. Task @deployer:compile_hook@
49
+
50
+ This task will copy @hooks/post-receive@ hook to your project. This step is optional and you will use the task you in case that you aren't happy with the default @post-receive@ hook distributed with git-deployer and you want to customize things. But you shouldn't need this, there is a bunch of arguments which you can use for influencing the generated @post-receive@ hook.
51
+
52
+ h3. Task @deployer:remote:copy_hook@
53
+
54
+ Again, you typically don't need this task, because it run during @deployer:setup@. However if you changed something in the @post-receive@ hook, you might want to run this task which will install @post-receive@ on remote servers. By default the hook will be installed to all the servers, but you can specify just a subset via @./tasks.rb deployer:remote:copy_hook server1 server2@.
55
+
56
+ h4. Setup
57
+
58
+ h2. Restricting Just for @deploy@ Branch
59
+
60
+ You might not want to deploy every branch you push to origin.
61
+
62
+ h3. Task @deployer:run@
63
+
64
+ If you pushed to the remote server but the hook failed, this is the way how you can re-run it. Just fix the problem and run @./tasks.rb deployer:run@. By default it runs on all the servers, but you can run it just on some servers via @./tasks.rb deployer:run server1 server2@.
65
+
66
+ h3. Task @deploy@
67
+
68
+ This task is useful for deployment to *multiple servers*. Just run @git push server1 master && git push server1 master@ or @./tasks.rb deploy@ which is a shortcut for pushing current branch to all or specified remote servers.
69
+
70
+ h1. FAQ
71
+
72
+ *Q:* _I had typo in my hooks, so it failed during deploy, how can I rerun it?_
73
+
74
+ *A:* @./tasks.rb deployer:run@ with optional argument which
75
+
76
+ *Q:* _You are using "Nake":http://github.com/botanicus/nake, but everyone's using Rake. Is there any chance that you will support Rake in future?_
77
+
78
+ *A:* The trouble with Rake is that Rake doesn't support configuration and it also really suck in command-line parsing. If Rake will support at least the command line arguments in a reasonable way, I can think about it.
@@ -0,0 +1,14 @@
1
+ h1. About
2
+
3
+ This is a "git-deployer":http://github.com/botanicus/git-deployer demo.
4
+
5
+ h1. Usage
6
+
7
+ # Copy this directory out of the git-deployer repository.
8
+ # Edit connection details in @tasks.rb@.
9
+ # Ensure you have "Nake":http://github.com/botanicus/nake task manager installed.
10
+ # Run @./tasks.rb deployer:setup@
11
+ # Run @git init && git add . && git commit -a -m "Initial import"@ and then @git remote add@ with the URL of remote repository.
12
+ # Run @git push origin master@ and see what's going on.
13
+
14
+ Of course if you want to see something real, you have to point your web server to this repository, probably via vhost.
@@ -0,0 +1,31 @@
1
+ # === Documentation === #
2
+ # This is just a standard shell script, which is loaded from the
3
+ # post-receive hook when a new branch is created.
4
+
5
+ # Just don't forget that gems you have on your local machine probably
6
+ # aren't installed at the server, at least before you run gem bundle.
7
+
8
+ # Your working directory is root of your application which was just cloned
9
+ # here. (Probably) unlike to your local machine, basename is name of the branch,
10
+ # not name of the application. It shouldn't matter in most cases, but sometimes
11
+ # it does, for example in Python where you are using import myapp.something.
12
+ # 1) Write an awful perl-ish script with sed -i / perl -i / ruby -i and just replace
13
+ # the name in your code. It might work, but come on, you don't want to do that.
14
+ # 2) Your application will be as a subdirectory of the root of the repository,
15
+ # so you may call it whatever you want.
16
+ # 3) Obviously the best solution is to change the post-receive script, for example:
17
+ # Task["deployer:compile_hook"].config[:target] = "myappname"
18
+
19
+ # Make sure this script isn't executable, otherwise the script will simply run,
20
+ # so you won't have access to shell functions from the post-receive hook.
21
+ # However this is useful if you want to run this script under another interpret.
22
+ # If you want to install hooks which will be executed rather than just
23
+ # loaded, use ./tasks.rb deployer:install --executable or add
24
+ # Task["deployer:install"].config[:executable] = false to your tasks.rb
25
+
26
+ # Also, post-receive hook run under /bin/sh by default, but you might want to
27
+ # use something more advance like bash or zsh. Since these shells are compatible
28
+ # with the original sh, it's easy, just run ./tasks.rb deployer:compile_hook --shebang="#!/bin/zsh"
29
+ # or add Task["deployer:compile_hook"].config[:shebang] = "#!/bin/zsh" to your tasks.rb and reinstall the hooks.
30
+
31
+ . "hooks/update"
@@ -0,0 +1,24 @@
1
+ # === Documentation === #
2
+ # This is just a standard shell script, which is loaded from the
3
+ # post-receive hook each time a branch is updated.
4
+
5
+ # Just don't forget that gems you have on your local machine probably
6
+ # aren't installed at the server, at least before you run gem bundle.
7
+
8
+ # Your working directory is root of your application which was just cloned
9
+ # here. (Probably) unlike to your local machine, basename is name of the branch,
10
+ # not name of the application. It shouldn't matter in most cases, but sometimes
11
+ # it does, for example in Python where you are using import myapp.something.
12
+ # 1) Write an awful perl-ish script with sed -i / perl -i / ruby -i and just replace
13
+ # the name in your code. It might work, but come on, you don't want to do that.
14
+ # 2) Your application will be as a subdirectory of the root of the repository,
15
+ # so you may call it whatever you want.
16
+ # 3) Obviously the best solution is to change the post-receive script, for example:
17
+ # Task["deployer:compile_hook"].config[:target] = "myappname"
18
+
19
+ # Make sure this script isn't executable, otherwise the script will simply run,
20
+ # so you won't have access to shell functions from the post-receive hook.
21
+ # However this is useful if you want to run this script under another interpret.
22
+ # If you want to install hooks which will be executed rather than just
23
+ # loaded, use ./tasks.rb deployer:install --executable or add
24
+ # Task["deployer:install"].config[:executable] = false to your tasks.rb
data/example/tasks.rb ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env nake
2
+
3
+ # TODO: rewrite the example to Rango, it would be more interesting
4
+ # Or maybe add more examples for jekyll, nanoc, Django, maybe Rails.
5
+ $:.unshift(File.join(File.dirname(__FILE__), "..", "tasks"))
6
+
7
+ load "git-deployer.nake"
8
+
9
+ Task["deployer:setup"].config[:user] = "TODO"
10
+ Task["deployer:setup"].config[:host] = "TODO"
11
+ Task["deployer:setup"].config[:path] = "/var/www/deploy-test"
12
+
@@ -0,0 +1,15 @@
1
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
2
+ "http://www.w3.org/TR/html4/loose.dtd">
3
+ <html>
4
+ <head>
5
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8">
6
+ <title>Hello World!</title>
7
+ </head>
8
+
9
+ <body>
10
+ <h1>Hello World!</h1>
11
+ <p>
12
+ This is an example page for <a href="http://github.com/botanicus/git-deployer">git-deployer</a>.
13
+ </p>
14
+ </body>
15
+ </html>
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env gem build
2
+ # encoding: utf-8
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "git-deployer"
6
+ s.version = "0.0.1"
7
+ s.authors = ["Jakub Šťastný aka Botanicus"]
8
+ s.homepage = "http://github.com/botanicus/git-deployer"
9
+ s.summary = "Easy deploy system based on Git hooks"
10
+ s.description = "" # TODO: long description
11
+ s.cert_chain = nil
12
+ s.email = ["knava.bestvinensis", "gmail.com"].join("@")
13
+ s.has_rdoc = false
14
+
15
+ # files
16
+ s.files = Dir.glob("**/*") - Dir.glob("*.gem")
17
+ s.require_paths = ["tasks"]
18
+
19
+ # dependencies
20
+ s.add_development_dependency "nake"
21
+
22
+ # RubyForge
23
+ s.rubyforge_project = "git-deployer"
24
+ end
@@ -0,0 +1,53 @@
1
+ <%= options[:shebang] %>
2
+
3
+ # === Documentation === #
4
+ # This hook run when a new branch is pushed. It's just a standard
5
+ # executable script, feel free to use ruby, python, shell or whatever.
6
+
7
+ # Just don't forget that gems you have on your local machine probably
8
+ # aren't installed at the server, at least before you run gem bundle.
9
+
10
+ # Your working directory is root of your application which was just cloned
11
+ # here. (Probably) unlike to your local machine, basename is name of the branch,
12
+ # not name of the application. It shouldn't matter in most cases, but sometimes
13
+ # it does, for example in Python where you are using import myapp.something.
14
+ # 1) Write an awful perl-ish script with sed -i / perl -i / ruby -i and just replace
15
+ # the name in your code. It might work, but come on, you don't want to do that.
16
+ # 2) Your application will be as a subdirectory of the root of the repository,
17
+ # so you may call it whatever you want.
18
+ # 3) Obviously the best solution is to change the post-receive script, for example:
19
+ # Task["deployer:compile_hook"].config[:target] = "myappname"
20
+
21
+ # Make sure this script is executable, otherwise the script will be just
22
+ # loaded from post-receive hook, which means your shebang will be ignored.
23
+ # However this is useful when you want to use functions defined in the hook.
24
+ # If you want to install hooks which will be loaded rather than just
25
+ # executed, use ./tasks.rb deployer:install --no-executable or add
26
+ # Task["deployer:install"].config[:executable] = false to your tasks.rb
27
+
28
+ # Ruby on Rails
29
+ export RAILS_ENV="stagging" # if you are deploying to more servers, you might want to setup this in your /etc/profile
30
+ echo "Please edit config/database.yml and rerun this hook via ./tasks.rb deployer:run if you need so"
31
+ test -f config/database.yml.sample && cp config/database.yml.sample config/database.yml
32
+ rake db:create
33
+ exec "hooks/update"
34
+
35
+ # Rango
36
+ export RACK_ENV="stagging" # if you are deploying to more servers, you might want to setup this in your /etc/profile
37
+ echo "Please edit environments.rb and rerun this hook via ./tasks.rb deployer:run if you need so"
38
+ test -f environments_sample.rb && cp environments_sample.rb environments.rb
39
+ exec "hooks/update"
40
+
41
+ # Django
42
+ echo "Please edit settings_local.py and rerun this hook via ./tasks.rb deployer:run if you need so"
43
+ test -f settings_local_sample.py && cp settings_local_sample.py settings_local.py
44
+
45
+ # === Hints === #
46
+ # If each branch means a subdomain, you can generate vhosts in this
47
+ # hook. If you do so, then don't forget to restart your server!
48
+ # git push origin alpha => alpha.example.com
49
+ # git push origin beta => beta.example.com
50
+ # git push origin master => example.com
51
+
52
+ echo "Don't forget to edit hooks/clone\!"
53
+ exit 1
@@ -0,0 +1,55 @@
1
+ # === Documentation === #
2
+ # This is just a standard shell script, which is loaded from the
3
+ # post-receive hook when a new branch is created.
4
+
5
+ # Just don't forget that gems you have on your local machine probably
6
+ # aren't installed at the server, at least before you run gem bundle.
7
+
8
+ # Your working directory is root of your application which was just cloned
9
+ # here. (Probably) unlike to your local machine, basename is name of the branch,
10
+ # not name of the application. It shouldn't matter in most cases, but sometimes
11
+ # it does, for example in Python where you are using import myapp.something.
12
+ # 1) Write an awful perl-ish script with sed -i / perl -i / ruby -i and just replace
13
+ # the name in your code. It might work, but come on, you don't want to do that.
14
+ # 2) Your application will be as a subdirectory of the root of the repository,
15
+ # so you may call it whatever you want.
16
+ # 3) Obviously the best solution is to change the post-receive script, for example:
17
+ # Task["deployer:compile_hook"].config[:target] = "myappname"
18
+
19
+ # Make sure this script isn't executable, otherwise the script will simply run,
20
+ # so you won't have access to shell functions from the post-receive hook.
21
+ # However this is useful if you want to run this script under another interpret.
22
+ # If you want to install hooks which will be executed rather than just
23
+ # loaded, use ./tasks.rb deployer:install --executable or add
24
+ # Task["deployer:install"].config[:executable] = false to your tasks.rb
25
+
26
+ # Also, post-receive hook run under /bin/sh by default, but you might want to
27
+ # use something more advance like bash or zsh. Since these shells are compatible
28
+ # with the original sh, it's easy, just run ./tasks.rb deployer:compile_hook --shebang="#!/bin/zsh"
29
+ # or add Task["deployer:compile_hook"].config[:shebang] = "#!/bin/zsh" to your tasks.rb and reinstall the hooks.
30
+
31
+ # Ruby on Rails
32
+ export RAILS_ENV="stagging" # if you are deploying to more servers, you might want to setup this in your /etc/profile
33
+ info "Please edit config/database.yml and rerun this hook via ./tasks.rb deployer:run if you need so"
34
+ test -f config/database.yml.sample && cp config/database.yml.sample config/database.yml
35
+ rake db:create
36
+ . "hooks/update"
37
+
38
+ # Rango
39
+ export RACK_ENV="stagging" # if you are deploying to more servers, you might want to setup this in your /etc/profile
40
+ info "Please edit environments.rb and rerun this hook via ./tasks.rb deployer:run if you need so"
41
+ test -f environments_sample.rb && cp environments_sample.rb environments.rb
42
+ . "hooks/update"
43
+
44
+ # Django
45
+ info "Please edit settings_local.py and rerun this hook via ./tasks.rb deployer:run if you need so"
46
+ test -f settings_local_sample.py && cp settings_local_sample.py settings_local.py
47
+
48
+ # === Hints === #
49
+ # If each branch means a subdomain, you can generate vhosts in this
50
+ # hook. If you do so, then don't forget to restart your server!
51
+ # git push origin alpha => alpha.example.com
52
+ # git push origin beta => beta.example.com
53
+ # git push origin master => example.com
54
+
55
+ abort "Don't forget to edit hooks/clone\!"
@@ -0,0 +1,64 @@
1
+ <%= options[:shebang] %>
2
+
3
+ # === Documentation === #
4
+ # This hooks run each time the branch is updated. If a new branch is created,
5
+ # than the clone hook runs first. It's just a standard executable script, feel
6
+ # free to use ruby, python, shell or whatever.
7
+
8
+ # Just don't forget that gems you have on your local machine probably
9
+ # aren't installed at the server, at least before you run gem bundle.
10
+
11
+ # Your working directory is root of your application which was just cloned
12
+ # here. (Probably) unlike to your local machine, basename is name of the branch,
13
+ # not name of the application. It shouldn't matter in most cases, but sometimes
14
+ # it does, for example in Python where you are using import myapp.something.
15
+ # 1) Write an awful perl-ish script with sed -i / perl -i / ruby -i and just replace
16
+ # the name in your code. It might work, but come on, you don't want to do that.
17
+ # 2) Your application will be as a subdirectory of the root of the repository,
18
+ # so you may call it whatever you want.
19
+ # 3) Obviously the best solution is to change the post-receive script, for example:
20
+ # Task["deployer:compile_hook"].config[:target] = "myappname"
21
+
22
+ # Make sure this script is executable, otherwise the script will be just
23
+ # loaded from post-receive hook, which means your shebang will be ignored.
24
+ # However this is useful when you want to use functions defined in the hook.
25
+ # If you want to install hooks which will be loaded rather than just
26
+ # executed, use ./tasks.rb deployer:install --no-executable or add
27
+ # Task["deployer:install"].config[:executable] = false to your tasks.rb
28
+
29
+ # === Setup === #
30
+ # If we have everything bundled in bin, we have to put bin to the beginning of the PATH
31
+ # variable, so all commands like rake etc will be loaded from bin, if they are in there
32
+ export PATH="bin:$PATH" # TODO: maybe you are using script directory instead of bin?
33
+
34
+ # Ruby on Rails
35
+ export RAILS_ENV="stagging" # if you are deploying to more servers, you might want to setup this in your /etc/profile
36
+ gem bundle --cached # this requires bundler installed on your server
37
+ rake db:migrate
38
+ #rake db:seed
39
+
40
+ # Rango
41
+ export RACK_ENV="stagging" # if you are deploying to more servers, you might want to setup this in your /etc/profile
42
+ gem bundle --cached
43
+ ./tasks.rb db:autoupgrade
44
+ #./tasks.rb db:seed
45
+
46
+ # Django
47
+ # load data from fixtures
48
+ echo "Running syncdb ..."
49
+ python "manage.py syncdb --noinput"
50
+
51
+ # Jekyll
52
+ # point your vhost to the _site directory
53
+ jekyll --pygments
54
+
55
+ # Nanoc
56
+ # point your vhost to the output directory
57
+ nanoc3 compile
58
+
59
+ # Restart passenger application
60
+ echo "Restarting Passenger ..."
61
+ touch tmp/restart.txt
62
+
63
+ echo "Don't forget to edit hooks/update\!"
64
+ exit 1
@@ -0,0 +1,60 @@
1
+ # === Documentation === #
2
+ # This is just a standard shell script, which is loaded from the
3
+ # post-receive hook each time a branch is updated.
4
+
5
+ # Just don't forget that gems you have on your local machine probably
6
+ # aren't installed at the server, at least before you run gem bundle.
7
+
8
+ # Your working directory is root of your application which was just cloned
9
+ # here. (Probably) unlike to your local machine, basename is name of the branch,
10
+ # not name of the application. It shouldn't matter in most cases, but sometimes
11
+ # it does, for example in Python where you are using import myapp.something.
12
+ # 1) Write an awful perl-ish script with sed -i / perl -i / ruby -i and just replace
13
+ # the name in your code. It might work, but come on, you don't want to do that.
14
+ # 2) Your application will be as a subdirectory of the root of the repository,
15
+ # so you may call it whatever you want.
16
+ # 3) Obviously the best solution is to change the post-receive script, for example:
17
+ # Task["deployer:compile_hook"].config[:target] = "myappname"
18
+
19
+ # Make sure this script isn't executable, otherwise the script will simply run,
20
+ # so you won't have access to shell functions from the post-receive hook.
21
+ # However this is useful if you want to run this script under another interpret.
22
+ # If you want to install hooks which will be executed rather than just
23
+ # loaded, use ./tasks.rb deployer:install --executable or add
24
+ # Task["deployer:install"].config[:executable] = false to your tasks.rb
25
+
26
+ # === Setup === #
27
+ # If we have everything bundled in bin, we have to put bin to the beginning of the PATH
28
+ # variable, so all commands like rake etc will be loaded from bin, if they are in there
29
+ export PATH="bin:$PATH" # TODO: maybe you are using script directory instead of bin?
30
+
31
+ # Ruby on Rails
32
+ export RAILS_ENV="stagging" # if you are deploying to more servers, you might want to setup this in your /etc/profile
33
+ gem bundle --cached # this requires bundler installed on your server
34
+ rake db:migrate
35
+ #rake db:seed
36
+
37
+ # Rango
38
+ export RACK_ENV="stagging" # if you are deploying to more servers, you might want to setup this in your /etc/profile
39
+ gem bundle --cached
40
+ ./tasks.rb db:autoupgrade
41
+ #./tasks.rb db:seed
42
+
43
+ # Django
44
+ # load data from fixtures
45
+ info "Running syncdb ..."
46
+ python "manage.py syncdb --noinput"
47
+
48
+ # Jekyll
49
+ # point your vhost to the _site directory
50
+ jekyll --pygments
51
+
52
+ # Nanoc
53
+ # point your vhost to the output directory
54
+ nanoc3 compile
55
+
56
+ # Restart passenger application
57
+ info "Restarting Passenger ..."
58
+ touch tmp/restart.txt
59
+
60
+ abort "Don't forget to edit hooks/update\!"
@@ -0,0 +1,95 @@
1
+ <%= shebang %>
2
+
3
+ # This script is SH-compatible, but it doesn't mean you have to use SH.
4
+ # You can use bash or zsh and enjoy features of more powerful shells, just change the shebang!
5
+
6
+ # POST-RECEIVE HOOK
7
+ # ARGV: empty
8
+ # STDIN: [OLD HEAD] [NEW HEAD] refs/heads/alpha
9
+
10
+ <% if colors %>
11
+ export TERM="xterm-color"
12
+
13
+ abort() { printf "\e[1;31m$*\e[0m\n"; exit 1; }
14
+ success() { printf "\e[1;32m$*\e[0m\n"; }
15
+ info() { printf "\e[1;34m$*\e[0m\n"; }
16
+ debug() { $DEBUG && printf "\e[1;33m$*\e[0m\n"; }
17
+ <% else %>
18
+ abort() { printf "$*\n"; exit 1; }
19
+ success() { printf "$*\n"; }
20
+ info() { printf "$*\n"; }
21
+ debug() { $DEBUG && printf "$*\n"; }
22
+ <% end %>
23
+ run() { info $* ; $*; }
24
+
25
+ set -- $(cat /dev/stdin)
26
+
27
+ old=$1 && new=$2 && ref=$3
28
+ export BRANCH=$(basename $ref)
29
+ export DEBUG=<%= debug %>
30
+ export TARGET="<%= File.join(path, target) %>"
31
+ export REPO="<%= repo %>"
32
+
33
+ <% if branch %>
34
+ # restrict deployment just to given branch
35
+ if [ $BRANCH != <%= branch %> ]
36
+ info "Branch $BRANCH isn't supposed to be deployable, finishing"
37
+ exit
38
+ fi
39
+ <% end %>
40
+
41
+ cd $(dirname $TARGET) # the target might not exist yet
42
+
43
+ # GIT_DIR is "." which should points to bare repozitory
44
+ GIT_DIR="$REPO"
45
+
46
+ info "Reading /etc/profile ..."
47
+ . /etc/profile
48
+
49
+ debug
50
+ debug "=== Environment ==="
51
+ debug "PATH: $PATH"
52
+ debug "USER: $USER"
53
+ debug "TERM: $TERM"
54
+ debug "Ruby version: $(ruby --version)"
55
+ debug "Ruby path: $(which ruby)"
56
+ debug
57
+ debug "=== Git-deployer ==="
58
+ debug "TARGET: $TARGET"
59
+ debug "BRANCH: $BRANCH"
60
+ debug "REPO: $REPO"
61
+ debug "PWD: $PWD"
62
+ debug
63
+
64
+ if [ -d $TARGET ] ; then
65
+ cd $TARGET
66
+ info "Updating $BRANCH in `pwd` ... (from $old' to '$new')"
67
+ git fetch
68
+ git reset $new --hard
69
+ else
70
+ info "Cloning $BRANCH to $(pwd)/$TARGET (HEAD: '$new') ..."
71
+ git clone $REPO $TARGET
72
+ cd $TARGET
73
+ if [ -x "hooks/clone" ] ; then
74
+ info "[$PWD] Running clone hook"
75
+ exec "./hooks/clone"
76
+ elif [ -f "hooks/clone" ] ; then
77
+ info "[$PWD] Loading clone hook"
78
+ . "./hooks/clone" # so user can use functions defined in this hook in his clone hook
79
+ exit $?
80
+ else
81
+ abort "No clone hook found!"
82
+ fi
83
+ fi
84
+
85
+ # Update hook
86
+ if [ -x "hooks/update" ] ; then
87
+ info "[$PWD] Running update hook"
88
+ exec "./hooks/update"
89
+ elif [ -f "hooks/update" ] ; then
90
+ info "[$PWD] Loading update hook"
91
+ . "./hooks/update" # so user can use functions defined in this hook in his update hook
92
+ exit $?
93
+ else
94
+ abort "No update hook found!"
95
+ fi
@@ -0,0 +1,280 @@
1
+ #!/usr/bin/env nake
2
+
3
+ # TODO: what about a console support as capistrano has? Would be so helpful! Or at least ./tasks.rb deployer:ssh which starts ssh session for a server and cd to application path.
4
+ # TODO: run a command on all/given servers, like if you forget to create tmp in your clone hook
5
+
6
+ require "nake/template"
7
+
8
+ # === Helpers === #
9
+
10
+ # TODO: put it to nake
11
+ class Nake::Task
12
+ def run_from_task(task, *args)
13
+ self.call(*args)
14
+ rescue SystemExit => exception
15
+ Kernel.abort "Exception during task #{task}: #{exception.message}. Please re-run the task.\n#{exception.backtrace.join("\n- ")}"
16
+ rescue Exception => exception
17
+ abort "Exception during task #{task}: #{exception.message}. Please re-run the task.\n#{exception.backtrace.join("\n- ")}"
18
+ end
19
+ end
20
+
21
+ module SshMixin
22
+ def ssh(server, command)
23
+ sh "ssh %{user}@%{host} '#{command}'" % server
24
+ end
25
+
26
+ def servers(*names, &block)
27
+ names.map! { |name| name.to_sym }
28
+ config = Task["deployer:setup"].config
29
+
30
+ if ! config.has_key?(:servers) || config[:servers].empty?
31
+ abort "You have to configure servers. Read documentation online at http://github.com/botanicus/git-deployer"
32
+ end
33
+
34
+ names = config[:servers].keys if names.empty?
35
+ names.each do |name|
36
+ server = config[:servers][name]
37
+ raise "There isn't any server named #{name}. Please specify one of #{config[:servers].keys} or add #{name} to your configuration." if server.nil?
38
+
39
+ [:user, :host, :repo, :path].each do |key|
40
+ unless server.has_key?(key)
41
+ abort "Server #{name} doesn't have key #{key}, you have to provide it!"
42
+ end
43
+ end
44
+
45
+ info "Server #{name} #{server.inspect}"
46
+ block.call(name, server)
47
+ end
48
+ end
49
+ end
50
+
51
+ # === Tasks === #
52
+
53
+ # @settings
54
+ # Task["deployer:install"].config[:executable] = true
55
+ # @options
56
+ # --[no-]force Overwrite local hooks. Default is false.
57
+ # --[no-]executable Install hooks as executable scripts, so you can use whichever interpret,
58
+ # but you can't access to shell functions from post-receive.
59
+ Task.new("deployer:install") do |task|
60
+ task.description = "Install clone and update hooks to the project."
61
+
62
+ # path to the given hook
63
+ task.define_singleton_method(:path) do |name, options|
64
+ basename = options[:executable] ? "#{name}.exec.erb" : "#{name}.source.erb"
65
+ File.join(File.dirname(__FILE__), "..", "hooks", "project", basename)
66
+ end
67
+
68
+ # install given hook from its template
69
+ task.define_singleton_method(:install) do |source, target, options|
70
+ mkdir_p File.dirname(target)
71
+ note "Creating #{target} from #{source}"
72
+ if ! File.exist?(target) || options[:force]
73
+ erb source, target, options: options
74
+ sh "chmod +x #{target}" if options[:executable]
75
+ else
76
+ abort "File #{target} already exist. Run this hook with --force to override the file."
77
+ end
78
+ end
79
+
80
+ task.define do |options|
81
+ self.install(self.path("clone", options), "hooks/clone", options)
82
+ self.install(self.path("update", options), "hooks/update", options)
83
+ end
84
+ end
85
+
86
+ # @settings
87
+ # Task["deployer:setup"].config[:servers] = {
88
+ # server1: {
89
+ # user: "www",
90
+ # host: "127.0.0.1",
91
+ # repo: "/var/sources/deploy-test.git",
92
+ # path: "/var/www/deploy-test"
93
+ # }
94
+ # }
95
+ # @options
96
+ # --[no-]force Overwrite remote repository and application path. Default is false.
97
+ # Also, this tasks takes the same arguments as deployer:remote:copy_hook.
98
+ # @see Task["deployer:remote:copy_hook"] for configuring generation of the post-receive hook.
99
+ Task.new("deployer:setup") do |task|
100
+ task.description = "Install Git hooks on remote server"
101
+ task.extend(SshMixin)
102
+
103
+ task.define do |options|
104
+ servers do |name, server|
105
+ if options[:force]
106
+ ssh server, "test -d %{path} && rm -rf %{path}; test -d %{repo} && rm -rf %{repo}"
107
+ end
108
+
109
+ unless ssh server, "test -d %{path}"
110
+ ssh server, "mkdir -p %{path}" || abort("Creating of some necessary directories failed.")
111
+ else
112
+ abort "Path %{path} already exist. Try to run with --force if you want to overwrite it." % server
113
+ end
114
+
115
+ unless ssh server, "test -d %{repo}"
116
+ ssh server, "mkdir -p %{repo}" || abort("Creating of some necessary directories failed.")
117
+ ssh server, "cd %{repo} && git init --bare" || abort("There was a problems during attempt to create a bare repository.")
118
+ sh "git remote add #{name} %{user}@%{host}:%{repo}" % server
119
+ else
120
+ abort "Repository %{repo} already exist. Try to run with --force if you want to overwrite it." % server
121
+ end
122
+
123
+ info "Setup at server #{name} finished"
124
+ end
125
+
126
+ # copy post-receive hooks
127
+ Task["deployer:remote:copy_hook"].run_from_task("deployer:setup", [], options)
128
+ end
129
+ end
130
+
131
+ # @options
132
+ # This tasks takes the same arguments as deployer:compile_hook.
133
+ # @see Task["deployer:compile_hook"] for configuring generation of the post-receive hook.
134
+ Task.new("deployer:remote:copy_hook") do |task|
135
+ task.description = "Copy Git hook to remote server"
136
+ task.extend(SshMixin)
137
+
138
+ # TODO: change gemspec to require Ruby 1.9
139
+ task.define_singleton_method(:template) do |path|
140
+ path.end_with?(".erb") ? path : compile_template(path)
141
+ end
142
+
143
+ # Template precedence:
144
+ # 1) hooks/post-receive.server_name
145
+ # 2) hooks/post-receive.server_name.erb
146
+ # 3) hooks/post-receive
147
+ # 3) hooks/post-receive.erb
148
+ # 5) the default template distributed with git-deployer
149
+ task.define_singleton_method(:find_template) do |name|
150
+ ["hooks/post-receive.#{name}", "hooks/post-receive"].find do |template|
151
+ File.exist?(template)
152
+ end
153
+ end
154
+
155
+ # @return [String] path to the post-receive hook which was generated
156
+ task.define_singleton_method(:compile_template) do |name|
157
+ path = ["hooks/post-receive.#{name}.erb", "hooks/post-receive.erb"].find do |template|
158
+ if File.exist?(template)
159
+ info "Compiling template #{template}"
160
+ Task["deployer:compile_hook"].call(template, name, options)
161
+ end
162
+ end
163
+ path.sub(/\.erb$/, "") if path
164
+ end
165
+
166
+ task.define_singleton_method(:upload) do |server, local_path|
167
+ sh "scp #{local_path} %{user}@%{host}:%{repo}/hooks/post-receive" % server
168
+ ssh server, "chmod +x %{repo}/hooks/post-receive"
169
+ end
170
+
171
+ task.define do |*names, options|
172
+ servers(*names) do |name, server|
173
+ # generate the hook if it doesn't exist
174
+ if local_path = self.find_template(name)
175
+ info "Using hook #{local_path}"
176
+ self.upload(server, local_path)
177
+ elsif local_path = self.compile_template(name)
178
+ self.upload(server, local_path)
179
+ sh "rm #{local_path}"
180
+ else
181
+ template = File.join(File.dirname(__FILE__), "..", "hooks", "server", "post-receive.erb")
182
+ info "Generating hook from default post-receive template"
183
+ Task["deployer:compile_hook"].call([template, name], options)
184
+ local_path = "hooks/post-receive.#{name}"
185
+ self.upload(server, local_path)
186
+ sh "rm #{local_path}"
187
+ end
188
+ end
189
+ end
190
+ end
191
+
192
+ # TODO: Task["deployer:compile_hook"].config[:colors] is fine, but there should be also server-specific configuration in Task["deployer:setup"].config[:servers][:origin][:colors]
193
+
194
+ # @example
195
+ # ./tasks.rb deployer:compile_hook hooks/post-receive.erb --colors
196
+ # @settings
197
+ # Task["deployer:compile_hook"].config[:colors] = false
198
+ # Task["deployer:compile_hook"].config[:debug] = true
199
+ # Task["deployer:compile_hook"].config[:branch] = "master"
200
+ # Task["deployer:compile_hook"].config[:shebang] = "#!/usr/bin/env ruby"
201
+ # Task["deployer:compile_hook"].config[:target] = "$BRANCH"
202
+ # @options
203
+ # --[no-]force Overwrite local post-receive hook. Default is keep it.
204
+ # --[no-]colors Do not use colors in the hook. Some servers might have problems with them.
205
+ # --[no-]debug Print debug messages from the post-receive hook.
206
+ # --branch=deploy Deploy just this specified branch. Default is deploy all of them.
207
+ # --shebang='#!/bin/zsh' Use this shebang in the post-receive hook.
208
+ # --target='$BRANCH' Relative path from the apps root to the application. So if we have apps root in /var/www/myapp and we
209
+ # specify target to '$BRANCH', then each branch will be located in directory with same name as the branch,
210
+ # i. e. /var/www/myapp/master. Empty target means put everything directly into the apps root. It's reasonable
211
+ # just if you specify also the --branch=mybranch switch, otherwise the code will be reset in each push to the
212
+ # different branch which isn't probably what you want. But if you deploy just one branch, then it's OK.
213
+ Task.new("deployer:compile_hook") do |task|
214
+ task.description = "Copy Git hook locally, so you can edit it and at the next remote copy it will be used instead of the hook distributed with git-deployer."
215
+ task.extend(SshMixin)
216
+
217
+ # default configuration
218
+ task.config[:shebang] = "#!/bin/sh"
219
+ task.config[:debug] = true
220
+ task.config[:colors] = true
221
+ task.config[:branch] = nil
222
+ task.config[:target] = "$BRANCH"
223
+
224
+ # We have to generate one hook for each server configuration because we have to specify local paths
225
+ task.define do |source = nil, server_name = nil, options|
226
+ abort "[#1] You have to specify the template you want to compile!" if source.nil?
227
+ abort "[#2] You have to specify the the server_name!" if server_name.nil?
228
+ abort "First argument has to be a template with .erb extension!" unless source.end_with?(".erb")
229
+ server = Task["deployer:setup"].config[:servers][server_name]
230
+ target = "hooks/post-receive.#{server_name}"
231
+ if ! File.exist?(target) || options[:force]
232
+ info "Creating #{target} from template #{source}"
233
+ erb source, target, {repo: server[:repo], path: server[:path]}.merge(config).merge(options)
234
+ else
235
+ abort "File #{target} already exist. Run this task with --force option to override."
236
+ end
237
+ end
238
+ end
239
+
240
+ Task.new("deployer:copy_hook") do |task|
241
+ task.description = "Copy Git hook locally, so you can edit it and at the next remote copy it will be used instead of the hook distributed with git-deployer."
242
+
243
+ task.define do |target = "hooks/post-receive", options|
244
+ source = File.join(File.dirname(__FILE__), "..", "hooks", "server", "post-receive.erb")
245
+ if ! File.exist?(target) || options[:force]
246
+ cp source, target
247
+ else
248
+ abort "File #{target} already exist. Run this task with --force option to override."
249
+ end
250
+ end
251
+ end
252
+
253
+ Task.new("deployer:run") do |task|
254
+ task.description = "Run remote hook"
255
+ task.extend(SshMixin)
256
+
257
+ # STDIN for post-receive:
258
+ # SHA1 SHA1 refs/heads/master
259
+ task.define do
260
+ servers do |name, server|
261
+ head = `git rev-parse HEAD`
262
+ refs = `cat .git/HEAD | awk '{ print $2 }'`
263
+ ssh server, "cd %{path} && echo #{head} #{head} #{refs} | ./hooks/post-receive"
264
+ end
265
+ end
266
+ end
267
+
268
+ # ./tasks.rb deployer:remove
269
+ # ./tasks.rb deployer:remove server1 server2
270
+ Task.new("deployer:remove") do |task|
271
+ task.description = "Remove created directory for remote servers"
272
+ task.config = Task["deployer:setup"].config
273
+ task.extend(SshMixin)
274
+
275
+ task.define do |*names, options|
276
+ servers(names) do |name, server|
277
+ ssh "rm -rf %{path}; rm -rf %repo"
278
+ end
279
+ end
280
+ end
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: git-deployer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - "Jakub \xC5\xA0\xC5\xA5astn\xC3\xBD aka Botanicus"
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain:
11
+ date: 2010-01-03 00:00:00 +01:00
12
+ default_executable:
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: nake
16
+ type: :development
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: "0"
23
+ version:
24
+ description: ""
25
+ email: knava.bestvinensis@gmail.com
26
+ executables: []
27
+
28
+ extensions: []
29
+
30
+ extra_rdoc_files: []
31
+
32
+ files:
33
+ - example/hooks/clone
34
+ - example/hooks/update
35
+ - example/README.textile
36
+ - example/tasks.rb
37
+ - example/www/index.html
38
+ - git-deployer.gemspec
39
+ - hooks/project/clone.exec.erb
40
+ - hooks/project/clone.source.erb
41
+ - hooks/project/update.exec.erb
42
+ - hooks/project/update.source.erb
43
+ - hooks/server/post-receive.erb
44
+ - README.textile
45
+ - tasks/git-deployer.nake
46
+ has_rdoc: true
47
+ homepage: http://github.com/botanicus/git-deployer
48
+ licenses: []
49
+
50
+ post_install_message:
51
+ rdoc_options: []
52
+
53
+ require_paths:
54
+ - tasks
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: "0"
60
+ version:
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: "0"
66
+ version:
67
+ requirements: []
68
+
69
+ rubyforge_project: git-deployer
70
+ rubygems_version: 1.3.5
71
+ signing_key:
72
+ specification_version: 3
73
+ summary: Easy deploy system based on Git hooks
74
+ test_files: []
75
+