pulsar 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -129,6 +129,28 @@ load_recipes do
129
129
  end
130
130
  ```
131
131
 
132
+ ---
133
+
134
+ You can specify some recipes to be loaded only when you run Pulsar from inside a Rack application directory.
135
+ This is useful with recipes that require something inside that directory (like retrieving the database/assets
136
+ from a staging environment).
137
+
138
+ You can do that like this:
139
+
140
+ ```ruby
141
+ #
142
+ # Somewhere inside apps/
143
+ #
144
+
145
+ #
146
+ # These recipes will be available only if you're running
147
+ # Pulsar inside a Rack application (like Rails) directory
148
+ #
149
+ load_recipes(app_only: true) do
150
+ rails :assets_pull, :database_pull
151
+ end
152
+ ```
153
+
132
154
  ### Loading the repository
133
155
 
134
156
  Once the repository is ready, you'll need to tell Pulsar where it is. The repository location can be specified either
@@ -5,7 +5,7 @@ module Pulsar
5
5
  include Pulsar::Options::ConfRepo
6
6
 
7
7
  option [ "-l", "--log-level" ], "LOG LEVEL",
8
- "how much output will Capistrano print out. Can be any of: important, info, debug",
8
+ "how much output will Capistrano print out. Can be any of: important, info, debug, trace",
9
9
  :default => "important"
10
10
 
11
11
  option [ "-s", "--skip-cap-run" ], :flag,
@@ -16,22 +16,19 @@ module Pulsar
16
16
  parameter "APPLICATION", "the application which you would like to deploy. Pass a comma separated list to deploy multiple applications at once"
17
17
  end
18
18
 
19
- parameter "ENVIRONMENT", "the environment on which you would like to deploy" do |env|
20
- %w(production staging development).include?(env) ? env : raise(ArgumentError)
21
- end
19
+ parameter "STAGE", "the stage on which you would like to deploy"
22
20
 
23
21
  parameter "[TASKS] ...", "the arguments and/or options that will be passed to capistrano", :default => "deploy"
24
22
 
25
23
  def execute
26
24
  find_apps.each do |app|
27
- target = "#{app}:#{environment}"
28
-
29
25
  Bundler.with_clean_env do
30
26
  begin
31
27
  fetch_repo
28
+ validate(app, stage)
32
29
  bundle_install
33
30
  create_capfile
34
- build_capfile(target)
31
+ build_capfile(app, stage)
35
32
 
36
33
  unless skip_cap_run?
37
34
  cap_args = [ tasks_list ].flatten.join(" ")
@@ -3,7 +3,7 @@ module Pulsar
3
3
  include Pulsar::Helpers::Clamp
4
4
  include Pulsar::Options::Shared
5
5
 
6
- subcommand "list", "list all available apps and environments which you can deploy", ListCommand
6
+ subcommand "list", "list all available apps and stages which you can deploy", ListCommand
7
7
  subcommand "init", "generate a new configuration repo with some basic recipes to use with pulsar", InitCommand
8
8
  end
9
9
  end
@@ -1,5 +1,6 @@
1
1
  module Pulsar::Helpers
2
2
  autoload :Capistrano, "pulsar/helpers/capistrano"
3
3
  autoload :Clamp, "pulsar/helpers/clamp"
4
+ autoload :Path, "pulsar/helpers/path"
4
5
  autoload :Shell, "pulsar/helpers/shell"
5
6
  end
@@ -2,6 +2,7 @@ module Pulsar
2
2
  module Helpers
3
3
  module Clamp
4
4
  include Pulsar::Helpers::Shell
5
+ include Pulsar::Helpers::Path
5
6
 
6
7
  def self.included(base)
7
8
  base.extend(InstanceAndClassMethods)
@@ -21,9 +22,7 @@ module Pulsar
21
22
  Dir.pwd if from_application_path?
22
23
  end
23
24
 
24
- def build_capfile(args)
25
- app, stage = args.split(":")
26
-
25
+ def build_capfile(app, stage)
27
26
  # Variables
28
27
  set_log_level
29
28
  include_base_conf
@@ -39,20 +38,12 @@ module Pulsar
39
38
  end
40
39
  end
41
40
 
42
- def capfile_path
43
- @capfile_name ||= "#{tmp_dir}/capfile-#{time_to_deploy}"
44
- end
45
-
46
- def config_path
47
- @configuration_path ||= "#{tmp_dir}/conf-repo-#{time_to_deploy}"
48
- end
49
-
50
41
  def create_capfile
51
42
  touch(capfile_path, :verbose => verbose?)
52
43
  end
53
44
 
54
45
  def each_app
55
- Dir["#{config_path}/apps/*"].each do |path|
46
+ Dir["#{config_apps_path}/*"].each do |path|
56
47
  yield(File.basename(path)) if File.directory?(path)
57
48
  end
58
49
  end
@@ -71,46 +62,47 @@ module Pulsar
71
62
 
72
63
  def fetch_directory_repo(repo)
73
64
  if File.directory?("#{repo}/.git")
74
- fetch_git_repo(repo)
65
+ fetch_git_repo(repo, true)
75
66
  else
76
67
  run_cmd("cp -rp #{repo} #{config_path}", :verbose => verbose?)
77
68
  end
78
69
  end
79
70
 
80
- def fetch_git_repo(repo)
81
- git_options = "--quiet --depth=1 --branch #{conf_branch}"
71
+ def fetch_git_repo(repo, local=false)
72
+ git_options = "--quiet --branch #{conf_branch}"
73
+ git_options = "#{git_options} --depth=1" unless local
74
+
82
75
  run_cmd("git clone #{git_options} #{repo} #{config_path}", :verbose => verbose?)
83
76
  end
84
77
 
85
- def include_app(app, stage=nil)
86
- app_file = "#{config_path}/apps/#{app}/defaults.rb"
87
- stage_file = "#{config_path}/apps/#{app}/#{stage}.rb"
78
+ def include_app(app, stage)
79
+ app_file = config_app_defaults_path(app)
80
+ stage_file = config_stage_path(app, stage)
88
81
 
89
82
  if File.exists?(app_file)
90
83
  run_cmd("cat #{app_file} >> #{capfile_path}", :verbose => verbose?)
91
84
  end
92
85
 
93
- if stage
86
+ if File.exists?(stage_file)
94
87
  run_cmd("cat #{stage_file} >> #{capfile_path}", :verbose => verbose?)
95
88
  end
96
89
  end
97
90
 
98
- def include_app_recipes(app, stage=nil)
99
- recipes_dir = "#{config_path}/apps/#{app}/recipes"
91
+ def include_app_recipes(app, stage)
92
+ recipes_dir = config_app_recipes_path(app)
93
+ stage_recipes_dir = config_app_stage_recipes_path(app, stage)
100
94
 
101
95
  Dir.glob("#{recipes_dir}/*.rb").each do |recipe|
102
96
  run_cmd("cat #{recipe} >> #{capfile_path}", :verbose => verbose?)
103
97
  end
104
98
 
105
- if stage
106
- Dir.glob("#{recipes_dir}/#{stage}/*.rb").each do |recipe|
107
- run_cmd("cat #{recipe} >> #{capfile_path}", :verbose => verbose?)
108
- end
99
+ Dir.glob("#{stage_recipes_dir}/*.rb").each do |recipe|
100
+ run_cmd("cat #{recipe} >> #{capfile_path}", :verbose => verbose?)
109
101
  end
110
102
  end
111
103
 
112
104
  def include_base_conf
113
- run_cmd("cat #{config_path}/apps/base.rb >> #{capfile_path}", :verbose => verbose?)
105
+ run_cmd("cat #{config_base_path} >> #{capfile_path}", :verbose => verbose?)
114
106
  end
115
107
 
116
108
  def list_apps
@@ -164,7 +156,7 @@ module Pulsar
164
156
 
165
157
  def set_log_level
166
158
  level = log_level.upcase
167
- levels = %w(IMPORTANT INFO DEBUG)
159
+ levels = %w(IMPORTANT INFO DEBUG TRACE)
168
160
 
169
161
  level = levels.first unless levels.include?(level)
170
162
 
@@ -174,17 +166,20 @@ module Pulsar
174
166
  end
175
167
 
176
168
  def stages_for(app)
177
- environments = %w(development staging production)
169
+ exclude = %w(defaults recipes)
178
170
 
179
- Dir["#{config_path}/apps/#{app}/*"].map do |env|
171
+ Dir["#{config_app_path(app)}/*"].sort.map do |env|
180
172
  env_name = File.basename(env, '.rb')
181
173
 
182
- env_name if environments.include?(env_name)
174
+ env_name unless exclude.include?(env_name)
183
175
  end.compact
184
176
  end
185
177
 
186
- def time_to_deploy
187
- @now ||= Time.now.strftime("%Y-%m-%d-%H%M%S-s#{rand(9999)}")
178
+ def validate(app, stage)
179
+ app_path = config_app_path(app)
180
+ stage_path = config_stage_path(app, stage)
181
+
182
+ raise(ArgumentError) unless File.exists?(app_path) && File.exists?(stage_path)
188
183
  end
189
184
  end
190
185
  end
@@ -0,0 +1,46 @@
1
+ module Pulsar
2
+ module Helpers
3
+ module Path
4
+ def capfile_path
5
+ @capfile_name ||= "#{tmp_dir}/capfile-#{time_to_deploy}"
6
+ end
7
+
8
+ def config_path
9
+ @configuration_path ||= "#{tmp_dir}/conf-repo-#{time_to_deploy}"
10
+ end
11
+
12
+ def config_app_path(app)
13
+ "#{config_apps_path}/#{app}"
14
+ end
15
+
16
+ def config_app_defaults_path(app)
17
+ "#{config_app_path(app)}/defaults.rb"
18
+ end
19
+
20
+ def config_app_recipes_path(app)
21
+ "#{config_app_path(app)}/recipes"
22
+ end
23
+
24
+ def config_app_stage_recipes_path(app, stage)
25
+ "#{config_app_recipes_path(app)}/#{stage}"
26
+ end
27
+
28
+ def config_apps_path
29
+ "#{config_path}/apps"
30
+ end
31
+
32
+ def config_base_path
33
+ "#{config_apps_path}/base.rb"
34
+ end
35
+
36
+ def config_stage_path(app, stage)
37
+ "#{config_app_path(app)}/#{stage}.rb"
38
+ end
39
+
40
+ private
41
+ def time_to_deploy
42
+ @now ||= Time.now.strftime("%Y-%m-%d-%H%M%S-s#{rand(9999)}")
43
+ end
44
+ end
45
+ end
46
+ end
@@ -1,3 +1,3 @@
1
1
  module Pulsar
2
- VERSION = "0.2.3"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -25,8 +25,8 @@ Gem::Specification.new do |gem|
25
25
  gem.add_dependency "bundler", "~> 1.2"
26
26
  gem.add_dependency "colored", "~> 1.2"
27
27
 
28
- gem.add_development_dependency "rake"
29
- gem.add_development_dependency "rspec", "~> 2.12"
30
- gem.add_development_dependency "rr", "~> 1.0"
31
- gem.add_development_dependency "coveralls", "~> 0.6.3"
28
+ gem.add_development_dependency "rake", "10.0.4"
29
+ gem.add_development_dependency "rspec", "2.12.0"
30
+ gem.add_development_dependency "rr", "1.0.4"
31
+ gem.add_development_dependency "coveralls", "0.6.3"
32
32
  end
@@ -23,14 +23,13 @@ describe Pulsar::ListCommand do
23
23
  app_one = Regexp.escape("dummy_app".cyan)
24
24
  app_two = Regexp.escape("other_dummy_app".cyan)
25
25
 
26
- stages = [ "production".magenta, "staging".magenta ]
26
+ stages = [ "custom_stage".magenta, "production".magenta, "staging".magenta ]
27
27
  escaped_stages = Regexp.escape(stages.join(', '))
28
- reversed_stages = Regexp.escape(stages.reverse.join(', '))
29
28
 
30
29
  pulsar.run(full_list_args)
31
30
 
32
- stdout.should match(/#{app_one}: (#{escaped_stages})|(#{reversed_stages})/)
33
- stdout.should match(/#{app_two}: (#{escaped_stages})|(#{reversed_stages})/)
31
+ stdout.should match(/#{app_one}: #{escaped_stages}/)
32
+ stdout.should match(/#{app_two}: #{escaped_stages}/)
34
33
  end
35
34
 
36
35
  it "reads configuration variables from .pulsar file in home" do
@@ -101,6 +101,14 @@ describe Pulsar::MainCommand do
101
101
  end
102
102
  end
103
103
 
104
+ it "errors out if application does not exist in configuration repository" do
105
+ expect { pulsar.run(full_cap_args + %w(non_existant_app production)) }.to raise_error(ArgumentError)
106
+ end
107
+
108
+ it "errors out if stage does not exist in configuration repository" do
109
+ expect { pulsar.run(full_cap_args + dummy_app(:non_existant_stage)) }.to raise_error(ArgumentError)
110
+ end
111
+
104
112
  context "Capfile" do
105
113
  it "uses base.rb in staging stage" do
106
114
  pulsar.run(full_cap_args + dummy_app(:staging))
@@ -259,5 +267,11 @@ describe Pulsar::MainCommand do
259
267
 
260
268
  latest_capfile.should include("logger.level = logger.level = Capistrano::Logger::DEBUG")
261
269
  end
270
+
271
+ it "supports Capistrano TRACE" do
272
+ pulsar.run(full_cap_args + %w(--log-level trace) + dummy_app)
273
+
274
+ latest_capfile.should include("logger.level = logger.level = Capistrano::Logger::TRACE")
275
+ end
262
276
  end
263
277
  end
@@ -0,0 +1,5 @@
1
+ # This is apps/dummy_app/custom_stage.rb
2
+
3
+ server "dummy.it", :db, :web, :app, :primary => true
4
+
5
+ set :stage, "custom_stage"
@@ -0,0 +1,5 @@
1
+ # This is apps/other_dummy_app/custom_stage.rb
2
+
3
+ server "dummy.it", :db, :web, :app, :primary => true
4
+
5
+ set :stage, "custom_stage"
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.3
4
+ version: 0.3.0
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-12 00:00:00.000000000 Z
13
+ date: 2013-07-23 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: clamp
@@ -65,55 +65,55 @@ dependencies:
65
65
  requirement: !ruby/object:Gem::Requirement
66
66
  none: false
67
67
  requirements:
68
- - - ! '>='
68
+ - - '='
69
69
  - !ruby/object:Gem::Version
70
- version: '0'
70
+ version: 10.0.4
71
71
  type: :development
72
72
  prerelease: false
73
73
  version_requirements: !ruby/object:Gem::Requirement
74
74
  none: false
75
75
  requirements:
76
- - - ! '>='
76
+ - - '='
77
77
  - !ruby/object:Gem::Version
78
- version: '0'
78
+ version: 10.0.4
79
79
  - !ruby/object:Gem::Dependency
80
80
  name: rspec
81
81
  requirement: !ruby/object:Gem::Requirement
82
82
  none: false
83
83
  requirements:
84
- - - ~>
84
+ - - '='
85
85
  - !ruby/object:Gem::Version
86
- version: '2.12'
86
+ version: 2.12.0
87
87
  type: :development
88
88
  prerelease: false
89
89
  version_requirements: !ruby/object:Gem::Requirement
90
90
  none: false
91
91
  requirements:
92
- - - ~>
92
+ - - '='
93
93
  - !ruby/object:Gem::Version
94
- version: '2.12'
94
+ version: 2.12.0
95
95
  - !ruby/object:Gem::Dependency
96
96
  name: rr
97
97
  requirement: !ruby/object:Gem::Requirement
98
98
  none: false
99
99
  requirements:
100
- - - ~>
100
+ - - '='
101
101
  - !ruby/object:Gem::Version
102
- version: '1.0'
102
+ version: 1.0.4
103
103
  type: :development
104
104
  prerelease: false
105
105
  version_requirements: !ruby/object:Gem::Requirement
106
106
  none: false
107
107
  requirements:
108
- - - ~>
108
+ - - '='
109
109
  - !ruby/object:Gem::Version
110
- version: '1.0'
110
+ version: 1.0.4
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: coveralls
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  none: false
115
115
  requirements:
116
- - - ~>
116
+ - - '='
117
117
  - !ruby/object:Gem::Version
118
118
  version: 0.6.3
119
119
  type: :development
@@ -121,7 +121,7 @@ dependencies:
121
121
  version_requirements: !ruby/object:Gem::Requirement
122
122
  none: false
123
123
  requirements:
124
- - - ~>
124
+ - - '='
125
125
  - !ruby/object:Gem::Version
126
126
  version: 0.6.3
127
127
  description: Manage your Capistrano deployments with ease
@@ -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/path.rb
168
169
  - lib/pulsar/helpers/shell.rb
169
170
  - lib/pulsar/options/all.rb
170
171
  - lib/pulsar/options/conf_repo.rb
@@ -182,12 +183,14 @@ files:
182
183
  - spec/support/dummies/dummy_app/config.ru
183
184
  - spec/support/dummies/dummy_conf/Gemfile
184
185
  - spec/support/dummies/dummy_conf/apps/base.rb
186
+ - spec/support/dummies/dummy_conf/apps/dummy_app/custom_stage.rb
185
187
  - spec/support/dummies/dummy_conf/apps/dummy_app/defaults.rb
186
188
  - spec/support/dummies/dummy_conf/apps/dummy_app/production.rb
187
189
  - spec/support/dummies/dummy_conf/apps/dummy_app/recipes/custom_recipe.rb
188
190
  - spec/support/dummies/dummy_conf/apps/dummy_app/recipes/production/custom_recipe.rb
189
191
  - spec/support/dummies/dummy_conf/apps/dummy_app/recipes/staging/custom_recipe.rb
190
192
  - spec/support/dummies/dummy_conf/apps/dummy_app/staging.rb
193
+ - spec/support/dummies/dummy_conf/apps/other_dummy_app/custom_stage.rb
191
194
  - spec/support/dummies/dummy_conf/apps/other_dummy_app/defaults.rb
192
195
  - spec/support/dummies/dummy_conf/apps/other_dummy_app/production.rb
193
196
  - spec/support/dummies/dummy_conf/apps/other_dummy_app/staging.rb
@@ -209,7 +212,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
209
212
  version: '0'
210
213
  segments:
211
214
  - 0
212
- hash: 882451203726848959
215
+ hash: 2226446731285894531
213
216
  required_rubygems_version: !ruby/object:Gem::Requirement
214
217
  none: false
215
218
  requirements:
@@ -218,7 +221,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
218
221
  version: '0'
219
222
  segments:
220
223
  - 0
221
- hash: 882451203726848959
224
+ hash: 2226446731285894531
222
225
  requirements: []
223
226
  rubyforge_project:
224
227
  rubygems_version: 1.8.25
@@ -239,12 +242,14 @@ test_files:
239
242
  - spec/support/dummies/dummy_app/config.ru
240
243
  - spec/support/dummies/dummy_conf/Gemfile
241
244
  - spec/support/dummies/dummy_conf/apps/base.rb
245
+ - spec/support/dummies/dummy_conf/apps/dummy_app/custom_stage.rb
242
246
  - spec/support/dummies/dummy_conf/apps/dummy_app/defaults.rb
243
247
  - spec/support/dummies/dummy_conf/apps/dummy_app/production.rb
244
248
  - spec/support/dummies/dummy_conf/apps/dummy_app/recipes/custom_recipe.rb
245
249
  - spec/support/dummies/dummy_conf/apps/dummy_app/recipes/production/custom_recipe.rb
246
250
  - spec/support/dummies/dummy_conf/apps/dummy_app/recipes/staging/custom_recipe.rb
247
251
  - spec/support/dummies/dummy_conf/apps/dummy_app/staging.rb
252
+ - spec/support/dummies/dummy_conf/apps/other_dummy_app/custom_stage.rb
248
253
  - spec/support/dummies/dummy_conf/apps/other_dummy_app/defaults.rb
249
254
  - spec/support/dummies/dummy_conf/apps/other_dummy_app/production.rb
250
255
  - spec/support/dummies/dummy_conf/apps/other_dummy_app/staging.rb