mirror of
https://github.com/capistrano/capistrano
synced 2023-03-27 23:21:18 -04:00
Merge pull request #1687 from irvingwashington/doctor_task_servers
[wip] doctor:servers task
This commit is contained in:
commit
058621c885
7 changed files with 206 additions and 5 deletions
|
@ -6,6 +6,7 @@ Reverse Chronological Order:
|
|||
|
||||
https://github.com/capistrano/capistrano/compare/v3.5.0...HEAD
|
||||
|
||||
* Added a `doctor:servers` subtask that outputs a summary of servers, roles & properties (@irvingwashington)
|
||||
* Raise a better error when an ‘after’ hook isn’t found (@jdelStrother)
|
||||
* Restrict the uploaded git wrapper script permissions to 700 (@irvingwashington)
|
||||
* Make path to git wrapper script configurable (@thickpaddy)
|
||||
|
|
|
@ -133,16 +133,16 @@ module Capistrano
|
|||
installer.install(plugin, load_hooks: load_hooks)
|
||||
end
|
||||
|
||||
def servers
|
||||
@servers ||= Servers.new
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def cmdline_filters
|
||||
@cmdline_filters ||= []
|
||||
end
|
||||
|
||||
def servers
|
||||
@servers ||= Servers.new
|
||||
end
|
||||
|
||||
def installer
|
||||
@installer ||= PluginInstaller.new
|
||||
end
|
||||
|
|
|
@ -119,6 +119,10 @@ module Capistrano
|
|||
end
|
||||
end
|
||||
|
||||
def to_h
|
||||
@properties
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def lvalue(key)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
require "capistrano/doctor/environment_doctor"
|
||||
require "capistrano/doctor/gems_doctor"
|
||||
require "capistrano/doctor/variables_doctor"
|
||||
require "capistrano/doctor/servers_doctor"
|
||||
|
||||
load File.expand_path("../tasks/doctor.rake", __FILE__)
|
||||
|
|
105
lib/capistrano/doctor/servers_doctor.rb
Normal file
105
lib/capistrano/doctor/servers_doctor.rb
Normal file
|
@ -0,0 +1,105 @@
|
|||
require "capistrano/doctor/output_helpers"
|
||||
|
||||
module Capistrano
|
||||
module Doctor
|
||||
class ServersDoctor
|
||||
include Capistrano::Doctor::OutputHelpers
|
||||
|
||||
def initialize(env=Capistrano::Configuration.env)
|
||||
@servers = env.servers.to_a
|
||||
end
|
||||
|
||||
def call
|
||||
title("Servers (#{servers.size})")
|
||||
rwc = RoleWhitespaceChecker.new(servers)
|
||||
|
||||
table(servers) do |server, row|
|
||||
sd = ServerDecorator.new(server)
|
||||
|
||||
row << sd.uri_form
|
||||
row << sd.roles
|
||||
row << sd.properties
|
||||
row.yellow if rwc.any_has_whitespace?(server.roles)
|
||||
end
|
||||
|
||||
if rwc.whitespace_roles.any?
|
||||
warning "\nWhitespace detected in role(s) #{rwc.whitespace_roles_decorated}. " \
|
||||
"This might be a result of a mistyped \"%w()\" array literal."
|
||||
end
|
||||
puts
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :servers
|
||||
|
||||
class RoleWhitespaceChecker
|
||||
attr_reader :whitespace_roles, :servers
|
||||
|
||||
def initialize(servers)
|
||||
@servers = servers
|
||||
@whitespace_roles = find_whitespace_roles
|
||||
end
|
||||
|
||||
def any_has_whitespace?(roles)
|
||||
roles.any? { |role| include_whitespace?(role) }
|
||||
end
|
||||
|
||||
def include_whitespace?(role)
|
||||
role =~ /\s/
|
||||
end
|
||||
|
||||
def whitespace_roles_decorated
|
||||
whitespace_roles.map(&:inspect).join(", ")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_whitespace_roles
|
||||
servers.map(&:roles).map(&:to_a).flatten.uniq
|
||||
.select { |role| include_whitespace?(role) }
|
||||
end
|
||||
end
|
||||
|
||||
class ServerDecorator
|
||||
def initialize(server)
|
||||
@server = server
|
||||
end
|
||||
|
||||
def uri_form
|
||||
[
|
||||
server.user,
|
||||
server.user && "@",
|
||||
server.hostname,
|
||||
server.port && ":",
|
||||
server.port
|
||||
].compact.join
|
||||
end
|
||||
|
||||
def roles
|
||||
server.roles.to_a.inspect
|
||||
end
|
||||
|
||||
def properties
|
||||
return "" unless server.properties.keys.any?
|
||||
pretty_inspect(server.properties.to_h)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :server
|
||||
|
||||
# Hashes with proper padding
|
||||
def pretty_inspect(element)
|
||||
return element.inspect unless element.is_a?(Hash)
|
||||
|
||||
pairs_string = element.keys.map do |key|
|
||||
[pretty_inspect(key), pretty_inspect(element.fetch(key))].join(" => ")
|
||||
end.join(", ")
|
||||
|
||||
"{ #{pairs_string} }"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,5 +1,5 @@
|
|||
desc "Display a Capistrano troubleshooting report (all doctor: tasks)"
|
||||
task doctor: ["doctor:environment", "doctor:gems", "doctor:variables"]
|
||||
task doctor: ["doctor:environment", "doctor:gems", "doctor:variables", "doctor:servers"]
|
||||
|
||||
namespace :doctor do
|
||||
desc "Display Ruby environment details"
|
||||
|
@ -16,4 +16,9 @@ namespace :doctor do
|
|||
task :variables do
|
||||
Capistrano::Doctor::VariablesDoctor.new.call
|
||||
end
|
||||
|
||||
desc "Display the effective servers configuration"
|
||||
task :servers do
|
||||
Capistrano::Doctor::ServersDoctor.new.call
|
||||
end
|
||||
end
|
||||
|
|
85
spec/lib/capistrano/doctor/servers_doctor_spec.rb
Normal file
85
spec/lib/capistrano/doctor/servers_doctor_spec.rb
Normal file
|
@ -0,0 +1,85 @@
|
|||
require "spec_helper"
|
||||
require "capistrano/doctor/servers_doctor"
|
||||
|
||||
module Capistrano
|
||||
module Doctor
|
||||
describe ServersDoctor do
|
||||
include Capistrano::DSL
|
||||
let(:doc) { ServersDoctor.new }
|
||||
|
||||
after { Capistrano::Configuration.reset! }
|
||||
|
||||
it "prints using 4-space indentation" do
|
||||
expect { doc.call }.to output(/^ {4}/).to_stdout
|
||||
end
|
||||
|
||||
it "prints the number of defined servers" do
|
||||
role :app, %w(example.com)
|
||||
server "www@example.com:22"
|
||||
|
||||
expect { doc.call }.to output(/Servers \(2\)/).to_stdout
|
||||
end
|
||||
|
||||
describe "prints the server's details" do
|
||||
it "including username" do
|
||||
server "www@example.com"
|
||||
expect { doc.call }.to output(/www@example.com/).to_stdout
|
||||
end
|
||||
|
||||
it "including port" do
|
||||
server "www@example.com:22"
|
||||
expect { doc.call }.to output(/www@example.com:22/).to_stdout
|
||||
end
|
||||
|
||||
it "including roles" do
|
||||
role :app, %w(example.com)
|
||||
expect { doc.call }.to output(/example.com\s+\[:app\]/).to_stdout
|
||||
end
|
||||
|
||||
it "including empty roles" do
|
||||
server "example.com"
|
||||
expect { doc.call }.to output(/example.com\s+\[\]/).to_stdout
|
||||
end
|
||||
|
||||
it "including properties" do
|
||||
server "example.com", roles: %w(app db), primary: true
|
||||
expect { doc.call }.to \
|
||||
output(/example.com\s+\[:app, :db\]\s+\{ :primary => true \}/).to_stdout
|
||||
end
|
||||
|
||||
it "including misleading role name alert" do
|
||||
server "example.com", roles: ["web app db"]
|
||||
warning_msg = 'Whitespace detected in role(s) :"web app db". ' \
|
||||
'This might be a result of a mistyped "%w()" array literal'
|
||||
|
||||
expect { doc.call }.to output(/#{Regexp.escape(warning_msg)}/).to_stdout
|
||||
end
|
||||
end
|
||||
|
||||
it "doesn't fail for no servers" do
|
||||
expect { doc.call }.to output("\nServers (0)\n \n").to_stdout
|
||||
end
|
||||
|
||||
describe "Rake" do
|
||||
before do
|
||||
load File.expand_path("../../../../../lib/capistrano/doctor.rb",
|
||||
__FILE__)
|
||||
end
|
||||
|
||||
after do
|
||||
Rake::Task.clear
|
||||
end
|
||||
|
||||
it "has an doctor:servers task that calls ServersDoctor" do
|
||||
ServersDoctor.any_instance.expects(:call)
|
||||
Rake::Task["doctor:servers"].invoke
|
||||
end
|
||||
|
||||
it "has a doctor task that depends on doctor:servers" do
|
||||
expect(Rake::Task["doctor"].prerequisites).to \
|
||||
include("doctor:servers")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue