capistrano-template 0.0.1

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.
Files changed (33) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +22 -0
  5. data/.rubocop_todo.yml +8 -0
  6. data/.travis.yml +4 -0
  7. data/.versions.conf +4 -0
  8. data/CHANGELOG.md +0 -0
  9. data/Gemfile +9 -0
  10. data/LICENSE.txt +22 -0
  11. data/README.md +66 -0
  12. data/Rakefile +16 -0
  13. data/capistrano-template.gemspec +35 -0
  14. data/lib/capistrano/capistrano_plugin_template.rb +5 -0
  15. data/lib/capistrano/template.rb +11 -0
  16. data/lib/capistrano/template/helpers/dsl.rb +61 -0
  17. data/lib/capistrano/template/helpers/paths_lookup.rb +33 -0
  18. data/lib/capistrano/template/helpers/renderer.rb +30 -0
  19. data/lib/capistrano/template/helpers/template_digester.rb +19 -0
  20. data/lib/capistrano/template/helpers/uploader.rb +94 -0
  21. data/lib/capistrano/template/tasks/template_defaults.cap +13 -0
  22. data/lib/capistrano/template/version.rb +5 -0
  23. data/spec/integration/capistrano/template/helpers/dsl_spec.rb +117 -0
  24. data/spec/integration/capistrano/template/helpers/paths_lookup_spec.rb +46 -0
  25. data/spec/integration/capistrano/template/helpers/uploader_spec.rb +100 -0
  26. data/spec/spec_helper.rb +42 -0
  27. data/spec/unit/capistrano/template/helpers/dsl_spec.rb +60 -0
  28. data/spec/unit/capistrano/template/helpers/paths_lookup_spec.rb +54 -0
  29. data/spec/unit/capistrano/template/helpers/renderer_spec.rb +43 -0
  30. data/spec/unit/capistrano/template/helpers/template_digester_spec.rb +36 -0
  31. data/spec/unit/capistrano/template/helpers/uploader_spec.rb +103 -0
  32. data/spec/unit/capistrano/template_spec.rb +7 -0
  33. metadata +186 -0
