Skip to content

Commit c593d70

Browse files
Merge pull request #12325 from rabbitmq/mk-cli-alias-experimental-flag
2 parents 9b0d564 + 47210c8 commit c593d70

File tree

2 files changed

+97
-34
lines changed

2 files changed

+97
-34
lines changed

deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/enable_feature_flag_command.ex

Lines changed: 74 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,58 +7,65 @@
77
defmodule RabbitMQ.CLI.Ctl.Commands.EnableFeatureFlagCommand do
88
@behaviour RabbitMQ.CLI.CommandBehaviour
99

10-
def switches(), do: [experimental: :boolean]
11-
def aliases(), do: [e: :experimental]
10+
def switches(), do: [experimental: :boolean, opt_in: :boolean]
11+
def aliases(), do: [e: :experimental, o: :opt_in]
1212

13-
def merge_defaults(args, opts), do: { args, Map.merge(%{experimental: false}, opts) }
13+
def merge_defaults(args, opts), do: { args, Map.merge(%{experimental: false, opt_in: false}, opts) }
1414

1515
def validate([], _opts), do: {:validation_failure, :not_enough_args}
1616
def validate([_ | _] = args, _opts) when length(args) > 1, do: {:validation_failure, :too_many_args}
1717

1818
def validate([""], _opts),
19-
do: {:validation_failure, {:bad_argument, "feature_flag cannot be an empty string."}}
19+
do: {:validation_failure, {:bad_argument, "feature flag (or group) name cannot be an empty string"}}
2020

2121
def validate([_], _opts), do: :ok
2222

2323
use RabbitMQ.CLI.Core.RequiresRabbitAppRunning
2424

25-
def run(["all"], %{node: node_name, experimental: experimental}) do
26-
case experimental do
27-
true ->
28-
{:error, RabbitMQ.CLI.Core.ExitCodes.exit_usage(), "`--experimental` flag is not allowed when enabling all feature flags.\nUse --experimental with a specific feature flag if you want to enable an experimental feature."}
29-
false ->
30-
case :rabbit_misc.rpc_call(node_name, :rabbit_feature_flags, :enable_all, []) do
31-
{:badrpc, _} = err -> err
32-
other -> other
33-
end
34-
end
25+
def run(["all"], %{node: node_name, opt_in: opt_in, experimental: experimental}) do
26+
has_opted_in = (opt_in || experimental)
27+
enable_all(node_name, has_opted_in)
3528
end
3629

37-
def run([feature_flag], %{node: node_name, experimental: experimental}) do
38-
case {experimental, :rabbit_misc.rpc_call(node_name, :rabbit_feature_flags, :get_stability, [
39-
String.to_atom(feature_flag)
40-
])} do
41-
{_, {:badrpc, _} = err} -> err
42-
{false, :experimental} ->
43-
{:error, RabbitMQ.CLI.Core.ExitCodes.exit_usage(), "Feature flag #{feature_flag} is experimental. If you understand the risk, use --experimental to enable it."}
44-
_ ->
45-
case :rabbit_misc.rpc_call(node_name, :rabbit_feature_flags, :enable, [
46-
String.to_atom(feature_flag)
47-
]) do
48-
{:badrpc, _} = err -> err
49-
other -> other
50-
end
51-
end
30+
def run(["all"], %{node: node_name, opt_in: has_opted_in}) do
31+
enable_all(node_name, has_opted_in)
5232
end
5333

34+
def run(["all"], %{node: node_name, experimental: has_opted_in}) do
35+
enable_all(node_name, has_opted_in)
36+
end
37+
38+
def run(["all"], %{node: node_name}) do
39+
enable_all(node_name, false)
40+
end
41+
42+
43+
def run([feature_flag], %{node: node_name, opt_in: opt_in, experimental: experimental}) do
44+
has_opted_in = (opt_in || experimental)
45+
enable_one(node_name, feature_flag, has_opted_in)
46+
end
47+
48+
def run([feature_flag], %{node: node_name, opt_in: has_opted_in}) do
49+
enable_one(node_name, feature_flag, has_opted_in)
50+
end
51+
52+
def run([feature_flag], %{node: node_name, experimental: has_opted_in}) do
53+
enable_one(node_name, feature_flag, has_opted_in)
54+
end
55+
56+
def run([feature_flag], %{node: node_name}) do
57+
enable_one(node_name, feature_flag, false)
58+
end
59+
60+
5461
def output({:error, :unsupported}, %{node: node_name}) do
5562
{:error, RabbitMQ.CLI.Core.ExitCodes.exit_usage(),
5663
"This feature flag is not supported by node #{node_name}"}
5764
end
5865

5966
use RabbitMQ.CLI.DefaultOutput
6067

61-
def usage, do: "enable_feature_flag [--experimental] <all | feature_flag>"
68+
def usage, do: "enable_feature_flag [--opt-in] <all | feature_flag>"
6269

