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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 57e7b128b972ea3d1ef6479f4eff02bacd010969
4
- data.tar.gz: 433092dffd702bc42225e8b120cebe5eec7f26f0
3
+ metadata.gz: 687953197199b61ff409d6d2ca46af228ddd046b
4
+ data.tar.gz: 8ac0ee0ec0b9637728ca792c6e2b6301bd963acc
5
5
  SHA512:
6
- metadata.gz: e8da835126fc8f176e186dd0e503ce3c39379866257db1a9fffdb965a0232b941ae05e148b37ea60e65691c0375f1bbd9e0e3eccb6c89717661fe483ad833e63
7
- data.tar.gz: 4e29ddaee9c5f1522664e0458472f6c9b511193467520dd774bf8bce4e7f9217836c34024ecf8083984ee118d962a2730c2df3a620774a0ef6eebfd660da1f61
6
+ metadata.gz: ef1939faf699e13754e73d363725f4f8fb9ad448c022e88f4a11c98cb9041f00414f960422426342da392309774385fac921691e19027054e07a38119ae0ba89
7
+ data.tar.gz: bbd659c40f1589b2d7ff3c497f73052c1dc452158309df8b7e73385e8d754a7b0e789ceaa152c1449d8f166ac99e53474b8f6c85e2bdb4728f1a92b9a6a50e45
@@ -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
 
@@ -5,23 +5,42 @@ module Statistrano
5
5
  class Config
6
6
  include RakeTaskWithContextCreation
7
7
 
8
- attr_reader :options
9
- attr_reader :tasks
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=nil, tasks=nil
15
- @options = options.nil? ? {} : options.clone
16
- @tasks = tasks.nil? ? {} : tasks.clone
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
- @options[name] = args[0]
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"
@@ -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 = Shell.run_local "rsync #{rsync_options} " +
67
- "-e ssh #{local_path}/ " +
68
- "#{host_connection}:#{remote_path}/"
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
 
@@ -14,4 +14,4 @@ module Statistrano
14
14
  end
15
15
 
16
16
  end
17
- end
17
+ end
@@ -1,3 +1,3 @@
1
1
  module Statistrano
2
- VERSION = "1.2.3"
2
+ VERSION = "1.3.0"
3
3
  end
@@ -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 & tasks to a blank hash" do
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 & tasks, but clones so the originals don't get modified" do
19
- options = { foo: 'bar' }
20
- tasks = { foo: 'bar' }
21
- subject = described_class.new options, tasks
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.foo = 'baz'
24
- subject.tasks[:foo] = 'baz'
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
- end
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
- .merge(hostname: 'web01', remote_dir: 'web01_remote_dir'))
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.2.3
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-03-17 00:00:00.000000000 Z
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