pulsar 0.2.2 → 0.2.3

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.md CHANGED
@@ -1,16 +1,240 @@
1
- # Pulsar
1
+ # Pulsar [![Gem Version](https://badge.fury.io/rb/pulsar.png)](http://badge.fury.io/rb/pulsar) [![Build Status](https://secure.travis-ci.org/nebulab/pulsar.png?branch=master)](http://travis-ci.org/nebulab/pulsar) [![Coverage Status](https://coveralls.io/repos/nebulab/pulsar/badge.png?branch=master)](https://coveralls.io/r/nebulab/pulsar) [![Code Climate](https://codeclimate.com/github/nebulab/pulsar.png)](https://codeclimate.com/github/nebulab/pulsar)
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/pulsar.png)](http://badge.fury.io/rb/pulsar)
4
- [![Build Status](https://secure.travis-ci.org/nebulab/pulsar.png?branch=master)](http://travis-ci.org/nebulab/pulsar)
5
- [![Coverage Status](https://coveralls.io/repos/nebulab/pulsar/badge.png?branch=master)](https://coveralls.io/r/nebulab/pulsar)
6
- [![Code Climate](https://codeclimate.com/github/nebulab/pulsar.png)](https://codeclimate.com/github/nebulab/pulsar)
3
+ The easy [Capistrano](https://rubygems.org/gems/capistrano) deploy and configuration manager.
7
4
 
8
- Pulsar is a little tool that helps with deploys. Its main purpose is building capfiles for [Capistrano](https://rubygems.org/gems/capistrano)
9
- to run. It makes it easy to manage a large number of apps via a separate configuration repository.
5
+ Pulsar allows you to run capistrano tasks via a separate repository where all your deploy configurations are stored.
6
+ Once you have your own repository, you can gradully add configurations and recipes so that you never have to duplicate code again.
10
7
 
11
- ## Installation & Usage
8
+ The way Pulsar works means that you can deploy without actually having the application on your local machine (and neither
9
+ have all your application dependencies installed). This lets you integrate Pulsar with nearly any deploy strategy you can think of.
12
10
 
13
- Refer to the [GitHub Page](http://pulsar.nebulab.it).
11
+ Some of the benefits of using Pulsar:
12
+ * No capistrano configurations in the application code
13
+ * No need to have the application locally to deploy
14
+ * Multistage support by default
15
+ * Every recipe can be shared between all applications
16
+ * Can easily be integrated with other tools
17
+ * Write the least possible code to deploy
18
+
19
+ ## Installation
20
+
21
+ The most useful way of installing Pulsar is as a system gem:
22
+
23
+ ```bash
24
+ $ gem install pulsar
25
+ ```
26
+
27
+ This will install two commands: `pulsar` and `pulsar-utils`. The first command is required to run capistrano,
28
+ the other is for everything else.
29
+
30
+ ---
31
+
32
+ You'll need to create your own configuration repo:
33
+
34
+ ```bash
35
+ $ pulsar-utils init ~/Desktop/pulsar-conf
36
+ ```
37
+
38
+ This will create a basic start point for building your configuration repository. As soon as you're done configuring
39
+ you should consider storing this folder as an actual git repository.
40
+
41
+ Here it is possible to see how this configuration repository will look like: [Pulsar Conf Demo](http://github.com/nebulab/pulsar-conf-demo)
42
+
43
+ **NOTE**: Pulsar only supports git and *nix systems.
44
+
45
+ ## Configuration
46
+
47
+ This is an example repository configuration layout:
48
+
49
+ ```bash
50
+ pulsar-conf/
51
+ |── Gemfile
52
+ ├── Gemfile.lock
53
+ ├── apps
54
+ │   ├── base.rb
55
+ │   └── my_application
56
+ │      ├── defaults.rb
57
+ │      ├── production.rb
58
+ │      ├── recipes
59
+ │      │   └── custom_recipe.rb
60
+ │      └── staging.rb
61
+ └── recipes
62
+ ├── generic
63
+ │   ├── cleanup.rb
64
+ │   ├── maintenance_mode.rb
65
+ │   ├── notify.rb
66
+ │   └── rake.rb
67
+ ├── rails
68
+ │   ├── passenger.rb
69
+ │   ├── repair_permissions.rb
70
+ │   ├── symlink_configs.rb
71
+ │   ├── unicorn.rb
72
+ │   └── whenever.rb
73
+ └── spree_1
74
+ └── symlink_assets.rb
75
+ ```
76
+
77
+ Pulsar uses these files to build capistrano configurations on the fly, depending on how you invoke the `pulsar` command.
78
+ Since Pulsar it's basically a capistrano wrapper, the content of these files is plain old capistrano syntax.
79
+
80
+ ### _apps_ directory
81
+
82
+ This directory contains your application configurations. You'll have one directory per application.
83
+
84
+ * `base.rb` has configurations that are shared by all applications
85
+ * `my_application/defaults.rb` includes configuration shared by every stage of the application
86
+ * `my_application/staging.rb` and `my_application/production.rb` files include stage configurations
87
+ * `my_application/recipes/` are recipes that are always included for that application (no need to use `load_recipes`)
88
+
89
+ ### _recipes_ directory
90
+
91
+ This directory contains your recipes. You can create any number of directories to organize your recipes.
92
+ To load a recipe from your configurations you can use the `load_recipes` helper:
93
+
94
+ ```ruby
95
+ #
96
+ # Somewhere inside apps/
97
+ #
98
+ load_recipes do
99
+ rails :repair_permissions, :unicorn
100
+ generic :cleanup, :rake
101
+ end
102
+ ```
103
+
104
+ This will use capistrano's `load` method to include recipes from `rails/` and `generic/`.
105
+
106
+ ---
107
+
108
+ Another way to include your recipes is by using the `Gemfile`. Many gems already include custom recipes for capistrano so
109
+ you just need to require those. An example with [Whenever](https://github.com/javan/whenever):
110
+
111
+ ```ruby
112
+ #
113
+ # Inside Gemfile
114
+ #
115
+ gem 'whenever'
116
+
117
+ #
118
+ # Inside recipes/rails/whenever.rb
119
+ #
120
+ require 'whenever/capistrano'
121
+
122
+ set :whenever_command, "bundle exec whenever"
123
+
124
+ #
125
+ # Somewhere inside apps/
126
+ #
127
+ load_recipes do
128
+ rails :whenever
129
+ end
130
+ ```
131
+
132
+ ### Loading the repository
133
+
134
+ Once the repository is ready, you'll need to tell Pulsar where it is. The repository location can be specified either
135
+ as a full git path or a github repository path (`gh-user/pulsar-conf`).
136
+
137
+ Since Pulsar requires the repository for everything, there are multiple ways to store this information so that
138
+ you don't have to type it everytime.
139
+
140
+ You have three possibilities:
141
+
142
+ * `-c` command line option
143
+ * `PULSAR_CONF_REPO` environment variable
144
+ * `~/.pulsar` configuration file
145
+
146
+ The fastest way is probably the `.pulsar` hidden file inside your home directory:
147
+
148
+ ```bash
149
+ #
150
+ # Inside ~/.pulsar
151
+ #
152
+ PULSAR_CONF_REPO="gh-user/pulsar-conf"
153
+
154
+ #
155
+ # Also supported
156
+ #
157
+ # PULSAR_CONF_REPO="git://github.com/gh-user/pulsar-conf.git"
158
+ ```
159
+
160
+ Pulsar will read this file and set the environment variables properly.
161
+
162
+ ---
163
+
164
+ If you don't want to add another file to your home directory you can export the variables yourself:
165
+
166
+ ```bash
167
+ #
168
+ # Inside ~/.bash_profile or ~/.zshrc
169
+ #
170
+ export PULSAR_CONF_REPO="gh-user/pulsar-conf"
171
+ ```
172
+
173
+ ## Usage
174
+
175
+ After the repository is ready, running Pulsar is straightforward. To deploy `my_application` to `production`:
176
+
177
+ ```bash
178
+ $ pulsar my_application production
179
+ ```
180
+
181
+ As a rule of thumb, anything that's added at the end of the command is passed to capistrano. Some examples:
182
+
183
+ ```bash
184
+ $ pulsar my_application production --tasks
185
+
186
+ $ pulsar my_application staging deploy:migrations
187
+
188
+ $ pulsar my_application staging shell
189
+
190
+ #
191
+ # Deploy multiple apps by using commas
192
+ #
193
+ $ pulsar my_app1,my_app2,my_app3 production
194
+ ```
195
+
196
+ ### Running inside a Rack application (e.g. Ruby on Rails application)
197
+
198
+ In case you frequently work from a Rack application and would like a workflow similar to that of capistrano, Pulsar
199
+ supports running from inside a Rack application directory. If you use this a lot, you should consider installing
200
+ Pulsar via the application `Gemfile`.
201
+
202
+ When deploying from inside a Rack application you can omit the application name:
203
+
204
+ ```bash
205
+ $ cd /path/to/my_application
206
+
207
+ $ pulsar production
208
+
209
+ $ pulsar staging deploy:migrations
210
+ ```
211
+
212
+ ---
213
+
214
+ If you need a particular configuration for an application you can store a `.pulsar` file inside the application
215
+ directory:
216
+
217
+ ```bash
218
+ #
219
+ # Inside /path/to/my_application/.pulsar
220
+ #
221
+ PULSAR_CONF_REPO="gh-user/pulsar-conf"
222
+
223
+ #
224
+ # If the application directory name is different than what
225
+ # you configured inside the Pulsar configuration repository
226
+ #
227
+ # PULSAR_APP_NAME="my-application"
228
+ ```
229
+
230
+ ## Integrations
231
+
232
+ Pulsar is easy to integrate, you just need access to the configurations repository and the ability to
233
+ run a command.
234
+
235
+ ### Hubot
236
+
237
+ https://gist.github.com/mtylty/5324075
14
238
 
15
239
  ## Contributing
16
240
 
@@ -1,4 +1,5 @@
1
1
  module Pulsar::Helpers
2
2
  autoload :Capistrano, "pulsar/helpers/capistrano"
3
3
  autoload :Clamp, "pulsar/helpers/clamp"
4
+ autoload :Shell, "pulsar/helpers/shell"
4
5
  end
@@ -1,17 +1,18 @@
1
1
  module Pulsar
2
2
  module Helpers
3
3
  module Capistrano
4
- require "pulsar/helpers/clamp"
5
-
6
4
  class DSL
7
5
  include Pulsar::Helpers::Clamp
8
6
 
9
- def initialize(cap_conf, &dsl_code)
10
- @cap_conf = cap_conf
7
+ def initialize(capistrano, opts, &dsl_code)
8
+ @capistrano = capistrano
9
+ @options = opts
11
10
  instance_eval(&dsl_code)
12
11
  end
13
12
 
14
13
  def method_missing(meth, *args, &block)
14
+ return if !@capistrano.from_application_path? && @options[:app_only]
15
+
15
16
  recipes = "#{ENV['CONFIG_PATH']}/recipes/#{meth}"
16
17
 
17
18
  File.directory?(recipes) || raise("There are no recipes of type #{meth}")
@@ -20,18 +21,27 @@ module Pulsar
20
21
  recipe = "#{recipes}/#{arg}.rb"
21
22
  File.exists?(recipe) || raise("There is no #{arg} recipe")
22
23
 
23
- @cap_conf.send(:load, recipe)
24
+ @capistrano.send(:load, recipe)
24
25
  end
25
26
  end
26
27
  end
27
28
 
28
- def load_recipes(&block)
29
- DSL.new(self, &block)
30
- end
31
-
29
+ #
30
+ # This method can be called directly inside
31
+ # capistrano configurations but needs:
32
+ #
33
+ # defer { from_application_path? }
34
+ #
35
+ # otherwise capistrano will interpret it
36
+ # as a variable and error out
37
+ #
32
38
  def from_application_path?
33
39
  ENV.has_key?('APP_PATH')
34
40
  end
41
+
42
+ def load_recipes(opts = {}, &block)
43
+ DSL.new(self, opts, &block)
44
+ end
35
45
  end
36
46
  end
37
47
  end
@@ -1,9 +1,7 @@
1
- require 'fileutils'
2
-
3
1
  module Pulsar
4
2
  module Helpers
5
3
  module Clamp
6
- include FileUtils
4
+ include Pulsar::Helpers::Shell
7
5
 
8
6
  def self.included(base)
9
7
  base.extend(InstanceAndClassMethods)
@@ -22,7 +20,7 @@ module Pulsar
22
20
  def application_path
23
21
  Dir.pwd if from_application_path?
24
22
  end
25
-
23
+
26
24
  def build_capfile(args)
27
25
  app, stage = args.split(":")
28
26
 
@@ -45,11 +43,6 @@ module Pulsar
45
43
  @capfile_name ||= "#{tmp_dir}/capfile-#{time_to_deploy}"
46
44
  end
47
45
 
48
- def cd(path, opts, &block)
49
- puts "Directory: #{path.white}".yellow if opts[:verbose]
50
- FileUtils.cd(path) { yield }
51
- end
52
-
53
46
  def config_path
54
47
  @configuration_path ||= "#{tmp_dir}/conf-repo-#{time_to_deploy}"
55
48
  end
@@ -58,6 +51,12 @@ module Pulsar
58
51
  touch(capfile_path, :verbose => verbose?)
59
52
  end
60
53
 
54
+ def each_app
55
+ Dir["#{config_path}/apps/*"].each do |path|
56
+ yield(File.basename(path)) if File.directory?(path)
57
+ end
58
+ end
59
+
61
60
  def fetch_repo
62
61
  if File.directory?(conf_repo)
63
62
  fetch_directory_repo(conf_repo)
@@ -115,31 +114,14 @@ module Pulsar
115
114
  end
116
115
 
117
116
  def list_apps
118
- apps = Dir["#{config_path}/apps/*"].each do |app|
119
- if File.directory?(app)
120
- app_name = File.basename(app)
121
- app_envs = []
122
-
123
- Dir["#{app}/*"].each do |env|
124
- environments = %w(development staging production)
125
- env_name = File.basename(env, '.rb')
126
-
127
- if environments.include?(env_name)
128
- app_envs << env_name
129
- end
130
- end
131
-
132
- puts "#{app_name.cyan}: #{app_envs.map(&:magenta).join(', ')}"
133
- end
117
+ each_app do |name|
118
+ puts "#{name.cyan}: #{stages_for(name).map(&:magenta).join(', ')}"
134
119
  end
135
120
  end
136
121
 
137
122
  def load_configuration
138
- conf_path = application_path || Dir.home
139
- conf_file = File.join(conf_path, ".pulsar")
140
-
141
- if File.file?(conf_file)
142
- File.readlines(conf_file).each do |line|
123
+ unless pulsar_configuration.nil?
124
+ File.readlines(pulsar_configuration).each do |line|
143
125
  conf, value = line.split("=")
144
126
 
145
127
  ENV[conf] = value.chomp.gsub('"', '') if !conf.nil? && !value.nil?
@@ -147,6 +129,15 @@ module Pulsar
147
129
  end
148
130
  end
149
131
 
132
+ def pulsar_configuration
133
+ conf_file = ".pulsar"
134
+ inside_app = File.join(application_path, conf_file) rescue nil
135
+ inside_home = File.join(Dir.home, conf_file) rescue nil
136
+
137
+ return inside_app if inside_app && File.file?(inside_app)
138
+ return inside_home if inside_home && File.file?(inside_home)
139
+ end
140
+
150
141
  def remove_capfile
151
142
  rm_rf(capfile_path, :verbose => verbose?)
152
143
  end
@@ -171,18 +162,6 @@ module Pulsar
171
162
  end
172
163
  end
173
164
 
174
- def rm_rf(path, opts)
175
- puts "Remove: #{path.white}".yellow if opts[:verbose]
176
- FileUtils.rm_rf(path)
177
- end
178
-
179
- def run_cmd(cmd, opts)
180
- puts "Command: #{cmd.white}".yellow if opts[:verbose]
181
- system(cmd)
182
-
183
- raise "Command #{cmd} Failed" if $? != 0
184
- end
185
-
186
165
  def set_log_level
187
166
  level = log_level.upcase
188
167
  levels = %w(IMPORTANT INFO DEBUG)
@@ -194,13 +173,18 @@ module Pulsar
194
173
  run_cmd(cmd, :verbose => verbose?)
195
174
  end
196
175
 
197
- def time_to_deploy
198
- @now ||= Time.now.strftime("%Y-%m-%d-%H%M%S-s#{rand(9999)}")
176
+ def stages_for(app)
177
+ environments = %w(development staging production)
178
+
179
+ Dir["#{config_path}/apps/#{app}/*"].map do |env|
180
+ env_name = File.basename(env, '.rb')
181
+
182
+ env_name if environments.include?(env_name)
183
+ end.compact
199
184
  end
200
185
 
201
- def touch(file, opts)
202
- puts "Touch: #{file.white}".yellow if opts[:verbose]
203
- FileUtils.touch(file)
186
+ def time_to_deploy
187
+ @now ||= Time.now.strftime("%Y-%m-%d-%H%M%S-s#{rand(9999)}")
204
188
  end
205
189
  end
206
190
  end
@@ -0,0 +1,31 @@
1
+ require "fileutils"
2
+
3
+ module Pulsar
4
+ module Helpers
5
+ module Shell
6
+ include FileUtils
7
+
8
+ def cd(path, opts, &block)
9
+ puts "Directory: #{path.white}".yellow if opts[:verbose]
10
+ FileUtils.cd(path) { yield }
11
+ end
12
+
13
+ def rm_rf(path, opts)
14
+ puts "Remove: #{path.white}".yellow if opts[:verbose]
15
+ FileUtils.rm_rf(path)
16
+ end
17
+
18
+ def run_cmd(cmd, opts)
19
+ puts "Command: #{cmd.white}".yellow if opts[:verbose]
20
+ system(cmd)
21
+
22
+ raise "Command #{cmd} Failed" if $? != 0
23
+ end
24
+
25
+ def touch(file, opts)
26
+ puts "Touch: #{file.white}".yellow if opts[:verbose]
27
+ FileUtils.touch(file)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,3 +1,3 @@
1
1
  module Pulsar
2
- VERSION = "0.2.2"
2
+ VERSION = "0.2.3"
3
3
  end
@@ -19,6 +19,20 @@ describe Pulsar::ListCommand do
19
19
  Dir.glob("#{tmp_path}/conf-repo*").should be_empty
20
20
  end
21
21
 
22
+ it "lists configured apps and stages" do
23
+ app_one = Regexp.escape("dummy_app".cyan)
24
+ app_two = Regexp.escape("other_dummy_app".cyan)
25
+
26
+ stages = [ "production".magenta, "staging".magenta ]
27
+ escaped_stages = Regexp.escape(stages.join(', '))
28
+ reversed_stages = Regexp.escape(stages.reverse.join(', '))
29
+
30
+ pulsar.run(full_list_args)
31
+
32
+ stdout.should match(/#{app_one}: (#{escaped_stages})|(#{reversed_stages})/)
33
+ stdout.should match(/#{app_two}: (#{escaped_stages})|(#{reversed_stages})/)
34
+ end
35
+
22
36
  it "reads configuration variables from .pulsar file in home" do
23
37
  env_vars = [ "PULSAR_CONF_REPO=\"#{dummy_conf_path}\"\n"]
24
38
 
@@ -47,6 +61,34 @@ describe Pulsar::ListCommand do
47
61
  ENV['PULSAR_CONF_REPO'].should == dummy_conf_path
48
62
  end
49
63
 
64
+ it "skips lines which cannot parse when reading .pulsar file" do
65
+ env_vars = [ "wrong_line", "# comment"]
66
+
67
+ File.stub(:file?).and_return(true)
68
+ File.stub(:readlines).with("#{File.expand_path(dummy_rack_app_path)}/.pulsar").and_return(env_vars)
69
+
70
+ FileUtils.cd(dummy_rack_app_path) do
71
+ reload_main_command
72
+
73
+ expect { pulsar.run(full_list_args) }.not_to raise_error
74
+ end
75
+ end
76
+
77
+ it "falls back to .pulsar file in home directory if it's not in the rack app directory" do
78
+ env_vars = [ "PULSAR_APP_NAME=\"dummy_app\"\n", "PULSAR_CONF_REPO=\"#{dummy_conf_path}\"\n"]
79
+
80
+ File.stub(:file?).and_return(true)
81
+ File.stub(:file?).with("#{File.expand_path(dummy_rack_app_path)}/.pulsar").and_return(false)
82
+
83
+ File.should_receive(:readlines).with("#{Dir.home}/.pulsar").and_return(env_vars)
84
+
85
+ FileUtils.cd(dummy_rack_app_path) do
86
+ reload_main_command
87
+
88
+ pulsar.run(full_list_args)
89
+ end
90
+ end
91
+
50
92
  context "--conf-repo option" do
51
93
  it "is required" do
52
94
  expect { pulsar.parse([]) }.to raise_error(Clamp::UsageError)
@@ -86,6 +86,21 @@ describe Pulsar::MainCommand do
86
86
  end
87
87
  end
88
88
 
89
+ it "falls back to .pulsar file in home directory if it's not in the rack app directory" do
90
+ env_vars = [ "PULSAR_APP_NAME=\"dummy_app\"\n", "PULSAR_CONF_REPO=\"#{dummy_conf_path}\"\n"]
91
+
92
+ File.stub(:file?).and_return(true)
93
+ File.stub(:file?).with("#{File.expand_path(dummy_rack_app_path)}/.pulsar").and_return(false)
94
+
95
+ File.should_receive(:readlines).with("#{Dir.home}/.pulsar").and_return(env_vars)
96
+
97
+ FileUtils.cd(dummy_rack_app_path) do
98
+ reload_main_command
99
+
100
+ pulsar.run(full_cap_args + %w(production))
101
+ end
102
+ end
103
+
89
104
  context "Capfile" do
90
105
  it "uses base.rb in staging stage" do
91
106
  pulsar.run(full_cap_args + dummy_app(:staging))
@@ -26,6 +26,26 @@ describe Pulsar::Helpers::Capistrano do
26
26
 
27
27
  expect { load_recipes { generic :missing_recipe } }.to raise_error(RuntimeError, /no missing_recipe recipe/)
28
28
  end
29
+
30
+ it "does not call load if :app_only is true and pulsar is not called from inside application" do
31
+ ENV.delete('APP_PATH')
32
+ File.stub(:directory?).and_return(true)
33
+ File.stub(:exists?).and_return(true)
34
+
35
+ self.should_not_receive(:load)
36
+
37
+ load_recipes(:app_only => true) { generic :recipe }
38
+ end
39
+
40
+ it "calls load if :app_only is true and pulsar is called from inside application" do
41
+ ENV['APP_PATH'] = "/app/path"
42
+ File.stub(:directory?).and_return(true)
43
+ File.stub(:exists?).and_return(true)
44
+
45
+ self.should_receive(:load)
46
+
47
+ load_recipes(:app_only => true) { generic :recipe }
48
+ end
29
49
  end
30
50
 
31
51
  context "from_application_path?" do
@@ -50,12 +50,6 @@ describe Pulsar::Helpers::Clamp do
50
50
  end
51
51
  end
52
52
 
53
- context "run_cmd" do
54
- it "raises exception if command fails" do
55
- expect { run_cmd("return 1", {}) }.to raise_error
56
- end
57
- end
58
-
59
53
  context "reset_for_other_app!" do
60
54
  it "resets instance variables written by the module" do
61
55
  cap, conf, time = capfile_path, config_path, time_to_deploy
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe Pulsar::Helpers::Shell do
4
+ include Pulsar::Helpers::Shell
5
+
6
+ context "run_cmd" do
7
+ it "raises exception if command fails" do
8
+ expect { run_cmd("return 1", {}) }.to raise_error
9
+ end
10
+ end
11
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pulsar
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-05-02 00:00:00.000000000 Z
13
+ date: 2013-05-12 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: clamp
@@ -165,6 +165,7 @@ files:
165
165
  - lib/pulsar/helpers/all.rb
166
166
  - lib/pulsar/helpers/capistrano.rb
167
167
  - lib/pulsar/helpers/clamp.rb
168
+ - lib/pulsar/helpers/shell.rb
168
169
  - lib/pulsar/options/all.rb
169
170
  - lib/pulsar/options/conf_repo.rb
170
171
  - lib/pulsar/options/shared.rb
@@ -176,6 +177,7 @@ files:
176
177
  - spec/pulsar/commands/utils_spec.rb
177
178
  - spec/pulsar/helpers/capistrano_spec.rb
178
179
  - spec/pulsar/helpers/clamp_spec.rb
180
+ - spec/pulsar/helpers/shell_spec.rb
179
181
  - spec/spec_helper.rb
180
182
  - spec/support/dummies/dummy_app/config.ru
181
183
  - spec/support/dummies/dummy_conf/Gemfile
@@ -207,7 +209,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
207
209
  version: '0'
208
210
  segments:
209
211
  - 0
210
- hash: 2516214880330231667
212
+ hash: 882451203726848959
211
213
  required_rubygems_version: !ruby/object:Gem::Requirement
212
214
  none: false
213
215
  requirements:
@@ -216,7 +218,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
216
218
  version: '0'
217
219
  segments:
218
220
  - 0
219
- hash: 2516214880330231667
221
+ hash: 882451203726848959
220
222
  requirements: []
221
223
  rubyforge_project:
222
224
  rubygems_version: 1.8.25
@@ -232,6 +234,7 @@ test_files:
232
234
  - spec/pulsar/commands/utils_spec.rb
233
235
  - spec/pulsar/helpers/capistrano_spec.rb
234
236
  - spec/pulsar/helpers/clamp_spec.rb
237
+ - spec/pulsar/helpers/shell_spec.rb
235
238
  - spec/spec_helper.rb
236
239
  - spec/support/dummies/dummy_app/config.ru
237
240
  - spec/support/dummies/dummy_conf/Gemfile