nanoc-deploying 1.0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ab7916826cd210ddc7bfacca3b6798df30ce86a5945cd1848e7ec4b6ed4d2dd5
4
+ data.tar.gz: '059736d6529ced037de1e7cebd6aa7071ab1d0213a2dae47f6b1e1b46c41dabc'
5
+ SHA512:
6
+ metadata.gz: f02b27a4e978eb3edc2b339e07924defdc7643953c03e61035916fc8eb934b00a16a5537ae81e8cef6658187dc71a81e09c095ba230fc1be4897814fd6667ff9
7
+ data.tar.gz: 40a9a102559188234e1185d9a23c5f4bd23458bf88a0a0b6a09eec2f58dcdaa845836da937a0b1bfd0ee15a679d40a4db5ba378ed2c63b2c156ab10704025007
data/NEWS.md ADDED
@@ -0,0 +1,5 @@
1
+ # nanoc-deploying news
2
+
3
+ ## 1.0.0 (2020-03-07)
4
+
5
+ Initial release (extracted from nanoc)
@@ -0,0 +1,5 @@
1
+ # nanoc-deploying
2
+
3
+ This provides the `deploy` command and associated functionality for [Nanoc](https://nanoc.ws).
4
+
5
+ For details, see the [Deploying Nanoc sites](https://nanoc.ws/doc/deploying/) chapter of the Nanoc documentation.
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'nanoc/deploying'
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'nanoc-core'
4
+ require 'nanoc-cli'
5
+
6
+ module Nanoc
7
+ module Deploying
8
+ end
9
+ end
10
+
11
+ require 'nanoc/deploying/version'
12
+ require 'nanoc/deploying/deployer'
13
+ require 'nanoc/deploying/deployers'
14
+
15
+ require 'nanoc/deploying/command_runners'
16
+
17
+ root = File.dirname(__FILE__)
18
+ deploying_command_path = File.join(root, 'deploying', 'commands', 'deploy.rb')
19
+ command = Cri::Command.load_file(deploying_command_path, infer_name: true)
20
+
21
+ Nanoc::CLI.after_setup do
22
+ Nanoc::CLI.add_command(command)
23
+ Nanoc::CLI::Commands::ShowPlugins.add_plugin_class(Nanoc::Deploying::Deployer, 'Deployers')
24
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ module Nanoc
5
+ module Deploying
6
+ module CommandRunners
7
+ end
8
+ end
9
+ end
10
+
11
+ require_relative 'command_runners/deploy'
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Deploying
5
+ module CommandRunners
6
+ class Deploy < ::Nanoc::CLI::CommandRunner
7
+ def run
8
+ @site = load_site
9
+ Nanoc::Core::Compiler.new_for(@site).run_until_preprocessed
10
+
11
+ if options[:'list-deployers']
12
+ list_deployers
13
+ elsif options[:list]
14
+ list_deploy_configs
15
+ else
16
+ deploy
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def list_deployers
23
+ deployers = Nanoc::Deploying::Deployer.all
24
+ deployer_names = deployers.map(&:identifier).sort
25
+ puts 'Available deployers:'
26
+ deployer_names.each do |name|
27
+ puts " #{name}"
28
+ end
29
+ end
30
+
31
+ def list_deploy_configs
32
+ if deploy_configs.empty?
33
+ puts 'No deployment configurations.'
34
+ else
35
+ puts 'Available deployment configurations:'
36
+ deploy_configs.each_key do |name|
37
+ puts " #{name}"
38
+ end
39
+ end
40
+ end
41
+
42
+ def deploy
43
+ deployer = deployer_for(deploy_config)
44
+
45
+ checks_successful = options[:'no-check'] ? true : check
46
+ return unless checks_successful
47
+
48
+ deployer.run
49
+ end
50
+
51
+ def deploy_config
52
+ if deploy_configs.empty?
53
+ raise Nanoc::Core::TrivialError, 'The site has no deployment configurations.'
54
+ end
55
+
56
+ if arguments.length > 1
57
+ raise Nanoc::Core::TrivialError, "usage: #{command.usage}"
58
+ end
59
+
60
+ target_from_arguments = arguments[0]
61
+ target_from_options = options.fetch(:target, nil)
62
+ if target_from_arguments && target_from_options
63
+ raise Nanoc::Core::TrivialError, 'Only one deployment target can be specified on the command line.'
64
+ end
65
+
66
+ target = target_from_arguments || target_from_options || :default
67
+ deploy_configs.fetch(target.to_sym) do
68
+ raise Nanoc::Core::TrivialError, "The site has no deployment configuration named `#{target}`."
69
+ end
70
+ end
71
+
72
+ def deployer_for(config)
73
+ deployer_class_for_config(config).new(
74
+ @site.config.output_dir,
75
+ config,
76
+ dry_run: options[:'dry-run'],
77
+ )
78
+ end
79
+
80
+ def check
81
+ runner = Nanoc::Checking::Runner.new(@site)
82
+ if runner.any_enabled_checks?
83
+ puts 'Running issue checks…'
84
+ is_success = runner.run_for_deploy
85
+ if is_success
86
+ puts 'No issues found. Deploying!'
87
+ else
88
+ puts 'Issues found, deploy aborted.'
89
+ end
90
+ is_success
91
+ else
92
+ true
93
+ end
94
+ end
95
+
96
+ def deploy_configs
97
+ @site.config.fetch(:deploy, {})
98
+ end
99
+
100
+ def deployer_class_for_config(config)
101
+ name = config.fetch(:kind) do
102
+ $stderr.puts 'Warning: The specified deploy target does not have a kind attribute. Assuming rsync.'
103
+ 'rsync'
104
+ end
105
+
106
+ deployer_class = Nanoc::Deploying::Deployer.named(name.to_sym)
107
+ if deployer_class.nil?
108
+ names = Nanoc::Deploying::Deployer.all.map(&:identifier)
109
+ raise Nanoc::Core::TrivialError, "The specified deploy target has an unrecognised kind “#{name}” (expected one of #{names.join(', ')})."
110
+ end
111
+ deployer_class
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ usage 'deploy [target] [options]'
4
+ summary 'deploy the compiled site'
5
+ description "
6
+ Deploys the compiled site. The compiled site contents in the output directory will be uploaded to the destination, which is specified using the `--target` option.
7
+ "
8
+
9
+ option :t, :target, 'specify the location to deploy to (default: `default`)', argument: :required
10
+ flag :C, :'no-check', 'do not run the issue checks marked for deployment'
11
+ flag :L, :list, 'list available locations to deploy to'
12
+ flag :D, :'list-deployers', 'list available deployers'
13
+ option :n, :'dry-run', 'show what would be deployed'
14
+
15
+ runner Nanoc::Deploying::CommandRunners::Deploy
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Deploying
5
+ # Represents a deployer, an object that allows uploading the compiled site
6
+ # to a specific (remote) location.
7
+ #
8
+ # @abstract Subclass and override {#run} to implement a custom filter.
9
+ #
10
+ # @api private
11
+ class Deployer
12
+ extend DDPlugin::Plugin
13
+
14
+ # @return [String] The path to the directory that contains the files to
15
+ # upload. It should not have a trailing slash.
16
+ attr_reader :source_path
17
+
18
+ # @return [Hash] The deployer configuration
19
+ attr_reader :config
20
+
21
+ # @return [Boolean] true if the deployer should only show what would be
22
+ # deployed instead of doing the actual deployment
23
+ attr_reader :dry_run
24
+ alias dry_run? dry_run
25
+
26
+ # @param [String] source_path The path to the directory that contains the
27
+ # files to upload. It should not have a trailing slash.
28
+ #
29
+ # @return [Hash] config The deployer configuration
30
+ #
31
+ # @param [Boolean] dry_run true if the deployer should
32
+ # only show what would be deployed instead actually deploying
33
+ def initialize(source_path, config, dry_run: false)
34
+ @source_path = source_path
35
+ @config = config
36
+ @dry_run = dry_run
37
+ end
38
+
39
+ # Performs the actual deployment.
40
+ #
41
+ # @abstract
42
+ def run
43
+ raise NotImplementedError.new('Nanoc::Deploying::Deployer subclasses must implement #run')
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'tty-command'
4
+
5
+ # @api private
6
+ module Nanoc
7
+ module Deploying
8
+ module Deployers
9
+ end
10
+ end
11
+ end
12
+
13
+ require_relative 'deployers/fog'
14
+ require_relative 'deployers/git'
15
+ require_relative 'deployers/rsync'
@@ -0,0 +1,224 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Deploying
5
+ module Deployers
6
+ # A deployer that deploys a site using [fog](https://github.com/fog/fog).
7
+ #
8
+ # @example A deployment configuration with public and staging configurations
9
+ #
10
+ # deploy:
11
+ # public:
12
+ # kind: fog
13
+ # bucket: nanoc-site
14
+ # cdn_id: XXXXXX
15
+ # preprod:
16
+ # kind: fog
17
+ # provider: local
18
+ # local_root: ~/myCloud
19
+ # bucket: nanoc-site
20
+ # staging:
21
+ # kind: fog
22
+ # provider: local
23
+ # local_root: ~/myCloud
24
+ # bucket: nanoc-site-staging
25
+ #
26
+ # @api private
27
+ class Fog < ::Nanoc::Deploying::Deployer
28
+ identifier :fog
29
+
30
+ class FogWrapper
31
+ def initialize(directory, is_dry_run)
32
+ @directory = directory
33
+ @is_dry_run = is_dry_run
34
+ end
35
+
36
+ def upload(source_filename, destination_key)
37
+ log_effectful("uploading #{source_filename} -> #{destination_key}")
38
+
39
+ unless dry_run?
40
+ File.open(source_filename) do |io|
41
+ @directory.files.create(
42
+ key: destination_key,
43
+ body: io,
44
+ public: true,
45
+ )
46
+ end
47
+ end
48
+ end
49
+
50
+ def remove(keys)
51
+ keys.each do |key|
52
+ log_effectful("removing #{key}")
53
+
54
+ unless dry_run?
55
+ @directory.files.get(key).destroy
56
+ end
57
+ end
58
+ end
59
+
60
+ def invalidate(keys, cdn, distribution)
61
+ keys.each_slice(1000) do |keys_slice|
62
+ keys_slice.each do |key|
63
+ log_effectful("invalidating #{key}")
64
+ end
65
+
66
+ unless dry_run?
67
+ cdn.post_invalidation(distribution, keys_slice)
68
+ end
69
+ end
70
+ end
71
+
72
+ def dry_run?
73
+ @is_dry_run
74
+ end
75
+
76
+ def log_effectful(str)
77
+ if @is_dry_run
78
+ puts "[dry run] #{str}"
79
+ else
80
+ puts str
81
+ end
82
+ end
83
+ end
84
+
85
+ # @see Nanoc::Deploying::Deployer#run
86
+ def run
87
+ require 'fog/core'
88
+
89
+ src = File.expand_path(source_path)
90
+ bucket = config[:bucket] || config[:bucket_name]
91
+ path = config[:path]
92
+ cdn_id = config[:cdn_id]
93
+
94
+ if path&.end_with?('/')
95
+ raise "The path `#{path}` is not supposed to have a trailing slash"
96
+ end
97
+
98
+ connection = connect
99
+ directory = get_or_create_bucket(connection, bucket, path)
100
+ wrapper = FogWrapper.new(directory, dry_run?)
101
+
102
+ remote_files = list_remote_files(directory)
103
+ etags = read_etags(remote_files)
104
+
105
+ modified_keys, retained_keys = upload_all(src, path, etags, wrapper)
106
+
107
+ removed_keys = remote_files.map(&:key) - retained_keys - modified_keys
108
+ wrapper.remove(removed_keys)
109
+
110
+ if cdn_id
111
+ cdn = ::Fog::CDN.new(config_for_fog)
112
+ distribution = cdn.get_distribution(cdn_id)
113
+ wrapper.invalidate(modified_keys + removed_keys, cdn, distribution)
114
+ end
115
+ end
116
+
117
+ private
118
+
119
+ def config_for_fog
120
+ config.dup.tap do |c|
121
+ c.delete(:bucket)
122
+ c.delete(:bucket_name)
123
+ c.delete(:path)
124
+ c.delete(:cdn_id)
125
+ c.delete(:kind)
126
+ end
127
+ end
128
+
129
+ def connect
130
+ ::Fog::Storage.new(config_for_fog)
131
+ rescue ArgumentError
132
+ require "fog/#{config[:provider]}"
133
+ ::Fog::Storage.new(config_for_fog)
134
+ end
135
+
136
+ def get_or_create_bucket(connection, bucket, path)
137
+ directory =
138
+ begin
139
+ connection.directories.get(bucket, prefix: path)
140
+ rescue ::Excon::Errors::NotFound
141
+ nil
142
+ end
143
+
144
+ if directory
145
+ directory
146
+ elsif dry_run?
147
+ puts '[dry run] creating bucket'
148
+ else
149
+ puts 'creating bucket'
150
+ connection.directories.create(key: bucket, prefix: path)
151
+ end
152
+ end
153
+
154
+ def remote_key_for_local_filename(local_filename, src, path)
155
+ relative_local_filename = local_filename.sub(/\A#{src}\//, '')
156
+
157
+ if path
158
+ File.join(path, relative_local_filename)
159
+ else
160
+ relative_local_filename
161
+ end
162
+ end
163
+
164
+ def list_remote_files(directory)
165
+ if directory
166
+ [].tap do |files|
167
+ directory.files.each { |file| files << file }
168
+ end
169
+ else
170
+ []
171
+ end
172
+ end
173
+
174
+ def list_local_files(src)
175
+ Dir[src + '/**/*'].select { |f| File.file?(f) }
176
+ end
177
+
178
+ def upload_all(src, path, etags, wrapper)
179
+ modified_keys = []
180
+ retained_keys = []
181
+
182
+ local_files = list_local_files(src)
183
+ local_files.each do |file_path|
184
+ key = remote_key_for_local_filename(file_path, src, path)
185
+ if needs_upload?(key, file_path, etags)
186
+ wrapper.upload(file_path, key)
187
+ modified_keys.push(key)
188
+ else
189
+ retained_keys.push(key)
190
+ end
191
+ end
192
+
193
+ [modified_keys, retained_keys]
194
+ end
195
+
196
+ def needs_upload?(key, file_path, etags)
197
+ remote_etag = etags[key]
198
+ return true if remote_etag.nil?
199
+
200
+ local_etag = calc_local_etag(file_path)
201
+ remote_etag != local_etag
202
+ end
203
+
204
+ def read_etags(files)
205
+ case config[:provider]
206
+ when 'aws'
207
+ files.each_with_object({}) do |file, etags|
208
+ etags[file.key] = file.etag
209
+ end
210
+ else
211
+ {}
212
+ end
213
+ end
214
+
215
+ def calc_local_etag(file_path)
216
+ case config[:provider]
217
+ when 'aws'
218
+ Digest::MD5.file(file_path).hexdigest
219
+ end
220
+ end
221
+ end
222
+ end
223
+ end
224
+ end
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Deploying
5
+ module Deployers
6
+ # A deployer that deploys a site using [Git](https://git-scm.com).
7
+ #
8
+ # @example A deployment configuration for GitHub Pages:
9
+ #
10
+ # deploy:
11
+ # default:
12
+ # kind: git
13
+ # remote: git@github.com:myself/myproject.git
14
+ # branch: gh-pages
15
+ # forced: true
16
+ #
17
+ class Git < ::Nanoc::Deploying::Deployer
18
+ identifier :git
19
+
20
+ module Errors
21
+ class Generic < ::Nanoc::Core::Error
22
+ end
23
+
24
+ class OutputDirDoesNotExist < Generic
25
+ def initialize(path)
26
+ super("The directory to deploy, #{path}, does not exist.")
27
+ end
28
+ end
29
+
30
+ class OutputDirIsNotAGitRepo < Generic
31
+ def initialize(path)
32
+ super("The directory to deploy, #{path}, is not a Git repository.")
33
+ end
34
+ end
35
+
36
+ class RemoteDoesNotExist < Generic
37
+ def initialize(remote)
38
+ super("The remote to deploy to, #{remote}, does not exist.")
39
+ end
40
+ end
41
+
42
+ class BranchDoesNotExist < Generic
43
+ def initialize(branch)
44
+ super("The branch to deploy, #{branch}, does not exist.")
45
+ end
46
+ end
47
+ end
48
+
49
+ def run
50
+ unless File.exist?(source_path)
51
+ raise Errors::OutputDirDoesNotExist.new(source_path)
52
+ end
53
+
54
+ remote = config.fetch(:remote, 'origin')
55
+ branch = config.fetch(:branch, 'master')
56
+ forced = config.fetch(:forced, false)
57
+
58
+ puts "Deploying via Git to branch “#{branch}” on remote “#{remote}”…"
59
+
60
+ Dir.chdir(source_path) do
61
+ unless File.exist?('.git')
62
+ raise Errors::OutputDirIsNotAGitRepo.new(source_path)
63
+ end
64
+
65
+ # Verify existence of remote, if remote is not a URL
66
+ if remote_is_name?(remote)
67
+ begin
68
+ run_cmd(%W[git config --get remote.#{remote}.url])
69
+ rescue TTY::Command::ExitError
70
+ raise Errors::RemoteDoesNotExist.new(remote)
71
+ end
72
+ end
73
+
74
+ # If the branch exists then switch to it, otherwise prompt the user to create one.
75
+ begin
76
+ run_cmd_unless_dry(%W[git checkout #{branch}])
77
+ rescue TTY::Command::ExitError
78
+ raise Errors::BranchDoesNotExist.new(branch)
79
+ end
80
+
81
+ return if clean_repo?
82
+
83
+ msg = "Automated commit at #{Time.now.utc} by Nanoc #{Nanoc::VERSION}"
84
+ author = 'Nanoc <>'
85
+ run_cmd_unless_dry(%w[git add -A])
86
+ run_cmd_unless_dry(%W[git commit -a --author #{author} -m #{msg}])
87
+
88
+ if forced
89
+ run_cmd_unless_dry(%W[git push -f #{remote} #{branch}])
90
+ else
91
+ run_cmd_unless_dry(%W[git push #{remote} #{branch}])
92
+ end
93
+ end
94
+ end
95
+
96
+ private
97
+
98
+ def remote_is_name?(remote)
99
+ remote !~ /:\/\/|@.+:/
100
+ end
101
+
102
+ def run_cmd(cmd, dry_run: false)
103
+ TTY::Command.new(printer: :null).run(*cmd, dry_run: dry_run)
104
+ end
105
+
106
+ def run_cmd_unless_dry(cmd)
107
+ run_cmd(cmd, dry_run: dry_run)
108
+ end
109
+
110
+ def clean_repo?
111
+ TTY::Command.new(printer: :null).run('git status --porcelain').out.empty?
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Deploying
5
+ module Deployers
6
+ # A deployer that deploys a site using rsync.
7
+ #
8
+ # The configuration has should include a `:dst` value, a string containing
9
+ # the destination to where rsync should upload its data. It will likely be
10
+ # in `host:path` format. It should not end with a slash. For example,
11
+ # `"example.com:/var/www/sites/mysite/html"`.
12
+ #
13
+ # @example A deployment configuration with public and staging configurations
14
+ #
15
+ # deploy:
16
+ # public:
17
+ # kind: rsync
18
+ # dst: "ectype:sites/stoneship/public"
19
+ # staging:
20
+ # kind: rsync
21
+ # dst: "ectype:sites/stoneship-staging/public"
22
+ # options: [ "-glpPrtvz" ]
23
+ #
24
+ # @api private
25
+ class Rsync < ::Nanoc::Deploying::Deployer
26
+ identifier :rsync
27
+
28
+ # Default rsync options
29
+ DEFAULT_OPTIONS = [
30
+ '--group',
31
+ '--links',
32
+ '--perms',
33
+ '--partial',
34
+ '--progress',
35
+ '--recursive',
36
+ '--times',
37
+ '--verbose',
38
+ '--compress',
39
+ '--exclude=".hg"',
40
+ '--exclude=".svn"',
41
+ '--exclude=".git"',
42
+ ].freeze
43
+
44
+ # @see Nanoc::Deploying::Deployer#run
45
+ def run
46
+ # Get params
47
+ src = source_path + '/'
48
+ dst = config[:dst]
49
+ options = config[:options] || DEFAULT_OPTIONS
50
+
51
+ # Validate
52
+ raise 'No dst found in deployment configuration' if dst.nil?
53
+ raise 'dst requires no trailing slash' if dst[-1, 1] == '/'
54
+
55
+ # Run
56
+ if dry_run
57
+ warn 'Performing a dry-run; no actions will actually be performed'
58
+ run_shell_cmd(['echo', 'rsync', options, src, dst].flatten)
59
+ else
60
+ run_shell_cmd(['rsync', options, src, dst].flatten)
61
+ end
62
+ end
63
+
64
+ private
65
+
66
+ def run_shell_cmd(cmd)
67
+ TTY::Command.new(printer: :null).run(*cmd)
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Deploying
5
+ VERSION = '1.0.0'
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nanoc-deploying
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Denis Defreyne
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-03-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: nanoc-checking
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: nanoc-cli
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '4.11'
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: 4.11.15
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "~>"
42
+ - !ruby/object:Gem::Version
43
+ version: '4.11'
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 4.11.15
47
+ - !ruby/object:Gem::Dependency
48
+ name: nanoc-core
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '4.11'
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: 4.11.15
57
+ type: :runtime
58
+ prerelease: false
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - "~>"
62
+ - !ruby/object:Gem::Version
63
+ version: '4.11'
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: 4.11.15
67
+ description: Provides deploying functionality for Nanoc
68
+ email: denis+rubygems@denis.ws
69
+ executables: []
70
+ extensions: []
71
+ extra_rdoc_files: []
72
+ files:
73
+ - NEWS.md
74
+ - README.md
75
+ - lib/nanoc-deploying.rb
76
+ - lib/nanoc/deploying.rb
77
+ - lib/nanoc/deploying/command_runners.rb
78
+ - lib/nanoc/deploying/command_runners/deploy.rb
79
+ - lib/nanoc/deploying/commands/deploy.rb
80
+ - lib/nanoc/deploying/deployer.rb
81
+ - lib/nanoc/deploying/deployers.rb
82
+ - lib/nanoc/deploying/deployers/fog.rb
83
+ - lib/nanoc/deploying/deployers/git.rb
84
+ - lib/nanoc/deploying/deployers/rsync.rb
85
+ - lib/nanoc/deploying/version.rb
86
+ homepage: https://nanoc.ws/
87
+ licenses:
88
+ - MIT
89
+ metadata: {}
90
+ post_install_message:
91
+ rdoc_options: []
92
+ require_paths:
93
+ - lib
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - "~>"
97
+ - !ruby/object:Gem::Version
98
+ version: '2.4'
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ requirements: []
105
+ rubygems_version: 3.1.2
106
+ signing_key:
107
+ specification_version: 4
108
+ summary: Deploying support for Nanoc
109
+ test_files: []