cpflow 4.1.0 → 4.1.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.
- checksums.yaml +4 -4
- data/.gitignore +4 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile.lock +1 -1
- data/README.md +7 -7
- data/docs/commands.md +16 -0
- data/docs/terraform/details.md +415 -0
- data/docs/terraform/example/.controlplane/controlplane.yml +29 -0
- data/docs/terraform/example/.controlplane/templates/app.yml +38 -0
- data/docs/terraform/example/.controlplane/templates/postgres.yml +30 -0
- data/docs/terraform/example/.controlplane/templates/rails.yml +26 -0
- data/docs/terraform/overview.md +105 -0
- data/lib/command/base.rb +29 -5
- data/lib/command/base_sub_command.rb +15 -0
- data/lib/command/generate.rb +1 -1
- data/lib/command/ps.rb +1 -1
- data/lib/command/ps_stop.rb +2 -1
- data/lib/command/run.rb +1 -1
- data/lib/command/terraform/base.rb +35 -0
- data/lib/command/terraform/generate.rb +99 -0
- data/lib/command/terraform/import.rb +79 -0
- data/lib/core/controlplane.rb +3 -3
- data/lib/core/shell.rb +9 -4
- data/lib/core/terraform_config/agent.rb +31 -0
- data/lib/core/terraform_config/audit_context.rb +31 -0
- data/lib/core/terraform_config/base.rb +25 -0
- data/lib/core/terraform_config/dsl.rb +102 -0
- data/lib/core/terraform_config/generator.rb +184 -0
- data/lib/core/terraform_config/gvc.rb +63 -0
- data/lib/core/terraform_config/identity.rb +35 -0
- data/lib/core/terraform_config/local_variable.rb +30 -0
- data/lib/core/terraform_config/policy.rb +151 -0
- data/lib/core/terraform_config/provider.rb +22 -0
- data/lib/core/terraform_config/required_provider.rb +23 -0
- data/lib/core/terraform_config/secret.rb +138 -0
- data/lib/core/terraform_config/volume_set.rb +155 -0
- data/lib/core/terraform_config/workload/main.tf +316 -0
- data/lib/core/terraform_config/workload/required_providers.tf +8 -0
- data/lib/core/terraform_config/workload/variables.tf +263 -0
- data/lib/core/terraform_config/workload.rb +132 -0
- data/lib/cpflow/version.rb +1 -1
- data/lib/cpflow.rb +50 -9
- data/lib/generator_templates/templates/postgres.yml +1 -1
- data/lib/patches/array.rb +8 -0
- data/lib/patches/hash.rb +47 -0
- data/lib/patches/string.rb +34 -0
- data/script/update_command_docs +6 -2
- metadata +33 -3
@@ -0,0 +1,263 @@
|
|
1
|
+
variable "containers" {
|
2
|
+
type = map(
|
3
|
+
object({
|
4
|
+
args = optional(list(string))
|
5
|
+
command = optional(string)
|
6
|
+
cpu = optional(string, "1000m")
|
7
|
+
envs = optional(map(string))
|
8
|
+
image = string
|
9
|
+
inherit_env = optional(bool)
|
10
|
+
liveness_probe = optional(
|
11
|
+
object({
|
12
|
+
exec = optional(
|
13
|
+
object({
|
14
|
+
command = list(string)
|
15
|
+
})
|
16
|
+
)
|
17
|
+
failure_threshold = optional(number)
|
18
|
+
grpc = optional(
|
19
|
+
object({
|
20
|
+
port = optional(number)
|
21
|
+
})
|
22
|
+
)
|
23
|
+
http_get = optional(
|
24
|
+
object({
|
25
|
+
http_headers = optional(map(string))
|
26
|
+
path = optional(string)
|
27
|
+
port = optional(number)
|
28
|
+
scheme = optional(string)
|
29
|
+
})
|
30
|
+
)
|
31
|
+
initial_delay_seconds = optional(number)
|
32
|
+
period_seconds = optional(number)
|
33
|
+
success_threshold = optional(number)
|
34
|
+
timeout_seconds = optional(number)
|
35
|
+
tcp_socket = optional(
|
36
|
+
object({
|
37
|
+
port = optional(number)
|
38
|
+
})
|
39
|
+
)
|
40
|
+
})
|
41
|
+
)
|
42
|
+
memory = optional(string, "2048Mi")
|
43
|
+
ports = optional(
|
44
|
+
list(
|
45
|
+
object({
|
46
|
+
number = number
|
47
|
+
protocol = string
|
48
|
+
})
|
49
|
+
),
|
50
|
+
[],
|
51
|
+
)
|
52
|
+
post_start_command = optional(string)
|
53
|
+
pre_stop_command = optional(string)
|
54
|
+
readiness_probe = optional(
|
55
|
+
object({
|
56
|
+
exec = optional(
|
57
|
+
object({
|
58
|
+
command = list(string)
|
59
|
+
})
|
60
|
+
)
|
61
|
+
failure_threshold = optional(number)
|
62
|
+
grpc = optional(
|
63
|
+
object({
|
64
|
+
port = optional(number)
|
65
|
+
})
|
66
|
+
)
|
67
|
+
http_get = optional(
|
68
|
+
object({
|
69
|
+
http_headers = optional(map(string))
|
70
|
+
path = optional(string)
|
71
|
+
port = optional(number)
|
72
|
+
scheme = optional(string)
|
73
|
+
})
|
74
|
+
)
|
75
|
+
initial_delay_seconds = optional(number)
|
76
|
+
period_seconds = optional(number)
|
77
|
+
success_threshold = optional(number)
|
78
|
+
timeout_seconds = optional(number)
|
79
|
+
tcp_socket = optional(
|
80
|
+
object({
|
81
|
+
port = optional(number)
|
82
|
+
})
|
83
|
+
)
|
84
|
+
})
|
85
|
+
)
|
86
|
+
volumes = optional(
|
87
|
+
list(
|
88
|
+
object({
|
89
|
+
path = string
|
90
|
+
uri = string
|
91
|
+
})
|
92
|
+
),
|
93
|
+
[],
|
94
|
+
)
|
95
|
+
})
|
96
|
+
)
|
97
|
+
}
|
98
|
+
|
99
|
+
variable "description" {
|
100
|
+
type = string
|
101
|
+
default = null
|
102
|
+
}
|
103
|
+
|
104
|
+
variable "firewall_spec" {
|
105
|
+
type = object({
|
106
|
+
external = optional(
|
107
|
+
object({
|
108
|
+
inbound_allow_cidr = optional(list(string))
|
109
|
+
outbound_allow_hostname = optional(list(string))
|
110
|
+
outbound_allow_cidr = optional(list(string))
|
111
|
+
outbound_allow_port = optional(
|
112
|
+
list(
|
113
|
+
object({
|
114
|
+
number = number
|
115
|
+
protocol = optional(string, "tcp")
|
116
|
+
})
|
117
|
+
),
|
118
|
+
[]
|
119
|
+
)
|
120
|
+
})
|
121
|
+
)
|
122
|
+
internal = optional(
|
123
|
+
object({
|
124
|
+
inbound_allow_type = optional(string)
|
125
|
+
inbound_allow_workload = optional(list(string))
|
126
|
+
}),
|
127
|
+
)
|
128
|
+
})
|
129
|
+
default = null
|
130
|
+
}
|
131
|
+
|
132
|
+
variable "gvc" {
|
133
|
+
type = string
|
134
|
+
}
|
135
|
+
|
136
|
+
variable "identity_link" {
|
137
|
+
type = string
|
138
|
+
default = null
|
139
|
+
}
|
140
|
+
|
141
|
+
variable "job" {
|
142
|
+
type = object({
|
143
|
+
active_deadline_seconds = optional(number)
|
144
|
+
concurrency_policy = optional(string, "Forbid")
|
145
|
+
history_limit = optional(number, 5)
|
146
|
+
restart_policy = optional(string, "Never")
|
147
|
+
schedule = string
|
148
|
+
})
|
149
|
+
default = null
|
150
|
+
}
|
151
|
+
|
152
|
+
variable "load_balancer" {
|
153
|
+
type = object({
|
154
|
+
direct = optional(
|
155
|
+
object({
|
156
|
+
enabled = bool
|
157
|
+
port = optional(
|
158
|
+
list(
|
159
|
+
object({
|
160
|
+
container_port = optional(number)
|
161
|
+
external_port = number
|
162
|
+
protocol = string
|
163
|
+
scheme = optional(string)
|
164
|
+
})
|
165
|
+
),
|
166
|
+
[]
|
167
|
+
)
|
168
|
+
})
|
169
|
+
)
|
170
|
+
geo_location = optional(
|
171
|
+
object({
|
172
|
+
enabled = optional(bool)
|
173
|
+
headers = optional(
|
174
|
+
object({
|
175
|
+
asn = optional(string)
|
176
|
+
city = optional(string)
|
177
|
+
country = optional(string)
|
178
|
+
region = optional(string)
|
179
|
+
})
|
180
|
+
)
|
181
|
+
})
|
182
|
+
)
|
183
|
+
})
|
184
|
+
default = null
|
185
|
+
}
|
186
|
+
|
187
|
+
variable "local_options" {
|
188
|
+
type = object({
|
189
|
+
autoscaling = optional(
|
190
|
+
object({
|
191
|
+
metric = optional(string)
|
192
|
+
metric_percentile = optional(string)
|
193
|
+
target = optional(number)
|
194
|
+
max_scale = optional(number)
|
195
|
+
min_scale = optional(number)
|
196
|
+
scale_to_zero_delay = optional(number)
|
197
|
+
max_concurrency = optional(number)
|
198
|
+
})
|
199
|
+
)
|
200
|
+
location = string
|
201
|
+
capacity_ai = optional(bool, true)
|
202
|
+
debug = optional(bool, false)
|
203
|
+
suspend = optional(bool, false)
|
204
|
+
timeout_seconds = optional(number, 5)
|
205
|
+
})
|
206
|
+
default = null
|
207
|
+
}
|
208
|
+
|
209
|
+
variable "name" {
|
210
|
+
type = string
|
211
|
+
}
|
212
|
+
|
213
|
+
variable "options" {
|
214
|
+
type = object({
|
215
|
+
autoscaling = optional(
|
216
|
+
object({
|
217
|
+
max_concurrency = optional(number)
|
218
|
+
max_scale = optional(number)
|
219
|
+
metric = optional(string)
|
220
|
+
metric_percentile = optional(string)
|
221
|
+
min_scale = optional(number)
|
222
|
+
scale_to_zero_delay = optional(number)
|
223
|
+
target = optional(number)
|
224
|
+
})
|
225
|
+
)
|
226
|
+
capacity_ai = optional(bool, true)
|
227
|
+
debug = optional(bool, false)
|
228
|
+
suspend = optional(bool, false)
|
229
|
+
timeout_seconds = optional(number, 5)
|
230
|
+
})
|
231
|
+
default = null
|
232
|
+
}
|
233
|
+
|
234
|
+
variable "rollout_options" {
|
235
|
+
type = object({
|
236
|
+
max_surge_replicas = optional(string)
|
237
|
+
max_unavailable_replicas = optional(string)
|
238
|
+
min_ready_seconds = optional(number)
|
239
|
+
scaling_policy = optional(string, "OrderedReady")
|
240
|
+
})
|
241
|
+
default = null
|
242
|
+
}
|
243
|
+
|
244
|
+
variable "security_options" {
|
245
|
+
type = object({
|
246
|
+
file_system_group_id = optional(number)
|
247
|
+
})
|
248
|
+
default = null
|
249
|
+
}
|
250
|
+
|
251
|
+
variable "support_dynamic_tags" {
|
252
|
+
type = bool
|
253
|
+
default = false
|
254
|
+
}
|
255
|
+
|
256
|
+
variable "tags" {
|
257
|
+
type = map(string)
|
258
|
+
default = {}
|
259
|
+
}
|
260
|
+
|
261
|
+
variable "type" {
|
262
|
+
type = string
|
263
|
+
}
|
@@ -0,0 +1,132 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TerraformConfig
|
4
|
+
class Workload < Base # rubocop:disable Metrics/ClassLength
|
5
|
+
RAW_ARGS = %i[
|
6
|
+
containers options local_options rollout_options security_options
|
7
|
+
firewall_spec load_balancer job
|
8
|
+
].freeze
|
9
|
+
|
10
|
+
OPTIONS_KEYS = %i[autoscaling capacity_ai suspend timeout_seconds].freeze
|
11
|
+
LOCAL_OPTIONS_KEYS = (OPTIONS_KEYS + %i[location]).freeze
|
12
|
+
ROLLOUT_OPTIONS_KEYS = %i[min_ready_seconds max_unavailable_replicas max_surge_replicas scaling_policy].freeze
|
13
|
+
SECURITY_OPTIONS_KEYS = %i[file_system_group_id].freeze
|
14
|
+
LOAD_BALANCER_KEYS = %i[direct geo_location].freeze
|
15
|
+
FIREWALL_SPEC_KEYS = %i[internal external].freeze
|
16
|
+
VOLUME_KEYS = %i[uri path].freeze
|
17
|
+
JOB_KEYS = %i[schedule concurrency_policy history_limit restart_policy active_deadline_seconds].freeze
|
18
|
+
LIVENESS_PROBE_KEYS = %i[
|
19
|
+
exec http_get tcp_socket grpc
|
20
|
+
failure_threshold initial_delay_seconds period_seconds success_threshold timeout_seconds
|
21
|
+
].freeze
|
22
|
+
|
23
|
+
attr_reader :type, :name, :gvc, :containers,
|
24
|
+
:description, :tags, :support_dynamic_tags, :firewall_spec, :identity_link,
|
25
|
+
:options, :local_options, :rollout_options, :security_options, :load_balancer, :job
|
26
|
+
|
27
|
+
def initialize( # rubocop:disable Metrics/ParameterLists, Metrics/MethodLength
|
28
|
+
type:,
|
29
|
+
gvc:,
|
30
|
+
name:,
|
31
|
+
containers:,
|
32
|
+
description: nil,
|
33
|
+
tags: nil,
|
34
|
+
support_dynamic_tags: false,
|
35
|
+
firewall_spec: nil,
|
36
|
+
identity_link: nil,
|
37
|
+
options: nil,
|
38
|
+
local_options: nil,
|
39
|
+
rollout_options: nil,
|
40
|
+
security_options: nil,
|
41
|
+
load_balancer: nil,
|
42
|
+
job: nil
|
43
|
+
)
|
44
|
+
super()
|
45
|
+
|
46
|
+
@type = type
|
47
|
+
@gvc = gvc
|
48
|
+
|
49
|
+
@name = name
|
50
|
+
@description = description
|
51
|
+
@tags = tags
|
52
|
+
|
53
|
+
@containers = containers
|
54
|
+
@firewall_spec = firewall_spec
|
55
|
+
@identity_link = identity_link
|
56
|
+
|
57
|
+
@options = options
|
58
|
+
@local_options = local_options
|
59
|
+
@rollout_options = rollout_options
|
60
|
+
@security_options = security_options
|
61
|
+
|
62
|
+
@load_balancer = load_balancer
|
63
|
+
@support_dynamic_tags = support_dynamic_tags
|
64
|
+
@job = job
|
65
|
+
end
|
66
|
+
|
67
|
+
def importable?
|
68
|
+
true
|
69
|
+
end
|
70
|
+
|
71
|
+
def reference
|
72
|
+
"module.#{name}.cpln_workload.workload"
|
73
|
+
end
|
74
|
+
|
75
|
+
def to_tf
|
76
|
+
block :module, name do
|
77
|
+
argument :source, "../workload"
|
78
|
+
|
79
|
+
argument :type, type
|
80
|
+
argument :name, name
|
81
|
+
argument :gvc, gvc
|
82
|
+
argument :identity_link, identity_link, optional: true
|
83
|
+
argument :support_dynamic_tags, support_dynamic_tags, optional: true
|
84
|
+
|
85
|
+
RAW_ARGS.each { |arg_name| argument arg_name, send(:"#{arg_name}_arg"), raw: true, optional: true }
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def locals
|
90
|
+
containers.reduce({}) do |result, container|
|
91
|
+
envs = container[:env].to_h { |env_var| [env_var[:name], env_var[:value]] }
|
92
|
+
next result if envs.empty?
|
93
|
+
|
94
|
+
envs_name = :"#{container.fetch(:name)}_envs"
|
95
|
+
result.merge("#{envs_name}.tf" => LocalVariable.new(envs_name => envs))
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
def containers_arg
|
102
|
+
containers.reduce({}) { |result, container| result.merge(container_args(container)) }.crush
|
103
|
+
end
|
104
|
+
|
105
|
+
def container_args(container) # rubocop:disable Metrics/MethodLength
|
106
|
+
container_name = container.fetch(:name)
|
107
|
+
|
108
|
+
args = container.slice(:args, :command, :image, :cpu, :memory).merge(
|
109
|
+
post_start: container.dig(:lifecycle, :post_start, :exec, :command),
|
110
|
+
pre_stop: container.dig(:lifecycle, :pre_stop, :exec, :command),
|
111
|
+
inherit_env: container.fetch(:inherit_env, nil),
|
112
|
+
envs: ("local.#{container_name}_envs" if container[:env]&.any?),
|
113
|
+
ports: container.fetch(:ports, nil),
|
114
|
+
readiness_probe: container.fetch(:readiness_probe, nil)&.slice(*LIVENESS_PROBE_KEYS),
|
115
|
+
liveness_probe: container.fetch(:liveness_probe, nil)&.slice(*LIVENESS_PROBE_KEYS),
|
116
|
+
volumes: container.fetch(:volumes, nil)&.map { |volume| volume.slice(*VOLUME_KEYS) }
|
117
|
+
)
|
118
|
+
|
119
|
+
{ container_name => args }
|
120
|
+
end
|
121
|
+
|
122
|
+
RAW_ARGS.each do |spec|
|
123
|
+
next if spec == :containers
|
124
|
+
|
125
|
+
define_method("#{spec}_arg") do
|
126
|
+
return if send(spec).nil?
|
127
|
+
|
128
|
+
send(spec).slice(*self.class.const_get("#{spec.upcase}_KEYS"))
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
data/lib/cpflow/version.rb
CHANGED
data/lib/cpflow.rb
CHANGED
@@ -17,6 +17,9 @@ require_relative "constants/exit_code"
|
|
17
17
|
|
18
18
|
# We need to require base before all commands, since the commands inherit from it
|
19
19
|
require_relative "command/base"
|
20
|
+
require_relative "command/terraform/base"
|
21
|
+
# We need to require base terraform config before all commands, since the terraform configs inherit from it
|
22
|
+
require_relative "core/terraform_config/base"
|
20
23
|
|
21
24
|
modules = Dir["#{__dir__}/**/*.rb"].reject do |file|
|
22
25
|
file == __FILE__ || file.end_with?("base.rb")
|
@@ -33,9 +36,15 @@ end
|
|
33
36
|
|
34
37
|
require_relative "patches/thor"
|
35
38
|
|
39
|
+
require_relative "patches/string"
|
40
|
+
|
36
41
|
module Cpflow
|
37
42
|
class Error < StandardError; end
|
38
43
|
|
44
|
+
def self.root_path
|
45
|
+
Pathname.new(File.expand_path("../", __dir__))
|
46
|
+
end
|
47
|
+
|
39
48
|
class Cli < Thor # rubocop:disable Metrics/ClassLength
|
40
49
|
package_name "cpflow"
|
41
50
|
default_task :no_command
|
@@ -95,12 +104,21 @@ module Cpflow
|
|
95
104
|
def self.fix_help_option
|
96
105
|
help_mappings = Thor::HELP_MAPPINGS + ["help"]
|
97
106
|
matches = help_mappings & ARGV
|
107
|
+
|
108
|
+
# Help option works correctly for subcommands
|
109
|
+
return if matches && subcommand?
|
110
|
+
|
98
111
|
matches.each do |match|
|
99
112
|
ARGV.delete(match)
|
100
113
|
ARGV.unshift(match)
|
101
114
|
end
|
102
115
|
end
|
103
116
|
|
117
|
+
def self.subcommand?
|
118
|
+
(subcommand_names & ARGV).any?
|
119
|
+
end
|
120
|
+
private_class_method :subcommand?
|
121
|
+
|
104
122
|
# Needed to silence deprecation warning
|
105
123
|
def self.exit_on_failure?
|
106
124
|
true
|
@@ -131,6 +149,10 @@ module Cpflow
|
|
131
149
|
::Command::Base.all_commands.merge(deprecated_commands)
|
132
150
|
end
|
133
151
|
|
152
|
+
def self.subcommand_names
|
153
|
+
Dir["#{__dir__}/command/*"].filter_map { |name| File.basename(name) if File.directory?(name) }
|
154
|
+
end
|
155
|
+
|
134
156
|
def self.process_option_params(params)
|
135
157
|
# Ensures that if no value is provided for a non-boolean option (e.g., `cpflow command --option`),
|
136
158
|
# it defaults to an empty string instead of the option name (which is the default Thor behavior)
|
@@ -139,8 +161,21 @@ module Cpflow
|
|
139
161
|
params
|
140
162
|
end
|
141
163
|
|
164
|
+
def self.klass_for(subcommand_name)
|
165
|
+
klass_name = subcommand_name.to_s.split("-").map(&:capitalize).join
|
166
|
+
full_klass_name = "Cpflow::#{klass_name}"
|
167
|
+
return const_get(full_klass_name) if const_defined?(full_klass_name)
|
168
|
+
|
169
|
+
Cpflow.const_set(klass_name, Class.new(BaseSubCommand)).tap do |subcommand_klass|
|
170
|
+
desc(subcommand_name, "#{subcommand_name.capitalize} commands")
|
171
|
+
subcommand(subcommand_name, subcommand_klass)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
private_class_method :klass_for
|
175
|
+
|
142
176
|
@commands_with_required_options = []
|
143
177
|
@commands_with_extra_options = []
|
178
|
+
cli_package_name = @package_name
|
144
179
|
|
145
180
|
::Command::Base.common_options.each do |option|
|
146
181
|
params = process_option_params(option[:params])
|
@@ -151,6 +186,7 @@ module Cpflow
|
|
151
186
|
deprecated = deprecated_commands[command_key]
|
152
187
|
|
153
188
|
name = command_class::NAME
|
189
|
+
subcommand_name = command_class::SUBCOMMAND_NAME
|
154
190
|
name_for_method = deprecated ? command_key : name.tr("-", "_")
|
155
191
|
usage = command_class::USAGE.empty? ? name : command_class::USAGE
|
156
192
|
requires_args = command_class::REQUIRES_ARGS
|
@@ -170,21 +206,26 @@ module Cpflow
|
|
170
206
|
# so we store it here to be able to use it
|
171
207
|
raise_args_error = ->(*args) { handle_argument_error(commands[name_for_method], ArgumentError, *args) }
|
172
208
|
|
173
|
-
desc(usage, description, hide: hide)
|
174
|
-
long_desc(long_description)
|
175
|
-
|
176
|
-
command_options.each do |option|
|
177
|
-
params = process_option_params(option[:params])
|
178
|
-
method_option(option[:name], **params)
|
179
|
-
end
|
180
|
-
|
181
209
|
# We'll handle required options manually in `Config`
|
182
210
|
required_options = command_options.select { |option| option[:params][:required] }.map { |option| option[:name] }
|
183
211
|
@commands_with_required_options.push(name_for_method.to_sym) if required_options.any?
|
184
212
|
|
185
213
|
@commands_with_extra_options.push(name_for_method.to_sym) if accepts_extra_options
|
186
214
|
|
187
|
-
|
215
|
+
klass = subcommand_name ? klass_for(subcommand_name) : self
|
216
|
+
|
217
|
+
klass.class_eval do
|
218
|
+
package_name(cli_package_name) if subcommand_name
|
219
|
+
desc(usage, description, hide: hide)
|
220
|
+
long_desc(long_description)
|
221
|
+
|
222
|
+
command_options.each do |option|
|
223
|
+
params = Cpflow::Cli.process_option_params(option[:params])
|
224
|
+
method_option(option[:name], **params)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
klass.define_method(name_for_method) do |*provided_args| # rubocop:disable Metrics/BlockLength, Metrics/MethodLength
|
188
229
|
if deprecated
|
189
230
|
normalized_old_name = ::Helpers.normalize_command_name(command_key)
|
190
231
|
::Shell.warn_deprecated("Command '#{normalized_old_name}' is deprecated, " \
|
@@ -133,7 +133,7 @@ spec:
|
|
133
133
|
value: cpln://secret/postgres-poc-credentials.password
|
134
134
|
- name: POSTGRES_USER #The name of the default user
|
135
135
|
value: cpln://secret/postgres-poc-credentials.username
|
136
|
-
name:
|
136
|
+
name: postgres
|
137
137
|
image: postgres:15
|
138
138
|
command: /bin/bash
|
139
139
|
args:
|
data/lib/patches/hash.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Hash
|
4
|
+
# Copied from Rails
|
5
|
+
def deep_symbolize_keys
|
6
|
+
deep_transform_keys { |key| key.to_sym rescue key } # rubocop:disable Style/RescueModifier
|
7
|
+
end
|
8
|
+
|
9
|
+
def deep_underscore_keys
|
10
|
+
deep_transform_keys do |key|
|
11
|
+
underscored = key.to_s.underscore
|
12
|
+
key.is_a?(Symbol) ? underscored.to_sym : underscored
|
13
|
+
rescue StandardError
|
14
|
+
key
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def crush
|
19
|
+
crushed = each_with_object({}) do |(key, value), hash|
|
20
|
+
crushed_value = value.respond_to?(:crush) ? value.crush : value
|
21
|
+
hash[key] = crushed_value unless crushed_value.nil?
|
22
|
+
end
|
23
|
+
|
24
|
+
crushed unless crushed.empty?
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
# Copied from Rails
|
30
|
+
def deep_transform_keys(&block)
|
31
|
+
deep_transform_keys_in_object(self, &block)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Copied from Rails
|
35
|
+
def deep_transform_keys_in_object(object, &block)
|
36
|
+
case object
|
37
|
+
when Hash
|
38
|
+
object.each_with_object(self.class.new) do |(key, value), result|
|
39
|
+
result[yield(key)] = deep_transform_keys_in_object(value, &block)
|
40
|
+
end
|
41
|
+
when Array
|
42
|
+
object.map { |e| deep_transform_keys_in_object(e, &block) }
|
43
|
+
else
|
44
|
+
object
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# rubocop:disable Style/OptionalBooleanParameter, Lint/UnderscorePrefixedVariableName
|
4
|
+
class String
|
5
|
+
# Copied from Rails
|
6
|
+
def indent(amount, indent_string = nil, indent_empty_lines = false)
|
7
|
+
dup.tap { |_| _.indent!(amount, indent_string, indent_empty_lines) }
|
8
|
+
end
|
9
|
+
|
10
|
+
# Copied from Rails
|
11
|
+
def indent!(amount, indent_string = nil, indent_empty_lines = false)
|
12
|
+
indent_string = indent_string || self[/^[ \t]/] || " "
|
13
|
+
re = indent_empty_lines ? /^/ : /^(?!$)/
|
14
|
+
gsub!(re, indent_string * amount)
|
15
|
+
end
|
16
|
+
|
17
|
+
def unindent
|
18
|
+
gsub(/^#{scan(/^[ \t]+(?=\S)/).min}/, "")
|
19
|
+
end
|
20
|
+
|
21
|
+
# Copied from Rails
|
22
|
+
def underscore
|
23
|
+
gsub("::", "/").gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').gsub(/([a-z\d])([A-Z])/, '\1_\2').tr("-", "_").downcase
|
24
|
+
end
|
25
|
+
|
26
|
+
# Covers only simple cases and used for pluralizing controlplane template kinds (`gvc`, `secret`, `policy`, etc.)
|
27
|
+
def pluralize
|
28
|
+
return self if empty?
|
29
|
+
return "#{self[...-1]}ies" if end_with?("y")
|
30
|
+
|
31
|
+
"#{self}s"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
# rubocop:enable Style/OptionalBooleanParameter, Lint/UnderscorePrefixedVariableName
|
data/script/update_command_docs
CHANGED
@@ -12,12 +12,16 @@ commands.keys.sort.each do |command_key|
|
|
12
12
|
next if command_class::HIDE
|
13
13
|
|
14
14
|
name = command_class::NAME
|
15
|
-
|
15
|
+
subcommand_name = command_class::SUBCOMMAND_NAME
|
16
|
+
|
17
|
+
full_command = [subcommand_name, name].compact.join(" ")
|
18
|
+
|
19
|
+
usage = command_class::USAGE.empty? ? full_command : command_class::USAGE
|
16
20
|
options = command_class::OPTIONS
|
17
21
|
long_description = command_class::LONG_DESCRIPTION
|
18
22
|
examples = command_class::EXAMPLES
|
19
23
|
|
20
|
-
command_str = "### `#{
|
24
|
+
command_str = "### `#{full_command}`\n\n"
|
21
25
|
command_str += "#{long_description.strip}\n\n"
|
22
26
|
|
23
27
|
if examples.empty?
|