diff --git a/deps/rabbitmq_cli/BUILD.bazel b/deps/rabbitmq_cli/BUILD.bazel index 35931ebe5f54..4356a0b9f270 100644 --- a/deps/rabbitmq_cli/BUILD.bazel +++ b/deps/rabbitmq_cli/BUILD.bazel @@ -1,6 +1,7 @@ load("@rules_erlang//:dialyze.bzl", "dialyze", "plt") load(":rabbitmqctl.bzl", "rabbitmqctl") load(":rabbitmqctl_check_formatted.bzl", "rabbitmqctl_check_formatted_test") +load(":rabbitmqctl_compile_warnings_as_errors.bzl", "rabbitmqctl_compile_warnings_as_errors_test") load(":rabbitmqctl_test.bzl", "rabbitmqctl_test") load("//:rabbitmq_home.bzl", "rabbitmq_home") load("//:rabbitmq_run.bzl", "rabbitmq_run") @@ -97,6 +98,52 @@ test_suite( tests = ["check_formatted"], ) +rabbitmqctl_compile_warnings_as_errors_test( + name = "compile_warnings_as_errors", + size = "small", + srcs = [ + ".formatter.exs", + "config/config.exs", + "mix.exs", + ] + glob([ + "lib/**/*.ex", + "test/**/*.exs", + ]), + data = glob(["test/fixtures/**/*"]), + archives = [ + "@hex//:archive", + ], + source_deps = { + "@amqp//:sources": "amqp", + "@csv//:sources": "csv", + "@json//:sources": "json", + "@temp//:sources": "temp", + "@x509//:sources": "x509", + }, + deps = [ + "//deps/amqp_client:erlang_app", + "//deps/rabbit:erlang_app", + "//deps/rabbit_common:erlang_app", + "@observer_cli//:erlang_app", + "@stdout_formatter//:erlang_app", + ], + target_compatible_with = select({ + "@platforms//os:macos": [ + "@platforms//os:macos", + "@elixir_config//:elixir_1_15", + ], + "//conditions:default": [ + "@platforms//os:linux", + "@elixir_config//:elixir_1_15", + ], + }), +) + +test_suite( + name = "rabbitmqctl_compile_warnings_as_errors", + tests = ["compile_warnings_as_errors"], +) + plt( name = "deps_plt", apps = [ diff --git a/deps/rabbitmq_cli/lib/rabbitmq/cli/core/command_modules.ex b/deps/rabbitmq_cli/lib/rabbitmq/cli/core/command_modules.ex index 09dce670bcc9..bc9189092e16 100644 --- a/deps/rabbitmq_cli/lib/rabbitmq/cli/core/command_modules.ex +++ b/deps/rabbitmq_cli/lib/rabbitmq/cli/core/command_modules.ex @@ -69,7 +69,7 @@ defmodule RabbitMQ.CLI.Core.CommandModules do {:ok, enabled_plugins_file} = PluginsHelpers.enabled_plugins_file(opts) require Logger - Logger.warn( + Logger.warning( "Unable to read the enabled plugins file.\n" <> " Reason: #{inspect(err)}\n" <> " Commands provided by plugins will not be available.\n" <> diff --git a/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/add_user_command.ex b/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/add_user_command.ex index a9d907944f79..44d3a0224c5a 100644 --- a/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/add_user_command.ex +++ b/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/add_user_command.ex @@ -83,7 +83,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.AddUserCommand do def run( [username, base64_encoded_password_hash], - %{node: node_name, pre_hashed_password: true} = opts + %{node: node_name, pre_hashed_password: true} ) do case Base.decode64(base64_encoded_password_hash) do {:ok, password_hash} -> diff --git a/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/force_standalone_khepri_boot.ex b/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/force_standalone_khepri_boot.ex new file mode 100644 index 000000000000..d0f648622348 --- /dev/null +++ b/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/force_standalone_khepri_boot.ex @@ -0,0 +1,45 @@ +## This Source Code Form is subject to the terms of the Mozilla Public +## License, v. 2.0. If a copy of the MPL was not distributed with this +## file, You can obtain one at https://mozilla.org/MPL/2.0/. +## +## Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved. + +defmodule RabbitMQ.CLI.Ctl.Commands.ForceStandaloneKhepriBootCommand do + alias RabbitMQ.CLI.Core.DocGuide + + @behaviour RabbitMQ.CLI.CommandBehaviour + + use RabbitMQ.CLI.Core.MergesNoDefaults + use RabbitMQ.CLI.Core.AcceptsNoPositionalArguments + + def run([], %{node: node_name}) do + ret = + :rabbit_misc.rpc_call(node_name, :rabbit_khepri, :force_shrink_member_to_current_member, []) + + case ret do + {:badrpc, {:EXIT, {:undef, _}}} -> + {:error, RabbitMQ.CLI.Core.ExitCodes.exit_usage(), + "This command is not supported by node #{node_name}"} + + _ -> + ret + end + end + + use RabbitMQ.CLI.DefaultOutput + + def usage, do: "force_standalone_khepri_boot" + + def usage_doc_guides() do + [ + DocGuide.clustering() + ] + end + + def help_section(), do: :cluster_management + + def description(), + do: "Forces node to start as a standalone node" + + def banner(_, _), do: nil +end diff --git a/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/forget_cluster_node_command.ex b/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/forget_cluster_node_command.ex index 2e958add426e..e934a6ff09d3 100644 --- a/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/forget_cluster_node_command.ex +++ b/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/forget_cluster_node_command.ex @@ -53,6 +53,12 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ForgetClusterNodeCommand do {:error, "RabbitMQ on node #{node_to_remove} must be stopped with 'rabbitmqctl -n #{node_to_remove} stop_app' before it can be removed"} +<<<<<<< HEAD +======= + {:error, {:failed_to_remove_node, ^atom_name, :unavailable}} -> + {:error, "Node #{node_to_remove} must be running before it can be removed"} + +>>>>>>> c285651636 (Resolve elixirc warnings) {:error, _} = error -> error diff --git a/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/join_cluster_command.ex b/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/join_cluster_command.ex index f75498831fdb..ce6004504bd2 100644 --- a/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/join_cluster_command.ex +++ b/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/join_cluster_command.ex @@ -64,6 +64,24 @@ defmodule RabbitMQ.CLI.Ctl.Commands.JoinClusterCommand do "Error: cannot cluster node with itself: #{node_name}"} end +<<<<<<< HEAD +======= + def output({:error, {:node_type_unsupported, db, node_type}}, %{node: _node_name}) do + {:error, RabbitMQ.CLI.Core.ExitCodes.exit_software(), + "Error: `#{node_type}` node type is unsupported by the #{db} by database engine"} + end + + def output( + {:error, + {:khepri_mnesia_migration_ex, :all_mnesia_nodes_must_run, + %{all_nodes: nodes, running_nodes: running}}}, + _opts + ) do + {:error, RabbitMQ.CLI.Core.ExitCodes.exit_software(), + "Error: all mnesia nodes must run to join the cluster, mnesia nodes: #{inspect(nodes)}, running nodes: #{inspect(running)}"} + end + +>>>>>>> c285651636 (Resolve elixirc warnings) use RabbitMQ.CLI.DefaultOutput def banner([target_node], %{node: node_name}) do diff --git a/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/rename_cluster_node_command.ex b/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/rename_cluster_node_command.ex index 1d9afcb1e7fc..09e55030dc8f 100644 --- a/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/rename_cluster_node_command.ex +++ b/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/rename_cluster_node_command.ex @@ -6,8 +6,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.RenameClusterNodeCommand do require Integer - alias RabbitMQ.CLI.Core.{DocGuide, Validators} - import RabbitMQ.CLI.Core.DataCoercion + alias RabbitMQ.CLI.Core.DocGuide @behaviour RabbitMQ.CLI.CommandBehaviour @@ -21,6 +20,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.RenameClusterNodeCommand do :ok end +<<<<<<< HEAD def validate_execution_environment(args, opts) do Validators.chain( [ @@ -43,6 +43,10 @@ defmodule RabbitMQ.CLI.Ctl.Commands.RenameClusterNodeCommand do _, reason -> {:rename_failed, reason} end +======= + def run(_nodes, %{node: _node_name}) do + :ok +>>>>>>> c285651636 (Resolve elixirc warnings) end use RabbitMQ.CLI.DefaultOutput diff --git a/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/update_cluster_nodes_command.ex b/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/update_cluster_nodes_command.ex index 778d78d9bbe9..6c7ffb412f98 100644 --- a/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/update_cluster_nodes_command.ex +++ b/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/update_cluster_nodes_command.ex @@ -5,7 +5,7 @@ ## Copyright (c) 2016-2023 VMware, Inc. or its affiliates. All rights reserved. defmodule RabbitMQ.CLI.Ctl.Commands.UpdateClusterNodesCommand do - alias RabbitMQ.CLI.Core.{Config, DocGuide, Helpers} + alias RabbitMQ.CLI.Core.DocGuide @behaviour RabbitMQ.CLI.CommandBehaviour diff --git a/deps/rabbitmq_cli/lib/rabbitmq/cli/diagnostics/commands/check_if_any_deprecated_features_are_used_command.ex b/deps/rabbitmq_cli/lib/rabbitmq/cli/diagnostics/commands/check_if_any_deprecated_features_are_used_command.ex new file mode 100644 index 000000000000..25463173b66a --- /dev/null +++ b/deps/rabbitmq_cli/lib/rabbitmq/cli/diagnostics/commands/check_if_any_deprecated_features_are_used_command.ex @@ -0,0 +1,98 @@ +## This Source Code Form is subject to the terms of the Mozilla Public +## License, v. 2.0. If a copy of the MPL was not distributed with this +## file, You can obtain one at https://mozilla.org/MPL/2.0/. +## +## Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved. + +defmodule RabbitMQ.CLI.Diagnostics.Commands.CheckIfAnyDeprecatedFeaturesAreUsedCommand do + @behaviour RabbitMQ.CLI.CommandBehaviour + + def scopes(), do: [:ctl, :diagnostics] + + use RabbitMQ.CLI.Core.AcceptsDefaultSwitchesAndTimeout + use RabbitMQ.CLI.Core.MergesNoDefaults + use RabbitMQ.CLI.Core.AcceptsNoPositionalArguments + use RabbitMQ.CLI.Core.RequiresRabbitAppRunning + + def run([], opts) do + are_deprecated_features_used = %{ + :classic_queue_mirroring => is_used_classic_queue_mirroring(opts) + } + + deprecated_features_list = + Enum.reduce( + are_deprecated_features_used, + [], + fn + {_feat, _result}, {:badrpc, _} = acc -> + acc + + {feat, result}, acc -> + case result do + {:badrpc, _} = err -> err + {:error, _} = err -> err + true -> [feat | acc] + false -> acc + end + end + ) + + # health checks return true if they pass + case deprecated_features_list do + {:badrpc, _} = err -> err + {:error, _} = err -> err + [] -> true + xs when is_list(xs) -> {false, deprecated_features_list} + end + end + + def is_used_classic_queue_mirroring(%{node: node_name, timeout: timeout}) do + :rabbit_misc.rpc_call( + node_name, + :rabbit_mirror_queue_misc, + :are_cmqs_used, + [:none], + timeout + ) + end + + def output(true, %{formatter: "json"}) do + {:ok, %{"result" => "ok"}} + end + + def output(true, %{silent: true}) do + {:ok, :check_passed} + end + + def output(true, %{}) do + {:ok, "Cluster reported no deprecated features in use"} + end + + def output({false, deprecated_features_list}, %{formatter: "json"}) do + {:error, :check_failed, + %{ + "result" => "error", + "deprecated_features" => deprecated_features_list, + "message" => "Cluster reported deprecated features in use" + }} + end + + def output({false, _deprecated_features_list}, %{silent: true}) do + {:error, :check_failed} + end + + def output({false, deprecated_features_list}, _) do + {:error, :check_failed, deprecated_features_list} + end + + use RabbitMQ.CLI.DefaultOutput + + def usage, do: "check_if_any_deprecated_features_are_used" + + def help_section(), do: :observability_and_health_checks + + def description(), + do: "Generate a report listing all deprecated features in use" + + def banner(_, %{node: _node_name}), do: "Checking if any deprecated features are used ..." +end diff --git a/deps/rabbitmq_cli/lib/rabbitmq/cli/diagnostics/commands/list_policies_that_match.ex b/deps/rabbitmq_cli/lib/rabbitmq/cli/diagnostics/commands/list_policies_that_match.ex index ac3ebdbdc29b..7422c71ce9ce 100644 --- a/deps/rabbitmq_cli/lib/rabbitmq/cli/diagnostics/commands/list_policies_that_match.ex +++ b/deps/rabbitmq_cli/lib/rabbitmq/cli/diagnostics/commands/list_policies_that_match.ex @@ -56,16 +56,16 @@ defmodule RabbitMQ.CLI.Diagnostics.Commands.ListPoliciesThatMatchCommand do end end - def output([], %{node: node_name, formatter: "json"}) do + def output([], %{node: _node_name, formatter: "json"}) do {:ok, %{"result" => "ok", "policies" => []}} end - def output({:error, :not_found}, %{node: node_name, formatter: "json"}) do + def output({:error, :not_found}, %{node: _node_name, formatter: "json"}) do {:ok, %{"result" => "error", "message" => "object (queue, exchange) not found", "policies" => []}} end - def output(value, %{node: node_name, formatter: "json"}) when is_list(value) do + def output(value, %{node: _node_name, formatter: "json"}) when is_list(value) do {:ok, %{"result" => "ok", "policies" => value}} end diff --git a/deps/rabbitmq_cli/lib/rabbitmq/cli/diagnostics/commands/metadata_store_status_command.ex b/deps/rabbitmq_cli/lib/rabbitmq/cli/diagnostics/commands/metadata_store_status_command.ex new file mode 100644 index 000000000000..dbff928791d7 --- /dev/null +++ b/deps/rabbitmq_cli/lib/rabbitmq/cli/diagnostics/commands/metadata_store_status_command.ex @@ -0,0 +1,34 @@ +## This Source Code Form is subject to the terms of the Mozilla Public +## License, v. 2.0. If a copy of the MPL was not distributed with this +## file, You can obtain one at https://mozilla.org/MPL/2.0/. +## +## Copyright (c) 2022 VMware, Inc. or its affiliates. All rights reserved. + +defmodule RabbitMQ.CLI.Diagnostics.Commands.MetadataStoreStatusCommand do + @behaviour RabbitMQ.CLI.CommandBehaviour + def scopes(), do: [:diagnostics] + + def merge_defaults(args, opts), do: {args, Map.merge(%{vhost: "/"}, opts)} + + use RabbitMQ.CLI.Core.AcceptsNoPositionalArguments + use RabbitMQ.CLI.Core.RequiresRabbitAppRunning + + def run([] = _args, %{node: node_name}) do + :rabbit_misc.rpc_call(node_name, :rabbit_khepri, :status, []) + end + + use RabbitMQ.CLI.DefaultOutput + + def formatter(), do: RabbitMQ.CLI.Formatters.PrettyTable + + def usage() do + "metadata_store_status" + end + + def help_section(), do: :observability_and_health_checks + + def description(), do: "Displays quorum status of Khepri metadata store" + + def banner([], %{node: node_name}), + do: "Status of metadata store on node #{node_name} ..." +end diff --git a/deps/rabbitmq_cli/lib/rabbitmq/cli/diagnostics/commands/remote_shell_command.ex b/deps/rabbitmq_cli/lib/rabbitmq/cli/diagnostics/commands/remote_shell_command.ex index 44766dedcd61..2896c112ea92 100644 --- a/deps/rabbitmq_cli/lib/rabbitmq/cli/diagnostics/commands/remote_shell_command.ex +++ b/deps/rabbitmq_cli/lib/rabbitmq/cli/diagnostics/commands/remote_shell_command.ex @@ -38,7 +38,7 @@ defmodule RabbitMQ.CLI.Diagnostics.Commands.RemoteShellCommand do case :shell.start_interactive({node_name, {:shell, :start, []}}) do :ok -> :ok {:error, :already_started} -> :ok - {error, _} -> {:error, {:badrpc, :nodedown}} + {:error, _} -> {:error, {:badrpc, :nodedown}} end :timer.sleep(:infinity) diff --git a/deps/rabbitmq_cli/lib/rabbitmq/cli/streams/commands/coordinator_status_command.ex b/deps/rabbitmq_cli/lib/rabbitmq/cli/streams/commands/coordinator_status_command.ex new file mode 100644 index 000000000000..f111a1d5d248 --- /dev/null +++ b/deps/rabbitmq_cli/lib/rabbitmq/cli/streams/commands/coordinator_status_command.ex @@ -0,0 +1,52 @@ +## This Source Code Form is subject to the terms of the Mozilla Public +## License, v. 2.0. If a copy of the MPL was not distributed with this +## file, You can obtain one at https://mozilla.org/MPL/2.0/. +## +## Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved. + +defmodule RabbitMQ.CLI.Queues.Commands.CoordinatorStatusCommand do + alias RabbitMQ.CLI.Core.DocGuide + + @behaviour RabbitMQ.CLI.CommandBehaviour + def scopes(), do: [:diagnostics, :streams] + + def merge_defaults(args, opts), do: {args, opts} + + use RabbitMQ.CLI.Core.AcceptsNoPositionalArguments + use RabbitMQ.CLI.Core.RequiresRabbitAppRunning + + def run([] = _args, %{node: node_name}) do + case :rabbit_misc.rpc_call(node_name, :rabbit_stream_coordinator, :status, []) do + {:error, :coordinator_not_started_or_available} -> + {:error, "Cannot get coordinator status as coordinator not started or unavailable"} + + other -> + other + end + end + + use RabbitMQ.CLI.DefaultOutput + + def formatter(), do: RabbitMQ.CLI.Formatters.PrettyTable + + def usage() do + "coordinator_status" + end + + def usage_additional do + [] + end + + def usage_doc_guides() do + [ + DocGuide.streams() + ] + end + + def help_section(), do: :observability_and_health_checks + + def description(), do: "Displays raft status of the stream coordinator" + + def banner([], %{node: _node_name}), + do: "Status of stream coordinator ..." +end diff --git a/deps/rabbitmq_cli/rabbitmqctl_compile_warnings_as_errors.bzl b/deps/rabbitmq_cli/rabbitmqctl_compile_warnings_as_errors.bzl new file mode 100644 index 000000000000..731eb945bf67 --- /dev/null +++ b/deps/rabbitmq_cli/rabbitmqctl_compile_warnings_as_errors.bzl @@ -0,0 +1,202 @@ +load("@bazel_skylib//lib:shell.bzl", "shell") +load( + "@rules_erlang//:erlang_app_info.bzl", + "ErlangAppInfo", +) +load( + "@rules_erlang//:util.bzl", + "path_join", + "windows_path", +) +load( + "@rules_erlang//private:util.bzl", + "additional_file_dest_relative_path", +) +load( + "//bazel/elixir:elixir_toolchain.bzl", + "elixir_dirs", + "erlang_dirs", + "maybe_install_erlang", +) +load( + ":rabbitmqctl.bzl", + "deps_dir_contents", +) + +def _impl(ctx): + (erlang_home, _, erlang_runfiles) = erlang_dirs(ctx) + (elixir_home, elixir_runfiles) = elixir_dirs(ctx, short_path = True) + + deps_dir = ctx.label.name + "_deps" + + deps_dir_files = deps_dir_contents( + ctx, + ctx.attr.deps, + deps_dir, + ) + + for dep, app_name in ctx.attr.source_deps.items(): + for src in dep.files.to_list(): + if not src.is_directory: + rp = additional_file_dest_relative_path(dep.label, src) + f = ctx.actions.declare_file(path_join( + deps_dir, + app_name, + rp, + )) + ctx.actions.symlink( + output = f, + target_file = src, + ) + deps_dir_files.append(f) + + package_dir = path_join( + ctx.label.workspace_root, + ctx.label.package, + ) + + precompiled_deps = " ".join([ + dep[ErlangAppInfo].app_name + for dep in ctx.attr.deps + ]) + + if not ctx.attr.is_windows: + output = ctx.actions.declare_file(ctx.label.name) + script = """set -euo pipefail + +{maybe_install_erlang} + +if [[ "{elixir_home}" == /* ]]; then + ABS_ELIXIR_HOME="{elixir_home}" +else + ABS_ELIXIR_HOME=$PWD/{elixir_home} +fi + +export PATH="$ABS_ELIXIR_HOME"/bin:"{erlang_home}"/bin:${{PATH}} + +export LANG="en_US.UTF-8" +export LC_ALL="en_US.UTF-8" + +INITIAL_DIR="$(pwd)" + +if [ ! -f ${{INITIAL_DIR}}/{package_dir}/test/test_helper.exs ]; then + echo "test_helper.exs cannot be found. 'bazel clean' might fix this." + exit 1 +fi + +cp -r ${{INITIAL_DIR}}/{package_dir}/config ${{TEST_UNDECLARED_OUTPUTS_DIR}} +cp -r ${{INITIAL_DIR}}/{package_dir}/lib ${{TEST_UNDECLARED_OUTPUTS_DIR}} +cp -r ${{INITIAL_DIR}}/{package_dir}/test ${{TEST_UNDECLARED_OUTPUTS_DIR}} +cp ${{INITIAL_DIR}}/{package_dir}/mix.exs ${{TEST_UNDECLARED_OUTPUTS_DIR}} +cp ${{INITIAL_DIR}}/{package_dir}/.formatter.exs ${{TEST_UNDECLARED_OUTPUTS_DIR}} + +cd ${{TEST_UNDECLARED_OUTPUTS_DIR}} + +export IS_BAZEL=true +export HOME=${{PWD}} +export DEPS_DIR=$TEST_SRCDIR/$TEST_WORKSPACE/{package_dir}/{deps_dir} +export MIX_ENV=test +export ERL_COMPILER_OPTIONS=deterministic +for archive in {archives}; do + "${{ABS_ELIXIR_HOME}}"/bin/mix archive.install --force $INITIAL_DIR/$archive +done +set -x +"${{ABS_ELIXIR_HOME}}"/bin/mix deps.compile +"${{ABS_ELIXIR_HOME}}"/bin/mix compile --warnings-as-errors +""".format( + maybe_install_erlang = maybe_install_erlang(ctx, short_path = True), + erlang_home = erlang_home, + elixir_home = elixir_home, + package_dir = package_dir, + deps_dir = deps_dir, + archives = " ".join([shell.quote(a.short_path) for a in ctx.files.archives]), + precompiled_deps = precompiled_deps, + ) + else: + output = ctx.actions.declare_file(ctx.label.name + ".bat") + script = """@echo off +:: set LANG="en_US.UTF-8" +:: set LC_ALL="en_US.UTF-8" + +set PATH="{elixir_home}\\bin";"{erlang_home}\\bin";%PATH% + +set OUTPUTS_DIR=%TEST_UNDECLARED_OUTPUTS_DIR:/=\\% + +:: robocopy exits non-zero when files are copied successfully +:: https://social.msdn.microsoft.com/Forums/en-US/d599833c-dcea-46f5-85e9-b1f028a0fefe/robocopy-exits-with-error-code-1?forum=tfsbuild +robocopy {package_dir}\\config %OUTPUTS_DIR%\\config /E /NFL /NDL /NJH /NJS /nc /ns /np +robocopy {package_dir}\\lib %OUTPUTS_DIR%\\lib /E /NFL /NDL /NJH /NJS /nc /ns /np +robocopy {package_dir}\\test %OUTPUTS_DIR%\\test /E /NFL /NDL /NJH /NJS /nc /ns /np +copy {package_dir}\\mix.exs %OUTPUTS_DIR%\\mix.exs || goto :error +copy {package_dir}\\.formatter.exs %OUTPUTS_DIR%\\.formatter.exs || goto :error + +cd %OUTPUTS_DIR% || goto :error + +set DEPS_DIR=%TEST_SRCDIR%/%TEST_WORKSPACE%/{package_dir}/{deps_dir} +set DEPS_DIR=%DEPS_DIR:/=\\% +set ERL_COMPILER_OPTIONS=deterministic +set MIX_ENV=test +for %%a in ({archives}) do ( + set ARCH=%TEST_SRCDIR%/%TEST_WORKSPACE%/%%a + set ARCH=%ARCH:/=\\% + "{elixir_home}\\bin\\mix" archive.install --force %ARCH% || goto :error +) +"{elixir_home}\\bin\\mix" deps.compile || goto :error +"{elixir_home}\\bin\\mix" compile --warnings-as-errors || goto :error +goto :EOF +:error +exit /b 1 +""".format( + erlang_home = windows_path(erlang_home), + elixir_home = windows_path(elixir_home), + package_dir = windows_path(ctx.label.package), + deps_dir = deps_dir, + archives = " ".join([shell.quote(a.short_path) for a in ctx.files.archives]), + precompiled_deps = precompiled_deps, + ) + + ctx.actions.write( + output = output, + content = script, + ) + + runfiles = ctx.runfiles( + files = ctx.files.srcs + ctx.files.data + ctx.files.archives, + transitive_files = depset(deps_dir_files), + ).merge_all([ + erlang_runfiles, + elixir_runfiles, + ]) + + return [DefaultInfo( + runfiles = runfiles, + executable = output, + )] + +rabbitmqctl_compile_warnings_as_errors_private_test = rule( + implementation = _impl, + attrs = { + "is_windows": attr.bool(mandatory = True), + "srcs": attr.label_list(allow_files = [".ex", ".exs"]), + "data": attr.label_list(allow_files = True), + "deps": attr.label_list(providers = [ErlangAppInfo]), + "archives": attr.label_list( + allow_files = [".ez"], + ), + "source_deps": attr.label_keyed_string_dict(), + }, + toolchains = [ + "//bazel/elixir:toolchain_type", + ], + test = True, +) + +def rabbitmqctl_compile_warnings_as_errors_test(**kwargs): + rabbitmqctl_compile_warnings_as_errors_private_test( + is_windows = select({ + "@bazel_tools//src/conditions:host_windows": True, + "//conditions:default": False, + }), + **kwargs + ) +