statistrano 1.2.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.
- checksums.yaml +7 -0
- data/changelog.md +161 -0
- data/doc/config/file-permissions.md +33 -0
- data/doc/config/log-files.md +32 -0
- data/doc/config/task-definitions.md +88 -0
- data/doc/getting-started.md +96 -0
- data/doc/strategies/base.md +38 -0
- data/doc/strategies/branches.md +82 -0
- data/doc/strategies/releases.md +110 -0
- data/doc/strategies.md +17 -0
- data/lib/statistrano/config/configurable.rb +53 -0
- data/lib/statistrano/config/rake_task_with_context_creation.rb +43 -0
- data/lib/statistrano/config.rb +52 -0
- data/lib/statistrano/deployment/log_file.rb +44 -0
- data/lib/statistrano/deployment/manifest.rb +88 -0
- data/lib/statistrano/deployment/rake_tasks.rb +74 -0
- data/lib/statistrano/deployment/registerable.rb +11 -0
- data/lib/statistrano/deployment/releaser/revisions.rb +163 -0
- data/lib/statistrano/deployment/releaser/single.rb +48 -0
- data/lib/statistrano/deployment/releaser.rb +2 -0
- data/lib/statistrano/deployment/strategy/base.rb +132 -0
- data/lib/statistrano/deployment/strategy/branches/index/template.html.erb +78 -0
- data/lib/statistrano/deployment/strategy/branches/index.rb +40 -0
- data/lib/statistrano/deployment/strategy/branches/release.rb +73 -0
- data/lib/statistrano/deployment/strategy/branches.rb +198 -0
- data/lib/statistrano/deployment/strategy/check_git.rb +43 -0
- data/lib/statistrano/deployment/strategy/invoke_tasks.rb +58 -0
- data/lib/statistrano/deployment/strategy/releases.rb +76 -0
- data/lib/statistrano/deployment/strategy.rb +37 -0
- data/lib/statistrano/deployment.rb +10 -0
- data/lib/statistrano/log/default_logger.rb +105 -0
- data/lib/statistrano/log.rb +33 -0
- data/lib/statistrano/remote/file.rb +79 -0
- data/lib/statistrano/remote.rb +111 -0
- data/lib/statistrano/shell.rb +17 -0
- data/lib/statistrano/util/file_permissions.rb +34 -0
- data/lib/statistrano/util.rb +27 -0
- data/lib/statistrano/version.rb +3 -0
- data/lib/statistrano.rb +55 -0
- data/readme.md +247 -0
- data/spec/integration_tests/base_integration_spec.rb +103 -0
- data/spec/integration_tests/branches_integration_spec.rb +189 -0
- data/spec/integration_tests/releases/deploy_integration_spec.rb +116 -0
- data/spec/integration_tests/releases/list_releases_integration_spec.rb +38 -0
- data/spec/integration_tests/releases/prune_releases_integration_spec.rb +86 -0
- data/spec/integration_tests/releases/rollback_release_integration_spec.rb +46 -0
- data/spec/lib/statistrano/config/configurable_spec.rb +88 -0
- data/spec/lib/statistrano/config/rake_task_with_context_creation_spec.rb +73 -0
- data/spec/lib/statistrano/config_spec.rb +34 -0
- data/spec/lib/statistrano/deployment/log_file_spec.rb +75 -0
- data/spec/lib/statistrano/deployment/manifest_spec.rb +171 -0
- data/spec/lib/statistrano/deployment/rake_tasks_spec.rb +107 -0
- data/spec/lib/statistrano/deployment/registerable_spec.rb +19 -0
- data/spec/lib/statistrano/deployment/releaser/revisions_spec.rb +486 -0
- data/spec/lib/statistrano/deployment/releaser/single_spec.rb +59 -0
- data/spec/lib/statistrano/deployment/strategy/base_spec.rb +158 -0
- data/spec/lib/statistrano/deployment/strategy/branches_spec.rb +19 -0
- data/spec/lib/statistrano/deployment/strategy/check_git_spec.rb +39 -0
- data/spec/lib/statistrano/deployment/strategy/invoke_tasks_spec.rb +66 -0
- data/spec/lib/statistrano/deployment/strategy/releases_spec.rb +257 -0
- data/spec/lib/statistrano/deployment/strategy_spec.rb +76 -0
- data/spec/lib/statistrano/deployment_spec.rb +4 -0
- data/spec/lib/statistrano/log/default_logger_spec.rb +172 -0
- data/spec/lib/statistrano/log_spec.rb +36 -0
- data/spec/lib/statistrano/remote/file_spec.rb +166 -0
- data/spec/lib/statistrano/remote_spec.rb +226 -0
- data/spec/lib/statistrano/util/file_permissions_spec.rb +25 -0
- data/spec/lib/statistrano/util_spec.rb +23 -0
- data/spec/lib/statistrano_spec.rb +52 -0
- data/spec/spec_helper.rb +86 -0
- data/spec/support/given.rb +39 -0
- metadata +223 -0
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Statistrano::Deployment::Strategy::Releases#prune_releases integration", :integration do
|
4
|
+
|
5
|
+
context "with multiple_targets target" do
|
6
|
+
|
7
|
+
before :each do
|
8
|
+
Given.fixture "releases-deployed"
|
9
|
+
@subject = define_deployment "releases", :releases do
|
10
|
+
build_task "remote:copy"
|
11
|
+
local_dir "build"
|
12
|
+
hostname "localhost"
|
13
|
+
remote_dir File.join( Dir.pwd, "deployment" )
|
14
|
+
|
15
|
+
release_count 1
|
16
|
+
remotes [
|
17
|
+
{ remote_dir: File.join( Dir.pwd, "deployment", "target01" ) },
|
18
|
+
{ remote_dir: File.join( Dir.pwd, "deployment", "target02" ) },
|
19
|
+
{ remote_dir: File.join( Dir.pwd, "deployment", "target03" ) }
|
20
|
+
]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
after :each do
|
25
|
+
Given.cleanup!
|
26
|
+
end
|
27
|
+
|
28
|
+
it "removes older releases beyond release count" do
|
29
|
+
@subject.prune_releases
|
30
|
+
expect( multi_release_folder_contents )
|
31
|
+
.to match_array [ "target01/releases/1372040000",
|
32
|
+
"target02/releases/1372040000",
|
33
|
+
"target03/releases/1372040000" ]
|
34
|
+
end
|
35
|
+
|
36
|
+
it "removes stray/untracked releases" do
|
37
|
+
Given.file "deployment/target01/releases/foo_bar/index.html", ''
|
38
|
+
Given.file "deployment/target02/releases/foo_bar/index.html", ''
|
39
|
+
Given.file "deployment/target03/releases/foo_bar/index.html", ''
|
40
|
+
@subject.prune_releases
|
41
|
+
expect( multi_release_folder_contents )
|
42
|
+
.to match_array [ "target01/releases/1372040000",
|
43
|
+
"target02/releases/1372040000",
|
44
|
+
"target03/releases/1372040000" ]
|
45
|
+
end
|
46
|
+
|
47
|
+
it "won't remove the currently symlinked release" do
|
48
|
+
Given.symlink "deployment/target01/releases/1372030000", "deployment/target01/current"
|
49
|
+
Given.symlink "deployment/target02/releases/1372030000", "deployment/target02/current"
|
50
|
+
Given.symlink "deployment/target03/releases/1372030000", "deployment/target03/current"
|
51
|
+
|
52
|
+
@subject.prune_releases
|
53
|
+
|
54
|
+
expect( multi_release_folder_contents )
|
55
|
+
.to match_array [ "target01/releases/1372030000",
|
56
|
+
"target01/releases/1372040000",
|
57
|
+
|
58
|
+
"target02/releases/1372030000",
|
59
|
+
"target02/releases/1372040000",
|
60
|
+
|
61
|
+
"target03/releases/1372030000",
|
62
|
+
"target03/releases/1372040000" ]
|
63
|
+
end
|
64
|
+
|
65
|
+
it "won't remove the currently symlinked release even if untracked" do
|
66
|
+
Given.file "deployment/target01/releases/foo_bar/index.html", ''
|
67
|
+
Given.file "deployment/target02/releases/foo_bar/index.html", ''
|
68
|
+
Given.file "deployment/target03/releases/foo_bar/index.html", ''
|
69
|
+
Given.symlink "deployment/target01/releases/foo_bar", "deployment/target01/current"
|
70
|
+
Given.symlink "deployment/target02/releases/foo_bar", "deployment/target02/current"
|
71
|
+
Given.symlink "deployment/target03/releases/foo_bar", "deployment/target03/current"
|
72
|
+
|
73
|
+
@subject.prune_releases
|
74
|
+
|
75
|
+
expect( multi_release_folder_contents )
|
76
|
+
.to match_array [ "target01/releases/foo_bar",
|
77
|
+
"target01/releases/1372040000",
|
78
|
+
|
79
|
+
"target02/releases/foo_bar",
|
80
|
+
"target02/releases/1372040000",
|
81
|
+
|
82
|
+
"target03/releases/foo_bar",
|
83
|
+
"target03/releases/1372040000" ]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Statistrano::Deployment::Strategy::Releases#rollback_release integration", :integration do
|
4
|
+
|
5
|
+
context "with multiple_targets target" do
|
6
|
+
|
7
|
+
before :each do
|
8
|
+
Given.fixture "releases-deployed"
|
9
|
+
@subject = define_deployment "releases", :releases do
|
10
|
+
build_task "remote:copy"
|
11
|
+
local_dir "build"
|
12
|
+
hostname "localhost"
|
13
|
+
remote_dir File.join( Dir.pwd, "deployment" )
|
14
|
+
|
15
|
+
release_count 2
|
16
|
+
remotes [
|
17
|
+
{ remote_dir: File.join( Dir.pwd, "deployment", "target01" ) },
|
18
|
+
{ remote_dir: File.join( Dir.pwd, "deployment", "target02" ) },
|
19
|
+
{ remote_dir: File.join( Dir.pwd, "deployment", "target03" ) }
|
20
|
+
]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
after :each do
|
25
|
+
Given.cleanup!
|
26
|
+
end
|
27
|
+
|
28
|
+
it "reverts to the previous release" do
|
29
|
+
# just to verify that 137204000 is the current release
|
30
|
+
# on all targets
|
31
|
+
["target01","target02","target03"].each do |target|
|
32
|
+
ls_before = HereOrThere::Local.new.run("ls -la deployment/#{target}")
|
33
|
+
expect( ls_before.stdout ).to match /current ->(.+)tmp\/deployment\/#{target}\/releases\/1372040000/
|
34
|
+
end
|
35
|
+
|
36
|
+
@subject.rollback_release
|
37
|
+
|
38
|
+
["target01","target02","target03"].each do |target|
|
39
|
+
ls_after = HereOrThere::Local.new.run("ls -la deployment/#{target}")
|
40
|
+
expect( ls_after.stdout ).to match /current ->(.+)tmp\/deployment\/#{target}\/releases\/1372030000/
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Statistrano::Config::Configurable do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
class Subject
|
7
|
+
extend ::Statistrano::Config::Configurable
|
8
|
+
|
9
|
+
option :foo, "bar"
|
10
|
+
option :wu
|
11
|
+
option :proc, -> { "hello" }
|
12
|
+
|
13
|
+
options :one, :two
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:subject) { Subject.new }
|
18
|
+
|
19
|
+
describe "#option" do
|
20
|
+
|
21
|
+
it "sets the given default value" do
|
22
|
+
expect( subject.config.foo ).to eq("bar")
|
23
|
+
end
|
24
|
+
|
25
|
+
it "defaults to setting nil" do
|
26
|
+
expect( subject.config.wu ).to be_nil
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
describe "#options" do
|
33
|
+
it "creates an accessor for each given option" do
|
34
|
+
names = [:one,:two]
|
35
|
+
|
36
|
+
names.each do |meth|
|
37
|
+
expect( subject.config.respond_to? meth ).to be_truthy
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
it "defaults those values to nil" do
|
42
|
+
names = [:one,:two]
|
43
|
+
|
44
|
+
names.each do |meth|
|
45
|
+
expect( subject.config.public_send meth ).to be_nil
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "option accessor" do
|
51
|
+
let(:config) { subject.config }
|
52
|
+
|
53
|
+
it "returns the value if given no arguments" do
|
54
|
+
expect( config.foo ).to eq("bar")
|
55
|
+
end
|
56
|
+
|
57
|
+
it "sets the value if given one argument" do
|
58
|
+
config.foo "baz"
|
59
|
+
expect( config.foo ).to eq("baz")
|
60
|
+
end
|
61
|
+
|
62
|
+
it "sets the value if given an #=" do
|
63
|
+
config.foo = "badazz"
|
64
|
+
expect( config.foo ).to eq("badazz")
|
65
|
+
end
|
66
|
+
|
67
|
+
it "sets the value to a block if given one" do
|
68
|
+
config.foo do
|
69
|
+
"badazz"
|
70
|
+
end
|
71
|
+
expect( config.foo.call ).to eq "badazz"
|
72
|
+
end
|
73
|
+
|
74
|
+
it "calls a block if `:call` is passed" do
|
75
|
+
config.foo :call do
|
76
|
+
"badazz"
|
77
|
+
end
|
78
|
+
expect( config.foo ).to eq "badazz"
|
79
|
+
end
|
80
|
+
|
81
|
+
it "raises and ArgumentError if given more than 1 argument" do
|
82
|
+
expect{ config.foo "bar", "baz" }.to raise_error ArgumentError
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Statistrano::Config::RakeTaskWithContextCreation do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
Subject = Class.new
|
7
|
+
Subject.send(:include, described_class)
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "::included" do
|
11
|
+
it "creates user_task_namespaces method defaulting to []" do
|
12
|
+
expect( Subject.new.methods ).to include :user_task_namespaces
|
13
|
+
expect( Subject.new.user_task_namespaces ).to eq []
|
14
|
+
end
|
15
|
+
|
16
|
+
it "creates user_tasks method defaulting to []" do
|
17
|
+
expect( Subject.new.methods ).to include :user_tasks
|
18
|
+
expect( Subject.new.user_tasks ).to eq []
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#task" do
|
23
|
+
it "adds a task to the user_tasks store with name and namespaces" do
|
24
|
+
subject = Subject.new
|
25
|
+
block = lambda { }
|
26
|
+
subject.task 'hello', &block
|
27
|
+
|
28
|
+
expect( subject.user_tasks ).to include name: 'hello',
|
29
|
+
namespaces: [],
|
30
|
+
block: block
|
31
|
+
end
|
32
|
+
|
33
|
+
it "adds optional desc to task" do
|
34
|
+
subject = Subject.new
|
35
|
+
block = lambda { }
|
36
|
+
subject.task 'hello', 'I a method', &block
|
37
|
+
|
38
|
+
expect( subject.user_tasks ).to include name: 'hello',
|
39
|
+
desc: 'I a method',
|
40
|
+
namespaces: [],
|
41
|
+
block: block
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "#namespace" do
|
46
|
+
it "evaluates given block appending the namespaces" do
|
47
|
+
subject = Subject.new
|
48
|
+
block = lambda { }
|
49
|
+
|
50
|
+
subject.namespace 'hello' do
|
51
|
+
task 'world', &block
|
52
|
+
|
53
|
+
namespace 'foo' do
|
54
|
+
task 'bar', &block
|
55
|
+
task 'bang', &block
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
expect( subject.user_tasks ).to include name: 'world',
|
60
|
+
namespaces: ['hello'],
|
61
|
+
block: block
|
62
|
+
|
63
|
+
expect( subject.user_tasks ).to include name: 'bar',
|
64
|
+
namespaces: ['hello', 'foo'],
|
65
|
+
block: block
|
66
|
+
|
67
|
+
expect( subject.user_tasks ).to include name: 'bang',
|
68
|
+
namespaces: ['hello', 'foo'],
|
69
|
+
block: block
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Statistrano::Config do
|
4
|
+
|
5
|
+
describe "#initialize" do
|
6
|
+
it "defaults options & tasks to a blank hash" do
|
7
|
+
subject = described_class.new
|
8
|
+
|
9
|
+
expect( subject.options ).to eq({})
|
10
|
+
expect( subject.tasks ).to eq({})
|
11
|
+
end
|
12
|
+
|
13
|
+
it "defines an accessor for each given option" do
|
14
|
+
subject = described_class.new foo: 'bar'
|
15
|
+
expect( subject.foo ).to eq 'bar'
|
16
|
+
end
|
17
|
+
|
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
|
22
|
+
|
23
|
+
subject.foo = 'baz'
|
24
|
+
subject.tasks[:foo] = 'baz'
|
25
|
+
|
26
|
+
expect( subject.foo ).to eq 'baz'
|
27
|
+
expect( options ).to eq foo: 'bar'
|
28
|
+
|
29
|
+
expect( subject.tasks ).to eq foo: 'baz'
|
30
|
+
expect( tasks ).to eq foo: 'bar'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Statistrano::Deployment::LogFile do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
config = double("Statistrano::Config", remote_dir: '/remote_dir')
|
7
|
+
@remote = instance_double("Statistrano::Remote", config: config)
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#initialize" do
|
11
|
+
|
12
|
+
it "sets :remote to the given remote" do
|
13
|
+
subject = described_class.new 'foo/bar', @remote
|
14
|
+
expect( subject.remote ).to eq @remote
|
15
|
+
end
|
16
|
+
it "sets resolved_path to given path if absolute" do
|
17
|
+
subject = described_class.new '/var/log', @remote
|
18
|
+
expect( subject.resolved_path ).to eq '/var/log'
|
19
|
+
end
|
20
|
+
it "sets resolved_path relative to remote.config.remote_dir if relative" do
|
21
|
+
subject = described_class.new 'var/log', @remote
|
22
|
+
expect( subject.resolved_path ).to eq '/remote_dir/var/log'
|
23
|
+
end
|
24
|
+
it "sets file to Remote::File created with resolved_path and remote" do
|
25
|
+
expect( Statistrano::Remote::File ).to receive(:new)
|
26
|
+
.with( '/var/log', @remote )
|
27
|
+
|
28
|
+
described_class.new '/var/log', @remote
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#append!" do
|
33
|
+
it "calls #append_content! on Remote::File with entry converted to json" do
|
34
|
+
remote_file_double = instance_double("Statistrano::Remote::File")
|
35
|
+
allow( Statistrano::Remote::File ).to receive(:new)
|
36
|
+
.with( '/var/log', @remote )
|
37
|
+
.and_return(remote_file_double)
|
38
|
+
subject = described_class.new '/var/log', @remote
|
39
|
+
|
40
|
+
expect( remote_file_double ).to receive(:append_content!)
|
41
|
+
.with('{"log":"entry"}')
|
42
|
+
|
43
|
+
subject.append! log: 'entry'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#last_entry" do
|
48
|
+
|
49
|
+
before :each do
|
50
|
+
@remote_file_double = instance_double("Statistrano::Remote::File")
|
51
|
+
allow( Statistrano::Remote::File ).to receive(:new)
|
52
|
+
.with( '/var/log', @remote )
|
53
|
+
.and_return(@remote_file_double)
|
54
|
+
@subject = described_class.new '/var/log', @remote
|
55
|
+
end
|
56
|
+
|
57
|
+
it "returns hash of last entry data" do
|
58
|
+
allow( @remote_file_double ).to receive(:content)
|
59
|
+
.and_return "{\"log\":1}\n{\"log\":2}"
|
60
|
+
|
61
|
+
expect( @subject.last_entry ).to eq log: 2
|
62
|
+
end
|
63
|
+
|
64
|
+
it "returns empty hash if no entries" do
|
65
|
+
allow( @remote_file_double ).to receive(:content)
|
66
|
+
.and_return ""
|
67
|
+
|
68
|
+
expect( @subject.last_entry ).to eq({})
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "#tail" do
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Statistrano::Deployment::Manifest do
|
4
|
+
|
5
|
+
describe "#initialize" do
|
6
|
+
it "stores the provided remote_dir & remote" do
|
7
|
+
subject = described_class.new( "remote_dir", "remote" )
|
8
|
+
|
9
|
+
expect( subject.remote_dir ).to eq "remote_dir"
|
10
|
+
expect( subject.remote ).to eq "remote"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#data" do
|
15
|
+
it "returns serialized data from remote" do
|
16
|
+
remote = instance_double("Statistrano::Remote")
|
17
|
+
file = instance_double("Statistrano::Remote::File")
|
18
|
+
expect( Statistrano::Remote::File ).to receive(:new)
|
19
|
+
.and_return(file)
|
20
|
+
subject = described_class.new '/var/www/proj', remote
|
21
|
+
expect( file ).to receive(:content)
|
22
|
+
.and_return('[{"key":"val"}]')
|
23
|
+
|
24
|
+
expect( subject.data ).to match_array [{ key: 'val' }]
|
25
|
+
end
|
26
|
+
|
27
|
+
it "returns empty array if manifest file is missing" do
|
28
|
+
remote = instance_double("Statistrano::Remote")
|
29
|
+
file = instance_double("Statistrano::Remote::File")
|
30
|
+
expect( Statistrano::Remote::File ).to receive(:new)
|
31
|
+
.and_return(file)
|
32
|
+
expect( file ).to receive(:content)
|
33
|
+
.and_return('')
|
34
|
+
subject = described_class.new '/var/www/proj', remote
|
35
|
+
|
36
|
+
expect( subject.data ).to match_array []
|
37
|
+
end
|
38
|
+
|
39
|
+
it "logs error when manifest contains invalid JSON" do
|
40
|
+
config = double("Statistrano::Config", hostname: 'web01')
|
41
|
+
remote = instance_double("Statistrano::Remote", config: config )
|
42
|
+
file = instance_double("Statistrano::Remote::File")
|
43
|
+
expect( Statistrano::Remote::File ).to receive(:new)
|
44
|
+
.and_return(file)
|
45
|
+
subject = described_class.new '/var/www/proj', remote
|
46
|
+
expect( file ).to receive(:content)
|
47
|
+
.and_return('invalid')
|
48
|
+
expect( Statistrano::Log ).to receive(:error)
|
49
|
+
subject.data
|
50
|
+
end
|
51
|
+
|
52
|
+
it "returns @_data if set" do
|
53
|
+
remote = instance_double("Statistrano::Remote")
|
54
|
+
subject = described_class.new '/var/www/proj', remote
|
55
|
+
|
56
|
+
subject.instance_variable_set(:@_data, 'data')
|
57
|
+
expect( subject.data ).to eq 'data'
|
58
|
+
end
|
59
|
+
|
60
|
+
it "sets @_data with return" do
|
61
|
+
remote = instance_double("Statistrano::Remote")
|
62
|
+
subject = described_class.new '/var/www/proj', remote
|
63
|
+
allow( remote ).to receive(:run).and_return( HereOrThere::Response.new('[{"key":"val"}]','',true) )
|
64
|
+
|
65
|
+
data = subject.data
|
66
|
+
expect( subject.instance_variable_get(:@_data) ).to eq data
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "#push" do
|
71
|
+
it "adds data to the data array" do
|
72
|
+
remote = instance_double("Statistrano::Remote")
|
73
|
+
allow( remote ).to receive(:run).and_return( HereOrThere::Response.new('[{"key":"val"}]','',true) )
|
74
|
+
subject = described_class.new '/var/www/proj', remote
|
75
|
+
|
76
|
+
new_data = {foo: 'bar'}
|
77
|
+
subject.push new_data
|
78
|
+
expect( subject.data ).to include new_data
|
79
|
+
end
|
80
|
+
|
81
|
+
it "symbolizes keys in passed data" do
|
82
|
+
remote = instance_double("Statistrano::Remote")
|
83
|
+
allow( remote ).to receive(:run).and_return( HereOrThere::Response.new('[{"key":"val"}]','',true) )
|
84
|
+
subject = described_class.new '/var/www/proj', remote
|
85
|
+
|
86
|
+
new_data = {"foo" => 'bar'}
|
87
|
+
subject.push new_data
|
88
|
+
expect( subject.data ).to include foo: 'bar'
|
89
|
+
end
|
90
|
+
|
91
|
+
it "raises error if provided data cannot be converted to JSON" do
|
92
|
+
remote = instance_double("Statistrano::Remote")
|
93
|
+
allow( remote ).to receive(:run).and_return( HereOrThere::Response.new('[{"key":"val"}]','',true) )
|
94
|
+
subject = described_class.new '/var/www/proj', remote
|
95
|
+
|
96
|
+
data = double
|
97
|
+
expect( data ).to receive(:respond_to?)
|
98
|
+
.with(:to_json).and_return(false)
|
99
|
+
|
100
|
+
expect{
|
101
|
+
subject.push data
|
102
|
+
}.to raise_error ArgumentError, "data must be serializable as JSON"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe "#put" do
|
107
|
+
# a "safer" version of `push`, will update a
|
108
|
+
# data_glob in place matched on key
|
109
|
+
let(:remote) { instance_double("Statistrano::Remote") }
|
110
|
+
|
111
|
+
context "when item doesn't exist" do
|
112
|
+
it "adds the item w/o disturbing existing data" do
|
113
|
+
subject = described_class.new "remote_dir", remote
|
114
|
+
allow( remote ).to receive(:run)
|
115
|
+
.and_return( HereOrThere::Response.new('[{"key":"val"}]','',true) )
|
116
|
+
|
117
|
+
subject.put( { foo: "bar" }, :foo )
|
118
|
+
expect( subject.data ).to match_array [{key: "val"},{foo: "bar"}]
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
context "when item does exist" do
|
123
|
+
it "updates the item w/o distrubing existing data" do
|
124
|
+
subject = described_class.new "remote_dir", remote
|
125
|
+
allow( remote ).to receive(:run)
|
126
|
+
.and_return( HereOrThere::Response.new('[{"key":"val"},{"key":"foo","marker":"orig"}]','',true) )
|
127
|
+
|
128
|
+
subject.put( {key:"foo",marker:"new"}, :key )
|
129
|
+
expect( subject.data ).to match_array [{key: "val"},{key:"foo",marker:"new"}]
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe "#remove_if" do
|
135
|
+
it "removes data that matches the condition" do
|
136
|
+
remote = instance_double("Statistrano::Remote")
|
137
|
+
allow( remote ).to receive(:run).and_return( HereOrThere::Response.new('[{"key":"val"}]','',true) )
|
138
|
+
subject = described_class.new '/var/www/proj', remote
|
139
|
+
|
140
|
+
subject.remove_if { |item| item.has_key?(:key) }
|
141
|
+
expect( subject.data ).to match_array []
|
142
|
+
end
|
143
|
+
it "retains data that doesn't match condition" do
|
144
|
+
remote = instance_double("Statistrano::Remote")
|
145
|
+
allow( remote ).to receive(:run).and_return( HereOrThere::Response.new('[{"key":"val"}]','',true) )
|
146
|
+
subject = described_class.new '/var/www/proj', remote
|
147
|
+
|
148
|
+
subject.remove_if { |item| !item.has_key?(:key) }
|
149
|
+
expect( subject.data ).to match_array [{key:"val"}]
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
describe "#save!" do
|
154
|
+
it "calls update_content! for the remote_file" do
|
155
|
+
remote = instance_double("Statistrano::Remote")
|
156
|
+
file = instance_double("Statistrano::Remote::File")
|
157
|
+
|
158
|
+
expect( Statistrano::Remote::File ).to receive(:new)
|
159
|
+
.with("/path/manifest.json", remote)
|
160
|
+
.and_return(file)
|
161
|
+
expect( file ).to receive(:update_content!)
|
162
|
+
.with('[{"key":"val"}]')
|
163
|
+
|
164
|
+
subject = described_class.new "/path", remote
|
165
|
+
subject.instance_variable_set(:@_data, [{key: "val"}])
|
166
|
+
|
167
|
+
subject.save!
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Statistrano::Deployment::RakeTasks do
|
4
|
+
|
5
|
+
describe "::register" do
|
6
|
+
|
7
|
+
context "config tasks" do
|
8
|
+
before :each do
|
9
|
+
class RakeTasksSubject
|
10
|
+
extend Statistrano::Config::Configurable
|
11
|
+
include Statistrano::Deployment::Strategy::InvokeTasks
|
12
|
+
|
13
|
+
attr_reader :name
|
14
|
+
|
15
|
+
task :foo, :bar, "baz"
|
16
|
+
|
17
|
+
def initialize name
|
18
|
+
@name = name
|
19
|
+
end
|
20
|
+
|
21
|
+
def bar
|
22
|
+
"baz"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
after :each do
|
28
|
+
Rake::Task.clear
|
29
|
+
end
|
30
|
+
|
31
|
+
it "registers tasks using deployment's name as namespace" do
|
32
|
+
described_class.register RakeTasksSubject.new "woo"
|
33
|
+
expect( Rake::Task.tasks.map(&:to_s) ).to include 'woo:foo'
|
34
|
+
end
|
35
|
+
|
36
|
+
it "calls the tasks matching method on the deployment" do
|
37
|
+
subject = RakeTasksSubject.new "woo"
|
38
|
+
described_class.register subject
|
39
|
+
|
40
|
+
expect( subject ).to receive(:bar)
|
41
|
+
|
42
|
+
Rake::Task['woo:foo'].invoke
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context "user_tasks" do
|
47
|
+
|
48
|
+
after :each do
|
49
|
+
Rake::Task.clear
|
50
|
+
end
|
51
|
+
|
52
|
+
it "adds the task in the correct namespace" do
|
53
|
+
config = Statistrano::Config.new
|
54
|
+
deployment_double = instance_double("Statistrano::Deployment::Strategy::Base", name: 'name', config: config)
|
55
|
+
config.user_tasks.push name: 'start',
|
56
|
+
namespaces: ['puma'],
|
57
|
+
block: lambda { }
|
58
|
+
|
59
|
+
described_class.register deployment_double
|
60
|
+
|
61
|
+
expect( Rake::Task.tasks.map(&:to_s) ).to include 'name:puma:start'
|
62
|
+
end
|
63
|
+
|
64
|
+
it "registers the task at top level if no namespaces" do
|
65
|
+
config = Statistrano::Config.new
|
66
|
+
deployment_double = instance_double("Statistrano::Deployment::Strategy::Base", name: 'name', config: config)
|
67
|
+
config.user_tasks.push name: 'start',
|
68
|
+
namespaces: [],
|
69
|
+
block: lambda { }
|
70
|
+
|
71
|
+
described_class.register deployment_double
|
72
|
+
|
73
|
+
expect( Rake::Task.tasks.map(&:to_s) ).to include 'name:start'
|
74
|
+
end
|
75
|
+
|
76
|
+
it "adds description if given" do
|
77
|
+
config = Statistrano::Config.new
|
78
|
+
deployment_double = instance_double("Statistrano::Deployment::Strategy::Base", name: 'name', config: config)
|
79
|
+
config.user_tasks.push name: 'start',
|
80
|
+
desc: 'start something',
|
81
|
+
namespaces: [],
|
82
|
+
block: lambda { }
|
83
|
+
|
84
|
+
described_class.register deployment_double
|
85
|
+
|
86
|
+
expect( Rake::Task.tasks.map(&:to_s) ).to include 'name:start'
|
87
|
+
expect( Rake::Task.tasks.select { |t| t.full_comment == 'start something' } ).not_to be_empty
|
88
|
+
end
|
89
|
+
|
90
|
+
it "yields the deployment if arity is given" do
|
91
|
+
config = Statistrano::Config.new
|
92
|
+
deployment_double = instance_double("Statistrano::Deployment::Strategy::Base", name: 'name', config: config)
|
93
|
+
config.user_tasks.push name: 'start',
|
94
|
+
namespaces: ['puma'],
|
95
|
+
block: lambda { |dep| dep.remotes }
|
96
|
+
described_class.register deployment_double
|
97
|
+
|
98
|
+
expect( deployment_double ).to receive(:remotes)
|
99
|
+
|
100
|
+
Rake::Task['name:puma:start'].invoke
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|