defmodule Mix.Tasks.Bonny.Gen.Controller do @moduledoc """ Generates a new CRD controller An operator can have multiple controllers. Each controller handles the lifecycle of a custom resource. ```shell mix bonny.gen.controller ``` Open up your controller and add functionality for your resources lifecycle: * Add * Modify * Delete * Reconcile If you selected to add a CRD, also edit the generated CRD version module. """ # credo:disable-for-this-file Credo.Check.Refactor.CyclomaticComplexity use Mix.Task @switches [out: :string, help: :boolean] @aliases [o: :out, h: :help] @shortdoc "Generate a new CRD Controller for this operator" @spec run([binary()]) :: Keyword.t() def run(args) do Mix.Bonny.no_umbrella!() {opts, args, _} = Mix.Bonny.parse_args(args, [], switches: @switches, aliases: @aliases) if opts[:help] do print_usage() exit(:normal) end binding = args |> init_values() |> get_input() |> Keyword.put(:app_name, Mix.Bonny.app_name()) controller_filename = Macro.underscore(binding[:controller_name]) controller_out = opts[:out] || controller_path(controller_filename) test_out = opts[:out] || controller_test_path(controller_filename) "controller.ex" |> Mix.Bonny.template() |> EEx.eval_file(binding) |> Mix.Bonny.render(controller_out) "controller_test.ex" |> Mix.Bonny.template() |> EEx.eval_file(binding) |> Mix.Bonny.render(test_out) Owl.IO.puts([ Owl.Data.tag( "Don't forget to add the controller to controllers/2 in your operator.", :yellow ) ]) binding end # coveralls-ignore-start trivial code and we use stdout in tests defp controller_path(filename) do Path.join(["lib", Mix.Bonny.app_dir_name(), "controllers", "#{filename}.ex"]) end defp controller_test_path(filename) do Path.join([ "test", Mix.Bonny.app_dir_name(), "controllers", "#{filename}_test.exs" ]) end # coveralls-ignore-stop defp controller_name_valid?(controller_name) do controller_name =~ ~r/^[A-Z][^\W_]*(\.[A-Z]\[^\W_]*)*$/ end def get_input(input) do cond do is_nil(input[:controller_name]) -> controller_name = Owl.IO.input( label: "What's the name of your controller? This has to be a valid Elixir module name. e.g. CronTabController" ) input |> Keyword.put(:controller_name, controller_name) |> get_input() !controller_name_valid?(input[:controller_name]) -> Mix.Bonny.error( "The controller name you defined (#{input[:controller_name]}) is not a valid Elixir module name!" ) input |> Keyword.delete(:controller_name) |> get_input() true -> input end end defp init_values(args) do args |> Enum.with_index() |> Enum.flat_map(fn {arg, 0} -> [{:controller_name, arg}] end) end defp print_usage() do IO.puts(""" usage: mix bonny.gen.controller [options] [controller_name] controller_name: The module name of your controller - Should be a valid Elixir module name options: -h, --help Print this message -o, --out "-" prints to stdout """) end end