cap-util 0.3.0 → 0.4.0
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 +83 -0
- data/lib/cap-util/git_branch.rb +18 -0
- data/lib/cap-util/server_roles.rb +85 -0
- data/lib/cap-util/server_roles_yaml.rb +32 -0
- data/lib/cap-util/shared_path.rb +22 -0
- data/lib/cap-util/version.rb +1 -1
- data/test/git_branch_tests.rb +19 -0
- data/test/server_roles_tests.rb +120 -0
- data/test/server_roles_yaml_tests.rb +39 -0
- data/test/shared_path_tests.rb +30 -0
- metadata +16 -4
data/README.md
CHANGED
@@ -83,6 +83,89 @@ task :some_rake_task do
|
|
83
83
|
end
|
84
84
|
```
|
85
85
|
|
86
|
+
## GitBranch util
|
87
|
+
|
88
|
+
This util helps when working with git branches. Right now, it only has a singleton helpers for fetching the current branch the user is on. This can be useful in setting the `:branch` cap var if you always want to deploy from the branch you are currently on.
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
set (:branch) { CapUtil::GitBranch.current }
|
92
|
+
```
|
93
|
+
|
94
|
+
## SharedPath util
|
95
|
+
|
96
|
+
This utile helps when working with cap's `shared_path`. Right now, it only has a method for removing things from the shared_path
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
CapUtil::SharedPath.new(self).rm_rf 'cached-copy'
|
100
|
+
```
|
101
|
+
|
102
|
+
## Dynamic Server Roles helpers
|
103
|
+
|
104
|
+
CapUtil has a few utils for fetching and applying cap server roles from dynamic data. It assumes you have your server role data stored in yaml either locally or on some remote location.
|
105
|
+
|
106
|
+
### Format
|
107
|
+
|
108
|
+
The server role yaml needs to be in a format like:
|
109
|
+
|
110
|
+
```yaml
|
111
|
+
---
|
112
|
+
|
113
|
+
app:
|
114
|
+
server1: [primary]
|
115
|
+
server2: []
|
116
|
+
|
117
|
+
db:
|
118
|
+
server3: [primary, no_release]
|
119
|
+
```
|
120
|
+
|
121
|
+
### ServerRolesYaml util
|
122
|
+
|
123
|
+
This util serves as a base for fetching role yaml data. It provides a framework for subclasses to override and supply the necessary logic to fetch/validate/read yaml data. Use it to pull local or remote config files using the given hooks.
|
124
|
+
|
125
|
+
### ServerRoles util
|
126
|
+
|
127
|
+
This util, given a raw yaml string, will model out the roles and apply them to your cap invocation.
|
128
|
+
|
129
|
+
### Example
|
130
|
+
|
131
|
+
This example shows how a different set of roles could be used for different stages in cap. The yaml config files are located local to the 'my_server_roles_yaml.rb' file.
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
# in your Capfile...
|
135
|
+
require 'my_server_roles_yaml'
|
136
|
+
set (:server_roles_yaml) { MyServerRolesYaml.new(self, stage) }
|
137
|
+
set (:server_roles) { CapUtil::ServerRoles.new(self, server_roles_yaml.get) }
|
138
|
+
|
139
|
+
# in my_server_roles_yaml.rb
|
140
|
+
|
141
|
+
class MyServerRolesYaml < CapUtil::ServerRolesYaml
|
142
|
+
|
143
|
+
# fetch role data from the local config/#{stage}_server_roles.yaml file
|
144
|
+
|
145
|
+
def initialize(cap, stage)
|
146
|
+
super(cap, :desc => stage)
|
147
|
+
|
148
|
+
roles_file_name = "#{stage}_server_roles.yaml"
|
149
|
+
@roles_file_path = File.expand_path("../../../config/#{roles_file_name}", __FILE__)
|
150
|
+
end
|
151
|
+
|
152
|
+
def validate
|
153
|
+
if !valid?
|
154
|
+
say_error "`#{@roles_file_path}' does not exist."
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def valid?
|
159
|
+
File.exists?(@roles_file_path)
|
160
|
+
end
|
161
|
+
|
162
|
+
def read
|
163
|
+
File.read(@roles_file_path)
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
```
|
168
|
+
|
86
169
|
## Contributing
|
87
170
|
|
88
171
|
1. Fork it
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'cap-util'
|
2
|
+
|
3
|
+
module CapUtil
|
4
|
+
class GitBranch
|
5
|
+
include CapUtil
|
6
|
+
|
7
|
+
def self.current(action=:run)
|
8
|
+
git_cmd = "git symbolic-ref HEAD"
|
9
|
+
if action == :run
|
10
|
+
say "Fetching #{color "current git branch", :bold, :cyan} from HEAD"
|
11
|
+
(r = run_locally(git_cmd)).success? ? r.stdout.split('/').last.strip : halt
|
12
|
+
elsif action == :cmd
|
13
|
+
git_cmd
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'cap-util'
|
3
|
+
|
4
|
+
module CapUtil
|
5
|
+
|
6
|
+
class ServerRoles
|
7
|
+
include CapUtil
|
8
|
+
attr_reader :roles
|
9
|
+
|
10
|
+
def initialize(cap, roles_yaml)
|
11
|
+
@cap = cap
|
12
|
+
@roles = RoleSet.new(YAML.load(roles_yaml))
|
13
|
+
end
|
14
|
+
|
15
|
+
# Since this is a CapUtil, we can call cap cmds using the `cap` accessor.
|
16
|
+
# For each role, call cap's `role` method, passing the relevant values.
|
17
|
+
|
18
|
+
def apply
|
19
|
+
@roles.each do |name, host, opts|
|
20
|
+
cap.role name, host, opts
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
class RoleSet
|
26
|
+
|
27
|
+
attr_reader :role_defs
|
28
|
+
|
29
|
+
def initialize(roles_hash)
|
30
|
+
@role_defs = roles_hash.map do |(role_name, role_servers_hash)|
|
31
|
+
RoleDef.new(role_name, role_servers_hash)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def each(&block)
|
36
|
+
@role_defs.each {|role_def| role_def.apply(&block)}
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
class RoleDef
|
42
|
+
|
43
|
+
attr_reader :name, :servers
|
44
|
+
|
45
|
+
def initialize(name, servers_hash)
|
46
|
+
@name = name
|
47
|
+
@servers = servers_hash.map do |(server_name, server_options_list)|
|
48
|
+
ServerDef.new(server_name, server_options_list)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def apply(&block)
|
53
|
+
@servers.each do |server|
|
54
|
+
block.call @name, server.hostname, server.options
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
class ServerDef
|
61
|
+
|
62
|
+
attr_reader :hostname, :options
|
63
|
+
|
64
|
+
def initialize(name, options_list=[])
|
65
|
+
@hostname = "#{name}.reelfx.com"
|
66
|
+
@options = {}
|
67
|
+
|
68
|
+
# so, weird cap bug. options have to match type when using them in
|
69
|
+
# a task's definition. so if you have (string) 'primary' option, you
|
70
|
+
# have to use a string in your task defs.
|
71
|
+
# this is not the case for the role names (string or symbol works).
|
72
|
+
# so, I'm just defining each option, both in string (how it comes from
|
73
|
+
# the configs) and symbol form.
|
74
|
+
|
75
|
+
options_list.each do |option|
|
76
|
+
@options[option.to_s] = true
|
77
|
+
@options[option.to_sym] = true
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'cap-util'
|
2
|
+
|
3
|
+
module CapUtil
|
4
|
+
|
5
|
+
# the class should be use as a superclass for fetching server roles yaml.
|
6
|
+
|
7
|
+
class ServerRolesYaml
|
8
|
+
include CapUtil
|
9
|
+
attr_reader :desc, :source
|
10
|
+
|
11
|
+
def initialize(cap, opts=nil)
|
12
|
+
opts ||= {}
|
13
|
+
|
14
|
+
@cap = cap
|
15
|
+
@desc = opts[:desc] ? "#{opts[:desc]} server roles" : "server roles"
|
16
|
+
@source = opts[:source] ? " from #{opts[:source]}" : ""
|
17
|
+
end
|
18
|
+
|
19
|
+
def get
|
20
|
+
say "Applying #{color @desc, :bold, :cyan}#{@source}."
|
21
|
+
|
22
|
+
validate
|
23
|
+
valid? ? read : halt
|
24
|
+
end
|
25
|
+
|
26
|
+
def validate; raise NotImplementedError; end
|
27
|
+
def valid?; raise NotImplementedError; end
|
28
|
+
def read; raise NotImplementedError; end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'cap-util'
|
2
|
+
|
3
|
+
module CapUtil
|
4
|
+
|
5
|
+
# SharedPath models the path to the set of shared deployed code. named
|
6
|
+
# after cap's `shared_path` method b/c they point at similar locations.
|
7
|
+
|
8
|
+
class SharedPath
|
9
|
+
include CapUtil
|
10
|
+
|
11
|
+
def initialize(cap, path=nil)
|
12
|
+
@cap = cap
|
13
|
+
@shared_path = File.expand_path(path || cap.shared_path)
|
14
|
+
end
|
15
|
+
|
16
|
+
def rm_rf(rel_path)
|
17
|
+
run "rm -rf #{@shared_path}/#{rel_path}"
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
data/lib/cap-util/version.rb
CHANGED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'assert'
|
2
|
+
|
3
|
+
require 'cap-util/git_branch'
|
4
|
+
|
5
|
+
module CapUtil
|
6
|
+
|
7
|
+
class GitBranchTests < Assert::Context
|
8
|
+
desc "the GitBranch util"
|
9
|
+
subject { GitBranch }
|
10
|
+
|
11
|
+
should have_imeth :current
|
12
|
+
|
13
|
+
should "use the symbolic ref the HEAD is at for the current branch" do
|
14
|
+
assert_equal "git symbolic-ref HEAD", subject.current(:cmd)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'assert'
|
2
|
+
|
3
|
+
require 'cap-util/server_roles'
|
4
|
+
|
5
|
+
module CapUtil
|
6
|
+
|
7
|
+
class ServerRolesTests < Assert::Context
|
8
|
+
desc "the ServerRoles handler"
|
9
|
+
setup do
|
10
|
+
roles_yaml = <<YAML
|
11
|
+
---
|
12
|
+
hosts:
|
13
|
+
host1: [primary]
|
14
|
+
host2: []
|
15
|
+
YAML
|
16
|
+
@fake_cap = FakeCap.new
|
17
|
+
@server_roles = ServerRoles.new(@fake_cap, roles_yaml)
|
18
|
+
end
|
19
|
+
subject { @server_roles }
|
20
|
+
|
21
|
+
should have_reader :roles
|
22
|
+
should have_imeth :apply
|
23
|
+
|
24
|
+
should "build cap roles from yaml using the apply meth" do
|
25
|
+
subject.apply
|
26
|
+
roles = @fake_cap.roles.sort{|a,b| a[1] <=> b[1]}
|
27
|
+
|
28
|
+
assert_equal 2, @fake_cap.roles.size
|
29
|
+
assert_equal ['hosts', 'host2.reelfx.com', {}], roles.last
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
class ServerRoles
|
35
|
+
|
36
|
+
class RoleSetTests < Assert::Context
|
37
|
+
desc "the server roles RoleSet"
|
38
|
+
setup do
|
39
|
+
@roles_hash = {
|
40
|
+
'hosts' => {
|
41
|
+
'host1' => ['primary'],
|
42
|
+
'host2' => []
|
43
|
+
}
|
44
|
+
}
|
45
|
+
@role_set = RoleSet.new @roles_hash
|
46
|
+
end
|
47
|
+
subject { @role_set }
|
48
|
+
|
49
|
+
should have_reader :role_defs
|
50
|
+
should have_imeth :each
|
51
|
+
|
52
|
+
should "yield the name, hostname, and opts for each host/server when iterating the roles" do
|
53
|
+
exp = [
|
54
|
+
['hosts', 'host1.reelfx.com', {:primary => true, 'primary' => true}],
|
55
|
+
['hosts', 'host2.reelfx.com', {}]
|
56
|
+
]
|
57
|
+
actual = []
|
58
|
+
subject.each do |name, host, opts|
|
59
|
+
actual << [name, host, opts]
|
60
|
+
end
|
61
|
+
|
62
|
+
assert_equal exp, actual.sort{|a, b| a[1] <=> b[1]}
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class RoleDefTests < RoleSetTests
|
67
|
+
desc "the server roles RoleDef"
|
68
|
+
setup do
|
69
|
+
@role_servers_hash = {
|
70
|
+
'host1' => ['primary'],
|
71
|
+
'host2' => []
|
72
|
+
}
|
73
|
+
@role = RoleDef.new('hosts', @role_servers_hash)
|
74
|
+
end
|
75
|
+
subject { @role }
|
76
|
+
|
77
|
+
should have_reader :name, :servers
|
78
|
+
should have_imeth :apply
|
79
|
+
|
80
|
+
should "build a set of servers from a definition hash" do
|
81
|
+
servs = subject.servers.sort{|a, b| a.hostname <=> b.hostname }
|
82
|
+
|
83
|
+
assert_kind_of ::Array, servs
|
84
|
+
assert_equal 2, servs.size
|
85
|
+
assert_kind_of ServerDef, servs.first
|
86
|
+
assert_equal 'host2.reelfx.com', servs.last.hostname
|
87
|
+
assert_equal true, servs.first.options['primary']
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
class ServerDefTests < Assert::Context
|
93
|
+
desc "the server roles ServerDef"
|
94
|
+
setup do
|
95
|
+
@server = ServerDef.new('host1')
|
96
|
+
end
|
97
|
+
subject { @server }
|
98
|
+
|
99
|
+
should have_readers :hostname, :options
|
100
|
+
|
101
|
+
should "build its hostname from the server name" do
|
102
|
+
assert_equal "host1.reelfx.com", subject.hostname
|
103
|
+
end
|
104
|
+
|
105
|
+
should "have no options by defoult" do
|
106
|
+
assert_empty subject.options
|
107
|
+
end
|
108
|
+
|
109
|
+
should "build its options with both string and symbol keys" do
|
110
|
+
server = ServerDef.new('opts1', 'primary')
|
111
|
+
|
112
|
+
assert_equal true, server.options[:primary]
|
113
|
+
assert_equal true, server.options['primary']
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'assert'
|
2
|
+
|
3
|
+
require 'cap-util/server_roles_yaml'
|
4
|
+
|
5
|
+
module CapUtil
|
6
|
+
|
7
|
+
class ServerRolesYamlTests < Assert::Context
|
8
|
+
desc "the ServerRolesYaml util"
|
9
|
+
setup do
|
10
|
+
@roles_yaml = ServerRolesYaml.new(FakeCap.new )
|
11
|
+
end
|
12
|
+
subject { @roles_yaml }
|
13
|
+
|
14
|
+
should have_imeths :get, :validate, :valid?, :read
|
15
|
+
should have_reader :desc, :source
|
16
|
+
|
17
|
+
should "default the yaml's desc and source" do
|
18
|
+
assert_equal "server roles", subject.desc
|
19
|
+
assert_equal "", subject.source
|
20
|
+
end
|
21
|
+
|
22
|
+
should "use a custom desc and source if given" do
|
23
|
+
yml = ServerRolesYaml.new(FakeCap.new, {
|
24
|
+
:desc => 'staging',
|
25
|
+
:source => 'the place'
|
26
|
+
})
|
27
|
+
assert_equal "staging server roles", yml.desc
|
28
|
+
assert_equal " from the place", yml.source
|
29
|
+
end
|
30
|
+
|
31
|
+
should "raise appropriate NotImplementedErrors" do
|
32
|
+
assert_raises(NotImplementedError) { subject.validate }
|
33
|
+
assert_raises(NotImplementedError) { subject.valid? }
|
34
|
+
assert_raises(NotImplementedError) { subject.read }
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'assert'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'pathname'
|
4
|
+
|
5
|
+
require 'cap-util/shared_path'
|
6
|
+
|
7
|
+
module CapUtil
|
8
|
+
|
9
|
+
class SharedPathTests < Assert::Context
|
10
|
+
desc "the SharedPath util"
|
11
|
+
setup do
|
12
|
+
@fake_cap = FakeCap.new
|
13
|
+
@fake_cap.shared_path = Pathname.new File.expand_path("tmp/shared")
|
14
|
+
|
15
|
+
@shared_path = SharedPath.new(@fake_cap)
|
16
|
+
end
|
17
|
+
subject { @shared_path }
|
18
|
+
|
19
|
+
should have_imeths :rm_rf
|
20
|
+
|
21
|
+
should "remove a given relative path with the `rm_rf` method" do
|
22
|
+
subject.rm_rf 'cached-copy'
|
23
|
+
exp_cmd = "rm -rf #{File.expand_path("tmp/shared/cached-copy")}"
|
24
|
+
|
25
|
+
assert_equal [exp_cmd], @fake_cap.cmds_run.last
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cap-util
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 4
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.4.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Kelly Redding
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-10-
|
18
|
+
date: 2012-10-18 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: assert
|
@@ -78,19 +78,27 @@ files:
|
|
78
78
|
- cap-util.gemspec
|
79
79
|
- lib/cap-util.rb
|
80
80
|
- lib/cap-util/fake_cap.rb
|
81
|
+
- lib/cap-util/git_branch.rb
|
81
82
|
- lib/cap-util/halt.rb
|
82
83
|
- lib/cap-util/rake_task.rb
|
83
84
|
- lib/cap-util/run.rb
|
84
85
|
- lib/cap-util/say.rb
|
86
|
+
- lib/cap-util/server_roles.rb
|
87
|
+
- lib/cap-util/server_roles_yaml.rb
|
88
|
+
- lib/cap-util/shared_path.rb
|
85
89
|
- lib/cap-util/time.rb
|
86
90
|
- lib/cap-util/timer.rb
|
87
91
|
- lib/cap-util/unset_var.rb
|
88
92
|
- lib/cap-util/version.rb
|
89
93
|
- test/cap_util_tests.rb
|
90
94
|
- test/fake_cap_tests.rb
|
95
|
+
- test/git_branch_tests.rb
|
91
96
|
- test/helper.rb
|
92
97
|
- test/irb.rb
|
93
98
|
- test/rake_task_tests.rb
|
99
|
+
- test/server_roles_tests.rb
|
100
|
+
- test/server_roles_yaml_tests.rb
|
101
|
+
- test/shared_path_tests.rb
|
94
102
|
- test/timer_tests.rb
|
95
103
|
- test/unset_var_tests.rb
|
96
104
|
homepage: http://github.com/redding/cap-util
|
@@ -129,8 +137,12 @@ summary: A set of utilities for writing cap tasks.
|
|
129
137
|
test_files:
|
130
138
|
- test/cap_util_tests.rb
|
131
139
|
- test/fake_cap_tests.rb
|
140
|
+
- test/git_branch_tests.rb
|
132
141
|
- test/helper.rb
|
133
142
|
- test/irb.rb
|
134
143
|
- test/rake_task_tests.rb
|
144
|
+
- test/server_roles_tests.rb
|
145
|
+
- test/server_roles_yaml_tests.rb
|
146
|
+
- test/shared_path_tests.rb
|
135
147
|
- test/timer_tests.rb
|
136
148
|
- test/unset_var_tests.rb
|