capistrano-config 0.0.5 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -21,25 +21,91 @@ Or install it yourself as:
21
21
  This recipes will try to update application config during Capistrano `deploy` tasks.
22
22
 
23
23
  To enable this recipe, add following in your `config/deploy.rb`.
24
- The template of `config/config.yml` will be read from either `./config/templates/config/config.yml` or `./config/templates/config/config.yml.erb` by default.
25
24
 
26
- # in "config/deploy.rb"
27
- require 'capistrano-config'
28
- set(:config_files, %w(config/config.yml))
25
+ The configuration file `config/config.yml` will be generated from template in `config/templates` by default.
26
+ (The template will be used is either `config/templates/config/config.yml.erb` or `config/templates/config/config.yml`.)
29
27
 
30
- Following options are available to manage your configuration files.
28
+ # config/deploy.rb
29
+ require "capistrano-config"
30
+ set :config_files, ["config/config.yml"]
31
31
 
32
+ ## Examples
33
+
34
+ ### Setting up shared configuration
35
+
36
+ You might not want to generate configuration files on everytime of deployment.
37
+ There is _shared_ mode to generate configuration files just once during `deploy:setup`.
38
+
39
+ This is the configuration example for shared configuration mode.
40
+
41
+ # config/deploy.rb
42
+ set :config_use_shared, true
43
+ set :config_files, ["config/config.yml"]
44
+
45
+ The generated configuration files will be installed in `#{shared_path}/config/config.yml` during `deploy:setup`.
46
+ After the setup of shared configuration, symlink will be created at `#{release_path}/config/config.yml` during `deploy`.
47
+
48
+ If you want to update the shared configuration files, invoke `config:setup` will do that.
49
+
50
+ % cap config:setup
51
+
52
+ ### Setting up local configuration
53
+
54
+ With some build system, you might need to update some of local files during deployment.
55
+ There is _local_ mode to help you.
56
+
57
+ This is the configuration example for local configuration mode.
58
+
59
+ # config/deploy.rb
60
+ set :config_update_locally, true
61
+ set :config_files, ["config/config.yml"]
62
+
63
+ The local configuration files will be updated during `deploy`.
64
+
65
+ ### Setting up files with special parameters
66
+
67
+ You can set file parameters for each files with defining `:config_files` as a Hash.
68
+ The value of Hash will be passed to `safe_put` of [capistrano-file-transfer-ext](https://github.com/yyuu/capistran-file-transfer-ext).
69
+
70
+ # config/deploy.rb
71
+ set :config_files do
72
+ {
73
+ "config/secret.yml" => { :owner => "user", :group => "user", :mode => "640" }
74
+ }
75
+ end
76
+
77
+ If you want to apply for all configuration files, you can use `:config_files_options`.
78
+
79
+ # config/deploy.rb
80
+ set :config_files, ["config/secret.yml", "config/credentials.yml"]
81
+ set :config_files_options, :owner => "user", :group => "user", :mode => "640"
82
+
83
+ ### Setting up files with absolute paths
84
+
85
+ If the configuration file name starts with "/", it will be treated as absolute path.
86
+
87
+ # config/deploy.rb
88
+ set :config_files do
89
+ {
90
+ "/etc/init/foo.cnf" => { :configure_except => :local, :owner => "root", :group => "root", :mode => "644", :run_method => :sudo },
91
+ }
92
+ end
93
+
94
+
95
+ ## Reference
96
+
97
+ These options are available to manage your configuration files.
98
+
99
+ * `:config_files` - the definition of configuration files as in an array or a hash.
100
+ if given as hash, the key should be the value should be the file options.
32
101
  * `:config_update_remotely` - specify whether update config files on remote machines or not. `true` by default.
33
102
  * `:config_update_locally` - specify whether update config files on local machines or not. `false` by default.
34
- * `:config_use_sudo_locally` - specify whether use `sudo` or not on local execution. `false` by default.
35
- * `:config_use_sudo_remotely` - specify whether use `sudo` or not on remote execution. `true` by default.
103
+ * `:config_use_shared` - set `true` if you want to use _shared_ config. `false` by default.
36
104
  * `:config_path` - specify configuration base directory on remote machines. use `release_path` by default.
37
105
  * `:config_path_local` - specify configuration base directory on local machine. use `.` by default.
38
- * `:config_template_path` - specify configuration template directory on local machine. use `./config/templates` by default.
39
- * `:config_files` - specify list of configuration files in relative path. empty by default.
40
- * `:config_readable_files` - list of files which should be readable. empty by default.
41
- * `:config_writable_files` - list of files which should be writable. empty by default.
42
- * `:config_executable_files` - list of files which should be executable. empty by default.
106
+ * `:config_template_path` - specify configuration template directory on local machine. use `config/templates` by default.
107
+ * `:config_files_options` - the hash to be used as parameters for configuration files.
108
+
43
109
 
44
110
  ## Contributing
45
111
 
@@ -18,6 +18,9 @@ Gem::Specification.new do |gem|
18
18
  gem.require_paths = ["lib"]
19
19
 
20
20
  gem.add_dependency("capistrano")
21
- gem.add_dependency("capistrano-file-resources")
22
- gem.add_dependency("capistrano-file-transfer-ext", "~> 0.0.3")
21
+ gem.add_dependency("capistrano-file-resources", "~> 0.0.1")
22
+ gem.add_dependency("capistrano-file-transfer-ext", "~> 0.1.0")
23
+ gem.add_development_dependency("net-scp", "~> 1.0.4")
24
+ gem.add_development_dependency("net-ssh", "~> 2.2.2")
25
+ gem.add_development_dependency("vagrant", "~> 1.0.6")
23
26
  end
@@ -9,36 +9,60 @@ module Capistrano
9
9
  configuration.load {
10
10
  namespace(:config) {
11
11
  _cset(:config_path) { release_path }
12
- _cset(:config_path_local) { File.expand_path('.') }
13
- _cset(:config_template_path) { File.join(File.expand_path('.'), 'config', 'templates') }
12
+ _cset(:config_path_local) { File.expand_path(".") }
13
+ _cset(:config_template_path) { File.expand_path("config/templates") }
14
14
  _cset(:config_files, [])
15
15
 
16
16
  _cset(:config_use_shared, false)
17
- _cset(:config_shared_path) { File.join(shared_path, 'config') }
17
+ _cset(:config_shared_path) { File.join(shared_path, "config") }
18
18
 
19
- _cset(:config_readable_mode, "a+r")
19
+ _cset(:config_readable_mode, "444")
20
20
  _cset(:config_readable_files, [])
21
- _cset(:config_writable_mode, "a+rw")
21
+ _cset(:config_writable_mode, "644")
22
22
  _cset(:config_writable_files, [])
23
- _cset(:config_executable_mode, "a+rx")
23
+ _cset(:config_executable_mode, "755")
24
24
  _cset(:config_executable_files, [])
25
25
  _cset(:config_remove_files, [])
26
+ _cset(:config_files_options, {:install => :if_modified})
27
+
28
+ def _normalize_config_files(fs, options={})
29
+ options = config_files_options.merge(options)
30
+ case fs
31
+ when Array
32
+ fs = Hash[fs.map { |f|
33
+ if config_executable_files.include?(f)
34
+ options[:mode] = config_executable_mode
35
+ elsif config_writable_files.include?(f)
36
+ options[:mode] = config_writable_mode
37
+ elsif config_readable_files.include?(f)
38
+ options[:mode] = config_readable_mode
39
+ end
40
+ [f, options]
41
+ }]
42
+ when Hash
43
+ fs
44
+ else
45
+ raise TypeError.new("unexpected type: #{fs.class}")
46
+ end
47
+ end
48
+
49
+ def _target?(s, options={})
50
+ except = Array(options[:configure_except]).flatten.map { |s| s.to_sym }
51
+ only = Array(options[:configur_only]).flatten.map { |s| s.to_sym }
52
+ ( except.empty? or not(except.include?(s)) ) and ( only.empty? or only.include?(s) )
53
+ end
26
54
 
27
55
  desc("Setup shared application config.")
28
56
  task(:setup, :roles => :app, :except => { :no_release => true }) {
29
57
  if config_use_shared
30
- config_files.each do |f|
31
- safe_put(template(f, :path => config_template_path), File.join(config_shared_path, f), :place => :if_modified)
58
+ _normalize_config_files(config_files).each do |file, options|
59
+ if _target?(:shared, options)
60
+ safe_put(template(file, :path => config_template_path), File.join(config_shared_path, file), options)
61
+ end
32
62
  end
33
- execute = []
34
- execute << "#{try_sudo} chmod #{config_readable_mode} #{config_readable_files.map { |f| File.join(config_shared_path, f).dump }.join(' ')}" unless config_readable_files.empty?
35
- execute << "#{try_sudo} chmod #{config_writable_mode} #{config_writable_files.map { |f| File.join(config_shared_path, f).dump }.join(' ')}" unless config_writable_files.empty?
36
- execute << "#{try_sudo} chmod #{config_executable_mode} #{config_executable_files.map { |f| File.join(config_shared_path, f).dump }.join(' ')}" unless config_executable_files.empty?
37
- execute << "#{try_sudo} rm -f #{config_remove_files.map { |f| File.join(config_shared_path, f).dump }.join(' ')}" unless config_remove_files.empty?
38
- run(execute.join(" && ")) unless execute.empty?
39
63
  end
40
64
  }
41
- after 'deploy:setup', 'config:setup'
65
+ after "deploy:setup", "config:setup"
42
66
 
43
67
  desc("Update applicatin config.")
44
68
  task(:update, :roles => :app, :except => { :no_release => true }) {
@@ -47,39 +71,41 @@ module Capistrano
47
71
  update_locally if fetch(:config_update_locally, false)
48
72
  }
49
73
  }
50
- after 'deploy:finalize_update', 'config:update'
74
+ after "deploy:finalize_update", "config:update"
75
+
76
+ def _destination_file(file, options={})
77
+ file.start_with?("/") ? file : File.join(options.fetch(:path, "."), file)
78
+ end
51
79
 
52
80
  task(:update_remotely, :roles => :app, :except => { :no_release => true }) {
53
- if config_use_shared
54
- execute = []
55
- config_files.each do |f|
56
- execute << "( rm -f #{File.join(config_path, f).dump}; " +
57
- "ln -sf #{File.join(config_shared_path, f).dump} #{File.join(config_path, f).dump} )"
58
- end
59
- run(execute.join(" && ")) unless execute.empty?
60
- else
61
- config_files.each do |f|
62
- safe_put(template(f, :path => config_template_path), File.join(config_path, f), :place => :if_modified)
81
+ execute = []
82
+ _normalize_config_files(config_files).each do |file, options|
83
+ destination = _destination_file(file, :path => config_path)
84
+ if config_use_shared and _target?(:shared, options)
85
+ execute << "( rm -f #{destination.dump}; " +
86
+ "ln -sf #{File.join(config_shared_path, file).dump} #{destination.dump} )"
87
+ elsif _target?(:remote, options)
88
+ safe_put(template(file, :path => config_template_path), destination, options)
63
89
  end
64
- execute = []
65
- execute << "#{try_sudo} chmod #{config_readable_mode} #{config_readable_files.map { |f| File.join(config_path, f).dump }.join(' ')}" unless config_readable_files.empty?
66
- execute << "#{try_sudo} chmod #{config_writable_mode} #{config_writable_files.map { |f| File.join(config_path, f).dump }.join(' ')}" unless config_writable_files.empty?
67
- execute << "#{try_sudo} chmod #{config_executable_mode} #{config_executable_files.map { |f| File.join(config_path, f).dump }.join(' ')}" unless config_executable_files.empty?
68
- execute << "#{try_sudo} rm -f #{config_remove_files.map { |f| File.join(config_path, f).dump }.join(' ')}" unless config_remove_files.empty?
69
- run(execute.join(" && ")) unless execute.empty?
70
90
  end
91
+ run(execute.join(" && ")) unless execute.empty?
71
92
  }
72
93
 
94
+ def safe_put_locally(body, to, options={})
95
+ File.write(to, body)
96
+ if options.key?(:mode)
97
+ mode = options[:mode].is_a?(Numeric) ? options[:mode].to_s(8) : options[:mode].to_s
98
+ run_locally("chmod #{mode.dump} #{to.dump}")
99
+ end
100
+ end
101
+
73
102
  task(:update_locally, :roles => :app, :except => { :no_release => true }) {
74
- config_files.each do |f|
75
- File.write(File.join(config_path_local, f), template(f, :path => config_template_path))
103
+ _normalize_config_files(config_files).each do |file, options|
104
+ if _target?(:local, options)
105
+ destination = _destination_file(file, :path => config_path_local)
106
+ safe_put_locally(template(file, :path => config_template_path), destination, options)
107
+ end
76
108
  end
77
- execute = []
78
- execute << "#{try_sudo} chmod #{config_readable_mode} #{config_readable_files.map { |f| File.join(config_path_local, f).dump }.join(' ')}" unless config_readable_files.empty?
79
- execute << "#{try_sudo} chmod #{config_writable_mode} #{config_writable_files.map { |f| File.join(config_path_local, f).dump }.join(' ')}" unless config_writable_files.empty?
80
- execute << "#{try_sudo} chmod #{config_executable_mode} #{config_executable_files.map { |f| File.join(config_path_local, f).dump }.join(' ')}" unless config_executable_files.empty?
81
- execute << "#{try_sudo} rm -f #{config_remove_files.map { |f| File.join(config_path_local, f).dump }.join(' ')}" unless config_remove_files.empty?
82
- run(execute.join(" && ")) unless execute.empty?
83
109
  }
84
110
  }
85
111
  }
