moose-inventory 2.0 → 2.1

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.
Files changed (169) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/release.yml +2 -0
  3. data/.gitignore +2 -1
  4. data/.rubocop.yml +21 -0
  5. data/BACKLOG.md +630 -8
  6. data/Gemfile +2 -0
  7. data/Gemfile.lock +1 -1
  8. data/README.md +315 -39
  9. data/Rakefile +2 -0
  10. data/bin/moose-inventory +2 -1
  11. data/docs/architecture/architecture-and-trust-boundaries.md +444 -0
  12. data/docs/compatibility/cli-output-compatibility.md +76 -0
  13. data/docs/governance/approval-register.md +37 -0
  14. data/docs/maintenance/database-backup-restore-guidance.md +162 -0
  15. data/docs/maintenance/package-maintenance-and-agent-boundaries.md +260 -0
  16. data/docs/process/conformance-gap-analysis-2026-05-28.md +192 -0
  17. data/docs/product/product-brief.md +161 -0
  18. data/docs/product/requirements-baseline.md +477 -0
  19. data/docs/qa/qa-documentation-and-release-gates.md +283 -0
  20. data/docs/release/package-provenance-hardening.md +126 -0
  21. data/docs/release/publishing.md +11 -3
  22. data/docs/release/release-environment-protection.md +70 -0
  23. data/docs/release/release-readiness.md +23 -4
  24. data/docs/security/accepted-risk-register.md +84 -0
  25. data/docs/security/security-privacy-process.md +287 -0
  26. data/docs/security-audit-2026-05-26-rerun.md +2 -2
  27. data/docs/ux/cli-workflow-notes.md +287 -0
  28. data/examples/ansible/ansible.cfg +3 -0
  29. data/examples/ansible/inventory/moose_inventory.yml +5 -0
  30. data/examples/ansible/inventory_plugins/moose_inventory.py +100 -0
  31. data/examples/ci/README.md +16 -0
  32. data/examples/ci/github-actions/inventory-review.yml +38 -0
  33. data/examples/ci/inventory/example-snapshot.yml +19 -0
  34. data/examples/ci/scripts/validate-inventory-snapshot.sh +30 -0
  35. data/lib/moose_inventory/cli/application.rb +133 -5
  36. data/lib/moose_inventory/cli/association_rendering.rb +74 -0
  37. data/lib/moose_inventory/cli/association_rendering_support.rb +89 -0
  38. data/lib/moose_inventory/cli/audit.rb +62 -0
  39. data/lib/moose_inventory/cli/audit_recording.rb +40 -0
  40. data/lib/moose_inventory/cli/child_relation_rendering.rb +110 -0
  41. data/lib/moose_inventory/cli/console.rb +135 -0
  42. data/lib/moose_inventory/cli/db.rb +64 -0
  43. data/lib/moose_inventory/cli/factory.rb +28 -0
  44. data/lib/moose_inventory/cli/formatter.rb +8 -12
  45. data/lib/moose_inventory/cli/group.rb +5 -2
  46. data/lib/moose_inventory/cli/group_add.rb +11 -9
  47. data/lib/moose_inventory/cli/group_addchild.rb +23 -65
  48. data/lib/moose_inventory/cli/group_addhost.rb +16 -67
  49. data/lib/moose_inventory/cli/group_addvar.rb +27 -47
  50. data/lib/moose_inventory/cli/group_get.rb +8 -42
  51. data/lib/moose_inventory/cli/group_list.rb +7 -40
  52. data/lib/moose_inventory/cli/group_listvars.rb +9 -55
  53. data/lib/moose_inventory/cli/group_rm.rb +12 -10
  54. data/lib/moose_inventory/cli/group_rmchild.rb +26 -82
  55. data/lib/moose_inventory/cli/group_rmhost.rb +18 -53
  56. data/lib/moose_inventory/cli/group_rmvar.rb +30 -41
  57. data/lib/moose_inventory/cli/group_tags.rb +33 -0
  58. data/lib/moose_inventory/cli/helpers.rb +68 -1
  59. data/lib/moose_inventory/cli/host.rb +6 -3
  60. data/lib/moose_inventory/cli/host_add.rb +69 -29
  61. data/lib/moose_inventory/cli/host_addgroup.rb +22 -58
  62. data/lib/moose_inventory/cli/host_addvar.rb +28 -52
  63. data/lib/moose_inventory/cli/host_get.rb +9 -37
  64. data/lib/moose_inventory/cli/host_list.rb +24 -21
  65. data/lib/moose_inventory/cli/host_listvars.rb +9 -62
  66. data/lib/moose_inventory/cli/host_rm.rb +60 -42
  67. data/lib/moose_inventory/cli/host_rmgroup.rb +25 -44
  68. data/lib/moose_inventory/cli/host_rmvar.rb +31 -45
  69. data/lib/moose_inventory/cli/host_tags.rb +33 -0
  70. data/lib/moose_inventory/cli/listvars_support.rb +55 -0
  71. data/lib/moose_inventory/cli/plan_rendering.rb +50 -0
  72. data/lib/moose_inventory/cli/relation_transaction_support.rb +51 -0
  73. data/lib/moose_inventory/cli/tag_support.rb +97 -0
  74. data/lib/moose_inventory/cli/variable_rendering.rb +67 -0
  75. data/lib/moose_inventory/config/config.rb +185 -108
  76. data/lib/moose_inventory/db/db.rb +170 -195
  77. data/lib/moose_inventory/db/exceptions.rb +6 -3
  78. data/lib/moose_inventory/db/models.rb +16 -0
  79. data/lib/moose_inventory/db/schema_migrations.rb +248 -0
  80. data/lib/moose_inventory/inventory_context.rb +68 -2
  81. data/lib/moose_inventory/operations/add_associations.rb +20 -16
  82. data/lib/moose_inventory/operations/add_groups.rb +21 -13
  83. data/lib/moose_inventory/operations/add_hosts.rb +30 -17
  84. data/lib/moose_inventory/operations/add_variables.rb +77 -0
  85. data/lib/moose_inventory/operations/entity_variable_operation_support.rb +46 -0
  86. data/lib/moose_inventory/operations/group_child_relations.rb +23 -16
  87. data/lib/moose_inventory/operations/group_cleanup.rb +23 -8
  88. data/lib/moose_inventory/operations/import_inventory_snapshot.rb +41 -0
  89. data/lib/moose_inventory/operations/inventory_doctor.rb +172 -0
  90. data/lib/moose_inventory/operations/inventory_snapshot.rb +60 -0
  91. data/lib/moose_inventory/operations/inventory_snapshot_applier.rb +112 -0
  92. data/lib/moose_inventory/operations/inventory_snapshot_preview.rb +174 -0
  93. data/lib/moose_inventory/operations/inventory_snapshot_validator.rb +134 -0
  94. data/lib/moose_inventory/operations/operation_event_support.rb +27 -0
  95. data/lib/moose_inventory/operations/query_inventory/base_query.rb +24 -0
  96. data/lib/moose_inventory/operations/query_inventory/group_queries.rb +86 -0
  97. data/lib/moose_inventory/operations/query_inventory/host_queries.rb +106 -0
  98. data/lib/moose_inventory/operations/query_inventory.rb +47 -0
  99. data/lib/moose_inventory/operations/remove_associations.rb +30 -18
  100. data/lib/moose_inventory/operations/remove_groups.rb +12 -12
  101. data/lib/moose_inventory/operations/remove_hosts.rb +68 -0
  102. data/lib/moose_inventory/operations/remove_variables.rb +67 -0
  103. data/lib/moose_inventory/runtime_options.rb +31 -0
  104. data/lib/moose_inventory/version.rb +3 -1
  105. data/lib/moose_inventory.rb +10 -7
  106. data/moose-inventory.gemspec +19 -35
  107. data/scripts/check.sh +1 -0
  108. data/scripts/ci/check_generated_artifacts.sh +41 -0
  109. data/scripts/ci/check_permissions.sh +2 -0
  110. data/scripts/ci/check_rubocop.sh +30 -25
  111. data/scripts/files.rb +5 -4
  112. data/spec/examples/ci_examples_spec.rb +37 -0
  113. data/spec/lib/moose_inventory/ansible_plugin_examples_spec.rb +29 -0
  114. data/spec/lib/moose_inventory/cli/application_doctor_spec.rb +50 -0
  115. data/spec/lib/moose_inventory/cli/application_import_export_spec.rb +100 -0
  116. data/spec/lib/moose_inventory/cli/application_spec.rb +25 -15
  117. data/spec/lib/moose_inventory/cli/audit_spec.rb +56 -0
  118. data/spec/lib/moose_inventory/cli/cli_spec.rb +15 -19
  119. data/spec/lib/moose_inventory/cli/console_spec.rb +98 -0
  120. data/spec/lib/moose_inventory/cli/factory_spec.rb +27 -0
  121. data/spec/lib/moose_inventory/cli/formatter_spec.rb +95 -3
  122. data/spec/lib/moose_inventory/cli/group_add_spec.rb +140 -116
  123. data/spec/lib/moose_inventory/cli/group_addchild_spec.rb +89 -35
  124. data/spec/lib/moose_inventory/cli/group_addhost_spec.rb +81 -84
  125. data/spec/lib/moose_inventory/cli/group_addvar_spec.rb +65 -68
  126. data/spec/lib/moose_inventory/cli/group_get_spec.rb +17 -33
  127. data/spec/lib/moose_inventory/cli/group_list_spec.rb +16 -38
  128. data/spec/lib/moose_inventory/cli/group_listvar_spec.rb +33 -40
  129. data/spec/lib/moose_inventory/cli/group_rm_spec.rb +136 -96
  130. data/spec/lib/moose_inventory/cli/group_rmchild_spec.rb +66 -41
  131. data/spec/lib/moose_inventory/cli/group_rmhost_spec.rb +76 -78
  132. data/spec/lib/moose_inventory/cli/group_rmvar_spec.rb +57 -63
  133. data/spec/lib/moose_inventory/cli/group_spec.rb +2 -0
  134. data/spec/lib/moose_inventory/cli/helpers_spec.rb +146 -0
  135. data/spec/lib/moose_inventory/cli/host_add_spec.rb +170 -116
  136. data/spec/lib/moose_inventory/cli/host_addgroup_spec.rb +100 -83
  137. data/spec/lib/moose_inventory/cli/host_addvar_spec.rb +92 -74
  138. data/spec/lib/moose_inventory/cli/host_get_spec.rb +14 -33
  139. data/spec/lib/moose_inventory/cli/host_list_spec.rb +41 -33
  140. data/spec/lib/moose_inventory/cli/host_listvar_spec.rb +45 -53
  141. data/spec/lib/moose_inventory/cli/host_rm_spec.rb +66 -48
  142. data/spec/lib/moose_inventory/cli/host_rmgroup_spec.rb +73 -83
  143. data/spec/lib/moose_inventory/cli/host_rmvar_spec.rb +56 -63
  144. data/spec/lib/moose_inventory/cli/host_spec.rb +2 -0
  145. data/spec/lib/moose_inventory/cli/tags_spec.rb +81 -0
  146. data/spec/lib/moose_inventory/config/config_spec.rb +41 -3
  147. data/spec/lib/moose_inventory/db/db_spec.rb +396 -36
  148. data/spec/lib/moose_inventory/db/exceptions_spec.rb +18 -0
  149. data/spec/lib/moose_inventory/db/models_spec.rb +7 -3
  150. data/spec/lib/moose_inventory/db_lifecycle_spec.rb +73 -0
  151. data/spec/lib/moose_inventory/inventory_context_spec.rb +10 -0
  152. data/spec/lib/moose_inventory/operations/add_associations_spec.rb +34 -0
  153. data/spec/lib/moose_inventory/operations/add_groups_spec.rb +15 -0
  154. data/spec/lib/moose_inventory/operations/add_hosts_spec.rb +13 -0
  155. data/spec/lib/moose_inventory/operations/add_variables_spec.rb +103 -0
  156. data/spec/lib/moose_inventory/operations/group_child_relations_spec.rb +46 -0
  157. data/spec/lib/moose_inventory/operations/import_inventory_snapshot_spec.rb +226 -0
  158. data/spec/lib/moose_inventory/operations/inventory_doctor_spec.rb +77 -0
  159. data/spec/lib/moose_inventory/operations/inventory_snapshot_spec.rb +50 -0
  160. data/spec/lib/moose_inventory/operations/operation_event_support_spec.rb +78 -0
  161. data/spec/lib/moose_inventory/operations/query_inventory_spec.rb +146 -0
  162. data/spec/lib/moose_inventory/operations/remove_associations_spec.rb +35 -0
  163. data/spec/lib/moose_inventory/operations/remove_groups_spec.rb +21 -0
  164. data/spec/lib/moose_inventory/operations/remove_hosts_spec.rb +55 -0
  165. data/spec/lib/moose_inventory/operations/remove_variables_spec.rb +83 -0
  166. data/spec/shared/shared_config_setup.rb +4 -3
  167. data/spec/spec_helper.rb +50 -40
  168. data/spec/support/cli_harness.rb +33 -0
  169. metadata +80 -41
@@ -1,49 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Metrics/BlockLength
1
4
  require 'spec_helper'
2
5
 
3
- # TODO: the usual respond_to? method doesn't seem to work on Thor objects.
4
6
  # Why not? For now, we'll check against instance_methods.
5
7
 
6
8
  RSpec.describe Moose::Inventory::Cli::Host do
7
9
  before(:all) do
8
- # Set up the configuration object
9
- @mockarg_parts = {
10
- config: File.join(spec_root, 'config/config.yml'),
11
- format: 'yaml',
12
- env: 'test',
13
- }
14
-
15
- @mockargs = []
16
- @mockarg_parts.each do |key, val|
17
- @mockargs << "--#{key}"
18
- @mockargs << val
19
- end
20
-
21
- @console = Moose::Inventory::Cli::Formatter
22
- @config = Moose::Inventory::Config
23
- @config.init(@mockargs)
24
-
25
- @db = Moose::Inventory::DB
26
- @db.init if @db.db.nil?
27
-
28
- @host = Moose::Inventory::Cli::Host
29
- @app = Moose::Inventory::Cli::Application
10
+ setup_cli_harness(command_class: Moose::Inventory::Cli::Host, command_ivar: :@host)
30
11
  end
31
12
 
32
13
  before(:each) do
33
- @db.reset
14
+ reset_cli_harness
34
15
  end
