statistrano 1.2.3 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/changelog.md +10 -0
- data/lib/statistrano/config.rb +39 -8
- data/lib/statistrano/config/configurable.rb +13 -4
- data/lib/statistrano/deployment/strategy/base.rb +4 -1
- data/lib/statistrano/deployment/strategy/branches.rb +4 -0
- data/lib/statistrano/deployment/strategy/releases.rb +9 -0
- data/lib/statistrano/remote.rb +11 -3
- data/lib/statistrano/shell.rb +1 -1
- data/lib/statistrano/version.rb +1 -1
- data/spec/lib/statistrano/config/configurable_spec.rb +14 -1
- data/spec/lib/statistrano/config_spec.rb +57 -8
- data/spec/lib/statistrano/deployment/strategy/base_spec.rb +16 -0
- data/spec/lib/statistrano/deployment/strategy/branches_spec.rb +13 -1
- data/spec/lib/statistrano/deployment/strategy/releases_spec.rb +34 -2
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 687953197199b61ff409d6d2ca46af228ddd046b
|
4
|
+
data.tar.gz: 8ac0ee0ec0b9637728ca792c6e2b6301bd963acc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ef1939faf699e13754e73d363725f4f8fb9ad448c022e88f4a11c98cb9041f00414f960422426342da392309774385fac921691e19027054e07a38119ae0ba89
|
7
|
+
data.tar.gz: bbd659c40f1589b2d7ff3c497f73052c1dc452158309df8b7e73385e8d754a7b0e789ceaa152c1449d8f166ac99e53474b8f6c85e2bdb4728f1a92b9a6a50e45
|
data/changelog.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
# 1.3.0
|
2
|
+
- feat(config validation) setup validators for some optons that could be descructive if not set:
|
3
|
+
```
|
4
|
+
Base: remote_dir
|
5
|
+
Branches: public_dir
|
6
|
+
Releases: release_count, public_dir, releases_dir
|
7
|
+
```
|
8
|
+
- refactor(config) change the internal method signature of Config to use keyword arguments `options`, and `tasks`
|
9
|
+
- add a `run_local` method to Remote to wrap `Shell.run_local` to display commands when in verbose mode.
|
10
|
+
|
1
11
|
# 1.2.3
|
2
12
|
- fix bug in manifest creation/saving from changes in ruby 2.2.x
|
3
13
|
|
data/lib/statistrano/config.rb
CHANGED
@@ -5,23 +5,42 @@ module Statistrano
|
|
5
5
|
class Config
|
6
6
|
include RakeTaskWithContextCreation
|
7
7
|
|
8
|
-
attr_reader :options
|
9
|
-
|
8
|
+
attr_reader :options,
|
9
|
+
:tasks,
|
10
|
+
:validators
|
10
11
|
|
11
12
|
# initalize with the potential for seed options
|
12
13
|
# this is required so that when config'd classes
|
13
14
|
# are extended we can pass that configuration along
|
14
|
-
def initialize options
|
15
|
-
@options
|
16
|
-
@tasks
|
15
|
+
def initialize options: nil, tasks: nil, validators: nil
|
16
|
+
@options = options.nil? ? {} : options.clone
|
17
|
+
@tasks = tasks.nil? ? {} : tasks.clone
|
18
|
+
@validators = validators.nil? ? {} : validators.clone
|
17
19
|
|
18
20
|
@options.each do |key,val|
|
19
21
|
define_option_accessor key.to_sym
|
20
22
|
end
|
23
|
+
|
24
|
+
@validators.each do |key,val|
|
25
|
+
define_validator key.to_sym
|
26
|
+
end
|
21
27
|
end
|
22
28
|
|
23
29
|
private
|
24
30
|
|
31
|
+
def define_validator name
|
32
|
+
define_singleton_method(:"validator_for_#{name}") do |proc, message|
|
33
|
+
@validators[name] = { validator: proc,
|
34
|
+
message: message }
|
35
|
+
end
|
36
|
+
|
37
|
+
define_singleton_method(:"validate_#{name}") do |arg|
|
38
|
+
if @validators.has_key?(name) && !@validators[name][:validator].call(arg)
|
39
|
+
raise ValidationError, (@validators[name][:message] || "configuration option for '#{name}' failed it's validation")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
25
44
|
def define_option_accessor name
|
26
45
|
define_singleton_method(name) do |*args, &block|
|
27
46
|
if block
|
@@ -34,13 +53,22 @@ module Statistrano
|
|
34
53
|
end
|
35
54
|
|
36
55
|
if args.length == 1
|
37
|
-
|
56
|
+
val = args[0]
|
57
|
+
|
58
|
+
if @validators.has_key?(name)
|
59
|
+
val = val.call if val.respond_to?(:call)
|
60
|
+
send "validate_#{name}", val
|
61
|
+
end
|
62
|
+
|
63
|
+
@options[name] = val
|
38
64
|
elsif args.empty?
|
39
65
|
if @options[name].respond_to? :fetch
|
40
|
-
@options[name].fetch( :call, -> { @options[name] } ).call
|
66
|
+
opt = @options[name].fetch( :call, -> { @options[name] } ).call
|
41
67
|
else
|
42
|
-
@options[name]
|
68
|
+
opt = @options[name]
|
43
69
|
end
|
70
|
+
|
71
|
+
opt
|
44
72
|
else
|
45
73
|
raise ArgumentError, "wrong number of arguments (#{args.length} for 0..1)"
|
46
74
|
end
|
@@ -48,5 +76,8 @@ module Statistrano
|
|
48
76
|
define_singleton_method("#{name}=") { |arg| @options[name] = arg }
|
49
77
|
end
|
50
78
|
|
79
|
+
class ValidationError < StandardError
|
80
|
+
end
|
81
|
+
|
51
82
|
end
|
52
83
|
end
|
@@ -6,7 +6,7 @@ module Statistrano
|
|
6
6
|
@_configuration ||= Config.new()
|
7
7
|
end
|
8
8
|
|
9
|
-
def option key, value=nil, proc=nil
|
9
|
+
def option key, value=nil, proc=nil, opts={}
|
10
10
|
if proc
|
11
11
|
configuration.options[key] = { call: proc }
|
12
12
|
else
|
@@ -14,6 +14,13 @@ module Statistrano
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
+
def validate key, proc, message=nil
|
18
|
+
configuration.validators[key] = { validator: proc }
|
19
|
+
if message
|
20
|
+
configuration.validators[key][:message] = message
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
17
24
|
def options *args
|
18
25
|
args.each { |a| option(a) }
|
19
26
|
end
|
@@ -32,8 +39,9 @@ module Statistrano
|
|
32
39
|
extending_obj.send :define_method,
|
33
40
|
:config,
|
34
41
|
-> {
|
35
|
-
@_config ||= Config.new( self.class.configuration.options,
|
36
|
-
self.class.configuration.tasks
|
42
|
+
@_config ||= Config.new( options: self.class.configuration.options,
|
43
|
+
tasks: self.class.configuration.tasks,
|
44
|
+
validators: self.class.configuration.validators )
|
37
45
|
}
|
38
46
|
end
|
39
47
|
|
@@ -45,9 +53,10 @@ module Statistrano
|
|
45
53
|
subclass.superclass.class_eval do
|
46
54
|
subclass.configuration.options.merge! subclass.superclass.configuration.options
|
47
55
|
subclass.configuration.tasks.merge! subclass.superclass.configuration.tasks
|
56
|
+
subclass.configuration.validators.merge! subclass.superclass.configuration.validators
|
48
57
|
end
|
49
58
|
end
|
50
59
|
|
51
60
|
end
|
52
61
|
end
|
53
|
-
end
|
62
|
+
end
|
@@ -29,6 +29,9 @@ module Statistrano
|
|
29
29
|
|
30
30
|
option :verbose, false
|
31
31
|
|
32
|
+
validate :remote_dir, lambda { |d| !d.empty? && d != '/' },
|
33
|
+
"'remote_dir' must not be empty or '/'"
|
34
|
+
|
32
35
|
task :deploy, :deploy, "Deploy to remote"
|
33
36
|
task :build, :invoke_build_task, "Run build task"
|
34
37
|
task :post_deploy, :invoke_post_deploy_task, "Run post deploy task"
|
@@ -84,7 +87,7 @@ module Statistrano
|
|
84
87
|
return @_remotes if @_remotes
|
85
88
|
|
86
89
|
@_remotes = config.options[:remotes].map do |remote_options|
|
87
|
-
Remote.new Config.new( config.options.dup.merge(remote_options) )
|
90
|
+
Remote.new Config.new( options: config.options.dup.merge(remote_options) )
|
88
91
|
end
|
89
92
|
@_remotes.push Remote.new(config) if @_remotes.empty?
|
90
93
|
|
@@ -16,11 +16,15 @@ module Statistrano
|
|
16
16
|
d.generate_index
|
17
17
|
}
|
18
18
|
|
19
|
+
validate :public_dir, lambda { |d| !d.to_s.empty? && d != '/' },
|
20
|
+
"'public_dir' can't be an empty string or '/'"
|
21
|
+
|
19
22
|
task :list, :list_releases, "List branches"
|
20
23
|
task :prune, :prune_releases, "Prune a branch"
|
21
24
|
task :generate_index, :generate_index, "Generate a branch index"
|
22
25
|
task :open, :open_url, "Open the current branch URL"
|
23
26
|
|
27
|
+
|
24
28
|
# output a list of the releases in manifest
|
25
29
|
# @return [Void]
|
26
30
|
def list_releases
|
@@ -35,6 +35,15 @@ module Statistrano
|
|
35
35
|
|
36
36
|
option :remotes, []
|
37
37
|
|
38
|
+
validate :release_dir, lambda { |d| !d.to_s.empty? && d != '/' },
|
39
|
+
"'release_dir' can't be an empty string or '/'"
|
40
|
+
|
41
|
+
validate :public_dir, lambda { |d| !d.to_s.empty? && d != '/' },
|
42
|
+
"'public_dir' can't be an empty string or '/'"
|
43
|
+
|
44
|
+
validate :release_count, lambda { |c| c.is_a?(Integer) && c > 0 },
|
45
|
+
"'release_count' must be an integer greater than 0"
|
46
|
+
|
38
47
|
task :deploy, :deploy, "Deploy to all remotes"
|
39
48
|
task :rollback, :rollback_release, "Rollback to the previous release"
|
40
49
|
task :prune, :prune_releases, "Prune releases to release count"
|
data/lib/statistrano/remote.rb
CHANGED
@@ -38,6 +38,14 @@ module Statistrano
|
|
38
38
|
session.run command
|
39
39
|
end
|
40
40
|
|
41
|
+
def run_local command
|
42
|
+
if config.verbose
|
43
|
+
Log.info :local, "running cmd: #{command}"
|
44
|
+
end
|
45
|
+
|
46
|
+
Shell.run_local command
|
47
|
+
end
|
48
|
+
|
41
49
|
def done
|
42
50
|
session.close_session
|
43
51
|
end
|
@@ -63,9 +71,9 @@ module Statistrano
|
|
63
71
|
Log.info "Syncing files from '#{local_path}' to '#{remote_path}' on #{config.hostname}"
|
64
72
|
|
65
73
|
time_before = Time.now
|
66
|
-
resp =
|
67
|
-
|
68
|
-
|
74
|
+
resp = run_local "rsync #{rsync_options} " +
|
75
|
+
"-e ssh #{local_path}/ " +
|
76
|
+
"#{host_connection}:#{remote_path}/"
|
69
77
|
time_after = Time.now
|
70
78
|
total_time = (time_after - time_before).round(2)
|
71
79
|
|
data/lib/statistrano/shell.rb
CHANGED
data/lib/statistrano/version.rb
CHANGED
@@ -11,6 +11,9 @@ describe Statistrano::Config::Configurable do
|
|
11
11
|
option :proc, -> { "hello" }
|
12
12
|
|
13
13
|
options :one, :two
|
14
|
+
|
15
|
+
validate :three, lambda { |arg| arg }
|
16
|
+
validate :four, lambda { |arg| arg }, "didn't pass"
|
14
17
|
end
|
15
18
|
end
|
16
19
|
|
@@ -47,6 +50,16 @@ describe Statistrano::Config::Configurable do
|
|
47
50
|
end
|
48
51
|
end
|
49
52
|
|
53
|
+
describe "#validate" do
|
54
|
+
it "adds valiator to configuration.validators" do
|
55
|
+
expect( subject.config.validators.keys ).to include :three
|
56
|
+
end
|
57
|
+
|
58
|
+
it "adds validator with description if given" do
|
59
|
+
expect( subject.config.validators[:four][:message] ).to eq "didn't pass"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
50
63
|
describe "option accessor" do
|
51
64
|
let(:config) { subject.config }
|
52
65
|
|
@@ -85,4 +98,4 @@ describe Statistrano::Config::Configurable do
|
|
85
98
|
end
|
86
99
|
|
87
100
|
|
88
|
-
end
|
101
|
+
end
|
@@ -3,31 +3,80 @@ require 'spec_helper'
|
|
3
3
|
describe Statistrano::Config do
|
4
4
|
|
5
5
|
describe "#initialize" do
|
6
|
-
it "defaults options &
|
6
|
+
it "defaults options, tasks, & validators to a blank hash" do
|
7
7
|
subject = described_class.new
|
8
8
|
|
9
9
|
expect( subject.options ).to eq({})
|
10
10
|
expect( subject.tasks ).to eq({})
|
11
|
+
expect( subject.validators ).to eq({})
|
11
12
|
end
|
12
13
|
|
13
14
|
it "defines an accessor for each given option" do
|
14
|
-
subject = described_class.new foo: 'bar'
|
15
|
+
subject = described_class.new options: { foo: 'bar' }
|
15
16
|
expect( subject.foo ).to eq 'bar'
|
16
17
|
end
|
17
18
|
|
18
|
-
it "uses given options
|
19
|
-
options
|
20
|
-
tasks
|
21
|
-
|
19
|
+
it "uses given options, tasks, and validators, but clones so the originals don't get modified" do
|
20
|
+
options = { foo: 'bar' }
|
21
|
+
tasks = { foo: 'bar' }
|
22
|
+
validators = { foo: { validator: lambda { |arg| arg } } }
|
22
23
|
|
23
|
-
subject
|
24
|
-
|
24
|
+
subject = described_class.new options: options, tasks: tasks, validators: validators
|
25
|
+
|
26
|
+
subject.foo = 'baz'
|
27
|
+
subject.tasks[:foo] = 'baz'
|
28
|
+
subject.validators[:foo] = { validator: lambda { |arg| 'baz' } }
|
25
29
|
|
26
30
|
expect( subject.foo ).to eq 'baz'
|
27
31
|
expect( options ).to eq foo: 'bar'
|
28
32
|
|
29
33
|
expect( subject.tasks ).to eq foo: 'baz'
|
30
34
|
expect( tasks ).to eq foo: 'bar'
|
35
|
+
|
36
|
+
expect( subject.validators[:foo][:validator].call('arg') ).to eq 'baz'
|
37
|
+
expect( validators[:foo][:validator].call('arg') ).to eq 'arg'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#accessor set" do
|
42
|
+
context "when a validator is set" do
|
43
|
+
let(:subject) do
|
44
|
+
subject = described_class.new options: { string: '', integer: '' },
|
45
|
+
validators: {
|
46
|
+
string: { validator: lambda { |i| !i.to_s.empty? } },
|
47
|
+
integer: { validator: lambda { |i| i.is_a?(Integer) } }
|
48
|
+
}
|
49
|
+
|
50
|
+
subject.validators[:integer][:message] = "not an integer"
|
51
|
+
|
52
|
+
subject
|
53
|
+
end
|
54
|
+
|
55
|
+
it "is peachy with a valid value" do
|
56
|
+
expect{
|
57
|
+
subject.validate_string 'a string'
|
58
|
+
}.not_to raise_error
|
59
|
+
end
|
60
|
+
|
61
|
+
it "raises when validating invalid value" do
|
62
|
+
expect{
|
63
|
+
subject.validate_string ''
|
64
|
+
}.to raise_error Statistrano::Config::ValidationError
|
65
|
+
end
|
66
|
+
|
67
|
+
it "raises while validating with given message" do
|
68
|
+
expect{
|
69
|
+
subject.validate_integer 'foobar'
|
70
|
+
}.to raise_error Statistrano::Config::ValidationError, 'not an integer'
|
71
|
+
end
|
72
|
+
|
73
|
+
it "raises when set to invalid value" do
|
74
|
+
expect{
|
75
|
+
subject.integer 'foo'
|
76
|
+
}.to raise_error Statistrano::Config::ValidationError
|
77
|
+
end
|
78
|
+
|
79
|
+
|
31
80
|
end
|
32
81
|
end
|
33
82
|
|
@@ -13,6 +13,22 @@ describe Statistrano::Deployment::Strategy::Base do
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
+
describe "config validation" do
|
17
|
+
it "doesn't allow remote_dir to be empty" do
|
18
|
+
subject = described_class.new "hello"
|
19
|
+
expect{
|
20
|
+
subject.config.remote_dir ""
|
21
|
+
}.to raise_error Statistrano::Config::ValidationError
|
22
|
+
end
|
23
|
+
|
24
|
+
it "doesn't allow you to set remote_dir as /" do
|
25
|
+
subject = described_class.new "hello"
|
26
|
+
expect{
|
27
|
+
subject.config.remote_dir "/"
|
28
|
+
}.to raise_error Statistrano::Config::ValidationError
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
16
32
|
describe "#deploy" do
|
17
33
|
|
18
34
|
before :each do
|
@@ -16,4 +16,16 @@ describe Statistrano::Deployment::Strategy::Branches do
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
|
19
|
+
it "validates public_dir not empty or '/'" do
|
20
|
+
deployment = described_class.new("name")
|
21
|
+
|
22
|
+
expect{
|
23
|
+
deployment.config.public_dir ""
|
24
|
+
}.to raise_error Statistrano::Config::ValidationError
|
25
|
+
|
26
|
+
expect{
|
27
|
+
deployment.config.public_dir "/"
|
28
|
+
}.to raise_error Statistrano::Config::ValidationError
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -6,6 +6,38 @@ describe Statistrano::Deployment::Strategy::Releases do
|
|
6
6
|
expect( Statistrano::Deployment::Strategy.find(:releases) ).to eq described_class
|
7
7
|
end
|
8
8
|
|
9
|
+
describe "config validation" do
|
10
|
+
let(:subject) { described_class.new('hello') }
|
11
|
+
|
12
|
+
it "prevents release_dir from being empty or '/'" do
|
13
|
+
expect{
|
14
|
+
subject.config.release_dir ''
|
15
|
+
}.to raise_error Statistrano::Config::ValidationError
|
16
|
+
|
17
|
+
expect{
|
18
|
+
subject.config.release_dir '/'
|
19
|
+
}.to raise_error Statistrano::Config::ValidationError
|
20
|
+
end
|
21
|
+
it "prevents public_dir from being empty or '/'" do
|
22
|
+
expect{
|
23
|
+
subject.config.public_dir ''
|
24
|
+
}.to raise_error Statistrano::Config::ValidationError
|
25
|
+
|
26
|
+
expect{
|
27
|
+
subject.config.public_dir '/'
|
28
|
+
}.to raise_error Statistrano::Config::ValidationError
|
29
|
+
end
|
30
|
+
it "requires release_count to be an integer > 0" do
|
31
|
+
expect{
|
32
|
+
subject.config.release_count 'four'
|
33
|
+
}.to raise_error Statistrano::Config::ValidationError
|
34
|
+
|
35
|
+
expect{
|
36
|
+
subject.config.release_count 0
|
37
|
+
}.to raise_error Statistrano::Config::ValidationError
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
9
41
|
describe "#remotes" do
|
10
42
|
|
11
43
|
let(:default_options) do
|
@@ -73,8 +105,8 @@ describe Statistrano::Deployment::Strategy::Releases do
|
|
73
105
|
|
74
106
|
config_double = instance_double("Statistrano::Config")
|
75
107
|
expect( Statistrano::Config ).to receive(:new)
|
76
|
-
.with(default_options.merge({remotes: [{hostname: 'web01', remote_dir: 'web01_remote_dir'}]})
|
77
|
-
|
108
|
+
.with( options: default_options.merge({remotes: [{hostname: 'web01', remote_dir: 'web01_remote_dir'}]})
|
109
|
+
.merge(hostname: 'web01', remote_dir: 'web01_remote_dir'))
|
78
110
|
.and_return(config_double)
|
79
111
|
expect( Statistrano::Remote ).to receive(:new)
|
80
112
|
.with(config_double)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: statistrano
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jordan Andree
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-
|
12
|
+
date: 2015-11-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -184,7 +184,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
184
184
|
version: '0'
|
185
185
|
requirements: []
|
186
186
|
rubyforge_project:
|
187
|
-
rubygems_version: 2.4.5
|
187
|
+
rubygems_version: 2.4.5.1
|
188
188
|
signing_key:
|
189
189
|
specification_version: 4
|
190
190
|
summary: deployment tool for static sites
|