@@ -0,0 +1,13 @@
1
+ namespace :load do
2
+ task :defaults do
3
+ set :templating_digster, ->{ ->(data){ Digest::MD5.hexdigest(data)} }
4
+ set :templating_digest_cmd, %Q{test "Z$(openssl md5 %<path>s| sed "s/^.*= *//")" = "Z%<digest>s" } # alternative %Q{echo "%<digest>s %<path>s" | md5sum -c --status } should return true when the file content is the same
5
+ set :templating_mode_test_cmd, %Q{ [ "Z$(printf "%%.4o" 0$(stat -c "%%a" %<path>s 2>/dev/null || stat -f "%%A" %<path>s))" != "Z%<mode>s" ] } # mac uses different mode formatter
6
+ set :templating_paths , ->{ ["config/deploy/templates/#{fetch(:stage)}/%<host>s",
7
+ "config/deploy/templates/#{fetch(:stage)}",
8
+ "config/deploy/templates/shared/%<host>s",
9
+ "config/deploy/templates/shared"].map {|partial_path| (partial_path)} }
10
+ end
11
+ end
12
+
13
+
@@ -0,0 +1,5 @@
1
+ module Capistrano
2
+ module Template
3
+ VERSION = '0.0.1'
4
+ end
5
+ end
@@ -0,0 +1,117 @@
1
+ require 'spec_helper'
2
+
3
+ module Capistrano
4
+ module Template
5
+ module Helpers
6
+ module Integration # prodect from other dummy classes
7
+ module DSLSpec
8
+ class Dummy
9
+ include DSL
10
+ attr_accessor :data, :release_path
11
+
12
+ def initialize
13
+ self.data = {
14
+ templating_digster: ->(data) { Digest::MD5.hexdigest(data) },
15
+ templating_digest_cmd: %Q(echo "%<digest>s %<path>s" | md5sum -c --status ),
16
+ templating_mode_test_cmd: %Q{ [ "Z$(printf "%%.4o" 0$(stat -c "%%a" %<path>s 2>/dev/null || stat -f "%%A" %<path>s))" != "Z%<mode>s" ] }
17
+ }
18
+ end
19
+
20
+ # custom methods
21
+ def var1
22
+ 'my'
23
+ end
24
+
25
+ def var2
26
+ 'content'
27
+ end
28
+
29
+ # capistrano method
30
+ def fetch(*args)
31
+ data.fetch(*args)
32
+ end
33
+
34
+ # sshkit metthods
35
+
36
+ def host
37
+ 'localhost'
38
+ end
39
+
40
+ def test(*args)
41
+ execute(*args)
42
+ end
43
+
44
+ def execute(*args)
45
+ system(*args)
46
+ end
47
+
48
+ def upload!(io, filename)
49
+ File.write(filename, io.read, mode: 'w')
50
+ end
51
+
52
+ def capture(cmd)
53
+ `#{cmd}`
54
+ end
55
+
56
+ def info(*)
57
+ end
58
+
59
+ def error(*)
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ describe DSL do
66
+ subject do
67
+ Integration::DSLSpec::Dummy.new.tap do |d|
68
+ d.data[:templating_paths] = [tmp_folder]
69
+ d.release_path = tmp_folder
70
+ end
71
+ end
72
+
73
+ let(:template_name) { 'my_template.erb' }
74
+
75
+ let(:tmp_folder) { File.join(__dir__, '..', '..', '..', 'tmp') }
76
+
77
+ let(:template_content) { '<%=var1%> -- <%=var2%>' }
78
+ let(:expected_content) { 'my -- content' }
79
+
80
+ let(:template_name) { 'my_template.erb' }
81
+ let(:template_fullname) { File.join(tmp_folder, template_name) }
82
+ let(:remote_filename) { File.join(tmp_folder, 'my_template') }
83
+
84
+ let(:digest_algo) { ->(data) { Digest::MD5.hexdigest(data) } }
85
+ let(:digest_cmd) { %Q{test "Z$(openssl md5 %<path>s| sed "s/^.*= *//")" = "Z%<digest>s" } }
86
+
87
+ let(:mode_test_cmd) do
88
+ %Q{ [ "Z$(printf "%%.4o" 0$(stat -c "%%a" %<path>s 2>/dev/null || stat -f "%%A" %<path>s))" != "Z%<mode>s" ] }
89
+ end
90
+
91
+ before :each do
92
+ Dir.mkdir(tmp_folder) unless Dir.exist? tmp_folder
93
+ File.write(template_fullname, template_content, mode: 'w')
94
+ end
95
+
96
+ after :each do
97
+ [
98
+ template_fullname,
99
+ remote_filename
100
+ ].each do |f|
101
+ system('rm', '-f', f) if File.exist? f
102
+ end
103
+ end
104
+
105
+ describe '#template' do
106
+
107
+ it 'create the result file' do
108
+ subject.template(template_name)
109
+
110
+ expect(File.read(remote_filename)).to eq(expected_content)
111
+ end
112
+
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ module Capistrano
4
+ module Template
5
+ module Helpers
6
+ describe PathsLookup do
7
+ subject do
8
+ PathsLookup.new(lookup_paths, context)
9
+ end
10
+
11
+ let(:tmp_folder) { File.join(__dir__, '..', '..', '..', 'tmp') }
12
+
13
+ let(:lookup_paths) { ["#{tmp_folder}/%<host>s", "#{tmp_folder}"] }
14
+ let(:context) { OpenStruct.new(host: 'localhost') }
15
+
16
+ let(:template_content) { '<%=var1%> -- <%=var2%>' }
17
+ let(:template_name) { 'my_template.erb' }
18
+ let(:template_fullname) { File.join(tmp_folder, template_name) }
19
+
20
+ before :each do
21
+ Dir.mkdir(tmp_folder) unless Dir.exist? tmp_folder
22
+ File.write(template_fullname, template_content, mode: 'w')
23
+ end
24
+
25
+ after :each do
26
+ if File.exist? template_fullname
27
+ system('rm', '-f', File.join(tmp_folder, template_fullname))
28
+ end
29
+ end
30
+
31
+ describe '#template_exists?' do
32
+
33
+ it 'returns true when a template file exists' do
34
+ expect(subject.template_exists?(template_name)).to be_truthy
35
+ end
36
+
37
+ it 'returns false when a template does not file exists' do
38
+ expect(subject.template_exists?("#{template_name}.not_exists")).to be_falsy
39
+ end
40
+
41
+ end
42
+
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,100 @@
1
+ require 'spec_helper'
2
+
3
+ module Capistrano
4
+ module Template
5
+ module Helpers
6
+ describe Uploader do
7
+
8
+ before :each do
9
+ Dir.mkdir(tmp_folder) unless Dir.exist? tmp_folder
10
+ end
11
+
12
+ after :each do
13
+ system('rm', '-f', remote_filename) if File.exist? remote_filename
14
+ end
15
+
16
+ subject do
17
+ Uploader.new(
18
+ remote_filename,
19
+ context,
20
+ mode: 0640,
21
+ mode_test_cmd: mode_test_cmd,
22
+ digest: digest,
23
+ digest_cmd: digest_cmd,
24
+ io: as_io
25
+ )
26
+ end
27
+
28
+ let(:context) do
29
+ Struct.new(:host).new.tap do |cont|
30
+ cont.host = 'localhost'
31
+
32
+ allow(cont).to receive(:info)
33
+ allow(cont).to receive(:error)
34
+
35
+ def cont.test(*args)
36
+ system(*args)
37
+ end
38
+
39
+ def cont.execute(*args)
40
+ system(*args)
41
+ end
42
+
43
+ def cont.upload!(io, filename)
44
+ File.write(filename, io.read, mode: 'w')
45
+ end
46
+
47
+ end
48
+
49
+ end
50
+
51
+ let(:tmp_folder) { File.join(__dir__, '..', '..', '..', 'tmp') }
52
+
53
+ let(:rendered_template_content) { 'my -- content' }
54
+ let(:as_io) { StringIO.new(rendered_template_content) }
55
+
56
+ let(:remote_filename) { File.join(tmp_folder, 'my_template') }
57
+
58
+ let(:digest) { Digest::MD5.hexdigest(rendered_template_content) }
59
+ let(:digest_cmd) { %Q{test "Z$(openssl md5 %<path>s| sed "s/^.*= *//")" = "Z%<digest>s" } }
60
+
61
+ let(:mode_test_cmd) do
62
+ %Q{ [ "Z$(printf "%%.4o" 0$(stat -c "%%a" %<path>s 2>/dev/null || stat -f "%%A" %<path>s))" != "Z%<mode>s" ] }
63
+ end
64
+
65
+ describe '#call' do
66
+
67
+ it 'uploads a template when content has changed' do
68
+ subject.call
69
+ expect(File.exist?(remote_filename)).to be_truthy
70
+ end
71
+
72
+ it 'does not upload a template when content is equal' do
73
+ File.write(remote_filename, rendered_template_content, mode: 'w')
74
+
75
+ expect(context).not_to receive(:upload!)
76
+ subject.call
77
+ end
78
+
79
+ it 'evals the erb' do
80
+ subject.call
81
+ expect(File.read(remote_filename)).to eq(rendered_template_content)
82
+ end
83
+
84
+ it 'sets permissions' do
85
+ File.write(remote_filename, rendered_template_content, mode: 'w')
86
+ File.chmod(0400, remote_filename)
87
+
88
+ subject.call
89
+
90
+ mode = File.stat(remote_filename).mode & 0xFFF
91
+
92
+ expect(mode).to eq(0640)
93
+ end
94
+
95
+ end
96
+
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,42 @@
1
+ require 'bundler/setup'
2
+ Bundler.require(:development)
3
+
4
+ require 'coveralls'
5
+ Coveralls.wear! unless ENV['SIMPLE_COVERAGE']
6
+
7
+ begin
8
+ if ENV['SIMPLE_COVERAGE']
9
+ require 'simplecov'
10
+ SimpleCov.start do
11
+ add_group 'Lib', 'lib'
12
+
13
+ add_filter '/spec/'
14
+ end
15
+ end
16
+ rescue LoadError
17
+ warn '=' * 80
18
+ warn 'simplecov not installed. No coverage report'
19
+ warn '=' * 80
20
+ end
21
+
22
+ require 'capistrano/template'
23
+
24
+ Dir[File.join(File.expand_path(__dir__), 'support/**/*.rb')].each { |f| require f }
25
+
26
+ # This file was generated by the `rspec --init` command. Conventionally, all
27
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
28
+ # Require this file using `require "spec_helper"` to ensure that it is only
29
+ # loaded once.
30
+ #
31
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
32
+ RSpec.configure do |config|
33
+ config.treat_symbols_as_metadata_keys_with_true_values = true
34
+ config.run_all_when_everything_filtered = true
35
+ config.filter_run :focus
36
+
37
+ # Run specs in random order to surface order dependencies. If you find an
38
+ # order dependency and want to debug it, you can fix the order by providing
39
+ # the seed, which is printed after each run.
40
+ # --seed 1234
41
+ config.order = 'random'
42
+ end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+
3
+ module Capistrano
4
+ module Template
5
+ module Helpers
6
+ module Unit # prodect from other dummy classes
7
+ module DSLSpec
8
+ class Dummy
9
+ include DSL
10
+ attr_accessor :data, :file_exists
11
+
12
+ def initialize
13
+ self.file_exists = true
14
+ self.data = {
15
+ templating_paths: ['/tmp'],
16
+ }
17
+ end
18
+
19
+ def host
20
+ 'localhost'
21
+ end
22
+
23
+ def release_path
24
+ '/var/www/app/releases/20140510'
25
+ end
26
+
27
+ def fetch(*args)
28
+ data.fetch(*args)
29
+ end
30
+
31
+ def _paths_factory
32
+ lambda do |*args|
33
+ PathsLookup.new(*args).tap do |pl|
34
+ def pl.existence_check(*)
35
+ file_exists
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ describe DSL do
45
+ subject do
46
+ Unit::DSLSpec::Dummy.new
47
+ end
48
+
49
+ let(:template_name) { 'my_template.erb' }
50
+
51
+ describe '#template' do
52
+ it 'raises an exception when template does not exists' do
53
+ subject.file_exists = false
54
+ expect { subject.template(template_name) }.to raise_error(ArgumentError, /template #{template_name} not found Paths/)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ module Capistrano
4
+ module Template
5
+ module Helpers
6
+ describe PathsLookup do
7
+ subject do
8
+ PathsLookup.new(lookup_paths, context)
9
+ end
10
+
11
+ let(:lookup_paths) { ['path1/%<host>s', 'path2'] }
12
+ let(:context) { OpenStruct.new(host: 'localhost') }
13
+ let(:template_name) { 'my_template' }
14
+
15
+ describe '#template_exists?' do
16
+
17
+ it 'returns true when a template file exists' do
18
+ subject.stub(existence_check: true)
19
+ expect(subject.template_exists?(template_name)).to be_truthy
20
+ end
21
+
22
+ it 'returns false when a template does not file exists' do
23
+ subject.stub(existence_check: false)
24
+ expect(subject.template_exists?(template_name)).to be_falsy
25
+ end
26
+
27
+ it 'checks for every possible path existence' do
28
+ expect(subject).to receive(:existence_check).exactly(lookup_paths.count * 2).times
29
+ subject.template_exists?(template_name)
30
+ end
31
+
32
+ it 'stops search for first hit' do
33
+ expect(subject).to receive(:existence_check).exactly(2).times.and_return(false, true)
34
+ subject.template_exists?(template_name)
35
+ end
36
+
37
+ end
38
+
39
+ describe '#template_file' do
40
+ it 'returns the first found filename' do
41
+ allow(subject).to receive(:existence_check).and_return(false, false, true)
42
+ expect(subject.template_file(template_name)).to eq('path2/my_template.erb')
43
+ end
44
+
45
+ it 'expends the host' do
46
+ allow(subject).to receive(:existence_check).and_return(true)
47
+ expect(subject.template_file(template_name)).to eq('path1/localhost/my_template.erb')
48
+ end
49
+ end
50
+
51
+ end
52
+ end
53
+ end
54
+ end