6370
def usage_additional() do
6471
[
@@ -67,8 +74,8 @@ defmodule RabbitMQ.CLI.Ctl.Commands.EnableFeatureFlagCommand do
6774
"name of the feature flag to enable, or \"all\" to enable all supported flags"
6875
],
6976
[
70-
"--experimental",
71-
"required to enable experimental feature flags (make sure you understand the risks!)"
77+
"--opt-in",
78+
"required to enable certain feature flags (those with vast scope or maturing)"
7279
]
7380
]
7481
end
@@ -81,4 +88,39 @@ defmodule RabbitMQ.CLI.Ctl.Commands.EnableFeatureFlagCommand do
8188
def banner(["all"], _), do: "Enabling all feature flags ..."
8289

8390
def banner([feature_flag], _), do: "Enabling feature flag \"#{feature_flag}\" ..."
91+
92+
#
93+
# Implementation
94+
#
95+
96+
defp enable_all(node_name, has_opted_in) do
97+
case has_opted_in do
98+
true ->
99+
msg = "`--opt-in` (aliased as `--experimental`) flag is not allowed when enabling all feature flags.\nUse --opt-in with a specific feature flag name if to enable an opt-in flag"
100+
{:error, RabbitMQ.CLI.Core.ExitCodes.exit_usage(), msg}
101+
_ ->
102+
case :rabbit_misc.rpc_call(node_name, :rabbit_feature_flags, :enable_all, []) do
103+
{:badrpc, _} = err -> err
104+
other -> other
105+
end
106+
end
107+
end
108+
109+
defp enable_one(node_name, feature_flag, has_opted_in) do
110+
case {has_opted_in, :rabbit_misc.rpc_call(node_name, :rabbit_feature_flags, :get_stability, [
111+
String.to_atom(feature_flag)
112+
])} do
113+
{_, {:badrpc, _} = err} -> err
114+
{false, :experimental} ->
115+
msg = "Feature flag #{feature_flag} requires the user to explicitly opt-in.\nUse --opt-in with a specific feature flag name if to enable an opt-in flag"
116+
{:error, RabbitMQ.CLI.Core.ExitCodes.exit_usage(), msg}
117+
_ ->
118+
case :rabbit_misc.rpc_call(node_name, :rabbit_feature_flags, :enable, [
119+
String.to_atom(feature_flag)
120+
]) do
121+
{:badrpc, _} = err -> err
122+
other -> other
123+
end
124+
end
125+
end
84126
end

deps/rabbitmq_cli/test/ctl/enable_feature_flag_test.exs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,27 @@ defmodule EnableFeatureFlagCommandTest do
6767
assert list_feature_flags(:enabled) |> Map.has_key?(context[:feature_flag])
6868
end
6969

70-
test "run: attempt to use an unreachable node returns a nodedown" do
70+
test "run: attempt to use an unreachable node with --opt-in returns a nodedown" do
71+
opts = %{node: :jake@thedog, timeout: 200, opt_in: false}
72+
assert match?({:badrpc, _}, @command.run(["na"], opts))
73+
end
74+
75+
test "run: attempt to use an unreachable node with --experimental returns a nodedown" do
7176
opts = %{node: :jake@thedog, timeout: 200, experimental: false}
7277
assert match?({:badrpc, _}, @command.run(["na"], opts))
7378
end
7479

75-
test "run: enabling an experimental flag requires '--experimental'", context do
80+
test "run: enabling an experimental flag requires '--opt-in'", context do
81+
experimental_flag = Atom.to_string(context[:experimental_flag])
82+
assert match?(
83+
{:error, @usage_exit_code, _},
84+
@command.run([experimental_flag], context[:opts])
85+
)
86+
opts = Map.put(context[:opts], :opt_in, true)
87+
assert @command.run([experimental_flag], opts) == :ok
88+
end
89+
90+
test "run: enabling an experimental flag accepts '--experimental'", context do
7691
experimental_flag = Atom.to_string(context[:experimental_flag])
7792
assert match?(
7893
{:error, @usage_exit_code, _},
@@ -94,6 +109,12 @@ defmodule EnableFeatureFlagCommandTest do
94109
assert list_feature_flags(:enabled) |> Map.has_key?(context[:feature_flag])
95110
end
96111

112+
test "run: enabling all feature flags with '--opt-in' returns an error", context do
113+
enable_feature_flag(context[:feature_flag])
114+
opts = Map.put(context[:opts], :opt_in, true)
115+
assert match?({:error, @usage_exit_code, _}, @command.run(["all"], opts))
116+
end
117+
97118
test "run: enabling all feature flags with '--experimental' returns an error", context do
98119
enable_feature_flag(context[:feature_flag])
99120
opts = Map.put(context[:opts], :experimental, true)

0 commit comments

Comments
 (0)