kdeploy 1.1.9 → 1.2.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.
- checksums.yaml +4 -4
- data/README.md +852 -75
- data/exe/kdeploy +11 -11
- data/lib/kdeploy/banner.rb +1 -1
- data/lib/kdeploy/cli.rb +6 -1
- data/lib/kdeploy/command_executor.rb +88 -0
- data/lib/kdeploy/command_grouper.rb +38 -0
- data/lib/kdeploy/configuration.rb +25 -0
- data/lib/kdeploy/dsl.rb +2 -0
- data/lib/kdeploy/errors.rb +64 -0
- data/lib/kdeploy/executor.rb +5 -5
- data/lib/kdeploy/output.rb +69 -0
- data/lib/kdeploy/runner.rb +48 -71
- data/lib/kdeploy/version.rb +1 -1
- data/lib/kdeploy.rb +5 -1
- metadata +7 -2
data/exe/kdeploy
CHANGED
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
# 自动修复常见 gem 扩展
|
|
5
|
-
%w[debug rbs].zip(%w[1.7.1 2.8.2]).each do |gem_name, version|
|
|
6
|
-
|
|
7
|
-
rescue LoadError
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
end
|
|
5
|
+
# %w[debug rbs].zip(%w[1.7.1 2.8.2]).each do |gem_name, version|
|
|
6
|
+
# require gem_name
|
|
7
|
+
# rescue LoadError
|
|
8
|
+
# warn "[Kdeploy] 自动修复 #{gem_name}-#{version} ..."
|
|
9
|
+
# system("gem pristine #{gem_name} --version #{version}")
|
|
10
|
+
# begin
|
|
11
|
+
# require gem_name
|
|
12
|
+
# rescue LoadError
|
|
13
|
+
# warn "[Kdeploy] 依然无法加载 #{gem_name}-#{version},请手动修复。"
|
|
14
|
+
# end
|
|
15
|
+
# end
|
|
16
16
|
|
|
17
17
|
require 'kdeploy'
|
|
18
18
|
|
data/lib/kdeploy/banner.rb
CHANGED
data/lib/kdeploy/cli.rb
CHANGED
|
@@ -108,7 +108,8 @@ module Kdeploy
|
|
|
108
108
|
next
|
|
109
109
|
end
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
output = ConsoleOutput.new
|
|
112
|
+
runner = Runner.new(hosts, self.class.kdeploy_tasks, parallel: options[:parallel], output: output)
|
|
112
113
|
results = runner.run(task)
|
|
113
114
|
print_results(results, task)
|
|
114
115
|
end
|
|
@@ -127,6 +128,10 @@ module Kdeploy
|
|
|
127
128
|
|
|
128
129
|
# 用 instance_eval 并传递顶层 binding,兼容 heredoc
|
|
129
130
|
self.class.module_eval(File.read(file), file)
|
|
131
|
+
rescue StandardError => e
|
|
132
|
+
raise FileNotFoundError, file if e.message.include?('not found')
|
|
133
|
+
|
|
134
|
+
raise
|
|
130
135
|
end
|
|
131
136
|
|
|
132
137
|
def filter_hosts(limit, task_hosts)
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Kdeploy
|
|
4
|
+
# Executes a single command and records execution time
|
|
5
|
+
class CommandExecutor
|
|
6
|
+
def initialize(executor, output)
|
|
7
|
+
@executor = executor
|
|
8
|
+
@output = output
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def execute_run(command, host_name)
|
|
12
|
+
show_command_header(host_name, :run, command[:command])
|
|
13
|
+
result, duration = measure_time do
|
|
14
|
+
@executor.execute(command[:command])
|
|
15
|
+
end
|
|
16
|
+
show_command_output(result)
|
|
17
|
+
{ command: command[:command], output: result, duration: duration, type: :run }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def execute_upload(command, host_name)
|
|
21
|
+
show_command_header(host_name, :upload, "#{command[:source]} -> #{command[:destination]}")
|
|
22
|
+
_result, duration = measure_time do
|
|
23
|
+
@executor.upload(command[:source], command[:destination])
|
|
24
|
+
end
|
|
25
|
+
{
|
|
26
|
+
command: "upload: #{command[:source]} -> #{command[:destination]}",
|
|
27
|
+
duration: duration,
|
|
28
|
+
type: :upload
|
|
29
|
+
}
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def execute_upload_template(command, host_name)
|
|
33
|
+
show_command_header(host_name, :upload_template, "#{command[:source]} -> #{command[:destination]}")
|
|
34
|
+
_result, duration = measure_time do
|
|
35
|
+
@executor.upload_template(command[:source], command[:destination], command[:variables])
|
|
36
|
+
end
|
|
37
|
+
{
|
|
38
|
+
command: "upload_template: #{command[:source]} -> #{command[:destination]}",
|
|
39
|
+
duration: duration,
|
|
40
|
+
type: :upload_template
|
|
41
|
+
}
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def measure_time
|
|
47
|
+
start_time = Time.now
|
|
48
|
+
result = yield
|
|
49
|
+
duration = Time.now - start_time
|
|
50
|
+
[result, duration]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def show_command_output(output)
|
|
54
|
+
return unless output.is_a?(Hash)
|
|
55
|
+
|
|
56
|
+
pastel = @output.respond_to?(:pastel) ? @output.pastel : Pastel.new
|
|
57
|
+
|
|
58
|
+
if output[:stdout] && !output[:stdout].empty?
|
|
59
|
+
output[:stdout].each_line do |line|
|
|
60
|
+
@output.write_line(" #{line.rstrip}") unless line.strip.empty?
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
return unless output[:stderr] && !output[:stderr].empty?
|
|
65
|
+
|
|
66
|
+
output[:stderr].each_line do |line|
|
|
67
|
+
@output.write_line(pastel.green(" #{line.rstrip}")) unless line.strip.empty?
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def show_command_header(host_name, type, description)
|
|
72
|
+
pastel = @output.respond_to?(:pastel) ? @output.pastel : Pastel.new
|
|
73
|
+
@output.write_line(pastel.bright_white("\n#{host_name.ljust(24)} : "))
|
|
74
|
+
|
|
75
|
+
case type
|
|
76
|
+
when :run
|
|
77
|
+
@output.write_line(pastel.cyan(" [run] #{description.lines.first.strip}"))
|
|
78
|
+
description.lines[1..].each do |line|
|
|
79
|
+
@output.write_line(" > #{line.strip}") unless line.strip.empty?
|
|
80
|
+
end
|
|
81
|
+
when :upload
|
|
82
|
+
@output.write_line(pastel.green(" [upload] #{description}"))
|
|
83
|
+
when :upload_template
|
|
84
|
+
@output.write_line(pastel.yellow(" [template] #{description}"))
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Kdeploy
|
|
4
|
+
# Groups commands by type and generates task descriptions
|
|
5
|
+
class CommandGrouper
|
|
6
|
+
def self.group(commands)
|
|
7
|
+
commands.group_by do |cmd|
|
|
8
|
+
group_key_for(cmd)
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.group_key_for(cmd)
|
|
13
|
+
case cmd[:type]
|
|
14
|
+
when :upload
|
|
15
|
+
"#{cmd[:type]}_#{cmd[:source]}"
|
|
16
|
+
when :run
|
|
17
|
+
"#{cmd[:type]}_#{cmd[:command].to_s.lines.first.strip}"
|
|
18
|
+
when :upload_template
|
|
19
|
+
"#{cmd[:type]}_#{cmd[:source]}"
|
|
20
|
+
else
|
|
21
|
+
cmd[:type].to_s
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.task_description(command)
|
|
26
|
+
case command[:type]
|
|
27
|
+
when :upload
|
|
28
|
+
"upload #{command[:source]}"
|
|
29
|
+
when :upload_template
|
|
30
|
+
"template #{command[:source]}"
|
|
31
|
+
when :run
|
|
32
|
+
command[:command].to_s.lines.first.strip
|
|
33
|
+
else
|
|
34
|
+
command[:type].to_s
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Kdeploy
|
|
4
|
+
# Configuration management for Kdeploy
|
|
5
|
+
class Configuration
|
|
6
|
+
DEFAULT_PARALLEL = 10
|
|
7
|
+
DEFAULT_SSH_TIMEOUT = 30
|
|
8
|
+
DEFAULT_VERIFY_HOST_KEY = :never
|
|
9
|
+
|
|
10
|
+
class << self
|
|
11
|
+
attr_accessor :default_parallel,
|
|
12
|
+
:default_ssh_timeout,
|
|
13
|
+
:default_verify_host_key
|
|
14
|
+
|
|
15
|
+
def reset
|
|
16
|
+
@default_parallel = DEFAULT_PARALLEL
|
|
17
|
+
@default_ssh_timeout = DEFAULT_SSH_TIMEOUT
|
|
18
|
+
@default_verify_host_key = DEFAULT_VERIFY_HOST_KEY
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Initialize with defaults
|
|
23
|
+
reset
|
|
24
|
+
end
|
|
25
|
+
end
|
data/lib/kdeploy/dsl.rb
CHANGED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Kdeploy
|
|
4
|
+
# Base error class for all Kdeploy errors
|
|
5
|
+
class Error < StandardError; end
|
|
6
|
+
|
|
7
|
+
# Raised when a task is not found
|
|
8
|
+
class TaskNotFoundError < Error
|
|
9
|
+
def initialize(task_name)
|
|
10
|
+
super("Task not found: #{task_name}")
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Raised when a host is not found
|
|
15
|
+
class HostNotFoundError < Error
|
|
16
|
+
def initialize(host_name)
|
|
17
|
+
super("Host not found: #{host_name}")
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Raised when SSH operation fails
|
|
22
|
+
class SSHError < Error
|
|
23
|
+
def initialize(message, original_error = nil)
|
|
24
|
+
super("SSH operation failed: #{message}")
|
|
25
|
+
@original_error = original_error
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
attr_reader :original_error
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Raised when SCP operation fails
|
|
32
|
+
class SCPError < Error
|
|
33
|
+
def initialize(message, original_error = nil)
|
|
34
|
+
super("SCP upload failed: #{message}")
|
|
35
|
+
@original_error = original_error
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
attr_reader :original_error
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Raised when template operation fails
|
|
42
|
+
class TemplateError < Error
|
|
43
|
+
def initialize(message, original_error = nil)
|
|
44
|
+
super("Template operation failed: #{message}")
|
|
45
|
+
@original_error = original_error
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
attr_reader :original_error
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Raised when configuration is invalid
|
|
52
|
+
class ConfigurationError < Error
|
|
53
|
+
def initialize(message)
|
|
54
|
+
super("Configuration error: #{message}")
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Raised when file operation fails
|
|
59
|
+
class FileNotFoundError < Error
|
|
60
|
+
def initialize(file_path)
|
|
61
|
+
super("File not found: #{file_path}")
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
data/lib/kdeploy/executor.rb
CHANGED
|
@@ -21,7 +21,7 @@ module Kdeploy
|
|
|
21
21
|
|
|
22
22
|
ssh.open_channel do |channel|
|
|
23
23
|
channel.exec(command) do |_ch, success|
|
|
24
|
-
raise "Could not execute command: #{command}" unless success
|
|
24
|
+
raise SSHError, "Could not execute command: #{command}" unless success
|
|
25
25
|
|
|
26
26
|
channel.on_data do |_ch, data|
|
|
27
27
|
stdout << data
|
|
@@ -40,9 +40,9 @@ module Kdeploy
|
|
|
40
40
|
}
|
|
41
41
|
end
|
|
42
42
|
rescue Net::SSH::AuthenticationFailed => e
|
|
43
|
-
raise "SSH authentication failed: #{e.message}"
|
|
43
|
+
raise SSHError.new("SSH authentication failed: #{e.message}", e)
|
|
44
44
|
rescue StandardError => e
|
|
45
|
-
raise "SSH execution failed: #{e.message}"
|
|
45
|
+
raise SSHError.new("SSH execution failed: #{e.message}", e)
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
def upload(source, destination)
|
|
@@ -50,13 +50,13 @@ module Kdeploy
|
|
|
50
50
|
scp.upload!(source, destination)
|
|
51
51
|
end
|
|
52
52
|
rescue StandardError => e
|
|
53
|
-
raise "SCP upload failed: #{e.message}"
|
|
53
|
+
raise SCPError.new("SCP upload failed: #{e.message}", e)
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
def upload_template(source, destination, variables = {})
|
|
57
57
|
Template.render_and_upload(self, source, destination, variables)
|
|
58
58
|
rescue StandardError => e
|
|
59
|
-
raise "Template upload failed: #{e.message}"
|
|
59
|
+
raise TemplateError.new("Template upload failed: #{e.message}", e)
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
private
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'pastel'
|
|
4
|
+
|
|
5
|
+
module Kdeploy
|
|
6
|
+
# Abstract output interface
|
|
7
|
+
class Output
|
|
8
|
+
def write(message)
|
|
9
|
+
raise NotImplementedError, 'Subclasses must implement write'
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def write_line(message)
|
|
13
|
+
write("#{message}\n")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def write_error(message)
|
|
17
|
+
write_line(message)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Console output implementation
|
|
22
|
+
class ConsoleOutput < Output
|
|
23
|
+
def initialize
|
|
24
|
+
@pastel = Pastel.new
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def write(message)
|
|
28
|
+
print(message)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def write_line(message)
|
|
32
|
+
puts(message)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def write_error(message)
|
|
36
|
+
puts(@pastel.red(message))
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
attr_reader :pastel
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Silent output for testing
|
|
43
|
+
class SilentOutput < Output
|
|
44
|
+
attr_reader :messages, :errors
|
|
45
|
+
|
|
46
|
+
def initialize
|
|
47
|
+
@messages = []
|
|
48
|
+
@errors = []
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def write(message)
|
|
52
|
+
@messages << message
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def write_line(message)
|
|
56
|
+
@messages << "#{message}\n"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def write_error(message)
|
|
60
|
+
@errors << message
|
|
61
|
+
@messages << "#{message}\n"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def clear
|
|
65
|
+
@messages.clear
|
|
66
|
+
@errors.clear
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
data/lib/kdeploy/runner.rb
CHANGED
|
@@ -4,89 +4,22 @@ require 'concurrent'
|
|
|
4
4
|
|
|
5
5
|
module Kdeploy
|
|
6
6
|
class Runner
|
|
7
|
-
def initialize(hosts, tasks, parallel:
|
|
7
|
+
def initialize(hosts, tasks, parallel: Configuration.default_parallel, output: ConsoleOutput.new)
|
|
8
8
|
@hosts = hosts
|
|
9
9
|
@tasks = tasks
|
|
10
10
|
@parallel = parallel
|
|
11
|
+
@output = output
|
|
11
12
|
@pool = Concurrent::FixedThreadPool.new(@parallel)
|
|
12
13
|
@results = Concurrent::Hash.new
|
|
13
14
|
end
|
|
14
15
|
|
|
15
16
|
def run(task_name)
|
|
16
17
|
task = @tasks[task_name]
|
|
17
|
-
raise
|
|
18
|
+
raise TaskNotFoundError, task_name unless task
|
|
18
19
|
|
|
19
20
|
futures = @hosts.map do |name, config|
|
|
20
21
|
Concurrent::Future.execute(executor: @pool) do
|
|
21
|
-
|
|
22
|
-
result = { status: :success, output: [] }
|
|
23
|
-
|
|
24
|
-
task[:block].call.group_by do |cmd|
|
|
25
|
-
cmd[:type].to_s + (if cmd[:type] == :upload
|
|
26
|
-
cmd[:source].to_s
|
|
27
|
-
else
|
|
28
|
-
cmd[:type] == :run ? cmd[:command].to_s.lines.first.strip : ''
|
|
29
|
-
end)
|
|
30
|
-
end.each_value do |commands|
|
|
31
|
-
# 生成 TASK 横幅
|
|
32
|
-
pastel = Pastel.new
|
|
33
|
-
first_cmd = commands.first
|
|
34
|
-
task_desc = case first_cmd[:type]
|
|
35
|
-
when :upload
|
|
36
|
-
"upload #{first_cmd[:source]}"
|
|
37
|
-
when :upload_template
|
|
38
|
-
"template #{first_cmd[:source]}"
|
|
39
|
-
when :run
|
|
40
|
-
first_cmd[:command].to_s.lines.first.strip
|
|
41
|
-
else
|
|
42
|
-
first_cmd[:type].to_s
|
|
43
|
-
end
|
|
44
|
-
puts pastel.cyan("\nTASK [#{task_desc}] " + ('*' * 64))
|
|
45
|
-
commands.each do |command|
|
|
46
|
-
case command[:type]
|
|
47
|
-
when :run
|
|
48
|
-
pastel = Pastel.new
|
|
49
|
-
puts pastel.bright_white("\n#{name.ljust(24)} : ")
|
|
50
|
-
puts pastel.cyan(" [run] #{command[:command].lines.first.strip}")
|
|
51
|
-
command[:command].lines[1..].each { |line| puts " > #{line.strip}" unless line.strip.empty? }
|
|
52
|
-
t1 = Time.now
|
|
53
|
-
output = executor.execute(command[:command])
|
|
54
|
-
t2 = Time.now
|
|
55
|
-
duration = t2 - t1
|
|
56
|
-
# 统一输出命令结果
|
|
57
|
-
if output[:stdout] && !output[:stdout].empty?
|
|
58
|
-
output[:stdout].each_line { |line| puts " #{line.rstrip}" unless line.strip.empty? }
|
|
59
|
-
end
|
|
60
|
-
if output[:stderr] && !output[:stderr].empty?
|
|
61
|
-
output[:stderr].each_line { |line| puts pastel.green(" #{line.rstrip}") unless line.strip.empty? }
|
|
62
|
-
end
|
|
63
|
-
result[:output] << { command: command[:command], output: output, duration: duration, type: :run }
|
|
64
|
-
when :upload
|
|
65
|
-
pastel = Pastel.new
|
|
66
|
-
puts pastel.bright_white("\n#{name.ljust(24)} : ")
|
|
67
|
-
puts pastel.green(" [upload] #{command[:source]} -> #{command[:destination]}")
|
|
68
|
-
t1 = Time.now
|
|
69
|
-
executor.upload(command[:source], command[:destination])
|
|
70
|
-
t2 = Time.now
|
|
71
|
-
duration = t2 - t1
|
|
72
|
-
result[:output] << { command: "upload: #{command[:source]} -> #{command[:destination]}", duration: duration, type: :upload }
|
|
73
|
-
when :upload_template
|
|
74
|
-
pastel = Pastel.new
|
|
75
|
-
puts pastel.bright_white("\n#{name.ljust(24)} : ")
|
|
76
|
-
puts pastel.yellow(" [template] #{command[:source]} -> #{command[:destination]}")
|
|
77
|
-
t1 = Time.now
|
|
78
|
-
executor.upload_template(command[:source], command[:destination], command[:vars])
|
|
79
|
-
t2 = Time.now
|
|
80
|
-
duration = t2 - t1
|
|
81
|
-
result[:output] << { command: "upload_template: #{command[:source]} -> #{command[:destination]}", duration: duration,
|
|
82
|
-
type: :upload_template }
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
@results[name] = result
|
|
88
|
-
rescue StandardError => e
|
|
89
|
-
@results[name] = { status: :failed, error: e.message }
|
|
22
|
+
execute_task_for_host(name, config, task)
|
|
90
23
|
end
|
|
91
24
|
end
|
|
92
25
|
|
|
@@ -95,5 +28,49 @@ module Kdeploy
|
|
|
95
28
|
ensure
|
|
96
29
|
@pool.shutdown
|
|
97
30
|
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def execute_task_for_host(name, config, task)
|
|
35
|
+
executor = Executor.new(config)
|
|
36
|
+
command_executor = CommandExecutor.new(executor, @output)
|
|
37
|
+
result = { status: :success, output: [] }
|
|
38
|
+
|
|
39
|
+
commands = task[:block].call
|
|
40
|
+
grouped_commands = CommandGrouper.group(commands)
|
|
41
|
+
|
|
42
|
+
grouped_commands.each_value do |command_group|
|
|
43
|
+
first_cmd = command_group.first
|
|
44
|
+
task_desc = CommandGrouper.task_description(first_cmd)
|
|
45
|
+
show_task_header(task_desc)
|
|
46
|
+
|
|
47
|
+
command_group.each do |command|
|
|
48
|
+
step_result = execute_command(command_executor, command, name)
|
|
49
|
+
result[:output] << step_result
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
@results[name] = result
|
|
54
|
+
rescue StandardError => e
|
|
55
|
+
@results[name] = { status: :failed, error: e.message }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def execute_command(command_executor, command, host_name)
|
|
59
|
+
case command[:type]
|
|
60
|
+
when :run
|
|
61
|
+
command_executor.execute_run(command, host_name)
|
|
62
|
+
when :upload
|
|
63
|
+
command_executor.execute_upload(command, host_name)
|
|
64
|
+
when :upload_template
|
|
65
|
+
command_executor.execute_upload_template(command, host_name)
|
|
66
|
+
else
|
|
67
|
+
raise ConfigurationError, "Unknown command type: #{command[:type]}"
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def show_task_header(task_desc)
|
|
72
|
+
pastel = @output.respond_to?(:pastel) ? @output.pastel : Pastel.new
|
|
73
|
+
@output.write_line(pastel.cyan("\nTASK [#{task_desc}] " + ('*' * 64)))
|
|
74
|
+
end
|
|
98
75
|
end
|
|
99
76
|
end
|
data/lib/kdeploy/version.rb
CHANGED
data/lib/kdeploy.rb
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative 'kdeploy/version'
|
|
4
|
+
require_relative 'kdeploy/errors'
|
|
5
|
+
require_relative 'kdeploy/configuration'
|
|
6
|
+
require_relative 'kdeploy/output'
|
|
4
7
|
require_relative 'kdeploy/banner'
|
|
5
8
|
require_relative 'kdeploy/dsl'
|
|
6
9
|
require_relative 'kdeploy/executor'
|
|
10
|
+
require_relative 'kdeploy/command_grouper'
|
|
11
|
+
require_relative 'kdeploy/command_executor'
|
|
7
12
|
require_relative 'kdeploy/runner'
|
|
8
13
|
require_relative 'kdeploy/initializer'
|
|
9
14
|
require_relative 'kdeploy/template'
|
|
@@ -11,6 +16,5 @@ require_relative 'kdeploy/post_install'
|
|
|
11
16
|
require_relative 'kdeploy/cli'
|
|
12
17
|
|
|
13
18
|
module Kdeploy
|
|
14
|
-
class Error < StandardError; end
|
|
15
19
|
# Your code goes here...
|
|
16
20
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kdeploy
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kk
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-
|
|
11
|
+
date: 2025-11-18 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: concurrent-ruby
|
|
@@ -180,11 +180,16 @@ files:
|
|
|
180
180
|
- lib/kdeploy.rb
|
|
181
181
|
- lib/kdeploy/banner.rb
|
|
182
182
|
- lib/kdeploy/cli.rb
|
|
183
|
+
- lib/kdeploy/command_executor.rb
|
|
184
|
+
- lib/kdeploy/command_grouper.rb
|
|
183
185
|
- lib/kdeploy/completions/kdeploy.bash
|
|
184
186
|
- lib/kdeploy/completions/kdeploy.zsh
|
|
187
|
+
- lib/kdeploy/configuration.rb
|
|
185
188
|
- lib/kdeploy/dsl.rb
|
|
189
|
+
- lib/kdeploy/errors.rb
|
|
186
190
|
- lib/kdeploy/executor.rb
|
|
187
191
|
- lib/kdeploy/initializer.rb
|
|
192
|
+
- lib/kdeploy/output.rb
|
|
188
193
|
- lib/kdeploy/post_install.rb
|
|
189
194
|
- lib/kdeploy/runner.rb
|
|
190
195
|
- lib/kdeploy/template.rb
|