@@ -91,4 +117,4 @@ if Capistrano::Configuration.instance
91
117
  Capistrano::Configuration.instance.extend(Capistrano::ConfigRecipe)
92
118
  end
93
119
 
94
- # vim:set ft=ruby :
120
+ # vim:set ft=ruby sw=2 ts=2 :
@@ -1,5 +1,5 @@
1
1
  module Capistrano
2
2
  module ConfigRecipe
3
- VERSION = "0.0.5"
3
+ VERSION = "0.1.0"
4
4
  end
5
5
  end
@@ -0,0 +1,5 @@
1
+ /.bundle
2
+ /.vagrant
3
+ /known_hosts
4
+ /tmp
5
+ /vendor
@@ -0,0 +1,2 @@
1
+ load "deploy"
2
+ load "../config/deploy"
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gemspec(:path => "../..")
@@ -0,0 +1,99 @@
1
+ # -*- mode: ruby -*-
2
+ # vi: set ft=ruby :
3
+
4
+ Vagrant::Config.run do |config|
5
+ # All Vagrant configuration is done here. The most common configuration
6
+ # options are documented and commented below. For a complete reference,
7
+ # please see the online documentation at vagrantup.com.
8
+
9
+ # Every Vagrant virtual environment requires a box to build off of.
10
+ config.vm.box = "centos6-64"
11
+
12
+ # The url from where the 'config.vm.box' box will be fetched if it
13
+ # doesn't already exist on the user's system.
14
+ config.vm.box_url = "http://developer.nrel.gov/downloads/vagrant-boxes/CentOS-6.3-x86_64-v20130101.box"
15
+
16
+ # Boot with a GUI so you can see the screen. (Default is headless)
17
+ # config.vm.boot_mode = :gui
18
+
19
+ # Assign this VM to a host-only network IP, allowing you to access it
20
+ # via the IP. Host-only networks can talk to the host machine as well as
21
+ # any other machines on the same network, but cannot be accessed (through this
22
+ # network interface) by any external networks.
23
+ config.vm.network :hostonly, "192.168.33.10"
24
+
25
+ # Assign this VM to a bridged network, allowing you to connect directly to a
26
+ # network using the host's network device. This makes the VM appear as another
27
+ # physical device on your network.
28
+ # config.vm.network :bridged
29
+
30
+ # Forward a port from the guest to the host, which allows for outside
31
+ # computers to access the VM, whereas host only networking does not.
32
+ # config.vm.forward_port 80, 8080
33
+
34
+ # Share an additional folder to the guest VM. The first argument is
35
+ # an identifier, the second is the path on the guest to mount the
36
+ # folder, and the third is the path on the host to the actual folder.
37
+ # config.vm.share_folder "v-data", "/vagrant_data", "../data"
38
+
39
+ # Enable provisioning with Puppet stand alone. Puppet manifests
40
+ # are contained in a directory path relative to this Vagrantfile.
41
+ # You will need to create the manifests directory and a manifest in
42
+ # the file precise-amd64.pp in the manifests_path directory.
43
+ #
44
+ # An example Puppet manifest to provision the message of the day:
45
+ #
46
+ # # group { "puppet":
47
+ # # ensure => "present",
48
+ # # }
49
+ # #
50
+ # # File { owner => 0, group => 0, mode => 0644 }
51
+ # #
52
+ # # file { '/etc/motd':
53
+ # # content => "Welcome to your Vagrant-built virtual machine!
54
+ # # Managed by Puppet.\n"
55
+ # # }
56
+ #
57
+ # config.vm.provision :puppet do |puppet|
58
+ # puppet.manifests_path = "manifests"
59
+ # puppet.manifest_file = "precise-amd64.pp"
60
+ # end
61
+
62
+ # Enable provisioning with chef solo, specifying a cookbooks path, roles
63
+ # path, and data_bags path (all relative to this Vagrantfile), and adding
64
+ # some recipes and/or roles.
65
+ #
66
+ # config.vm.provision :chef_solo do |chef|
67
+ # chef.cookbooks_path = "../my-recipes/cookbooks"
68
+ # chef.roles_path = "../my-recipes/roles"
69
+ # chef.data_bags_path = "../my-recipes/data_bags"
70
+ # chef.add_recipe "mysql"
71
+ # chef.add_role "web"
72
+ #
73
+ # # You may also specify custom JSON attributes:
74
+ # chef.json = { :mysql_password => "foo" }
75
+ # end
76
+
77
+ # Enable provisioning with chef server, specifying the chef server URL,
78
+ # and the path to the validation key (relative to this Vagrantfile).
79
+ #
80
+ # The Opscode Platform uses HTTPS. Substitute your organization for
81
+ # ORGNAME in the URL and validation key.
82
+ #
83
+ # If you have your own Chef Server, use the appropriate URL, which may be
84
+ # HTTP instead of HTTPS depending on your configuration. Also change the
85
+ # validation key to validation.pem.
86
+ #
87
+ # config.vm.provision :chef_client do |chef|
88
+ # chef.chef_server_url = "https://api.opscode.com/organizations/ORGNAME"
89
+ # chef.validation_key_path = "ORGNAME-validator.pem"
90
+ # end
91
+ #
92
+ # If you're using the Opscode platform, your validator client is
93
+ # ORGNAME-validator, replacing ORGNAME with your organization name.
94
+ #
95
+ # IF you have your own Chef Server, the default validation client name is
96
+ # chef-validator, unless you changed the configuration.
97
+ #
98
+ # chef.validation_client_name = "ORGNAME-validator"
99
+ end
@@ -0,0 +1,7 @@
1
+ #!/bin/sh -e
2
+
3
+ bundle exec vagrant up
4
+ bundle exec cap test_all
5
+ bundle exec vagrant halt
6
+
7
+ # vim:set ft=sh :
@@ -0,0 +1,368 @@
1
+ set :application, "capistrano-config"
2
+ set :repository, "."
3
+ set :deploy_to do
4
+ File.join("/home", user, application)
5
+ end
6
+ set :deploy_via, :copy
7
+ set :scm, :none
8
+ set :use_sudo, false
9
+ set :user, "vagrant"
10
+ set :password, "vagrant"
11
+ set :ssh_options, {:user_known_hosts_file => "/dev/null"}
12
+
13
+ role :web, "192.168.33.10"
14
+ role :app, "192.168.33.10"
15
+ role :db, "192.168.33.10", :primary => true
16
+
17
+ $LOAD_PATH.push(File.expand_path("../../lib", File.dirname(__FILE__)))
18
+ require "capistrano-config"
19
+ require "tempfile"
20
+
21
+ def _invoke_command(cmdline, options={})
22
+ via = options.delete(:via)
23
+ if via == :run_locally
24
+ run_locally(cmdline)
25
+ else
26
+ invoke_command(cmdline, options)
27
+ end
28
+ end
29
+
30
+ def assert_file_content(file, content, options={})
31
+ begin
32
+ if options[:via] == :run_locally
33
+ remote_content = File.read(file)
34
+ else
35
+ tempfile = Tempfile.new("tmp")
36
+ download(file, tempfile.path)
37
+ remote_content = tempfile.read
38
+ end
39
+ abort if content != remote_content
40
+ rescue
41
+ logger.debug("assert_file_content(#{file}, #{content}) failed.")
42
+ _invoke_command("cat #{file.dump}", options)
43
+ raise
44
+ end
45
+ end
46
+
47
+ def assert_symlink(file, link_to, options={})
48
+ begin
49
+ _invoke_command("test -h #{file.dump} && test #{link_to.dump} = $(readlink #{file.dump})")
50
+ rescue
51
+ logger.debug("assert_symlink(#{file}, #{link_to}) failed.")
52
+ _invoke_command("ls -l #{file.dump}", options)
53
+ raise
54
+ end
55
+ end
56
+
57
+ def assert_file_mode(mode, file, options={})
58
+ mode = mode.to_i(8) if mode.is_a?(String)
59
+ smode = "%c%c%c%c%c%c%c%c%c%c" % [
60
+ ?-,
61
+ mode & 0400 == 0 ? ?- : ?r, mode & 0200 == 0 ? ?- : ?w, mode & 0100 == 0 ? ?- : ?x,
62
+ mode & 0040 == 0 ? ?- : ?r, mode & 0020 == 0 ? ?- : ?w, mode & 0010 == 0 ? ?- : ?x,
63
+ mode & 0004 == 0 ? ?- : ?r, mode & 0002 == 0 ? ?- : ?w, mode & 0001 == 0 ? ?- : ?x,
64
+ ]
65
+ begin
66
+ _invoke_command("test #{smode.dump} = $(ls -l #{file.dump} | cut -d ' ' -f 1)", options)
67
+ rescue
68
+ logger.debug("assert_file_mode(#{mode.to_s(8)}, #{file}) failed.")
69
+ _invoke_command("ls -l #{file.dump}", options)
70
+ raise
71
+ end
72
+ end
73
+
74
+ def assert_file_owner(uid, file, options={})
75
+ uid = uid.to_i
76
+ # `stat -c` => GNU, `stat -f` => BSD
77
+ begin
78
+ _invoke_command("test #{uid} -eq $( stat -c '%u' #{file.dump} || stat -f '%u' #{file.dump} )", options)
79
+ rescue
80
+ logger.debug("assert_file_owner(#{uid}, #{file}) failed.")
81
+ _invoke_command("ls -l #{file.dump}", options)
82
+ raise
83
+ end
84
+ end
85
+
86
+ def assert_file_group(gid, file, options={})
87
+ gid = gid.to_i
88
+ # `stat -c` => GNU, `stat -f` => BSD
89
+ begin
90
+ _invoke_command("test #{gid} -eq $( stat -c '%g' #{file.dump} || stat -f '%g' #{file.dump} )", options)
91
+ rescue
92
+ logger.debug("assert_file_group(#{gid}, #{file}) failed.")
93
+ _invoke_command("ls -l #{file.dump}", options)
94
+ raise
95
+ end
96
+ end
97
+
98
+ task(:test_all) {
99
+ find_and_execute_task("test_default")
100
+ find_and_execute_task("test_with_options")
101
+ find_and_execute_task("test_with_remote")
102
+ find_and_execute_task("test_with_local")
103
+ find_and_execute_task("test_with_shared")
104
+ }
105
+
106
+ namespace(:test_default) {
107
+ task(:default) {
108
+ methods.grep(/^test_/).each do |m|
109
+ send(m)
110
+ end
111
+ }
112
+ before "test_default", "test_default:setup"
113
+ after "test_default", "test_default:teardown"
114
+
115
+ task(:setup) {
116
+ run("rm -rf #{deploy_to.dump}")
117
+ run_locally("mkdir -p tmp/local")
118
+ set(:config_template_path, "tmp")
119
+ set(:config_files, %w(foo bar baz))
120
+ set(:config_executable_files, %w(foo))
121
+ set(:config_path_local, "tmp/local")
122
+ set(:config_use_shared, true)
123
+ set(:config_update_remotely, true)
124
+ set(:config_update_locally, true)
125
+ # find_and_execute_task("deploy:setup")
126
+ }
127
+
128
+ task(:teardown) {
129
+ run_locally("rm -rf tmp")
130
+ run("rm -rf #{deploy_to.dump}")
131
+ }
132
+
133
+ task(:test_deploy) {
134
+ # xxx
135
+ run_locally("rm -f tmp/foo; echo xxx > tmp/foo")
136
+ run_locally("rm -f tmp/bar; echo xxx > tmp/bar")
137
+ run_locally("rm -f tmp/baz; echo xxx > tmp/baz")
138
+ find_and_execute_task("deploy:setup")
139
+ assert_file_content(File.join(config_shared_path, "foo"), File.read("tmp/foo"))
140
+
141
+ # yyy
142
+ run_locally("rm -f tmp/foo; echo yyy > tmp/foo")
143
+ run_locally("rm -f tmp/bar; echo yyy > tmp/bar")
144
+ run_locally("rm -f tmp/baz; echo yyy > tmp/baz")
145
+ find_and_execute_task("deploy")
146
+ assert_file_content(File.join(config_shared_path, "foo"), "xxx\n")
147
+ assert_symlink(File.join(config_path, "foo"), File.join(config_shared_path, "foo"))
148
+ assert_file_content(File.join(config_path_local, "foo"), "yyy\n", :via => :run_locally)
149
+
150
+ # executable?
151
+ run("test -x #{File.join(config_shared_path, "foo").dump}")
152
+ run_locally("test -x #{File.join(config_path_local, "foo").dump}")
153
+ }
154
+ }
155
+
156
+ namespace(:test_with_options) {
157
+ task(:default) {
158
+ methods.grep(/^test_/).each do |m|
159
+ send(m)
160
+ end
161
+ }
162
+ before "test_with_options", "test_with_options:setup"
163
+ after "test_with_options", "test_with_options:teardown"
164
+
165
+ task(:setup) {
166
+ sudo("rm -f /etc/__privileged__")
167
+ run("rm -rf #{deploy_to.dump}")
168
+ run_locally("mkdir -p tmp/local")
169
+ set(:config_template_path, "tmp")
170
+ set(:config_files, {
171
+ "secret" => {:mode => 0640},
172
+ "/etc/__privileged__" => { :configure_except => :local, :run_method => :sudo, :owner => 0, :group => 0 },
173
+ })
174
+ set(:config_path_local, "tmp/local")
175
+ set(:config_use_shared, false)
176
+ set(:config_update_remotely, true)
177
+ set(:config_update_locally, true)
178
+ find_and_execute_task("deploy:setup")
179
+ }
180
+
181
+ task(:teardown) {
182
+ run_locally("rm -rf tmp")
183
+ run("rm -rf #{deploy_to.dump}")
184
+ sudo("rm -f /etc/__privileged__")
185
+ }
186
+
187
+ task(:test_deploy) {
188
+ run_locally("rm -f tmp/secret; echo secret > tmp/secret")
189
+ run_locally("rm -f tmp/etc/__privileged__; mkdir -p tmp/etc; echo __privileged__ > tmp/etc/__privileged__")
190
+ find_and_execute_task("deploy")
191
+ assert_file_content(File.join(config_path, "secret"), File.read("tmp/secret"))
192
+ assert_file_mode(0640, File.join(config_path, "secret"))
193
+
194
+ assert_file_content("/etc/__privileged__", File.read("tmp/etc/__privileged__"))
195
+ assert_file_owner(0, "/etc/__privileged__")
196
+ assert_file_group(0, "/etc/__privileged__")
197
+ }
198
+ }
199
+
200
+ namespace(:test_with_remote) {
201
+ task(:default) {
202
+ methods.grep(/^test_/).each do |m|
203
+ send(m)
204
+ end
205
+ }
206
+ before "test_with_remote", "test_with_remote:setup"
207
+ after "test_with_remote", "test_with_remote:teardown"
208
+
209
+ task(:setup) {
210
+ run("rm -rf #{deploy_to.dump}")
211
+ run_locally("mkdir -p tmp/local")
212
+ set(:config_template_path, "tmp")
213
+ set(:config_files, %w(foo bar baz))
214
+ set(:config_executable_files, %w(foo))
215
+ set(:config_path_local, "tmp/local")
216
+ set(:config_use_shared, false)
217
+ set(:config_update_remotely, true)
218
+ set(:config_update_locally, false)
219
+ find_and_execute_task("deploy:setup")
220
+ }
221
+
222
+ task(:teardown) {
223
+ run_locally("rm -rf tmp")
224
+ run("rm -rf #{deploy_to.dump}")
225
+ }
226
+
227
+ task(:test_deploy) {
228
+ run_locally("rm -f tmp/foo; echo foo > tmp/foo")
229
+ run_locally("rm -f tmp/bar; echo bar > tmp/bar")
230
+ run_locally("rm -f tmp/baz; echo baz > tmp/baz")
231
+ find_and_execute_task("deploy")
232
+ assert_file_content(File.join(config_path, "foo"), File.read("tmp/foo"))
233
+ assert_file_content(File.join(config_path, "bar"), File.read("tmp/bar"))
234
+ assert_file_content(File.join(config_path, "baz"), File.read("tmp/baz"))
235
+ }
236
+
237
+ task(:test_redeploy) {
238
+ run_locally("rm -f tmp/foo; echo bar > tmp/foo")
239
+ run_locally("rm -f tmp/bar; echo baz > tmp/bar")
240
+ run_locally("rm -f tmp/baz; echo foo > tmp/baz")
241
+ find_and_execute_task("deploy")
242
+ assert_file_content(File.join(config_path, "foo"), File.read("tmp/foo"))
243
+ assert_file_content(File.join(config_path, "bar"), File.read("tmp/bar"))
244
+ assert_file_content(File.join(config_path, "baz"), File.read("tmp/baz"))
245
+ }
246
+ }
247
+
248
+ namespace(:test_with_local) {
249
+ task(:default) {
250
+ methods.grep(/^test_/).each do |m|
251
+ send(m)
252
+ end
253
+ }
254
+ before "test_with_local", "test_with_local:setup"
255
+ after "test_with_local", "test_with_local:teardown"
256
+
257
+ task(:setup) {
258
+ run("rm -rf #{deploy_to.dump}")
259
+ run_locally("mkdir -p tmp/local")
260
+ set(:config_template_path, "tmp")
261
+ set(:config_files, %w(foo bar baz))
262
+ set(:config_executable_files, %w(foo))
263
+ set(:config_path_local, "tmp/local")
264
+ set(:config_use_shared, false)
265
+ set(:config_update_remotely, false)
266
+ set(:config_update_locally, true)
267
+ find_and_execute_task("deploy:setup")
268
+ }
269
+
270
+ task(:teardown) {
271
+ run_locally("rm -rf tmp")
272
+ run("rm -rf #{deploy_to.dump}")
273
+ }
274
+
275
+ task(:test_deploy) {
276
+ run_locally("rm -f tmp/foo; echo foo > tmp/foo")
277
+ run_locally("rm -f tmp/bar; echo bar > tmp/bar")
278
+ run_locally("rm -f tmp/baz; echo baz > tmp/baz")
279
+ find_and_execute_task("deploy")
280
+ assert_file_content(File.join(config_path_local, "foo"), File.read("tmp/foo"), :via => :run_locally)
281
+ assert_file_content(File.join(config_path_local, "bar"), File.read("tmp/bar"), :via => :run_locally)
282
+ assert_file_content(File.join(config_path_local, "baz"), File.read("tmp/baz"), :via => :run_locally)
283
+ }
284
+
285
+ task(:test_redeploy) {
286
+ run_locally("rm -f tmp/foo; echo bar > tmp/foo")
287
+ run_locally("rm -f tmp/bar; echo baz > tmp/bar")
288
+ run_locally("rm -f tmp/baz; echo foo > tmp/baz")
289
+ find_and_execute_task("deploy")
290
+ assert_file_content(File.join(config_path_local, "foo"), File.read("tmp/foo"), :via => :run_locally)
291
+ assert_file_content(File.join(config_path_local, "bar"), File.read("tmp/bar"), :via => :run_locally)
292
+ assert_file_content(File.join(config_path_local, "baz"), File.read("tmp/baz"), :via => :run_locally)
293
+ }
294
+ }
295
+
296
+ namespace(:test_with_shared) {
297
+ task(:default) {
298
+ methods.grep(/^test_/).each do |m|
299
+ send(m)
300
+ end
301
+ }
302
+ before "test_with_shared", "test_with_shared:setup"
303
+ after "test_with_shared", "test_with_shared:teardown"
304
+
305
+ task(:setup) {
306
+ run("rm -rf #{deploy_to.dump}")
307
+ run_locally("mkdir -p tmp/local")
308
+ set(:config_template_path, "tmp")
309
+ set(:config_files, %w(foo bar baz))
310
+ set(:config_executable_files, %w(foo))
311
+ set(:config_path_local, "tmp/local")
312
+ set(:config_use_shared, true)
313
+ set(:config_update_remotely, true)
314
+ set(:config_update_locally, false)
315
+ # find_and_execute_task("deploy:setup")
316
+ }
317
+
318
+ task(:teardown) {
319
+ run_locally("rm -rf tmp")
320
+ run("rm -rf #{deploy_to.dump}")
321
+ }
322
+
323
+ task(:test_setup) {
324
+ run_locally("rm -f tmp/foo; echo foo > tmp/foo")
325
+ run_locally("rm -f tmp/bar; echo bar > tmp/bar")
326
+ run_locally("rm -f tmp/baz; echo baz > tmp/baz")
327
+ find_and_execute_task("deploy:setup")
328
+ assert_file_content(File.join(config_shared_path, "foo"), File.read("tmp/foo"))
329
+ assert_file_content(File.join(config_shared_path, "bar"), File.read("tmp/bar"))
330
+ assert_file_content(File.join(config_shared_path, "baz"), File.read("tmp/baz"))
331
+ }
332
+
333
+ task(:test_resetup) {
334
+ run_locally("rm -f tmp/foo; echo bar > tmp/foo")
335
+ run_locally("rm -f tmp/bar; echo baz > tmp/bar")
336
+ run_locally("rm -f tmp/baz; echo foo > tmp/baz")
337
+ find_and_execute_task("deploy:setup")
338
+ assert_file_content(File.join(config_shared_path, "foo"), File.read("tmp/foo"))
339
+ assert_file_content(File.join(config_shared_path, "bar"), File.read("tmp/bar"))
340
+ assert_file_content(File.join(config_shared_path, "baz"), File.read("tmp/baz"))
341
+ }
342
+
343
+ task(:test_deploy) {
344
+ find_and_execute_task("deploy")
345
+ assert_symlink(File.join(config_path, "foo"), File.join(config_shared_path, "foo"))
346
+ assert_symlink(File.join(config_path, "bar"), File.join(config_shared_path, "bar"))
347
+ assert_symlink(File.join(config_path, "baz"), File.join(config_shared_path, "baz"))
348
+ }
349
+
350
+ task(:test_redeploy) {
351
+ find_and_execute_task("deploy")
352
+ assert_symlink(File.join(config_path, "foo"), File.join(config_shared_path, "foo"))
353
+ assert_symlink(File.join(config_path, "bar"), File.join(config_shared_path, "bar"))
354
+ assert_symlink(File.join(config_path, "baz"), File.join(config_shared_path, "baz"))
355
+ }
356
+
357
+ task(:test_update_config) {
358
+ run_locally("rm -f tmp/foo; echo unu > tmp/foo")
359
+ run_locally("rm -f tmp/bar; echo du > tmp/bar")
360
+ run_locally("rm -f tmp/baz; echo tri > tmp/baz")
361
+ find_and_execute_task("config:setup")
362
+ assert_file_content(File.join(config_path, "foo"), File.read("tmp/foo"))
363
+ assert_file_content(File.join(config_path, "bar"), File.read("tmp/bar"))
364
+ assert_file_content(File.join(config_path, "baz"), File.read("tmp/baz"))
365
+ }
366
+ }
367
+
368
+ # vim:set ft=ruby sw=2 ts=2 :
@@ -0,0 +1,5 @@
1
+ /.bundle
2
+ /.vagrant
3
+ /known_hosts
4
+ /tmp
5
+ /vendor
@@ -0,0 +1,2 @@
1
+ load "deploy"
2
+ load "../config/deploy"
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gemspec(:path => "../..")
@@ -0,0 +1,99 @@
1
+ # -*- mode: ruby -*-
2
+ # vi: set ft=ruby :
3
+
4
+ Vagrant::Config.run do |config|
5
+ # All Vagrant configuration is done here. The most common configuration
6
+ # options are documented and commented below. For a complete reference,
7
+ # please see the online documentation at vagrantup.com.
8
+
9
+ # Every Vagrant virtual environment requires a box to build off of.
10
+ config.vm.box = "precise64"
11
+
12
+ # The url from where the 'config.vm.box' box will be fetched if it
13
+ # doesn't already exist on the user's system.
14
+ config.vm.box_url = "http://files.vagrantup.com/precise64.box"
15
+
16
+ # Boot with a GUI so you can see the screen. (Default is headless)
17
+ # config.vm.boot_mode = :gui
18
+
19
+ # Assign this VM to a host-only network IP, allowing you to access it
20
+ # via the IP. Host-only networks can talk to the host machine as well as
21
+ # any other machines on the same network, but cannot be accessed (through this
22
+ # network interface) by any external networks.
23
+ config.vm.network :hostonly, "192.168.33.10"
24
+
25
+ # Assign this VM to a bridged network, allowing you to connect directly to a
26
+ # network using the host's network device. This makes the VM appear as another
27
+ # physical device on your network.
28
+ # config.vm.network :bridged
29
+
30
+ # Forward a port from the guest to the host, which allows for outside
31
+ # computers to access the VM, whereas host only networking does not.
32
+ # config.vm.forward_port 80, 8080
33
+
34
+ # Share an additional folder to the guest VM. The first argument is
35
+ # an identifier, the second is the path on the guest to mount the
36
+ # folder, and the third is the path on the host to the actual folder.
37
+ # config.vm.share_folder "v-data", "/vagrant_data", "../data"
38
+
39
+ # Enable provisioning with Puppet stand alone. Puppet manifests
40
+ # are contained in a directory path relative to this Vagrantfile.
41
+ # You will need to create the manifests directory and a manifest in
42
+ # the file precise-amd64.pp in the manifests_path directory.
43
+ #
44
+ # An example Puppet manifest to provision the message of the day:
45
+ #
46
+ # # group { "puppet":
47
+ # # ensure => "present",
48
+ # # }
49
+ # #
50
+ # # File { owner => 0, group => 0, mode => 0644 }
51
+ # #
52
+ # # file { '/etc/motd':
53
+ # # content => "Welcome to your Vagrant-built virtual machine!
54
+ # # Managed by Puppet.\n"
55
+ # # }
56
+ #
57
+ # config.vm.provision :puppet do |puppet|
58
+ # puppet.manifests_path = "manifests"
59
+ # puppet.manifest_file = "precise-amd64.pp"
60
+ # end
61
+
62
+ # Enable provisioning with chef solo, specifying a cookbooks path, roles
63
+ # path, and data_bags path (all relative to this Vagrantfile), and adding
64
+ # some recipes and/or roles.
65
+ #
66
+ # config.vm.provision :chef_solo do |chef|
67
+ # chef.cookbooks_path = "../my-recipes/cookbooks"
68
+ # chef.roles_path = "../my-recipes/roles"
69
+ # chef.data_bags_path = "../my-recipes/data_bags"
70
+ # chef.add_recipe "mysql"
71
+ # chef.add_role "web"
72
+ #
73
+ # # You may also specify custom JSON attributes:
74
+ # chef.json = { :mysql_password => "foo" }
75
+ # end
76
+
77
+ # Enable provisioning with chef server, specifying the chef server URL,
78
+ # and the path to the validation key (relative to this Vagrantfile).
79
+ #
80
+ # The Opscode Platform uses HTTPS. Substitute your organization for
81
+ # ORGNAME in the URL and validation key.
82
+ #
83
+ # If you have your own Chef Server, use the appropriate URL, which may be
84
+ # HTTP instead of HTTPS depending on your configuration. Also change the
85
+ # validation key to validation.pem.
86
+ #
87
+ # config.vm.provision :chef_client do |chef|
88
+ # chef.chef_server_url = "https://api.opscode.com/organizations/ORGNAME"
89
+ # chef.validation_key_path = "ORGNAME-validator.pem"
90
+ # end
91
+ #
92
+ # If you're using the Opscode platform, your validator client is
93
+ # ORGNAME-validator, replacing ORGNAME with your organization name.
94
+ #
95
+ # IF you have your own Chef Server, the default validation client name is
96
+ # chef-validator, unless you changed the configuration.
97
+ #
98
+ # chef.validation_client_name = "ORGNAME-validator"
99
+ end
@@ -0,0 +1,7 @@
1
+ #!/bin/sh -e
2
+
3
+ bundle exec vagrant up
4
+ bundle exec cap test_all
5
+ bundle exec vagrant halt
6
+
7
+ # vim:set ft=sh :
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capistrano-config
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-02-27 00:00:00.000000000 Z
12
+ date: 2013-03-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: capistrano
@@ -32,17 +32,17 @@ dependencies:
32
32
  requirement: !ruby/object:Gem::Requirement
