statistrano 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|