recap 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/.gitignore +3 -0
  2. data/.travis.yml +4 -0
  3. data/README.md +12 -3
  4. data/Rakefile +8 -0
  5. data/Vagrantfile +61 -0
  6. data/doc/index.html +45 -26
  7. data/doc/lib/recap/bootstrap.html +42 -0
  8. data/doc/lib/recap/bundler.html +36 -19
  9. data/doc/lib/recap/capistrano_extensions.html +28 -23
  10. data/doc/lib/recap/cli.html +3 -0
  11. data/doc/lib/recap/compatibility.html +6 -3
  12. data/doc/lib/recap/deploy.html +41 -86
  13. data/doc/lib/recap/env.html +6 -1
  14. data/doc/lib/recap/foreman.html +3 -0
  15. data/doc/lib/recap/namespace.html +42 -0
  16. data/doc/lib/recap/preflight.html +12 -7
  17. data/doc/lib/recap/rails.html +3 -0
  18. data/doc/lib/recap/version.html +3 -0
  19. data/doc/lib/recap.html +42 -0
  20. data/features/bundling-gems.feature +18 -0
  21. data/features/deploying-projects.feature +21 -0
  22. data/features/managing-processes.feature +17 -0
  23. data/features/setting-environment-variables.feature +21 -0
  24. data/features/steps/capistrano_steps.rb +98 -0
  25. data/features/support/project.rb +211 -0
  26. data/features/support/server.rb +53 -0
  27. data/features/templates/gem/binary.erb +43 -0
  28. data/features/templates/gem/gemspec.erb +11 -0
  29. data/features/templates/project/Capfile +21 -0
  30. data/features/templates/project/Capfile.erb +21 -0
  31. data/features/templates/project/Gemfile.erb +7 -0
  32. data/features/templates/project/Procfile.erb +1 -0
  33. data/index.rb +26 -17
  34. data/lib/recap/bootstrap.rb +47 -0
  35. data/lib/recap/bundler.rb +31 -21
  36. data/lib/recap/capistrano_extensions.rb +11 -9
  37. data/lib/recap/cli.rb +1 -1
  38. data/lib/recap/compatibility.rb +3 -3
  39. data/lib/recap/deploy.rb +45 -57
  40. data/lib/recap/env.rb +30 -26
  41. data/lib/recap/environment.rb +54 -0
  42. data/lib/recap/foreman.rb +28 -9
  43. data/lib/recap/namespace.rb +37 -0
  44. data/lib/recap/preflight.rb +10 -8
  45. data/lib/recap/rails.rb +6 -4
  46. data/lib/recap/ruby.rb +3 -0
  47. data/lib/recap/static.rb +1 -0
  48. data/lib/recap/version.rb +1 -1
  49. data/lib/recap.rb +12 -0
  50. data/recap.gemspec +8 -4
  51. data/spec/models/environment_spec.rb +143 -0
  52. data/spec/spec_helper.rb +7 -0
  53. data/spec/tasks/bootstrap_spec.rb +34 -0
  54. data/spec/tasks/bundler_spec.rb +126 -0
  55. data/spec/tasks/deploy_spec.rb +209 -0
  56. data/spec/tasks/env_spec.rb +38 -0
  57. data/spec/tasks/foreman_spec.rb +154 -0
  58. data/test-vm/manifests/base.pp +17 -0
  59. data/test-vm/share/.gitkeep +0 -0
  60. metadata +138 -19
  61. /data/bin/{tomafro-deploy → recap} +0 -0
