capistrano-multimarket 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .DS_Store
data/Gemfile ADDED
@@ -0,0 +1 @@
1
+ source "http://rubygems.org"
data/README.md ADDED
@@ -0,0 +1,102 @@
1
+ # capistrano-multimarket
2
+
3
+
4
+ #### NOTE
5
+ Forked from [capistrano-multiconfig](https://github.com/railsware/capistrano-multiconfig). But this extension loads both .yml and .rb files.
6
+ Use the main project if you want to load only rb files ;-)
7
+
8
+
9
+ ## Description
10
+
11
+ Capistrano extension that allows to use multiple configurations(Ruby and YAML files).
12
+
13
+ MultiMarket extension is similar to [multistage](https://github.com/capistrano/capistrano-ext) extenstion.
14
+ But it's not only about 'stage' configurations. It's about any configuration that you may need.
15
+ Extension recursively builds configuration list from configuration root directory.
16
+ Each configuration loads recursively configuration from it namespace files and own configuration file.
17
+
18
+ ## Usage
19
+
20
+ Install gem
21
+
22
+ $ gem install capistrano-multimarket
23
+
24
+
25
+ Add to `Capfile`
26
+
27
+ set :config, 'path/to/your/markets'
28
+ require 'capistrano/multimarket'
29
+
30
+ ## Example
31
+
32
+ Assume we have the following configurations:
33
+ ```bash
34
+ $ tree config/
35
+ config/
36
+ └── deploy
37
+ └── markets
38
+ ├── production
39
+ │   ├── blog
40
+ │   │   ├── site1.rb
41
+ │   │   └── site2.yml
42
+ │   └── blog.rb
43
+ ├── production.rb
44
+ └── staging
45
+ └── blog
46
+ ├── site1.rb
47
+ └── site1.yml
48
+ ```
49
+
50
+ Check tasks:
51
+ ```bash
52
+ $ cap -f check.rb -T
53
+ cap invoke # Invoke a single command on the remote servers.
54
+ cap production:blog:site1 # Load production:blog:site1 configuration
55
+ cap production:blog:site2 # Load production:blog:site2 configuration
56
+ cap shell # Begin an interactive Capistrano session.
57
+ cap staging:blog:site1 # Load staging:blog:site1 configuration
58
+ ```
59
+
60
+ Let's try to run task without specified configuration:
61
+ ```bash
62
+ $ cap -f check.rb shell
63
+ triggering start callbacks for `shell'
64
+ * executing `multimarket:ensure'
65
+ No configuration specified. Please specify one of:
66
+ * production:blog:site1
67
+ * staging:blog:site1
68
+ * production:blog:site2
69
+ (e.g. `cap production:blog:site1 shell')
70
+ ```
71
+
72
+ So we must provide configuration as first task:
73
+ ```bash
74
+ $ cap -f check.rb staging:blog:site1 shell
75
+ * executing `staging:blog:site1'
76
+ triggering start callbacks for `shell'
77
+ * executing `multimarket:ensure'
78
+ * executing `shell'
79
+ ```
80
+
81
+
82
+ ### Example of YAML config:
83
+ $ cat examples/config/deploy/markets/staging/blog/site1.yml
84
+
85
+ ```yaml
86
+ variables:
87
+ application: 'market1'
88
+ app_servers:
89
+ - web1.example.com
90
+ - web2.example.com
91
+ roles:
92
+ app:
93
+ - "app1.example.com"
94
+ - "app2.example.com"
95
+ db:
96
+ - "app1.example.com"
97
+ - {primary: true}
98
+ string: |
99
+ set :branch, :master
100
+ role(:web) { fetch(:app_servers) }
101
+ ```
102
+
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ require "capistrano/multi_market/version"
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "capistrano-multimarket"
8
+ s.version = Capistrano::MultiMarket::VERSION
9
+ s.authors = ["Marcos G. Zimmermann"]
10
+ s.email = ["mgzmaster@gmail.com"]
11
+ s.homepage = "https://github.com/marcosgz/capistrano-multimarket"
12
+ s.summary = %q{Capistrano multimarket}
13
+
14
+ s.rubyforge_project = "capistrano-multimarket"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_runtime_dependency "capistrano", "~> 2.14.1"
22
+ s.add_development_dependency "pry", "~> 0.9.11.4"
23
+ end
data/examples/check.rb ADDED
@@ -0,0 +1,10 @@
1
+ # run with cap -f ckeck.rb
2
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
3
+ require 'capistrano'
4
+ set :market_root, 'config/deploy/markets'
5
+ require 'capistrano/multimarket'
6
+
7
+ task :check, :roles => :app do
8
+ pp self[:app_servers]
9
+ pp self[:test_config]
10
+ end
@@ -0,0 +1 @@
1
+ set :test_config, 'markets/production/blog/site1.rb'
@@ -0,0 +1,2 @@
1
+ variables:
2
+ test_config: 'markets/production/blog/site2.yml'
@@ -0,0 +1 @@
1
+ set :test_config, 'markets/production/blog'
File without changes
@@ -0,0 +1 @@
1
+ set :test_config, 'markets/staging/blog/site1.rb'
@@ -0,0 +1,15 @@
1
+ variables:
2
+ application: 'market1'
3
+ app_servers:
4
+ - web1.example.com
5
+ - web2.example.com
6
+ roles:
7
+ app:
8
+ - "app1.example.com"
9
+ - "app2.example.com"
10
+ db:
11
+ - "app1.example.com"
12
+ - {primary: true}
13
+ string: |
14
+ set :branch, :master
15
+ role(:web) { fetch(:app_servers) }
@@ -0,0 +1,124 @@
1
+ Capistrano::Configuration.instance(true).load do
2
+ # configurations root directory
3
+ markets_root = File.expand_path(fetch(:markets_root, "config/deploy/markets"))
4
+
5
+ # list of configurations files
6
+ config_files = Dir["#{markets_root}/**/*.{rb,yml}"]
7
+
8
+ # remove configuration file if it's part of another configuration
9
+ config_files.reject! do |config_file|
10
+ config_dir = config_file.gsub(/\.(rb|yml)$/, '/')
11
+ config_files.any? { |file| file[0, config_dir.size] == config_dir }
12
+ end
13
+
14
+ # build configuration names list
15
+ config_names = config_files.map do |config_file|
16
+ config_file.sub("#{markets_root}/", '').sub(/\.(rb|yml)$/, '').gsub('/', ':')
17
+ end.uniq
18
+
19
+ # ensure that configuration segments don't override any method, task or namespace
20
+ config_names.each do |config_name|
21
+ config_name.split(':').each do |segment|
22
+ if all_methods.any? { |m| m == segment }
23
+ raise ArgumentError,
24
+ "Config task #{config_name} name overrides #{segment.inspect} (method|task|namespace)"
25
+ end
26
+ end
27
+ end
28
+
29
+ # create configuration task for each configuration name
30
+ config_names.each do |config_name|
31
+ segments = config_name.split(':')
32
+ namespace_names = segments[0, segments.size - 1]
33
+ task_name = segments.last
34
+
35
+ # create configuration task block.
36
+ # NOTE: Capistrano 'namespace' DSL invokes instance_eval that
37
+ # that pass evaluable object as argument to block.
38
+ block = lambda do |parent|
39
+ desc "Load #{config_name} configuration"
40
+ task(task_name) do
41
+ # set configuration name as :config_name variable
42
+ top.set(:config_name, config_name)
43
+
44
+ # recursively load configurations
45
+ segments.size.times do |i|
46
+ path = ([markets_root] + segments[0..i]).join('/')
47
+ yml_path = path + '.yml'
48
+ if File.exists?(yml_path)
49
+ # variables:
50
+ # application: "foo"
51
+ # app_servers:
52
+ # - test.com
53
+ # - test1.com
54
+ configs = YAML.load_file(yml_path)
55
+ (configs['variables'] || {}).each do |k, v|
56
+ top.set(k.to_sym, v)
57
+ end
58
+ # roles:
59
+ # web: "app1.example.com"
60
+ # roles:
61
+ # web:
62
+ # - "app1.example.com"
63
+ # - "app2.example.com"
64
+ # roles:
65
+ # db:
66
+ # - "app1.example.com"
67
+ # - {primary: true}
68
+ (configs['roles'] || {}).each do |k, v|
69
+ top.role(k.to_sym) { v }
70
+ end
71
+ # string: |
72
+ # set :scm, :subversion
73
+ # set :branch, :master
74
+ if (v=configs['string'])
75
+ top.load(:string => v)
76
+ end
77
+ end
78
+ rb_path = path + '.rb'
79
+ if File.exists?(rb_path)
80
+ top.load(:file => rb_path)
81
+ end
82
+ end
83
+ end
84
+ end
85
+
86
+ # wrap task block into namespace blocks
87
+ #
88
+ # namespace_names = [nsN, ..., ns2, ns1]
89
+ #
90
+ # block = block0 = lambda do |parent|
91
+ # desc "DESC"
92
+ # task(:task_name) { TASK }
93
+ # end
94
+ # block = block1 = lambda { |parent| parent.namespace(:ns1, &block0) }
95
+ # block = block2 = lambda { |parent| parent.namespace(:ns2, &block1) }
96
+ # ...
97
+ # block = blockN = lambda { |parent| parent.namespace(:nsN, &blockN-1) }
98
+ #
99
+ block = namespace_names.reverse.inject(block) do |child, name|
100
+ lambda do |parent|
101
+ parent.namespace(name, &child)
102
+ end
103
+ end
104
+
105
+ # create namespaced configuration task
106
+ #
107
+ # block = lambda do
108
+ # namespace :nsN do
109
+ # ...
110
+ # namespace :ns2 do
111
+ # namespace :ns1 do
112
+ # desc "DESC"
113
+ # task(:task_name) { TASK }
114
+ # end
115
+ # end
116
+ # ...
117
+ # end
118
+ # end
119
+ block.call(top)
120
+ end
121
+
122
+ # set configuration names list
123
+ set(:config_names, config_names)
124
+ end
@@ -0,0 +1,15 @@
1
+ Capistrano::Configuration.instance(true).load do
2
+ namespace :multimarket do
3
+ desc "[internal] Ensure that a configuration has been selected"
4
+ task :ensure do
5
+ unless exists?(:config_name)
6
+ puts "No configuration specified. Please specify one of:"
7
+ config_names.each { |name| puts " * #{name}" }
8
+ puts "(e.g. `cap #{config_names.first} #{ARGV.last}')"
9
+ abort
10
+ end
11
+ end
12
+ end
13
+
14
+ on :start, 'multimarket:ensure', :except => config_names
15
+ end
@@ -0,0 +1,5 @@
1
+ module Capistrano
2
+ module MultiMarket
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ require 'yaml'
2
+ require 'capistrano/multi_market/configurations'
3
+ require 'capistrano/multi_market/ensure'
metadata ADDED
@@ -0,0 +1,93 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: capistrano-multimarket
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Marcos G. Zimmermann
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-23 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: capistrano
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 2.14.1
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 2.14.1
30
+ - !ruby/object:Gem::Dependency
31
+ name: pry
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 0.9.11.4
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.9.11.4
46
+ description:
47
+ email:
48
+ - mgzmaster@gmail.com
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - .gitignore
54
+ - Gemfile
55
+ - README.md
56
+ - Rakefile
57
+ - capistrano-multimarket.gemspec
58
+ - examples/check.rb
59
+ - examples/config/deploy/markets/production.rb
60
+ - examples/config/deploy/markets/production/blog.rb
61
+ - examples/config/deploy/markets/production/blog/site1.rb
62
+ - examples/config/deploy/markets/production/blog/site2.yml
63
+ - examples/config/deploy/markets/staging/blog/site1.rb
64
+ - examples/config/deploy/markets/staging/blog/site1.yml
65
+ - lib/capistrano/multi_market/configurations.rb
66
+ - lib/capistrano/multi_market/ensure.rb
67
+ - lib/capistrano/multi_market/version.rb
68
+ - lib/capistrano/multimarket.rb
69
+ homepage: https://github.com/marcosgz/capistrano-multimarket
70
+ licenses: []
71
+ post_install_message:
72
+ rdoc_options: []
73
+ require_paths:
74
+ - lib
75
+ required_ruby_version: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ! '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ required_rubygems_version: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ! '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ requirements: []
88
+ rubyforge_project: capistrano-multimarket
89
+ rubygems_version: 1.8.23
90
+ signing_key:
91
+ specification_version: 3
92
+ summary: Capistrano multimarket
93
+ test_files: []