git-deployer 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+