@@ -0,0 +1,42 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="content-type" content="text/html;charset=utf-8">
5
+ <title>namespace.rb</title>
6
+ <link rel="stylesheet" href="http://jashkenas.github.com/docco/resources/docco.css">
7
+ </head>
8
+ <body>
9
+ <div id='container'>
10
+ <div id="background"></div>
11
+ <div id="jump_to">
12
+ Jump To &hellip;
13
+ <div id="jump_wrapper">
14
+ <div id="jump_page">
15
+ <a class="source" href="../../index.html">index.rb</a>
16
+ <a class="source" href="../recap.html">recap.rb</a>
17
+ <a class="source" href="bootstrap.html">bootstrap.rb</a>
18
+ <a class="source" href="bundler.html">bundler.rb</a>
19
+ <a class="source" href="capistrano_extensions.html">capistrano_extensions.rb</a>
20
+ <a class="source" href="cli.html">cli.rb</a>
21
+ <a class="source" href="compatibility.html">compatibility.rb</a>
22
+ <a class="source" href="deploy.html">deploy.rb</a>
23
+ <a class="source" href="env.html">env.rb</a>
24
+ <a class="source" href="foreman.html">foreman.rb</a>
25
+ <a class="source" href="namespace.html">namespace.rb</a>
26
+ <a class="source" href="preflight.html">preflight.rb</a>
27
+ <a class="source" href="rails.html">rails.rb</a>
28
+ <a class="source" href="version.html">version.rb</a>
29
+ </div>
30
+ </div>
31
+ </div>
32
+ <table cellspacing=0 cellpadding=0>
33
+ <thead>
34
+ <tr>
35
+ <th class=docs><h1>namespace.rb</h1></th>
36
+ <th class=code></th>
37
+ </tr>
38
+ </thead>
39
+ <tbody>
40
+ </table>
41
+ </div>
42
+ </body>
@@ -13,6 +13,8 @@
13
13
  <div id="jump_wrapper">
14
14
  <div id="jump_page">
15
15
  <a class="source" href="../../index.html">index.rb</a>
16
+ <a class="source" href="../recap.html">recap.rb</a>
17
+ <a class="source" href="bootstrap.html">bootstrap.rb</a>
16
18
  <a class="source" href="bundler.html">bundler.rb</a>
17
19
  <a class="source" href="capistrano_extensions.html">capistrano_extensions.rb</a>
18
20
  <a class="source" href="cli.html">cli.rb</a>
@@ -20,6 +22,7 @@
20
22
  <a class="source" href="deploy.html">deploy.rb</a>
21
23
  <a class="source" href="env.html">env.rb</a>
22
24
  <a class="source" href="foreman.html">foreman.rb</a>
25
+ <a class="source" href="namespace.html">namespace.rb</a>
23
26
  <a class="source" href="preflight.html">preflight.rb</a>
24
27
  <a class="source" href="rails.html">rails.rb</a>
25
28
  <a class="source" href="version.html">version.rb</a>
@@ -59,7 +62,10 @@ application specific files. Each deploying user should be added to the applicat
59
62
  should a check fail.</p>
60
63
  </td>
61
64
  <td class=code>
62
- <div class='highlight'><pre><span class="no">Capistrano</span><span class="o">::</span><span class="no">Configuration</span><span class="o">.</span><span class="n">instance</span><span class="p">(</span><span class="ss">:must_exist</span><span class="p">)</span><span class="o">.</span><span class="n">load</span> <span class="k">do</span></pre></div>
65
+ <div class='highlight'><pre><span class="k">module</span> <span class="nn">Recap::Preflight</span>
66
+ <span class="kp">extend</span> <span class="no">Recap</span><span class="o">::</span><span class="no">Namespace</span>
67
+
68
+ <span class="n">namespace</span> <span class="ss">:preflight</span> <span class="k">do</span></pre></div>
63
69
  </td>
64
70
  </tr>
65
71
  <tr id='section-2'>
@@ -70,12 +76,11 @@ should a check fail.</p>
70
76
  <p>The preflight check is pretty quick, so run it before every <code>deploy:setup</code> and <code>deploy</code></p>
71
77
  </td>
72
78
  <td class=code>