33
33
  none: false
34
34
  requirements:
35
- - - ! '>='
35
+ - - ~>
36
36
  - !ruby/object:Gem::Version
37
- version: '0'
37
+ version: 0.0.1
38
38
  type: :runtime
39
39
  prerelease: false
40
40
  version_requirements: !ruby/object:Gem::Requirement
41
41
  none: false
42
42
  requirements:
43
- - - ! '>='
43
+ - - ~>
44
44
  - !ruby/object:Gem::Version
45
- version: '0'
45
+ version: 0.0.1
46
46
  - !ruby/object:Gem::Dependency
47
47
  name: capistrano-file-transfer-ext
48
48
  requirement: !ruby/object:Gem::Requirement
@@ -50,7 +50,7 @@ dependencies:
50
50
  requirements:
51
51
  - - ~>
52
52
  - !ruby/object:Gem::Version
53
- version: 0.0.3
53
+ version: 0.1.0
54
54
  type: :runtime
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
@@ -58,7 +58,55 @@ dependencies:
58
58
  requirements:
59
59
  - - ~>
60
60
  - !ruby/object:Gem::Version
61
- version: 0.0.3
61
+ version: 0.1.0
62
+ - !ruby/object:Gem::Dependency
63
+ name: net-scp
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 1.0.4
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 1.0.4
78
+ - !ruby/object:Gem::Dependency
79
+ name: net-ssh
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: 2.2.2
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: 2.2.2
94
+ - !ruby/object:Gem::Dependency
95
+ name: vagrant
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ~>
100
+ - !ruby/object:Gem::Version
101
+ version: 1.0.6
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ~>
108
+ - !ruby/object:Gem::Version
109
+ version: 1.0.6
62
110
  description: a capistrano recipe to manage configurations files.