35
16
 
36
17
  # ============================
37
18
  describe 'add' do
38
19
  # --------------------
39
20
  it 'Host.add() method should be responsive' do
40
- result = @host.instance_methods(false).include?(:add)
21
+ result = @host.method_defined?(:add, false)
41
22
  expect(result).to eq(true)
42
23
  end
43
24
 
44
25
  # --------------------
45
26
  it '<no arguments> ... should bail with an error' do
46
- actual = runner { @app.start(%w(host add)) }
27
+ actual = runner { @app.start(%w[host add]) }
47
28
 
48
29
  desired = { aborted: true }
49
30
  desired[:STDERR] = "ERROR: Wrong number of arguments, 0 for 1 or more.\n"
@@ -54,18 +35,18 @@ RSpec.describe Moose::Inventory::Cli::Host do
54
35
  it 'HOST ... should add a host to the db' do
55
36
  name = 'test-host-add'
56
37
 
57
- actual = runner { @app.start(%W(host add #{name})) }
38
+ actual = runner { @app.start(%W[host add #{name}]) }
58
39
  # @console.out(actual,'y')
59
40
 
60
41
  # Check output
61
42
  desired = {}
62
43
  desired[:STDOUT] =
63
- "Add host '#{name}':\n"\
64
- " - Creating host '#{name}'...\n"\
65
- " - OK\n"\
66
- " - Adding automatic association {host:#{name} <-> group:ungrouped}...\n"\
67
- " - OK\n"\
68
- " - All OK\n"\
44
+ "Add host '#{name}':\n " \
45
+ "- Creating host '#{name}'...\n " \
46
+ "- OK\n " \
47
+ "- Adding automatic association {host:#{name} <-> group:ungrouped}...\n " \
48
+ "- OK\n " \
49
+ "- All OK\n" \
69
50
  "Succeeded\n"
70
51
 
71
52
  expected(actual, desired)
@@ -79,20 +60,94 @@ RSpec.describe Moose::Inventory::Cli::Host do
79
60
  expect(groups[name: 'ungrouped']).not_to be_nil
80
61
  end
81
62
 
63
+ # --------------------
64
+ it 'HOST --dry-run should show planned host creation without writing to the db' do
65
+ name = 'dry-run-host'
66
+
67
+ actual = runner { @app.start(%W[host add #{name} --dry-run]) }
68
+
69
+ desired = {}
70
+ desired[:STDOUT] =
71
+ "Add host '#{name}':\n " \
72
+ "- Creating host '#{name}'...\n " \
73
+ "- OK\n " \
74
+ "- Adding automatic association {host:#{name} <-> group:ungrouped}...\n " \
75
+ "- OK\n " \
76
+ "- All OK\n" \
77
+ "Dry run complete. No changes applied.\n" \
78
+ "Succeeded\n"
79
+
80
+ expected(actual, desired)
81
+ expect(@db.models[:host].find(name: name)).to be_nil
82
+ end
83
+
84
+ # --------------------
85
+ it 'HOST --groups GROUP --dry-run should not create the missing group or host' do
86
+ name = 'dry-run-host'
87
+ group_name = 'dry-run-group'
88
+
89
+ actual = runner { @app.start(%W[host add #{name} --groups #{group_name} --dry-run]) }
90
+
91
+ desired = {}
92
+ desired[:STDOUT] =
93
+ "Add host '#{name}':\n " \
94
+ "- Creating host '#{name}'...\n " \
95
+ "- OK\n " \
96
+ "- Adding association {host:#{name} <-> group:#{group_name}}...\n " \
97
+ "- OK\n " \
98
+ "- All OK\n" \
99
+ "Dry run complete. No changes applied.\n" \
100
+ "Succeeded\n"
101
+ desired[:STDERR] =
102
+ "WARNING: The group '#{group_name}' doesn't exist, but will be created.\n"
103
+
104
+ expected(actual, desired)
105
+ expect(@db.models[:host].find(name: name)).to be_nil
106
+ expect(@db.models[:group].find(name: group_name)).to be_nil
107
+ end
108
+ # --------------------
109
+ it 'HOST --dry-run --plan-format json should emit a machine-readable plan only' do
110
+ name = 'plan-host'
111
+
112
+ actual = runner { @app.start(%W[host add #{name} --dry-run --plan-format json]) }
113
+
114
+ expect(actual[:unexpected]).to eq(false)
115
+ expect(actual[:aborted]).to eq(false)
116
+ expect(actual[:STDERR]).to eq('')
117
+ expect(actual[:STDOUT]).not_to include('Succeeded')
118
+ plan = JSON.parse(actual[:STDOUT])
119
+ expect(plan['command']).to eq('host add')
120
+ expect(plan['dry_run']).to eq(true)
121
+ expect(plan['changes_applied']).to eq(false)
122
+ expect(plan['events'].map { |event| event['type'] }).to include('creating_host', 'dry_run_summary')
123
+ expect(@db.models[:host].find(name: name)).to be_nil
124
+ end
125
+
126
+ # --------------------
127
+ it 'HOST --plan-format json without --dry-run should abort before writing' do
128
+ name = 'plan-host-without-dry-run'
129
+
130
+ actual = runner { @app.start(%W[host add #{name} --plan-format json]) }
131
+
132
+ expect(actual[:aborted]).to eq(true)
133
+ expect(actual[:STDERR]).to eq("ERROR: --plan-format requires --dry-run.\n")
134
+ expect(@db.models[:host].find(name: name)).to be_nil
135
+ end
136
+
82
137
  # --------------------
83
138
  it 'HOST ... should skip HOST creation if HOST already exists' do
84
139
  name = 'test-host-add'
85
- runner { @app.start(%W(host add #{name})) }
140
+ runner { @app.start(%W[host add #{name}]) }
86
141
 
87
- actual = runner { @app.start(%W(host add #{name})) }
142
+ actual = runner { @app.start(%W[host add #{name}]) }
88
143
 
89
144
  # Check output
90
145
  desired = {}
91
146
  desired[:STDOUT] =
92
- "Add host '#{name}':\n"\
93
- " - Creating host '#{name}'...\n"\
94
- " - OK\n"\
95
- " - All OK\n"\
147
+ "Add host '#{name}':\n " \
148
+ "- Creating host '#{name}'...\n " \
149
+ "- OK\n " \
150
+ "- All OK\n" \
96
151
  "Succeeded\n"
97
152
 
98
153
  desired[:STDERR] =
@@ -103,22 +158,22 @@ RSpec.describe Moose::Inventory::Cli::Host do
103
158
 
104
159
  # --------------------
105
160
  it 'HOST1 HOST2 HOST3 ... should add multiple hosts' do
106
- names = %w(test1 test2 test3)
161
+ names = %w[test1 test2 test3]
107
162
 
108
- actual = runner { @app.start(%w(host add) + names) }
163
+ actual = runner { @app.start(%w[host add] + names) }
109
164
 
110
165
  # Check output
111
166
  desired = { STDOUT: '' }
112
167
  names.each do |name|
113
168
  desired[:STDOUT] = desired[:STDOUT] +
114
- "Add host '#{name}':\n"\
115
- " - Creating host '#{name}'...\n"\
116
- " - OK\n"\
117
- " - Adding automatic association {host:#{name} <-> group:ungrouped}...\n"\
118
- " - OK\n"\
119
- " - All OK\n"
169
+ "Add host '#{name}':\n " \
170
+ "- Creating host '#{name}'...\n " \
171
+ "- OK\n " \
172
+ "- Adding automatic association {host:#{name} <-> group:ungrouped}...\n " \
173
+ "- OK\n " \
174
+ "- All OK\n"
120
175
  end
121
- desired[:STDOUT] = desired[:STDOUT] + "Succeeded\n"
176
+ desired[:STDOUT] = "#{desired[:STDOUT]}Succeeded\n"
122
177
 
123
178
  expected(actual, desired)
124
179
 
@@ -134,25 +189,25 @@ RSpec.describe Moose::Inventory::Cli::Host do
134
189
  end
135
190
 
136
191
  # --------------------
137
- it 'HOST1 --groups GROUP ... should add the '\
138
- 'host and associate it with an existing group' do
192
+ it 'HOST1 --groups GROUP ... should add the ' \
193
+ 'host and associate it with an existing group' do
139
194
  group_name = 'testgroup'
140
195
  @db.models[:group].create(name: group_name)
141
196
 
142
197
  name = 'testhost'
143
198
  actual = runner do
144
- @app.start(%W(host add #{name} --groups #{group_name}))
199
+ @app.start(%W[host add #{name} --groups #{group_name}])
145
200
  end
146
201
 
147
202
  # Check output
148
203
  desired = {}
149
204
  desired[:STDOUT] =
150
- "Add host '#{name}':\n"\
151
- " - Creating host '#{name}'...\n"\
152
- " - OK\n"\
153
- " - Adding association {host:#{name} <-> group:#{group_name}}...\n"\
154
- " - OK\n"\
155
- " - All OK\n"\
205
+ "Add host '#{name}':\n " \
206
+ "- Creating host '#{name}'...\n " \
207
+ "- OK\n " \
208
+ "- Adding association {host:#{name} <-> group:#{group_name}}...\n " \
209
+ "- OK\n " \
210
+ "- All OK\n" \
156
211
  "Succeeded\n"
157
212
 
158
213
  expected(actual, desired)
@@ -166,26 +221,26 @@ RSpec.describe Moose::Inventory::Cli::Host do
166
221
  end
167
222
 
168
223
  # --------------------
169
- it 'HOST1 --groups GROUP ... should add the host and associate '\
170
- ' it with a non-existent group, creating the group' do
224
+ it 'HOST1 --groups GROUP ... should add the host and associate ' \
225
+ 'it with a non-existent group, creating the group' do
171
226
  group_name = 'testgroup'
172
227
 
173
228
  # DON'T MANUALLY CREATE THE GROUP! That's the point of the test.
174
229
 
175
230
  name = 'testhost'
176
231
  actual = runner do
177
- @app.start(%W(host add #{name} --groups #{group_name}))
232
+ @app.start(%W[host add #{name} --groups #{group_name}])
178
233
  end
179
234
 
180
235
  # Check output
181
236
  desired = {}
182
237
  desired[:STDOUT] =
183
- "Add host '#{name}':\n"\
184
- " - Creating host '#{name}'...\n"\
185
- " - OK\n"\
186
- " - Adding association {host:#{name} <-> group:#{group_name}}...\n"\
187
- " - OK\n"\
188
- " - All OK\n"\
238
+ "Add host '#{name}':\n " \
239
+ "- Creating host '#{name}'...\n " \
240
+ "- OK\n " \
241
+ "- Adding association {host:#{name} <-> group:#{group_name}}...\n " \
242
+ "- OK\n " \
243
+ "- All OK\n" \
189
244
  "Succeeded\n"
190
245
  desired[:STDERR] =
191
246
  "WARNING: The group '#{group_name}' doesn't exist, but will be created.\n"
@@ -206,20 +261,20 @@ RSpec.describe Moose::Inventory::Cli::Host do
206
261
  initial_group = 'initialgroup'
207
262
  new_group = 'newgroup'
208
263
 
209
- runner { @app.start(%W(host add #{name} --groups #{initial_group})) }
210
- actual = runner { @app.start(%W(host add #{name} --groups #{new_group})) }
264
+ runner { @app.start(%W[host add #{name} --groups #{initial_group}]) }
265
+ actual = runner { @app.start(%W[host add #{name} --groups #{new_group}]) }
211
266
 
212
267
  desired = {}
213
268
  desired[:STDOUT] =
214
- "Add host '#{name}':\n"\
215
- " - Creating host '#{name}'...\n"\
216
- " - OK\n"\
217
- " - Adding association {host:#{name} <-> group:#{new_group}}...\n"\
218
- " - OK\n"\
219
- " - All OK\n"\
269
+ "Add host '#{name}':\n " \
270
+ "- Creating host '#{name}'...\n " \
271
+ "- OK\n " \
272
+ "- Adding association {host:#{name} <-> group:#{new_group}}...\n " \
273
+ "- OK\n " \
274
+ "- All OK\n" \
220
275
  "Succeeded\n"
221
276
  desired[:STDERR] =
222
- "WARNING: The host '#{name}' already exists, skipping creation.\n"\
277
+ "WARNING: The host '#{name}' already exists, skipping creation.\n" \
223
278
  "WARNING: The group '#{new_group}' doesn't exist, but will be created.\n"
224
279
 
225
280
  expected(actual, desired)
@@ -236,20 +291,20 @@ RSpec.describe Moose::Inventory::Cli::Host do
236
291
  name = 'testhost'
237
292
  group_name = 'testgroup'
238
293
 
239
- runner { @app.start(%W(host add #{name} --groups #{group_name})) }
240
- actual = runner { @app.start(%W(host add #{name} --groups #{group_name})) }
294
+ runner { @app.start(%W[host add #{name} --groups #{group_name}]) }
295
+ actual = runner { @app.start(%W[host add #{name} --groups #{group_name}]) }
241
296
 
242
297
  desired = {}
243
298
  desired[:STDOUT] =
244
- "Add host '#{name}':\n"\
245
- " - Creating host '#{name}'...\n"\
246
- " - OK\n"\
247
- " - Adding association {host:#{name} <-> group:#{group_name}}...\n"\
248
- " - OK\n"\
249
- " - All OK\n"\
299
+ "Add host '#{name}':\n " \
300
+ "- Creating host '#{name}'...\n " \
301
+ "- OK\n " \
302
+ "- Adding association {host:#{name} <-> group:#{group_name}}...\n " \
303
+ "- OK\n " \
304
+ "- All OK\n" \
250
305
  "Succeeded\n"
251
306
  desired[:STDERR] =
252
- "WARNING: The host '#{name}' already exists, skipping creation.\n"\
307
+ "WARNING: The host '#{name}' already exists, skipping creation.\n" \
253
308
  "WARNING: Association {host:#{name} <-> group:#{group_name}} already exists, skipping creation.\n"
254
309
 
255
310
  expected(actual, desired)
@@ -264,7 +319,7 @@ RSpec.describe Moose::Inventory::Cli::Host do
264
319
  it 'HOST1 --groups ungrouped ... should abort with an error' do
265
320
  name = 'testhost'
266
321
  actual = runner do
267
- @app.start(%W(host add #{name} --groups ungrouped))
322
+ @app.start(%W[host add #{name} --groups ungrouped])
268
323
  end
269
324
 
270
325
  # Check output
@@ -279,13 +334,13 @@ RSpec.describe Moose::Inventory::Cli::Host do
279
334
  end
280
335
 
281
336
  # --------------------
282
- it 'HOST --groups GROUP1,GROUP2 ... should add the host and '\
283
- 'associate it with multiple groups' do
284
- group_names = %w(group1 group2 group3)
337
+ it 'HOST --groups GROUP1,GROUP2 ... should add the host and ' \
338
+ 'associate it with multiple groups' do
339
+ group_names = %w[group1 group2 group3]
285
340
 
286
341
  name = 'testhost'
287
342
  actual = runner do
288
- @app.start(%W(host add #{name} --groups #{group_names.join(',')}))
343
+ @app.start(%W[host add #{name} --groups #{group_names.join(',')}])
289
344
  end
290
345
 
291
346
  # @console.out(actual,'y')
@@ -293,19 +348,19 @@ RSpec.describe Moose::Inventory::Cli::Host do
293
348
  # Check output
294
349
  desired = { STDOUT: '', STDERR: '' }
295
350
  desired[:STDOUT] =
296
- "Add host '#{name}':\n"\
297
- " - Creating host '#{name}'...\n"\
298
- " - OK\n"\
351
+ "Add host '#{name}':\n " \
352
+ "- Creating host '#{name}'...\n " \
353
+ "- OK\n" \
299
354
 
300
355
  group_names.each do |group|
301
- desired[:STDOUT] = desired[:STDOUT] +
302
- " - Adding association {host:#{name} <-> group:#{group}}...\n"\
303
- " - OK\n"
304
- desired[:STDERR] = desired[:STDERR] +
305
- "WARNING: The group '#{group}' doesn't exist, but will be created.\n"
356
+ desired[:STDOUT] = desired[:STDOUT] +
357
+ " - Adding association {host:#{name} <-> group:#{group}}...\n " \
358
+ "- OK\n"
359
+ desired[:STDERR] = desired[:STDERR] +
360
+ "WARNING: The group '#{group}' doesn't exist, but will be created.\n"
306
361
  end
307
362
  desired[:STDOUT] = desired[:STDOUT] +
308
- " - All OK\n"\
363
+ " - All OK\n" \
309
364
  "Succeeded\n"
310
365
 
311
366
  expected(actual, desired)
@@ -320,13 +375,13 @@ RSpec.describe Moose::Inventory::Cli::Host do
320
375
  end
321
376
  end
322
377
 
323
- it 'HOST --groups GROUP1,ungrouped ... should bail '\
324
- 'with an error' do
378
+ it 'HOST --groups GROUP1,ungrouped ... should bail ' \
379
+ 'with an error' do
325
380
  name = 'testhost'
326
- group_names = %w(group1 ungrouped)
381
+ group_names = %w[group1 ungrouped]
327
382
 
328
383
  actual = runner do
329
- @app.start(%W(host add #{name} --groups #{group_names.join(',')}))
384
+ @app.start(%W[host add #{name} --groups #{group_names.join(',')}])
330
385
  end
331
386
 
332
387
  # Check output
@@ -337,38 +392,36 @@ RSpec.describe Moose::Inventory::Cli::Host do
337
392
  expected(actual, desired)
338
393
  end
339
394
 
340
- it 'HOST1 HOST2 --groups GROUP1,GROUP2 ... should add multiple '\
341
- 'hosts, associating each with multiple groups' do
342
- #
343
- group_names = %w(group1 group2 group3)
395
+ it 'HOST1 HOST2 --groups GROUP1,GROUP2 ... should add multiple ' \
396
+ 'hosts, associating each with multiple groups' do
397
+ group_names = %w[group1 group2 group3]
344
398
  # Note, relies on auto-generation of groups
345
399
 
346
- names = %w(host1 host2 host3)
400
+ names = %w[host1 host2 host3]
347
401
  actual = runner do
348
- @app.start(%w(host add) + names + %W(--groups #{group_names.join(',')}))
402
+ @app.start(%w[host add] + names + %W[--groups #{group_names.join(',')}])
349
403
  end
350
404
 
351
405
  # Check output
352
406
  desired = { aborted: false, STDERR: '', STDOUT: '' }
353
407
  names.each do |name|
354
408
  desired[:STDOUT] = desired[:STDOUT] +
355
- "Add host '#{name}':\n"\
356
- " - Creating host '#{name}'...\n"\
357
- " - OK\n"
409
+ "Add host '#{name}':\n " \
410
+ "- Creating host '#{name}'...\n " \
411
+ "- OK\n"
358
412
  group_names.each do |group|
359
413
  desired[:STDOUT] = desired[:STDOUT] +
360
- " - Adding association {host:#{name} <-> group:#{group}}...\n"\
361
- " - OK\n"
414
+ " - Adding association {host:#{name} <-> group:#{group}}...\n " \
415
+ "- OK\n"
362
416
  end
363
- desired[:STDOUT] = desired[:STDOUT] +
364
- " - All OK\n"
417
+ desired[:STDOUT] = "#{desired[:STDOUT]} - All OK\n"
365
418
  end
366
419
 
367
420
  group_names.each do |group|
368
421
  desired[:STDERR] = desired[:STDERR] +
369
422
  "WARNING: The group '#{group}' doesn't exist, but will be created.\n"
370
423
  end
371
- desired[:STDOUT] = desired[:STDOUT] + "Succeeded\n"
424
+ desired[:STDOUT] = "#{desired[:STDOUT]}Succeeded\n"
372
425
 
373
426
  # @console.out(desired,'y')
374
427
 
@@ -388,3 +441,4 @@ RSpec.describe Moose::Inventory::Cli::Host do
388
441
  end
389
442
  end
390
443
  end
444
+ # rubocop:enable Metrics/BlockLength