73
- <div class='highlight'><pre> <span class="n">before</span> <span class="s1">&#39;deploy:setup&#39;</span><span class="p">,</span> <span class="s1">&#39;preflight:check&#39;</span>
74
- <span class="n">before</span> <span class="s1">&#39;deploy&#39;</span><span class="p">,</span> <span class="s1">&#39;preflight:check&#39;</span>
79
+ <div class='highlight'><pre> <span class="n">before</span> <span class="s1">&#39;deploy:setup&#39;</span><span class="p">,</span> <span class="s1">&#39;preflight:check&#39;</span>
80
+ <span class="n">before</span> <span class="s1">&#39;deploy&#39;</span><span class="p">,</span> <span class="s1">&#39;preflight:check&#39;</span>
75
81
 
76
- <span class="n">set</span><span class="p">(</span><span class="ss">:remote_username</span><span class="p">)</span> <span class="p">{</span> <span class="n">capture</span><span class="p">(</span><span class="s1">&#39;whoami&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span> <span class="p">}</span>
82
+ <span class="n">set</span><span class="p">(</span><span class="ss">:remote_username</span><span class="p">)</span> <span class="p">{</span> <span class="n">capture</span><span class="p">(</span><span class="s1">&#39;whoami&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span> <span class="p">}</span>
77
83
 
78
- <span class="n">namespace</span> <span class="ss">:preflight</span> <span class="k">do</span>
79
84
  <span class="n">task</span> <span class="ss">:check</span> <span class="k">do</span></pre></div>
80
85
  </td>
81
86
  </tr>
@@ -87,7 +92,7 @@ should a check fail.</p>
87
92
  <p>First check the <code>application_user</code> exists</p>
88
93
  </td>
89
94
  <td class=code>
90
- <div class='highlight'><pre> <span class="k">if</span> <span class="n">capture</span><span class="p">(</span><span class="s2">&quot;id </span><span class="si">#{</span><span class="n">application_user</span><span class="si">}</span><span class="s2"> &gt; /dev/null 2&gt;&amp;1; echo $?&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span> <span class="o">!=</span> <span class="s2">&quot;0&quot;</span>
95
+ <div class='highlight'><pre> <span class="k">if</span> <span class="n">exit_code</span><span class="p">(</span><span class="s2">&quot;id </span><span class="si">#{</span><span class="n">application_user</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span> <span class="o">!=</span> <span class="s2">&quot;0&quot;</span>
91
96
  <span class="nb">abort</span> <span class="sx">%{</span>
92
97
  <span class="sx">The application user &#39;</span><span class="si">#{</span><span class="n">application_user</span><span class="si">}</span><span class="sx">&#39; doesn&#39;t exist. You can create this user by logging into the server and running:</span>
93
98
 
@@ -104,7 +109,7 @@ should a check fail.</p>
104
109
  <p>Then the <code>application_group</code></p>
105
110
  </td>
106
111
  <td class=code>
107
- <div class='highlight'><pre> <span class="k">if</span> <span class="n">capture</span><span class="p">(</span><span class="s2">&quot;id -g </span><span class="si">#{</span><span class="n">application_group</span><span class="si">}</span><span class="s2"> &gt; /dev/null 2&gt;&amp;1; echo $?&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span> <span class="o">!=</span> <span class="s2">&quot;0&quot;</span>
112
+ <div class='highlight'><pre> <span class="k">if</span> <span class="n">exit_code</span><span class="p">(</span><span class="s2">&quot;id -g </span><span class="si">#{</span><span class="n">application_group</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span> <span class="o">!=</span> <span class="s2">&quot;0&quot;</span>
108
113
  <span class="nb">abort</span> <span class="sx">%{</span>
109
114
  <span class="sx">The application group &#39;</span><span class="si">#{</span><span class="n">application_group</span><span class="si">}</span><span class="sx">&#39; doesn&#39;t exist. You can create this group by logging into the server and running:</span>
110
115
 
@@ -13,6 +13,8 @@
13
13
  <div id="jump_wrapper">
14
14
  <div id="jump_page">
15
15
  <a class="source" href="../../index.html">index.rb</a>
16
+ <a class="source" href="../recap.html">recap.rb</a>
17
+ <a class="source" href="bootstrap.html">bootstrap.rb</a>
16
18
  <a class="source" href="bundler.html">bundler.rb</a>
17
19
  <a class="source" href="capistrano_extensions.html">capistrano_extensions.rb</a>
18
20
  <a class="source" href="cli.html">cli.rb</a>
@@ -20,6 +22,7 @@
20
22
  <a class="source" href="deploy.html">deploy.rb</a>
21
23
  <a class="source" href="env.html">env.rb</a>
22
24
  <a class="source" href="foreman.html">foreman.rb</a>
25
+ <a class="source" href="namespace.html">namespace.rb</a>
23
26
  <a class="source" href="preflight.html">preflight.rb</a>
24
27
  <a class="source" href="rails.html">rails.rb</a>
25
28
  <a class="source" href="version.html">version.rb</a>
@@ -13,6 +13,8 @@
13
13
  <div id="jump_wrapper">
14
14
  <div id="jump_page">
15
15
  <a class="source" href="../../index.html">index.rb</a>
16
+ <a class="source" href="../recap.html">recap.rb</a>
17
+ <a class="source" href="bootstrap.html">bootstrap.rb</a>
16
18
  <a class="source" href="bundler.html">bundler.rb</a>
17
19
  <a class="source" href="capistrano_extensions.html">capistrano_extensions.rb</a>
18
20
  <a class="source" href="cli.html">cli.rb</a>
@@ -20,6 +22,7 @@
20
22
  <a class="source" href="deploy.html">deploy.rb</a>
21
23
  <a class="source" href="env.html">env.rb</a>
22
24
  <a class="source" href="foreman.html">foreman.rb</a>
25
+ <a class="source" href="namespace.html">namespace.rb</a>
23
26
  <a class="source" href="preflight.html">preflight.rb</a>
24
27
  <a class="source" href="rails.html">rails.rb</a>
25
28
  <a class="source" href="version.html">version.rb</a>
@@ -0,0 +1,42 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="content-type" content="text/html;charset=utf-8">
5
+ <title>recap.rb</title>
6
+ <link rel="stylesheet" href="http://jashkenas.github.com/docco/resources/docco.css">
7
+ </head>
8
+ <body>
9
+ <div id='container'>
10
+ <div id="background"></div>
11
+ <div id="jump_to">
12
+ Jump To &hellip;
13
+ <div id="jump_wrapper">
14
+ <div id="jump_page">
15
+ <a class="source" href="../index.html">index.rb</a>
16
+ <a class="source" href="recap.html">recap.rb</a>
17
+ <a class="source" href="recap/bootstrap.html">bootstrap.rb</a>
18
+ <a class="source" href="recap/bundler.html">bundler.rb</a>
19
+ <a class="source" href="recap/capistrano_extensions.html">capistrano_extensions.rb</a>
20
+ <a class="source" href="recap/cli.html">cli.rb</a>
21
+ <a class="source" href="recap/compatibility.html">compatibility.rb</a>
22
+ <a class="source" href="recap/deploy.html">deploy.rb</a>
23
+ <a class="source" href="recap/env.html">env.rb</a>
24
+ <a class="source" href="recap/foreman.html">foreman.rb</a>
25
+ <a class="source" href="recap/namespace.html">namespace.rb</a>
26
+ <a class="source" href="recap/preflight.html">preflight.rb</a>
27
+ <a class="source" href="recap/rails.html">rails.rb</a>
28
+ <a class="source" href="recap/version.html">version.rb</a>
29
+ </div>
30
+ </div>
31
+ </div>
32
+ <table cellspacing=0 cellpadding=0>
33
+ <thead>
34
+ <tr>
35
+ <th class=docs><h1>recap.rb</h1></th>
36
+ <th class=code></th>
37
+ </tr>
38
+ </thead>
39
+ <tbody>
40
+ </table>
41
+ </div>
42
+ </body>
@@ -0,0 +1,18 @@
1
+ Feature: Bundling gems in ruby projects
2
+
3
+ Scenario: Deploying a project with a Gemfile
4
+
5
+ Given a new ruby project and a bootstrapped server
6
+ And a bundle requiring version "1.0" of "example-gem"
7
+ When I run "cap deploy:setup deploy"
8
+ Then the project should be deployed
9
+ And the deployed project should include version "1.0" of "example-gem"
10
+
11
+ Scenario: Updating a project bundle
12
+
13
+ Given a new ruby project and a bootstrapped server
14
+ And a bundle requiring version "1.0" of "example-gem"
15
+ And I run "cap deploy:setup deploy"
16
+ When I update the bundle to require version "1.1" of "example-gem"
17
+ And I run "cap deploy"
18
+ Then the deployed project should include version "1.1" of "example-gem"
@@ -0,0 +1,21 @@
1
+ Feature: Deploying and rolling back deployments
2
+
3
+ Scenario: Deploying for the first time
4
+
5
+ Given a new project and a bootstrapped server
6
+ When I run "cap deploy:setup deploy"
7
+ Then the project should be deployed
8
+
9
+ Scenario: Deploying after changes
10
+
11
+ Given a deployed project
12
+ When I commit changes to the project
13
+ And I run "cap deploy"
14
+ Then the latest version of the project should be deployed
15
+
16
+ Scenario: Rolling back to the previous version
17
+
18
+ Given a deployed project
19
+ When I commit and deploy changes to the project
20
+ And I run "cap deploy:rollback"
21
+ Then the previous project version should be deployed
@@ -0,0 +1,17 @@
1
+
2
+ Feature: Managing processes with foreman
3
+
4
+ Scenario: Running an application process
5
+ Given a new ruby project and a bootstrapped server
6
+ And the project has an application process defined in a Procfile
7
+ When I run "cap deploy:setup deploy"
8
+ Then the project should own the running application process
9
+
10
+ Scenario: Running processes can read environment variables
11
+ Given a new ruby project and a bootstrapped server
12
+ And the project has an application process defined in a Procfile
13
+ And the variable "MONSTER" is set to "tricorn"
14
+ When I run "cap deploy:setup deploy"
15
+ And I wait for the server to start
16
+ Then the variable "MONSTER" should be set to "tricorn"
17
+ Then the running application process should know that "MONSTER" is set to "tricorn"
@@ -0,0 +1,21 @@
1
+ Feature: Setting and unsetting environment config variables
2
+
3
+ Scenario: Setting an environment variable
4
+
5
+ Given a new project and a bootstrapped server
6
+ When I run "cap env:set SECRET=very-secure"
7
+ Then the variable "SECRET" should be set to "very-secure"
8
+
9
+ @wip
10
+ Scenario: Setting an environment variable based on an existing variable
11
+
12
+ Given a new project and a bootstrapped server
13
+ When I run "cap env:set SUPER_PATH=\$PATH"
14
+ Then the variable "SUPER_PATH" should be set to the application's PATH
15
+
16
+ Scenario: Unsetting a variable
17
+
18
+ Given a new project and a bootstrapped server
19
+ And the variable "SECRET" is set to "very-secure"
20
+ When I run "cap env:set SECRET="
21
+ Then the variable "SECRET" should have no value
@@ -0,0 +1,98 @@
1
+ Before do
2
+ FileUtils.rm_rf 'test-vm/share/projects'
3
+ FileUtils.rm_rf 'test-vm/share/gems'
4
+ `bundle exec vagrant sandbox on` unless ENV['SKIP_ROLLBACK']
5
+ end
6
+
7
+ After do
8
+ `bundle exec vagrant sandbox rollback` unless ENV['SKIP_ROLLBACK']
9
+ if project
10
+ project.run_on_server "sudo stop #{project.name} || true"
11
+ project.run_on_server "sudo rm -rf /etc/init/#{project.name}* || true"
12
+ end
13
+ end
14
+
15
+ Given /^a new (ruby )?project and a bootstrapped server$/ do |project_type|
16
+ type = (project_type || 'static').strip
17
+ start_project server: server, capfile: { recap_require: "recap/#{type}" }
18
+ project.run_cap 'bootstrap'
19
+ end
20
+
21
+ Given /^a deployed project$/ do
22
+ start_project server: server
23
+ project.run_cap 'bootstrap'
24
+ project.run_cap 'deploy:setup deploy'
25
+ end
26
+
27
+ Given /^a bundle requiring version "([^"]*)" of "([^"]*)"$/ do |version, gem|
28
+ project.add_gem_to_bundle(gem, version)
29
+ end
30
+
31
+ Given /^the variable "([^"]*)" is set to "([^"]*)"$/ do |name, value|
32
+ project.run_cap "env:set #{name}=#{value}"
33
+ end
34
+
35
+ Given /^the project has an application process defined in a Procfile$/ do
36
+ @application_process = 'an-application-process'
37
+ project.add_foreman_to_bundle
38
+ project.add_gem_to_bundle @application_process, '1.0.0'
39
+ project.add_command_to_procfile 'process', "bin/#{@application_process} --server"
40
+ end
41
+
42
+ When /^I update the bundle to require version "([^"]*)" of "([^"]*)"$/ do |version, gem|
43
+ project.add_gem_to_bundle(gem, version)
44
+ end
45
+
46
+ When /^I run "cap ([^"]*)"$/ do |command|
47
+ project.run_cap command
48
+ end
49
+
50
+ When /^I commit changes to the project$/ do
51
+ project.commit_changes
52
+ end
53
+
54
+ When /^I commit and deploy changes to the project$/ do
55
+ project.commit_changes
56
+ project.run_cap 'deploy'
57
+ end
58
+
59
+ When /^I wait for the server to start$/ do
60
+ sleep(5)
61
+ end
62
+
63
+ Then /^the project should be deployed$/ do
64
+ project.deployed_version.should eql(project.latest_version)
65
+ end
66
+
67
+ Then /^the latest version of the project should be deployed$/ do
68
+ project.deployed_version.should eql(project.latest_version)
69
+ end
70
+
71
+ Then /^the previous project version should be deployed$/ do
72
+ project.deployed_version.should eql(project.previous_version)
73
+ end
74
+
75
+ Then /^the deployed project should include version "([^"]*)" of "([^"]*)"$/ do |version, gem|
76
+ project.run_on_server("bin/#{gem} --version").strip.should eql(version)
77
+ end
78
+
79
+ Then /^the variable "([^"]*)" should be set to "([^"]*)"$/ do |name, value|
80
+ project.run_on_server("sudo su - #{project.name} -c 'env | grep #{name}'").strip.should eql("#{name}=#{value}")
81
+ end
82
+
83
+ Then /^the variable "([^"]*)" should be set to the application's PATH$/ do |name|
84
+ path = project.run_on_server("echo $PATH").strip
85
+ project.run_on_server("sudo su - #{project.name} -c 'env | grep #{name}'").strip.should eql("#{name}=#{path}")
86
+ end
87
+
88
+ Then /^the variable "([^"]*)" should have no value$/ do |name|
89
+ project.run_on_server("sudo su - #{project.name} -c 'env'").include?("#{name}=").should be_false
90
+ end
91
+
92
+ Then /^the project should own the running application process$/ do
93
+ project.run_on_server("ps -U #{project.name} u").include?(@application_process).should be_true
94
+ end
95
+
96
+ Then /^the running application process should know that "([^"]*)" is set to "([^"]*)"$/ do |name, value|
97
+ project.run_on_server("/usr/bin/curl localhost:3500/env | grep #{name}").strip.should eql("#{name}=#{value}")
98
+ end
@@ -0,0 +1,211 @@
1
+ require 'fileutils'
2
+ require 'faker'
3
+ require 'erb'
4
+
5
+ module ProjectSupport
6
+ def project
7
+ @project
8
+ end
9
+
10
+ def start_project(options = {})
11
+ @project = Project.new(options)
12
+ end
13
+
14
+ class Template
15
+ def initialize(template_name)
16
+ @template_name = template_name
17
+ end
18
+
19
+ def template_root
20
+ File.expand_path("../../templates/", __FILE__)
21
+ end
22
+
23
+ def to_s
24
+ ERB.new(read_template).result(binding)
25
+ end
26
+
27
+ def write_to(path)
28
+ full_path = File.expand_path(path)
29
+ FileUtils.mkdir_p File.dirname(full_path)
30
+ File.write(full_path, to_s)
31
+ end
32
+
33
+ def read_template
34
+ template_path = File.join(template_root, @template_name)
35
+ File.read(template_path)
36
+ end
37
+ end
38
+
39
+ class Capfile < Template
40
+ attr_reader :project, :recap_require
41
+
42
+ def initialize(project, options = {})
43
+ super('project/Capfile.erb')
44
+ @project = project
45
+ @recap_require = options[:recap_require] || 'recap/static'
46
+ end
47
+ end
48
+
49
+ class Gemfile < Template
50
+ attr_accessor :foreman
51
+ attr_accessor :gems
52
+
53
+ def initialize(gems = {})
54
+ super('project/Gemfile.erb')
55
+ @gems = gems
56
+ end
57
+ end
58
+
59
+ class Procfile < Template
60
+ attr_reader :name, :command
61
+
62
+ def initialize(name, command)
63
+ super('project/Procfile.erb')
64
+ @name = name
65
+ @command = command
66
+ end
67
+ end
68
+
69
+ class BundledGem
70
+ def initialize(gem, version)
71
+ @gem = gem
72
+ @version = version
73
+ @output_path = File.expand_path("../../../test-vm/share/gems/#{gem}", __FILE__)
74
+ end
75
+
76
+ def generate
77
+ FileUtils.mkdir_p @output_path
78
+ FileUtils.chdir @output_path do
79
+ GemBinary.new(@gem, @version).write_to "bin/#{@gem}"
80
+ Gemspec.new(@gem, @version).write_to "#{@name}.gemspec"
81
+
82
+ `git init`
83
+ `git add --all`
84
+ `git commit -m 'Committed version #{@version}'`
85
+ `git tag #{@version}`
86
+ end
87
+ end
88
+
89
+ class Gemspec < Template
90
+ attr_reader :gem, :version
91
+
92
+ def initialize(gem, version)
93
+ super 'gem/gemspec.erb'
94
+ @gem = gem
95
+ @version = version
96
+ end
97
+ end
98
+
99
+ class GemBinary < Template
100
+ attr_reader :gem, :version
101
+
102
+ def initialize(name, version)
103
+ super 'gem/binary.erb'
104
+ @gem = name
105
+ @version = version
106
+ end
107
+ end
108
+ end
109
+
110
+ class Project
111
+ def initialize(options = {})
112
+ @server = options[:server]
113
+ @gems = {}
114
+ FileUtils.rm_rf repository_path
115
+ git 'init'
116
+ write_and_commit_file 'Capfile', Capfile.new(self, options[:capfile] || {})
117
+ end
118
+
119
+ def name
120
+ @name ||= Faker::Name.first_name.downcase
121
+ end
122
+
123
+ def private_key_path
124
+ @server.private_key_path
125
+ end
126
+
127
+ def latest_version
128
+ committed_versions[0]
129
+ end
130
+
131
+ def previous_version
132
+ committed_versions[1]
133
+ end
134
+
135
+ def committed_versions
136
+ `cd #{repository_path} && git log --pretty=format:"%H"`.split("\n")
137
+ end
138
+
139
+ def write_and_commit_file(path, content = "")
140
+ full_path = File.join(repository_path, path)
141
+ FileUtils.mkdir_p File.dirname(full_path)
142
+ File.write(full_path, content)
143
+ commit_files(path)
144
+ end
145
+
146
+ def commit_files(*paths)
147
+ git "add #{paths.join(' ')}"
148
+ git "commit -m 'Added #{paths.join(' ')}'"
149
+ end
150
+
151
+ def repository_path(path = "")
152
+ File.join('test-vm/share/projects/', name, path)
153
+ end
154
+
155
+ def deployment_path(path = "")
156
+ File.join("/home/#{name}/apps/#{name}", path)
157
+ end
158
+
159
+ def deployed_version
160
+ (@server.run "cd #{deployment_path} && git rev-parse HEAD").strip
161
+ end
162
+
163
+ def run_cap(command)
164
+ `cap -l capistrano.log -f #{repository_path('Capfile')} #{command}`
165
+ raise "Exit code returned running 'cap #{command}'" if $?.exitstatus != 0
166
+ end
167
+
168
+ def run_on_server(cmd)
169
+ @server.run("cd #{deployment_path} && #{cmd}")
170
+ end
171
+
172
+ def git(command)
173
+ FileUtils.mkdir_p repository_path
174
+ FileUtils.chdir repository_path do
175
+ `git #{command}`
176
+ end
177
+ end
178
+
179
+ def gemfile
180
+ @gemfile ||= Gemfile.new
181
+ end
182
+
183
+ def add_gem_to_bundle(gem, version)
184
+ gemfile.gems[gem] = version
185
+ BundledGem.new(gem, version).generate
186
+ regenerate_bundle
187
+ end
188
+
189
+ def add_foreman_to_bundle
190
+ gemfile.foreman = true
191
+ regenerate_bundle
192
+ end
193
+
194
+ def regenerate_bundle
195
+ write_and_commit_file 'Gemfile', gemfile
196
+ # Nasty hack to generate a Gemfile.lock
197
+ @server.run "cd /recap/share/projects/#{name} && bundle install"
198
+ commit_files 'Gemfile.lock'
199
+ end
200
+
201
+ def add_command_to_procfile(name, command)
202
+ write_and_commit_file 'Procfile', Procfile.new(name, command)
203
+ end
204
+
205
+ def commit_changes
206
+ write_and_commit_file 'project-file', Faker::Lorem.sentence
207
+ end
208
+ end
209
+ end
210
+
211
+ World(ProjectSupport)
@@ -0,0 +1,53 @@
1
+ require 'vagrant'
2
+
3
+ module ServerSupport
4
+ def server
5
+ @server ||= Server.instance
6
+ end
7
+
8
+ class Server
9
+ class << self
10
+ def instance
11
+ Server.new
12
+ end
13
+ end
14
+
15
+ def private_key_path
16
+ env.default_private_key_path
17
+ end
18
+
19
+ def run(command, user = 'vagrant')
20
+ output = nil
21
+ env.primary_vm.channel.sudo("su - #{user} -c '#{command}'") do |type, data|
22
+ output = data if type == :stdout
23
+ end
24
+ output
25
+ end
26
+
27
+ def has_user?(name)
28
+ test? "id -u #{name}"
29
+ end
30
+
31
+ def has_group?(name)
32
+ test? "id -g #{name}"
33
+ end
34
+
35
+ def has_directory?(path)
36
+ test? "[ -d #{path} ]"
37
+ end
38
+
39
+ def has_file?(path)
40
+ test? "[ -f #{path} ]"
41
+ end
42
+
43
+ def test?(command)
44
+ env.primary_vm.channel.test(command)
45
+ end
46
+
47
+ def env
48
+ @env ||= Vagrant::Environment.new
49
+ end
50
+ end
51
+ end
52
+
53
+ World(ServerSupport)