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
|
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)
|
* Raise a better error when an ‘after’ hook isn’t found (@jdelStrother)
|
||||||
* Restrict the uploaded git wrapper script permissions to 700 (@irvingwashington)
|
* Restrict the uploaded git wrapper script permissions to 700 (@irvingwashington)
|
||||||
* Make path to git wrapper script configurable (@thickpaddy)
|
* Make path to git wrapper script configurable (@thickpaddy)
|
||||||
|
|
|
@ -133,16 +133,16 @@ module Capistrano
|
||||||
installer.install(plugin, load_hooks: load_hooks)
|
installer.install(plugin, load_hooks: load_hooks)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def servers
|
||||||
|
@servers ||= Servers.new
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def cmdline_filters
|
def cmdline_filters
|
||||||
@cmdline_filters ||= []
|
@cmdline_filters ||= []
|
||||||
end
|
end
|
||||||
|
|
||||||
def servers
|
|
||||||
@servers ||= Servers.new
|
|
||||||
end
|
|
||||||
|
|
||||||
def installer
|
def installer
|
||||||
@installer ||= PluginInstaller.new
|
@installer ||= PluginInstaller.new
|
||||||
end
|
end
|
||||||
|
|
|
@ -119,6 +119,10 @@ module Capistrano
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def to_h
|
||||||
|
@properties
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def lvalue(key)
|
def lvalue(key)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
require "capistrano/doctor/environment_doctor"
|
require "capistrano/doctor/environment_doctor"
|
||||||
require "capistrano/doctor/gems_doctor"
|
require "capistrano/doctor/gems_doctor"
|
||||||
require "capistrano/doctor/variables_doctor"
|
require "capistrano/doctor/variables_doctor"
|
||||||
|
require "capistrano/doctor/servers_doctor"
|
||||||
|
|
||||||
load File.expand_path("../tasks/doctor.rake", __FILE__)
|
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)"
|
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
|
namespace :doctor do
|
||||||
desc "Display Ruby environment details"
|
desc "Display Ruby environment details"
|
||||||
|
@ -16,4 +16,9 @@ namespace :doctor do
|
||||||
task :variables do
|
task :variables do
|
||||||
Capistrano::Doctor::VariablesDoctor.new.call
|
Capistrano::Doctor::VariablesDoctor.new.call
|
||||||
end
|
end
|
||||||
|
|
||||||
|
desc "Display the effective servers configuration"
|
||||||
|
task :servers do
|
||||||
|
Capistrano::Doctor::ServersDoctor.new.call
|
||||||
|
end
|
||||||
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