kdeploy 1.2.30 → 1.2.38
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/AGENTS.md +18 -0
- data/README.md +78 -6
- data/README_EN.md +78 -6
- data/exe/kdeploy +0 -14
- data/lib/kdeploy/cli.rb +137 -14
- data/lib/kdeploy/command_executor.rb +30 -81
- data/lib/kdeploy/configuration.rb +9 -1
- data/lib/kdeploy/dsl.rb +109 -0
- data/lib/kdeploy/errors.rb +6 -2
- data/lib/kdeploy/executor.rb +23 -3
- data/lib/kdeploy/file_filter.rb +14 -3
- data/lib/kdeploy/help_formatter.rb +12 -1
- data/lib/kdeploy/initializer.rb +22 -30
- data/lib/kdeploy/output_formatter.rb +49 -43
- data/lib/kdeploy/runner.rb +74 -46
- data/lib/kdeploy/version.rb +1 -1
- data/lib/kdeploy.rb +0 -1
- data/r.md +1 -0
- metadata +4 -3
- data/lib/kdeploy/command_grouper.rb +0 -38
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 29a2ac38f02097f22a48646d3d6483b4e3fd65513f01eb6044ba7efd85f9e51f
|
|
4
|
+
data.tar.gz: 27d6af727a2929a8fe7ec7bca6e7b63a8b2acc6a373ab73baa89b536fbb76941
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6ec34aac0c945e25101d9a3d91b68121660a5ab16d47cb7d8cb736805d83ef4f09fd92701351051449ecf6427f85f955a93384ef99cffebebeae09cf1b9a11e1
|
|
7
|
+
data.tar.gz: 416f3adfc65db0a5534cafc2853296fe585742470a482802ad08156f13acb1259ff86bf33c5a10c6c5d671eaae2b04b5a8de3c1f2bdfb0e82646a58bc3512cfd
|
data/AGENTS.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<!-- OPENSPEC:START -->
|
|
2
|
+
# OpenSpec Instructions
|
|
3
|
+
|
|
4
|
+
These instructions are for AI assistants working in this project.
|
|
5
|
+
|
|
6
|
+
Always open `@/openspec/AGENTS.md` when the request:
|
|
7
|
+
- Mentions planning or proposals (words like proposal, spec, change, plan)
|
|
8
|
+
- Introduces new capabilities, breaking changes, architecture shifts, or big performance/security work
|
|
9
|
+
- Sounds ambiguous and you need the authoritative spec before coding
|
|
10
|
+
|
|
11
|
+
Use `@/openspec/AGENTS.md` to learn:
|
|
12
|
+
- How to create and apply change proposals
|
|
13
|
+
- Spec format and conventions
|
|
14
|
+
- Project structure and guidelines
|
|
15
|
+
|
|
16
|
+
Keep this managed block so 'openspec update' can refresh the instructions.
|
|
17
|
+
|
|
18
|
+
<!-- OPENSPEC:END -->
|
data/README.md
CHANGED
|
@@ -201,6 +201,11 @@ kdeploy execute deploy.rb deploy_web
|
|
|
201
201
|
- `--limit HOSTS`: 限制执行到特定主机(逗号分隔)
|
|
202
202
|
- `--parallel NUM`: 并行执行数量(默认: 10)
|
|
203
203
|
- `--dry-run`: 预览模式 - 显示将要执行的操作而不实际执行
|
|
204
|
+
- `--debug`: 调试模式 - 显示 `run` 命令的 stdout/stderr 详细输出(便于排查问题)
|
|
205
|
+
- `--no-banner`: 不输出 Banner(更适合脚本/CI 场景)
|
|
206
|
+
- `--format FORMAT`: 输出格式(`text`|`json`,默认 `text`)
|
|
207
|
+
- `--retries N`: 网络相关操作重试次数(默认 `0`)
|
|
208
|
+
- `--retry-delay SECONDS`: 每次重试间隔秒数(默认 `1`)
|
|
204
209
|
|
|
205
210
|
**示例:**
|
|
206
211
|
```bash
|
|
@@ -213,6 +218,15 @@ kdeploy execute deploy.rb deploy_web --limit web01,web02
|
|
|
213
218
|
# 使用自定义并行数量
|
|
214
219
|
kdeploy execute deploy.rb deploy_web --parallel 5
|
|
215
220
|
|
|
221
|
+
# 输出详细调试信息(stdout/stderr)
|
|
222
|
+
kdeploy execute deploy.rb deploy_web --debug
|
|
223
|
+
|
|
224
|
+
# 机器可读 JSON 输出(便于集成)
|
|
225
|
+
kdeploy execute deploy.rb deploy_web --format json --no-banner
|
|
226
|
+
|
|
227
|
+
# 重试网络抖动导致的失败
|
|
228
|
+
kdeploy execute deploy.rb deploy_web --retries 3 --retry-delay 1
|
|
229
|
+
|
|
216
230
|
# 组合选项
|
|
217
231
|
kdeploy execute deploy.rb deploy_web --limit web01 --parallel 3 --dry-run
|
|
218
232
|
```
|
|
@@ -515,6 +529,67 @@ sync "./config", "/etc/app",
|
|
|
515
529
|
- 同步静态资源文件
|
|
516
530
|
- 保持本地和远程目录结构一致
|
|
517
531
|
|
|
532
|
+
### Chef 风格资源 DSL
|
|
533
|
+
|
|
534
|
+
Kdeploy 提供类似 Chef 的声明式资源 DSL,可替代或与底层原语(`run`、`upload`、`upload_template`)混用。
|
|
535
|
+
|
|
536
|
+
#### `package` - 安装系统包
|
|
537
|
+
|
|
538
|
+
```ruby
|
|
539
|
+
package "nginx"
|
|
540
|
+
package "nginx", version: "1.18"
|
|
541
|
+
package "nginx", platform: :yum # CentOS/RHEL
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
默认使用 apt(Ubuntu/Debian);`platform: :yum` 生成 yum 命令。
|
|
545
|
+
|
|
546
|
+
#### `service` - 管理系统服务(systemd)
|
|
547
|
+
|
|
548
|
+
```ruby
|
|
549
|
+
service "nginx", action: [:enable, :start]
|
|
550
|
+
service "nginx", action: :restart
|
|
551
|
+
service "nginx", action: [:stop, :disable]
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
支持 `:start`、`:stop`、`:restart`、`:reload`、`:enable`、`:disable`。
|
|
555
|
+
|
|
556
|
+
#### `template` - 部署 ERB 模板
|
|
557
|
+
|
|
558
|
+
```ruby
|
|
559
|
+
template "/etc/nginx/nginx.conf", source: "./config/nginx.conf.erb", variables: { port: 3000 }
|
|
560
|
+
# 或 block 语法
|
|
561
|
+
template "/etc/app.conf" do
|
|
562
|
+
source "./config/app.erb"
|
|
563
|
+
variables(domain: "example.com")
|
|
564
|
+
end
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
#### `file` - 上传本地文件
|
|
568
|
+
|
|
569
|
+
```ruby
|
|
570
|
+
file "/etc/nginx/conf.d/app.conf", source: "./config/app.conf"
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
#### `directory` - 确保远程目录存在
|
|
574
|
+
|
|
575
|
+
```ruby
|
|
576
|
+
directory "/etc/nginx/conf.d"
|
|
577
|
+
directory "/var/log/app", mode: "0755"
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
**示例:使用资源 DSL 部署 Nginx**
|
|
581
|
+
|
|
582
|
+
```ruby
|
|
583
|
+
task :deploy_nginx, roles: :web do
|
|
584
|
+
package "nginx"
|
|
585
|
+
directory "/etc/nginx/conf.d"
|
|
586
|
+
template "/etc/nginx/nginx.conf", source: "./config/nginx.conf.erb", variables: { port: 3000 }
|
|
587
|
+
file "/etc/nginx/conf.d/app.conf", source: "./config/app.conf"
|
|
588
|
+
run "nginx -t"
|
|
589
|
+
service "nginx", action: [:enable, :restart]
|
|
590
|
+
end
|
|
591
|
+
```
|
|
592
|
+
|
|
518
593
|
### 模板支持
|
|
519
594
|
|
|
520
595
|
Kdeploy 支持 ERB(嵌入式 Ruby)模板,用于动态配置生成。
|
|
@@ -861,7 +936,6 @@ kdeploy execute deploy.rb deploy --parallel 3
|
|
|
861
936
|
- **Executor** (`executor.rb`): SSH/SCP 执行引擎
|
|
862
937
|
- **Runner** (`runner.rb`): 并发任务执行协调器
|
|
863
938
|
- **CommandExecutor** (`command_executor.rb`): 单个命令执行
|
|
864
|
-
- **CommandGrouper** (`command_grouper.rb`): 命令分组逻辑
|
|
865
939
|
- **Template** (`template.rb`): ERB 模板渲染
|
|
866
940
|
- **Output** (`output.rb`): 输出格式化和显示
|
|
867
941
|
- **Configuration** (`configuration.rb`): 配置管理
|
|
@@ -871,10 +945,9 @@ kdeploy execute deploy.rb deploy --parallel 3
|
|
|
871
945
|
|
|
872
946
|
1. **解析配置**: 加载并解析 `deploy.rb`
|
|
873
947
|
2. **解析主机**: 根据任务定义确定目标主机
|
|
874
|
-
3.
|
|
875
|
-
4.
|
|
876
|
-
5.
|
|
877
|
-
6. **显示输出**: 格式化并向用户显示结果
|
|
948
|
+
3. **并发执行**: 跨主机并行运行任务,按序执行每台主机上的命令
|
|
949
|
+
4. **收集结果**: 收集执行结果和状态
|
|
950
|
+
5. **显示输出**: 格式化并向用户显示结果
|
|
878
951
|
|
|
879
952
|
### 并发模型
|
|
880
953
|
|
|
@@ -914,7 +987,6 @@ kdeploy/
|
|
|
914
987
|
│ ├── executor.rb # SSH/SCP 执行器
|
|
915
988
|
│ ├── runner.rb # 任务运行器
|
|
916
989
|
│ ├── command_executor.rb # 命令执行器
|
|
917
|
-
│ ├── command_grouper.rb # 命令分组器
|
|
918
990
|
│ ├── template.rb # 模板处理器
|
|
919
991
|
│ ├── output.rb # 输出接口
|
|
920
992
|
│ ├── configuration.rb # 配置
|
data/README_EN.md
CHANGED
|
@@ -200,6 +200,11 @@ kdeploy execute deploy.rb deploy_web
|
|
|
200
200
|
- `--limit HOSTS`: Limit execution to specific hosts (comma-separated)
|
|
201
201
|
- `--parallel NUM`: Number of parallel executions (default: 10)
|
|
202
202
|
- `--dry-run`: Preview mode - show what would be done without executing
|
|
203
|
+
- `--debug`: Debug mode - show detailed stdout/stderr output for `run` steps
|
|
204
|
+
- `--no-banner`: Do not print banner (automation-friendly)
|
|
205
|
+
- `--format FORMAT`: Output format (`text`|`json`, default `text`)
|
|
206
|
+
- `--retries N`: Retry count for network operations (default `0`)
|
|
207
|
+
- `--retry-delay SECONDS`: Delay between retries in seconds (default `1`)
|
|
203
208
|
|
|
204
209
|
**Examples:**
|
|
205
210
|
```bash
|
|
@@ -212,6 +217,15 @@ kdeploy execute deploy.rb deploy_web --limit web01,web02
|
|
|
212
217
|
# Use custom parallel count
|
|
213
218
|
kdeploy execute deploy.rb deploy_web --parallel 5
|
|
214
219
|
|
|
220
|
+
# Show detailed stdout/stderr output
|
|
221
|
+
kdeploy execute deploy.rb deploy_web --debug
|
|
222
|
+
|
|
223
|
+
# Machine-readable JSON output
|
|
224
|
+
kdeploy execute deploy.rb deploy_web --format json --no-banner
|
|
225
|
+
|
|
226
|
+
# Retry transient network failures
|
|
227
|
+
kdeploy execute deploy.rb deploy_web --retries 3 --retry-delay 1
|
|
228
|
+
|
|
215
229
|
# Combine options
|
|
216
230
|
kdeploy execute deploy.rb deploy_web --limit web01 --parallel 3 --dry-run
|
|
217
231
|
```
|
|
@@ -472,6 +486,67 @@ upload_template "./config/nginx.conf.erb", "/etc/nginx/nginx.conf",
|
|
|
472
486
|
- `destination`: Remote file path
|
|
473
487
|
- `variables`: Hash of variables for template rendering
|
|
474
488
|
|
|
489
|
+
### Chef-Style Resource DSL
|
|
490
|
+
|
|
491
|
+
Kdeploy provides a declarative resource DSL similar to Chef, which can replace or mix with low-level primitives (`run`, `upload`, `upload_template`).
|
|
492
|
+
|
|
493
|
+
#### `package` - Install System Packages
|
|
494
|
+
|
|
495
|
+
```ruby
|
|
496
|
+
package "nginx"
|
|
497
|
+
package "nginx", version: "1.18"
|
|
498
|
+
package "nginx", platform: :yum # CentOS/RHEL
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
Uses apt (Ubuntu/Debian) by default; `platform: :yum` generates yum commands.
|
|
502
|
+
|
|
503
|
+
#### `service` - Manage System Services (systemd)
|
|
504
|
+
|
|
505
|
+
```ruby
|
|
506
|
+
service "nginx", action: [:enable, :start]
|
|
507
|
+
service "nginx", action: :restart
|
|
508
|
+
service "nginx", action: [:stop, :disable]
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
Supports `:start`, `:stop`, `:restart`, `:reload`, `:enable`, `:disable`.
|
|
512
|
+
|
|
513
|
+
#### `template` - Deploy ERB Templates
|
|
514
|
+
|
|
515
|
+
```ruby
|
|
516
|
+
template "/etc/nginx/nginx.conf", source: "./config/nginx.conf.erb", variables: { port: 3000 }
|
|
517
|
+
# Or block syntax
|
|
518
|
+
template "/etc/app.conf" do
|
|
519
|
+
source "./config/app.erb"
|
|
520
|
+
variables(domain: "example.com")
|
|
521
|
+
end
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
#### `file` - Upload Local Files
|
|
525
|
+
|
|
526
|
+
```ruby
|
|
527
|
+
file "/etc/nginx/conf.d/app.conf", source: "./config/app.conf"
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
#### `directory` - Ensure Remote Directory Exists
|
|
531
|
+
|
|
532
|
+
```ruby
|
|
533
|
+
directory "/etc/nginx/conf.d"
|
|
534
|
+
directory "/var/log/app", mode: "0755"
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
**Example: Deploy Nginx Using Resource DSL**
|
|
538
|
+
|
|
539
|
+
```ruby
|
|
540
|
+
task :deploy_nginx, roles: :web do
|
|
541
|
+
package "nginx"
|
|
542
|
+
directory "/etc/nginx/conf.d"
|
|
543
|
+
template "/etc/nginx/nginx.conf", source: "./config/nginx.conf.erb", variables: { port: 3000 }
|
|
544
|
+
file "/etc/nginx/conf.d/app.conf", source: "./config/app.conf"
|
|
545
|
+
run "nginx -t"
|
|
546
|
+
service "nginx", action: [:enable, :restart]
|
|
547
|
+
end
|
|
548
|
+
```
|
|
549
|
+
|
|
475
550
|
### Template Support
|
|
476
551
|
|
|
477
552
|
Kdeploy supports ERB (Embedded Ruby) templates for dynamic configuration generation.
|
|
@@ -869,7 +944,6 @@ Enable verbose output by checking the execution output. Kdeploy provides detaile
|
|
|
869
944
|
- **Executor** (`executor.rb`): SSH/SCP execution engine
|
|
870
945
|
- **Runner** (`runner.rb`): Concurrent task execution coordinator
|
|
871
946
|
- **CommandExecutor** (`command_executor.rb`): Individual command execution
|
|
872
|
-
- **CommandGrouper** (`command_grouper.rb`): Command grouping logic
|
|
873
947
|
- **Template** (`template.rb`): ERB template rendering
|
|
874
948
|
- **Output** (`output.rb`): Output formatting and display
|
|
875
949
|
- **Configuration** (`configuration.rb`): Configuration management
|
|
@@ -879,10 +953,9 @@ Enable verbose output by checking the execution output. Kdeploy provides detaile
|
|
|
879
953
|
|
|
880
954
|
1. **Parse Configuration**: Load and parse `deploy.rb`
|
|
881
955
|
2. **Resolve Hosts**: Determine target hosts based on task definition
|
|
882
|
-
3. **
|
|
883
|
-
4. **
|
|
884
|
-
5. **
|
|
885
|
-
6. **Display Output**: Format and display results to user
|
|
956
|
+
3. **Execute Concurrently**: Run tasks in parallel across hosts, executing commands in order per host
|
|
957
|
+
4. **Collect Results**: Gather execution results and status
|
|
958
|
+
5. **Display Output**: Format and display results to user
|
|
886
959
|
|
|
887
960
|
### Concurrency Model
|
|
888
961
|
|
|
@@ -922,7 +995,6 @@ kdeploy/
|
|
|
922
995
|
│ ├── executor.rb # SSH/SCP executor
|
|
923
996
|
│ ├── runner.rb # Task runner
|
|
924
997
|
│ ├── command_executor.rb # Command executor
|
|
925
|
-
│ ├── command_grouper.rb # Command grouper
|
|
926
998
|
│ ├── template.rb # Template handler
|
|
927
999
|
│ ├── output.rb # Output interface
|
|
928
1000
|
│ ├── configuration.rb # Configuration
|
data/exe/kdeploy
CHANGED
|
@@ -1,19 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
# 自动修复常见 gem 扩展
|
|
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
|
-
|
|
17
4
|
require 'kdeploy'
|
|
18
|
-
|
|
19
5
|
Kdeploy::CLI.start(ARGV)
|
data/lib/kdeploy/cli.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'thor'
|
|
4
|
+
require 'json'
|
|
4
5
|
require 'pastel'
|
|
5
6
|
require 'tty-table'
|
|
6
7
|
require 'tty-box'
|
|
@@ -43,9 +44,13 @@ module Kdeploy
|
|
|
43
44
|
|
|
44
45
|
desc 'execute TASK_FILE [TASK]', 'Execute deployment tasks from file'
|
|
45
46
|
method_option :limit, type: :string, desc: 'Limit to specific hosts (comma-separated)'
|
|
46
|
-
method_option :parallel, type: :numeric,
|
|
47
|
+
method_option :parallel, type: :numeric, desc: 'Number of parallel executions'
|
|
47
48
|
method_option :dry_run, type: :boolean, desc: 'Show what would be done'
|
|
48
49
|
method_option :debug, type: :boolean, desc: 'Show detailed command output (stdout/stderr)'
|
|
50
|
+
method_option :no_banner, type: :boolean, desc: 'Do not print banner'
|
|
51
|
+
method_option :format, type: :string, default: 'text', desc: 'Output format (text|json)'
|
|
52
|
+
method_option :retries, type: :numeric, desc: 'Retry count for network operations (default: 0)'
|
|
53
|
+
method_option :retry_delay, type: :numeric, desc: 'Retry delay seconds (default: 1)'
|
|
49
54
|
def execute(task_file, task_name = nil)
|
|
50
55
|
load_config_file
|
|
51
56
|
show_banner_once
|
|
@@ -53,7 +58,10 @@ module Kdeploy
|
|
|
53
58
|
load_task_file(task_file)
|
|
54
59
|
|
|
55
60
|
tasks_to_run = determine_tasks(task_name)
|
|
56
|
-
execute_tasks(tasks_to_run)
|
|
61
|
+
all_results = execute_tasks(tasks_to_run)
|
|
62
|
+
|
|
63
|
+
# Exit non-zero if any executed host failed.
|
|
64
|
+
exit 1 if any_failed?(all_results)
|
|
57
65
|
rescue StandardError => e
|
|
58
66
|
puts Kdeploy::Banner.show_error(e.message)
|
|
59
67
|
exit 1
|
|
@@ -134,21 +142,24 @@ module Kdeploy
|
|
|
134
142
|
print_summary(results, formatter) if show_summary
|
|
135
143
|
end
|
|
136
144
|
|
|
137
|
-
def print_host_result(
|
|
145
|
+
def print_host_result(host, result, formatter)
|
|
138
146
|
if %i[success changed].include?(result[:status])
|
|
139
|
-
print_success_result(result, formatter)
|
|
147
|
+
print_success_result(host, result, formatter)
|
|
140
148
|
else
|
|
141
|
-
print_failure_result(result, formatter)
|
|
149
|
+
print_failure_result(host, result, formatter)
|
|
142
150
|
end
|
|
151
|
+
|
|
152
|
+
duration = formatter.calculate_host_duration(result)
|
|
153
|
+
puts "#{formatter.host_prefix(host)}#{formatter.format_host_completed(duration)}" if duration.positive?
|
|
143
154
|
end
|
|
144
155
|
|
|
145
|
-
def print_success_result(result, formatter)
|
|
156
|
+
def print_success_result(host, result, formatter)
|
|
146
157
|
shown = {}
|
|
147
158
|
grouped = group_output_by_type(result[:output])
|
|
148
159
|
|
|
149
160
|
grouped.each do |type, steps|
|
|
150
161
|
output_lines = format_steps_by_type(type, steps, shown, formatter)
|
|
151
|
-
output_lines.each { |line| puts line }
|
|
162
|
+
output_lines.each { |line| puts "#{formatter.host_prefix(host)}#{line}" }
|
|
152
163
|
end
|
|
153
164
|
end
|
|
154
165
|
|
|
@@ -171,9 +182,21 @@ module Kdeploy
|
|
|
171
182
|
end
|
|
172
183
|
end
|
|
173
184
|
|
|
174
|
-
def print_failure_result(result, formatter)
|
|
185
|
+
def print_failure_result(host, result, formatter)
|
|
175
186
|
error_message = extract_error_message(result)
|
|
176
|
-
puts formatter.format_error(error_message)
|
|
187
|
+
puts "#{formatter.host_prefix(host)}#{formatter.format_error(error_message)}"
|
|
188
|
+
|
|
189
|
+
# On failure, show steps that were executed (and any captured output)
|
|
190
|
+
# to make troubleshooting easier, even if --debug is not enabled.
|
|
191
|
+
return unless result[:output].is_a?(Array) && result[:output].any?
|
|
192
|
+
|
|
193
|
+
debug_formatter = OutputFormatter.new(debug: true)
|
|
194
|
+
shown = {}
|
|
195
|
+
grouped = group_output_by_type(result[:output])
|
|
196
|
+
grouped.each do |type, steps|
|
|
197
|
+
output_lines = format_steps_by_type(type, steps, shown, debug_formatter)
|
|
198
|
+
output_lines.each { |line| puts "#{debug_formatter.host_prefix(host)}#{line}" }
|
|
199
|
+
end
|
|
177
200
|
end
|
|
178
201
|
|
|
179
202
|
def print_summary(results, formatter)
|
|
@@ -189,6 +212,7 @@ module Kdeploy
|
|
|
189
212
|
def show_banner_once
|
|
190
213
|
@banner_printed ||= false
|
|
191
214
|
return if @banner_printed
|
|
215
|
+
return if options[:no_banner]
|
|
192
216
|
|
|
193
217
|
puts Kdeploy::Banner.show
|
|
194
218
|
@banner_printed = true
|
|
@@ -205,10 +229,15 @@ module Kdeploy
|
|
|
205
229
|
task_results = execute_single_task(task)
|
|
206
230
|
# Collect results for final summary
|
|
207
231
|
all_results[task] = task_results if task_results
|
|
232
|
+
|
|
233
|
+
# Stop executing remaining tasks once any host failed for this task.
|
|
234
|
+
break if task_failed?(task_results)
|
|
208
235
|
end
|
|
209
236
|
|
|
210
237
|
# Show combined summary at the end for all tasks
|
|
211
|
-
print_all_tasks_summary(all_results) unless all_results.empty?
|
|
238
|
+
print_all_tasks_summary(all_results) unless all_results.empty? || options[:format] == 'json'
|
|
239
|
+
|
|
240
|
+
all_results
|
|
212
241
|
end
|
|
213
242
|
|
|
214
243
|
def execute_single_task(task)
|
|
@@ -221,7 +250,11 @@ module Kdeploy
|
|
|
221
250
|
end
|
|
222
251
|
|
|
223
252
|
if options[:dry_run]
|
|
224
|
-
|
|
253
|
+
if options[:format] == 'json'
|
|
254
|
+
print_dry_run_json(hosts, task)
|
|
255
|
+
else
|
|
256
|
+
print_dry_run(hosts, task)
|
|
257
|
+
end
|
|
225
258
|
return nil
|
|
226
259
|
end
|
|
227
260
|
|
|
@@ -232,20 +265,40 @@ module Kdeploy
|
|
|
232
265
|
output = ConsoleOutput.new
|
|
233
266
|
parallel_count = options[:parallel] || Configuration.default_parallel
|
|
234
267
|
debug_mode = options[:debug] || false
|
|
268
|
+
retries = options[:retries].nil? ? Configuration.default_retries : options[:retries]
|
|
269
|
+
retry_delay = options[:retry_delay].nil? ? Configuration.default_retry_delay : options[:retry_delay]
|
|
235
270
|
base_dir = @task_file_dir
|
|
236
271
|
runner = Runner.new(
|
|
237
272
|
hosts, self.class.kdeploy_tasks,
|
|
238
273
|
parallel: parallel_count,
|
|
239
274
|
output: output,
|
|
240
275
|
debug: debug_mode,
|
|
241
|
-
base_dir: base_dir
|
|
276
|
+
base_dir: base_dir,
|
|
277
|
+
retries: retries,
|
|
278
|
+
retry_delay: retry_delay
|
|
242
279
|
)
|
|
243
280
|
results = runner.run(task)
|
|
244
|
-
|
|
245
|
-
|
|
281
|
+
if options[:format] == 'json'
|
|
282
|
+
print_results_json(task, results)
|
|
283
|
+
else
|
|
284
|
+
# Don't show summary here - it will be shown at the end for all tasks
|
|
285
|
+
print_results(results, task, show_summary: false, debug: debug_mode)
|
|
286
|
+
end
|
|
246
287
|
results
|
|
247
288
|
end
|
|
248
289
|
|
|
290
|
+
def any_failed?(all_results)
|
|
291
|
+
all_results.values.any? do |task_results|
|
|
292
|
+
task_results.values.any? { |result| result[:status] == :failed }
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
def task_failed?(task_results)
|
|
297
|
+
return false unless task_results.is_a?(Hash)
|
|
298
|
+
|
|
299
|
+
task_results.values.any? { |result| result[:status] == :failed }
|
|
300
|
+
end
|
|
301
|
+
|
|
249
302
|
def print_all_tasks_summary(all_results)
|
|
250
303
|
debug_mode = options[:debug] || false
|
|
251
304
|
formatter = OutputFormatter.new(debug: debug_mode)
|
|
@@ -272,6 +325,76 @@ module Kdeploy
|
|
|
272
325
|
end
|
|
273
326
|
end
|
|
274
327
|
|
|
328
|
+
def print_results_json(task_name, results)
|
|
329
|
+
payload = {
|
|
330
|
+
task: task_name.to_s,
|
|
331
|
+
results: results.transform_values { |r| serialize_host_result(r) }
|
|
332
|
+
}
|
|
333
|
+
puts JSON.generate(payload)
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
def print_dry_run_json(hosts, task_name)
|
|
337
|
+
tasks = self.class.kdeploy_tasks
|
|
338
|
+
commands = tasks[task_name][:block].call
|
|
339
|
+
|
|
340
|
+
payload = {
|
|
341
|
+
task: task_name.to_s,
|
|
342
|
+
dry_run: true,
|
|
343
|
+
planned: hosts.transform_values do |_config|
|
|
344
|
+
commands.map { |cmd| serialize_planned_step(cmd) }
|
|
345
|
+
end
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
puts JSON.generate(payload)
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
def serialize_host_result(result)
|
|
352
|
+
{
|
|
353
|
+
status: result[:status].to_s,
|
|
354
|
+
error: result[:error],
|
|
355
|
+
steps: Array(result[:output]).map { |step| serialize_step(step) }
|
|
356
|
+
}
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
def serialize_step(step)
|
|
360
|
+
out = {
|
|
361
|
+
type: step[:type].to_s,
|
|
362
|
+
command: step[:command],
|
|
363
|
+
duration: step[:duration]
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
out[:result] = step[:result] if step[:type] == :sync
|
|
367
|
+
|
|
368
|
+
if options[:debug] && step[:type] == :run && step[:output].is_a?(Hash)
|
|
369
|
+
out[:stdout] = step[:output][:stdout]
|
|
370
|
+
out[:stderr] = step[:output][:stderr]
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
out
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
def serialize_planned_step(cmd)
|
|
377
|
+
case cmd[:type]
|
|
378
|
+
when :run
|
|
379
|
+
{ type: 'run', command: cmd[:command], sudo: cmd[:sudo] }
|
|
380
|
+
when :upload
|
|
381
|
+
{ type: 'upload', source: cmd[:source], destination: cmd[:destination] }
|
|
382
|
+
when :upload_template
|
|
383
|
+
{ type: 'upload_template', source: cmd[:source], destination: cmd[:destination], variables: cmd[:variables] }
|
|
384
|
+
when :sync
|
|
385
|
+
{
|
|
386
|
+
type: 'sync',
|
|
387
|
+
source: cmd[:source],
|
|
388
|
+
destination: cmd[:destination],
|
|
389
|
+
ignore: cmd[:ignore] || [],
|
|
390
|
+
exclude: cmd[:exclude] || [],
|
|
391
|
+
delete: cmd[:delete] || false
|
|
392
|
+
}
|
|
393
|
+
else
|
|
394
|
+
{ type: cmd[:type].to_s }
|
|
395
|
+
end
|
|
396
|
+
end
|
|
397
|
+
|
|
275
398
|
def extract_error_message(result)
|
|
276
399
|
return result[:error] if result[:error]
|
|
277
400
|
|