63
111
  email:
64
112
  - yamashita@geishatokyo.com
@@ -74,6 +122,17 @@ files:
74
122
  - capistrano-config.gemspec
75
123
  - lib/capistrano-config.rb
76
124
  - lib/capistrano-config/version.rb
125
+ - test/centos6-64/.gitignore
126
+ - test/centos6-64/Capfile
127
+ - test/centos6-64/Gemfile
128
+ - test/centos6-64/Vagrantfile
129
+ - test/centos6-64/run.sh
130
+ - test/config/deploy.rb
131
+ - test/precise64/.gitignore
132
+ - test/precise64/Capfile
133
+ - test/precise64/Gemfile
134
+ - test/precise64/Vagrantfile
135
+ - test/precise64/run.sh
77
136
  homepage: https://github.com/yyuu/capistrano-config
78
137
  licenses: []
79
138
  post_install_message:
@@ -98,4 +157,15 @@ rubygems_version: 1.8.23
98
157
  signing_key:
99
158
  specification_version: 3
100
159
  summary: a capistrano recipe to manage configurations files.
101
- test_files: []
160
+ test_files:
161
+ - test/centos6-64/.gitignore
162
+ - test/centos6-64/Capfile
163
+ - test/centos6-64/Gemfile
164
+ - test/centos6-64/Vagrantfile
165
+ - test/centos6-64/run.sh
166
+ - test/config/deploy.rb
167
+ - test/precise64/.gitignore
168
+ - test/precise64/Capfile
169
+ - test/precise64/Gemfile
170
+ - test/precise64/Vagrantfile
171
+ - test/precise64/run.sh