diff --git a/installer/test/mix_helper.exs b/installer/test/mix_helper.exs index 1addd2ec1f..baa047b732 100644 --- a/installer/test/mix_helper.exs +++ b/installer/test/mix_helper.exs @@ -28,7 +28,6 @@ defmodule MixHelper do end def in_tmp_project(which, function) do - conf_before = Application.get_env(:phoenix, :generators) || [] base = Path.join([tmp_path(), random_string(10)]) path = Path.join([base, to_string(which)]) @@ -38,24 +37,14 @@ defmodule MixHelper do File.cd!(path, fn -> File.touch!("mix.exs") - - File.write!(".formatter.exs", """ - [ - import_deps: [:phoenix, :ecto, :ecto_sql], - inputs: ["*.exs"] - ] - """) - - function.() + with_generator_env([format_extensions: []], function) end) after File.rm_rf!(base) - Application.put_env(:phoenix, :generators, conf_before) end end def in_tmp_umbrella_project(which, function) do - conf_before = Application.get_env(:phoenix, :generators) || [] base = Path.join([tmp_path(), random_string(10)]) path = Path.join([base, to_string(which)]) @@ -72,9 +61,10 @@ defmodule MixHelper do File.write!(Path.join(config_path, file), "import Config\n") end - File.cd!(apps_path, function) + File.cd!(apps_path, fn -> + with_generator_env([format_extensions: []], function) + end) after - Application.put_env(:phoenix, :generators, conf_before) File.rm_rf!(base) end end @@ -131,15 +121,15 @@ defmodule MixHelper do end def with_generator_env(app_name \\ :phoenix, new_env, fun) do - config_before = Application.fetch_env(app_name, :generators) - Application.put_env(app_name, :generators, new_env) + config_before = Application.get_env(app_name, :generators) + Application.put_env(app_name, :generators, Keyword.merge(config_before || [], new_env)) try do fun.() after case config_before do - {:ok, config} -> Application.put_env(app_name, :generators, config) - :error -> Application.delete_env(app_name, :generators) + nil -> Application.delete_env(app_name, :generators) + config -> Application.put_env(app_name, :generators, config) end end end diff --git a/integration_test/test/code_generation/app_with_defaults_test.exs b/integration_test/test/code_generation/app_with_defaults_test.exs index 57d069f794..cf8dd08605 100644 --- a/integration_test/test/code_generation/app_with_defaults_test.exs +++ b/integration_test/test/code_generation/app_with_defaults_test.exs @@ -27,7 +27,17 @@ defmodule Phoenix.Integration.CodeGeneration.AppWithDefaultsTest do with_installer_tmp("app_with_defaults", fn tmp_dir -> {app_root_path, _} = generate_phoenix_app(tmp_dir, "phx_blog") - mix_run!(~w(phx.gen.html Blog Post posts title:unique body:string status:enum:unpublished:published:deleted), app_root_path) + mix_run!( + ~w(phx.gen.html Blog Post posts + title:unique + body:string + preface + author_name + author_email + other_very_important_attribute + status:enum:unpublished:published:deleted), + app_root_path + ) modify_file(Path.join(app_root_path, "lib/phx_blog_web/router.ex"), fn file -> inject_before_final_end(file, """ @@ -74,7 +84,17 @@ defmodule Phoenix.Integration.CodeGeneration.AppWithDefaultsTest do with_installer_tmp("app_with_defaults", fn tmp_dir -> {app_root_path, _} = generate_phoenix_app(tmp_dir, "phx_blog") - mix_run!(~w(phx.gen.json Blog Post posts title:unique body:string status:enum:unpublished:published:deleted), app_root_path) + mix_run!( + ~w(phx.gen.json Blog Post posts + title:unique + body:string + preface + author_name + author_email + other_very_important_attribute + status:enum:unpublished:published:deleted), + app_root_path + ) modify_file(Path.join(app_root_path, "lib/phx_blog_web/router.ex"), fn file -> inject_before_final_end(file, """ @@ -121,7 +141,18 @@ defmodule Phoenix.Integration.CodeGeneration.AppWithDefaultsTest do with_installer_tmp("app_with_defaults", fn tmp_dir -> {app_root_path, _} = generate_phoenix_app(tmp_dir, "phx_blog", ["--live"]) - mix_run!(~w(phx.gen.live Blog Post posts title:unique body:string p:boolean s:enum:a:b:c), app_root_path) + mix_run!( + ~w(phx.gen.live Blog Post posts + title:unique + body:string + preface + author_name + author_email + other_very_important_attribute + public:boolean + status:enum:unpublished:published:deleted), + app_root_path + ) modify_file(Path.join(app_root_path, "lib/phx_blog_web/router.ex"), fn file -> inject_before_final_end(file, """ diff --git a/integration_test/test/code_generation/app_with_mssql_adapter_test.exs b/integration_test/test/code_generation/app_with_mssql_adapter_test.exs index 96ca203de2..0b9903b748 100644 --- a/integration_test/test/code_generation/app_with_mssql_adapter_test.exs +++ b/integration_test/test/code_generation/app_with_mssql_adapter_test.exs @@ -87,7 +87,14 @@ defmodule Phoenix.Integration.CodeGeneration.AppWithMSSQLAdapterTest do with_installer_tmp("new with defaults", fn tmp_dir -> {app_root_path, _} = generate_phoenix_app(tmp_dir, "phx_blog", ["--database", "mssql", "--live"]) - mix_run!(~w(phx.gen.html Accounts Group groups name), app_root_path) + mix_run!( + ~w(phx.gen.html Accounts Group groups + name + details + other_very_important_attribute + one_more_attribute_with_long_name), + app_root_path + ) modify_file(Path.join(app_root_path, "lib/phx_blog_web/router.ex"), fn file -> inject_before_final_end(file, """ diff --git a/integration_test/test/code_generation/app_with_mysql_adapter_test.exs b/integration_test/test/code_generation/app_with_mysql_adapter_test.exs index 0886d421f9..936efe9262 100644 --- a/integration_test/test/code_generation/app_with_mysql_adapter_test.exs +++ b/integration_test/test/code_generation/app_with_mysql_adapter_test.exs @@ -8,7 +8,17 @@ defmodule Phoenix.Integration.CodeGeneration.AppWithMySqlAdapterTest do {app_root_path, _} = generate_phoenix_app(tmp_dir, "default_mysql_app", ["--database", "mysql"]) - mix_run!(~w(phx.gen.html Blog Post posts title body:string status:enum:unpublished:published:deleted), app_root_path) + mix_run!( + ~w(phx.gen.html Blog Post posts + title + body:string + preface + author_name + author_email + other_very_important_attribute + status:enum:unpublished:published:deleted), + app_root_path + ) modify_file(Path.join(app_root_path, "lib/default_mysql_app_web/router.ex"), fn file -> inject_before_final_end(file, """ @@ -21,6 +31,9 @@ defmodule Phoenix.Integration.CodeGeneration.AppWithMySqlAdapterTest do """) end) + # TODO: Uncomment when fix unformatted code from `phx.new` generator. + # assert_no_compilation_warnings(app_root_path) + # assert_passes_formatter_check(app_root_path) drop_test_database(app_root_path) assert_tests_pass(app_root_path) end) @@ -34,7 +47,17 @@ defmodule Phoenix.Integration.CodeGeneration.AppWithMySqlAdapterTest do {app_root_path, _} = generate_phoenix_app(tmp_dir, "default_mysql_app", ["--database", "mysql"]) - mix_run!(~w(phx.gen.json Blog Post posts title body:string status:enum:unpublished:published:deleted), app_root_path) + mix_run!( + ~w(phx.gen.json Blog Post posts posts + title + body:string + preface + author_name + author_email + other_very_important_attribute + status:enum:unpublished:published:deleted), + app_root_path + ) modify_file(Path.join(app_root_path, "lib/default_mysql_app_web/router.ex"), fn file -> inject_before_final_end(file, """ @@ -47,6 +70,9 @@ defmodule Phoenix.Integration.CodeGeneration.AppWithMySqlAdapterTest do """) end) + # TODO: Uncomment when fix unformatted code from `phx.new` generator. + # assert_no_compilation_warnings(app_root_path) + # assert_passes_formatter_check(app_root_path) drop_test_database(app_root_path) assert_tests_pass(app_root_path) end) @@ -60,7 +86,17 @@ defmodule Phoenix.Integration.CodeGeneration.AppWithMySqlAdapterTest do {app_root_path, _} = generate_phoenix_app(tmp_dir, "default_mysql_app", ["--database", "mysql", "--live"]) - mix_run!(~w(phx.gen.live Blog Post posts title body:string status:enum:unpublished:published:deleted), app_root_path) + mix_run!( + ~w(phx.gen.live Blog Post posts posts + title + body:string + preface + author_name + author_email + other_very_important_attribute + status:enum:unpublished:published:deleted), + app_root_path + ) modify_file(Path.join(app_root_path, "lib/default_mysql_app_web/router.ex"), fn file -> inject_before_final_end(file, """ @@ -76,6 +112,9 @@ defmodule Phoenix.Integration.CodeGeneration.AppWithMySqlAdapterTest do """) end) + # TODO: Uncomment when fix unformatted code from `phx.new` generator. + # assert_no_compilation_warnings(app_root_path) + # assert_passes_formatter_check(app_root_path) drop_test_database(app_root_path) assert_tests_pass(app_root_path) end) diff --git a/integration_test/test/code_generation/app_with_sqlite3_adapter.exs b/integration_test/test/code_generation/app_with_sqlite3_adapter.exs index 4576a6cfc0..b0871603b1 100644 --- a/integration_test/test/code_generation/app_with_sqlite3_adapter.exs +++ b/integration_test/test/code_generation/app_with_sqlite3_adapter.exs @@ -8,7 +8,17 @@ defmodule Phoenix.Integration.CodeGeneration.AppWithSQLite3AdapterTest do {app_root_path, _} = generate_phoenix_app(tmp_dir, "default_sqlite3_app", ["--database", "sqlite3"]) - mix_run!(~w(phx.gen.html Blog Post posts title body:string status:enum:unpublished:published:deleted), app_root_path) + mix_run!( + ~w(phx.gen.html Blog Post posts + title + body:string + preface + author_name + author_email + other_very_important_attribute + status:enum:unpublished:published:deleted), + app_root_path + ) modify_file(Path.join(app_root_path, "lib/default_sqlite3_app_web/router.ex"), fn file -> inject_before_final_end(file, """ @@ -21,6 +31,8 @@ defmodule Phoenix.Integration.CodeGeneration.AppWithSQLite3AdapterTest do """) end) + assert_no_compilation_warnings(app_root_path) + assert_passes_formatter_check(app_root_path) drop_test_database(app_root_path) assert_tests_pass(app_root_path) end) @@ -34,7 +46,17 @@ defmodule Phoenix.Integration.CodeGeneration.AppWithSQLite3AdapterTest do {app_root_path, _} = generate_phoenix_app(tmp_dir, "default_sqlite3_app", ["--database", "sqlite3"]) - mix_run!(~w(phx.gen.json Blog Post posts title body:string status:enum:unpublished:published:deleted), app_root_path) + mix_run!( + ~w(phx.gen.json Blog Post posts + title + body:string + preface + author_name + author_email + other_very_important_attribute + status:enum:unpublished:published:deleted), + app_root_path + ) modify_file(Path.join(app_root_path, "lib/default_sqlite3_app_web/router.ex"), fn file -> inject_before_final_end(file, """ @@ -47,6 +69,8 @@ defmodule Phoenix.Integration.CodeGeneration.AppWithSQLite3AdapterTest do """) end) + assert_no_compilation_warnings(app_root_path) + assert_passes_formatter_check(app_root_path) drop_test_database(app_root_path) assert_tests_pass(app_root_path) end) @@ -60,7 +84,17 @@ defmodule Phoenix.Integration.CodeGeneration.AppWithSQLite3AdapterTest do {app_root_path, _} = generate_phoenix_app(tmp_dir, "default_sqlite3_app", ["--database", "sqlite3", "--live"]) - mix_run!(~w(phx.gen.live Blog Post posts title body:string status:enum:unpublished:published:deleted), app_root_path) + mix_run!( + ~w(phx.gen.live Blog Post posts + title + body:string + preface + author_name + author_email + other_very_important_attribute + status:enum:unpublished:published:deleted), + app_root_path + ) modify_file(Path.join(app_root_path, "lib/default_sqlite3_app_web/router.ex"), fn file -> inject_before_final_end(file, """ @@ -76,6 +110,8 @@ defmodule Phoenix.Integration.CodeGeneration.AppWithSQLite3AdapterTest do """) end) + assert_no_compilation_warnings(app_root_path) + assert_passes_formatter_check(app_root_path) drop_test_database(app_root_path) assert_tests_pass(app_root_path) end) diff --git a/integration_test/test/code_generation/umbrella_app_with_defaults_test.exs b/integration_test/test/code_generation/umbrella_app_with_defaults_test.exs index 9dc71ba64d..0fdd0b09a1 100644 --- a/integration_test/test/code_generation/umbrella_app_with_defaults_test.exs +++ b/integration_test/test/code_generation/umbrella_app_with_defaults_test.exs @@ -29,7 +29,17 @@ defmodule Phoenix.Integration.CodeGeneration.UmbrellaAppWithDefaultsTest do {app_root_path, _} = generate_phoenix_app(tmp_dir, "rainy_day", ["--umbrella"]) web_root_path = Path.join(app_root_path, "apps/rainy_day_web") - mix_run!(~w(phx.gen.html Blog Post posts title:unique body:string status:enum:unpublished:published:deleted), web_root_path) + mix_run!( + ~w(phx.gen.html Blog Post posts + title:unique + body:string + preface + author_name + author_email + other_very_important_attribute + status:enum:unpublished:published:deleted), + web_root_path + ) modify_file(Path.join(web_root_path, "lib/rainy_day_web/router.ex"), fn file -> inject_before_final_end(file, """ @@ -78,7 +88,17 @@ defmodule Phoenix.Integration.CodeGeneration.UmbrellaAppWithDefaultsTest do {app_root_path, _} = generate_phoenix_app(tmp_dir, "rainy_day", ["--umbrella"]) web_root_path = Path.join(app_root_path, "apps/rainy_day_web") - mix_run!(~w(phx.gen.json Blog Post posts title:unique body:string status:enum:unpublished:published:deleted), web_root_path) + mix_run!( + ~w(phx.gen.json Blog Post posts + title:unique + body:string + preface + author_name + author_email + other_very_important_attribute + status:enum:unpublished:published:deleted), + web_root_path + ) modify_file(Path.join(web_root_path, "lib/rainy_day_web/router.ex"), fn file -> inject_before_final_end(file, """ @@ -127,7 +147,17 @@ defmodule Phoenix.Integration.CodeGeneration.UmbrellaAppWithDefaultsTest do {app_root_path, _} = generate_phoenix_app(tmp_dir, "rainy_day", ["--umbrella", "--live"]) web_root_path = Path.join(app_root_path, "apps/rainy_day_web") - mix_run!(~w(phx.gen.live Blog Post posts title:unique body:string status:enum:unpublished:published:deleted), web_root_path) + mix_run!( + ~w(phx.gen.live Blog Post posts + title:unique + body:string + preface + author_name + author_email + other_very_important_attribute + status:enum:unpublished:published:deleted), + web_root_path + ) modify_file(Path.join(web_root_path, "lib/rainy_day_web/router.ex"), fn file -> inject_before_final_end(file, """ diff --git a/lib/mix/phoenix.ex b/lib/mix/phoenix.ex index 78181df0b1..24b5f1d793 100644 --- a/lib/mix/phoenix.ex +++ b/lib/mix/phoenix.ex @@ -65,6 +65,43 @@ defmodule Mix.Phoenix do defp to_app_source(app, source_dir) when is_atom(app), do: Application.app_dir(app, source_dir) + @default_format_extensions [".ex", ".exs", ".heex"] + @doc """ + Conditionally run `mix format` for generated files. + By default files with extensions `#{inspect(@default_format_extensions)}` are formatted. + It can be adjusted with generators config `format_extensions`, and turned off with value `[]`. + If no files pass condition, formatting is not performed. + """ + def maybe_format(files) when is_list(files) do + format_extensions = + Application.get_env(otp_app(), :generators, []) + |> Keyword.get(:format_extensions, @default_format_extensions) + + files = Enum.filter(files, &String.ends_with?(&1, format_extensions)) + if files != [], do: Mix.Task.run("format", files) + end + + @doc """ + Format docs with override instruction. + """ + def override_format_instruction do + """ + + Files with generated content (new and modified) are formatted with `mix format`. + + By default files with extensions `#{inspect(@default_format_extensions)}` are formatted. + List of extensions can be changed via generators config: + + config :your_app, :generators, + format_extensions: [".ex", ".exs"] + + Formatting can be turned off by setting empty list: + + config :your_app, :generators, + format_extensions: [] + """ + end + @doc """ Inflects path, scope, alias and more from the given name. diff --git a/lib/mix/tasks/phx.gen.context.ex b/lib/mix/tasks/phx.gen.context.ex index 1dfad60e39..6516ab8ff5 100644 --- a/lib/mix/tasks/phx.gen.context.ex +++ b/lib/mix/tasks/phx.gen.context.ex @@ -72,6 +72,10 @@ defmodule Mix.Tasks.Phx.Gen.Context do You can skip this prompt and automatically merge the new schema access functions and tests into the existing context using `--merge-with-existing-context`. To prevent changes to the existing context and exit the generator, use `--no-merge-with-existing-context`. + + ## Format + #{Mix.Phoenix.override_format_instruction()} + """ use Mix.Task @@ -112,6 +116,7 @@ defmodule Mix.Tasks.Phx.Gen.Context do context |> copy_new_files(paths, binding) + |> format_files() |> print_shell_instructions() end @@ -149,17 +154,18 @@ defmodule Mix.Tasks.Phx.Gen.Context do end @doc false + def files_to_be_generated(%Context{generate?: false}), do: [] + def files_to_be_generated(%Context{schema: schema}) do - if schema.generate? do - Gen.Schema.files_to_be_generated(schema) - else - [] - end + Gen.Schema.files_to_be_generated(schema) end @doc false + def copy_new_files(%Context{generate?: false} = context, _, _), do: context + def copy_new_files(%Context{schema: schema} = context, paths, binding) do - if schema.generate?, do: Gen.Schema.copy_new_files(schema, paths, binding) + Gen.Schema.copy_new_files(schema, paths, binding) + inject_schema_access(context, paths, binding) inject_tests(context, paths, binding) inject_test_fixture(context, paths, binding) @@ -293,13 +299,24 @@ defmodule Mix.Tasks.Phx.Gen.Context do end end + defp format_files(%Context{} = context) do + files_to_format(context) |> Mix.Phoenix.maybe_format() + context + end + + @doc false + def files_to_format(%Context{generate?: false}), do: [] + + def files_to_format(%Context{schema: schema} = context) do + [context.file, context.test_file, context.test_fixtures_file] ++ + Gen.Schema.files_to_format(schema) + end + @doc false + def print_shell_instructions(%Context{generate?: false}), do: :ok + def print_shell_instructions(%Context{schema: schema}) do - if schema.generate? do - Gen.Schema.print_shell_instructions(schema) - else - :ok - end + Gen.Schema.print_shell_instructions(schema) end defp schema_access_template(%Context{schema: schema}) do diff --git a/lib/mix/tasks/phx.gen.embedded.ex b/lib/mix/tasks/phx.gen.embedded.ex index 4e82eec674..edb9c644ce 100644 --- a/lib/mix/tasks/phx.gen.embedded.ex +++ b/lib/mix/tasks/phx.gen.embedded.ex @@ -28,7 +28,12 @@ defmodule Mix.Tasks.Phx.Gen.Embedded do #{for attr <- Mix.Phoenix.Schema.valid_types(), do: " * `#{inspect attr}`\n"} * `:datetime` - An alias for `:naive_datetime` + + ## Format + #{Mix.Phoenix.override_format_instruction()} + """ + use Mix.Task alias Mix.Phoenix.Schema @@ -47,13 +52,16 @@ defmodule Mix.Tasks.Phx.Gen.Embedded do prompt_for_conflicts(schema) - copy_new_files(schema, paths, schema: schema) + schema + |> copy_new_files(paths, schema: schema) + |> format_files() end @doc false def build(args) do {schema_opts, parsed, _} = OptionParser.parse(args, switches: @switches) [schema_name | attrs] = validate_args!(parsed) + opts = schema_opts |> Keyword.put(:embedded, true) @@ -72,6 +80,7 @@ defmodule Mix.Tasks.Phx.Gen.Embedded do raise_with_help "Expected the schema argument, #{inspect schema}, to be a valid module name" end end + def validate_args!(_) do raise_with_help "Invalid arguments" end @@ -96,16 +105,21 @@ defmodule Mix.Tasks.Phx.Gen.Embedded do |> Mix.Phoenix.prompt_for_conflicts() end - @doc false - def files_to_be_generated(%Schema{} = schema) do + defp files_to_be_generated(%Schema{} = schema) do [{:eex, "embedded_schema.ex", schema.file}] end - @doc false - def copy_new_files(%Schema{} = schema, paths, binding) do + defp copy_new_files(%Schema{} = schema, paths, binding) do files = files_to_be_generated(schema) Mix.Phoenix.copy_from(paths, "priv/templates/phx.gen.embedded", binding, files) schema end + + defp format_files(%Schema{} = schema) do + files_to_format(schema) |> Mix.Phoenix.maybe_format() + schema + end + + defp files_to_format(%Schema{} = schema), do: [schema.file] end diff --git a/lib/mix/tasks/phx.gen.html.ex b/lib/mix/tasks/phx.gen.html.ex index e9222dacc5..57410d1e24 100644 --- a/lib/mix/tasks/phx.gen.html.ex +++ b/lib/mix/tasks/phx.gen.html.ex @@ -88,7 +88,12 @@ defmodule Mix.Tasks.Phx.Gen.Html do You can also change the table name or configure the migrations to use binary ids for primary keys, see `mix phx.gen.schema` for more information. + + ## Format + #{Mix.Phoenix.override_format_instruction()} + """ + use Mix.Task alias Mix.Phoenix.{Context, Schema} @@ -107,31 +112,24 @@ defmodule Mix.Tasks.Phx.Gen.Html do {context, schema} = Gen.Context.build(args) Gen.Context.prompt_for_code_injection(context) - binding = [context: context, schema: schema, inputs: inputs(schema)] + binding = [context: context, schema: schema] paths = Mix.Phoenix.generator_paths() prompt_for_conflicts(context) context |> copy_new_files(paths, binding) + |> format_files() |> print_shell_instructions() end defp prompt_for_conflicts(context) do context |> files_to_be_generated() - |> Kernel.++(context_files(context)) + |> Kernel.++(Gen.Context.files_to_be_generated(context)) |> Mix.Phoenix.prompt_for_conflicts() end - defp context_files(%Context{generate?: true} = context) do - Gen.Context.files_to_be_generated(context) - end - - defp context_files(%Context{generate?: false}) do - [] - end - @doc false def files_to_be_generated(%Context{schema: schema, context_app: context_app}) do singular = schema.singular @@ -157,12 +155,25 @@ defmodule Mix.Tasks.Phx.Gen.Html do @doc false def copy_new_files(%Context{} = context, paths, binding) do + Gen.Context.copy_new_files(context, paths, binding) + + binding = Keyword.merge(binding, inputs: inputs(context.schema)) files = files_to_be_generated(context) Mix.Phoenix.copy_from(paths, "priv/templates/phx.gen.html", binding, files) - if context.generate?, do: Gen.Context.copy_new_files(context, paths, binding) + context end + defp format_files(%Context{} = context) do + files_to_format(context) |> Mix.Phoenix.maybe_format() + context + end + + defp files_to_format(%Context{} = context) do + (files_to_be_generated(context) |> Enum.map(fn {_, _, file} -> file end)) ++ + Gen.Context.files_to_format(context) + end + @doc false def print_shell_instructions(%Context{schema: schema, context_app: ctx_app} = context) do if schema.web_namespace do @@ -185,7 +196,7 @@ defmodule Mix.Tasks.Phx.Gen.Html do """) end - if context.generate?, do: Gen.Context.print_shell_instructions(context) + Gen.Context.print_shell_instructions(context) end @doc false diff --git a/lib/mix/tasks/phx.gen.json.ex b/lib/mix/tasks/phx.gen.json.ex index 97177b4935..a31fa32662 100644 --- a/lib/mix/tasks/phx.gen.json.ex +++ b/lib/mix/tasks/phx.gen.json.ex @@ -85,6 +85,10 @@ defmodule Mix.Tasks.Phx.Gen.Json do You can also change the table name or configure the migrations to use binary ids for primary keys, see `mix phx.gen.schema` for more information. + + ## Format + #{Mix.Phoenix.override_format_instruction()} + """ use Mix.Task @@ -116,24 +120,17 @@ defmodule Mix.Tasks.Phx.Gen.Json do context |> copy_new_files(paths, binding) + |> format_files() |> print_shell_instructions() end defp prompt_for_conflicts(context) do context |> files_to_be_generated() - |> Kernel.++(context_files(context)) + |> Kernel.++(Gen.Context.files_to_be_generated(context)) |> Mix.Phoenix.prompt_for_conflicts() end - defp context_files(%Context{generate?: true} = context) do - Gen.Context.files_to_be_generated(context) - end - - defp context_files(%Context{generate?: false}) do - [] - end - @doc false def files_to_be_generated(%Context{schema: schema, context_app: context_app}) do singular = schema.singular @@ -154,13 +151,24 @@ defmodule Mix.Tasks.Phx.Gen.Json do @doc false def copy_new_files(%Context{} = context, paths, binding) do + Gen.Context.copy_new_files(context, paths, binding) + files = files_to_be_generated(context) Mix.Phoenix.copy_from(paths, "priv/templates/phx.gen.json", binding, files) - if context.generate?, do: Gen.Context.copy_new_files(context, paths, binding) context end + defp format_files(%Context{} = context) do + files_to_format(context) |> Mix.Phoenix.maybe_format() + context + end + + defp files_to_format(%Context{} = context) do + (files_to_be_generated(context) |> Enum.map(fn {_, _, file} -> file end)) ++ + Gen.Context.files_to_format(context) + end + @doc false def print_shell_instructions(%Context{schema: schema, context_app: ctx_app} = context) do if schema.web_namespace do @@ -183,6 +191,6 @@ defmodule Mix.Tasks.Phx.Gen.Json do """) end - if context.generate?, do: Gen.Context.print_shell_instructions(context) + Gen.Context.print_shell_instructions(context) end end diff --git a/lib/mix/tasks/phx.gen.live.ex b/lib/mix/tasks/phx.gen.live.ex index 3aa01cdd02..27ef798fd9 100644 --- a/lib/mix/tasks/phx.gen.live.ex +++ b/lib/mix/tasks/phx.gen.live.ex @@ -99,7 +99,12 @@ defmodule Mix.Tasks.Phx.Gen.Live do You can also change the table name or configure the migrations to use binary ids for primary keys, see `mix help phx.gen.schema` for more information. + + ## Format + #{Mix.Phoenix.override_format_instruction()} + """ + use Mix.Task alias Mix.Phoenix.{Context, Schema} @@ -118,7 +123,7 @@ defmodule Mix.Tasks.Phx.Gen.Live do {context, schema} = Gen.Context.build(args) Gen.Context.prompt_for_code_injection(context) - binding = [context: context, schema: schema, inputs: inputs(schema)] + binding = [context: context, schema: schema] paths = Mix.Phoenix.generator_paths() prompt_for_conflicts(context) @@ -126,24 +131,17 @@ defmodule Mix.Tasks.Phx.Gen.Live do context |> copy_new_files(binding, paths) |> maybe_inject_imports() + |> format_files() |> print_shell_instructions() end defp prompt_for_conflicts(context) do context |> files_to_be_generated() - |> Kernel.++(context_files(context)) + |> Kernel.++(Gen.Context.files_to_be_generated(context)) |> Mix.Phoenix.prompt_for_conflicts() end - defp context_files(%Context{generate?: true} = context) do - Gen.Context.files_to_be_generated(context) - end - - defp context_files(%Context{generate?: false}) do - [] - end - defp files_to_be_generated(%Context{schema: schema, context_app: context_app}) do web_prefix = Mix.Phoenix.web_path(context_app) test_prefix = Mix.Phoenix.web_test_path(context_app) @@ -163,18 +161,19 @@ defmodule Mix.Tasks.Phx.Gen.Live do end defp copy_new_files(%Context{} = context, binding, paths) do - files = files_to_be_generated(context) + Gen.Context.copy_new_files(context, paths, binding) binding = Keyword.merge(binding, + inputs: inputs(context.schema), assigns: %{ web_namespace: inspect(context.web_module), gettext: true } ) + files = files_to_be_generated(context) Mix.Phoenix.copy_from(paths, "priv/templates/phx.gen.live", binding, files) - if context.generate?, do: Gen.Context.copy_new_files(context, paths, binding) context end @@ -224,6 +223,16 @@ defmodule Mix.Tasks.Phx.Gen.Live do end end + defp format_files(%Context{} = context) do + files_to_format(context) |> Mix.Phoenix.maybe_format() + context + end + + defp files_to_format(%Context{} = context) do + (files_to_be_generated(context) |> Enum.map(fn {_, _, file} -> file end)) ++ + Gen.Context.files_to_format(context) + end + @doc false def print_shell_instructions(%Context{schema: schema, context_app: ctx_app} = context) do prefix = Module.concat(context.web_module, schema.web_namespace) @@ -250,7 +259,7 @@ defmodule Mix.Tasks.Phx.Gen.Live do """) end - if context.generate?, do: Gen.Context.print_shell_instructions(context) + Gen.Context.print_shell_instructions(context) maybe_print_upgrade_info() end diff --git a/lib/mix/tasks/phx.gen.schema.ex b/lib/mix/tasks/phx.gen.schema.ex index 68f3c82ddf..35b03efd4a 100644 --- a/lib/mix/tasks/phx.gen.schema.ex +++ b/lib/mix/tasks/phx.gen.schema.ex @@ -107,7 +107,6 @@ defmodule Mix.Tasks.Phx.Gen.Schema do $ mix phx.gen.schema Blog.Post posts --migration-dir /path/to/directory - ## prefix By default migrations and schemas are generated without a prefix. @@ -147,7 +146,11 @@ defmodule Mix.Tasks.Phx.Gen.Schema do instead of a `NaiveDateTime`. This can also be set to `:utc_datetime_usec` for microsecond precision. + ## Format + #{Mix.Phoenix.override_format_instruction()} + """ + use Mix.Task alias Mix.Phoenix.Schema @@ -169,6 +172,7 @@ defmodule Mix.Tasks.Phx.Gen.Schema do schema |> copy_new_files(paths, schema: schema) + |> format_files() |> print_shell_instructions() end @@ -206,40 +210,54 @@ defmodule Mix.Tasks.Phx.Gen.Schema do end @doc false + def files_to_be_generated(%Schema{generate?: false}), do: [] + def files_to_be_generated(%Schema{} = schema) do [{:eex, "schema.ex", schema.file}] end @doc false - def copy_new_files(%Schema{context_app: ctx_app, repo: repo, opts: opts} = schema, paths, binding) do - files = files_to_be_generated(schema) + def copy_new_files(%Schema{generate?: false} = schema, _, _), do: schema + + def copy_new_files(%Schema{} = schema, paths, binding) do + migration_file = + if schema.migration?, do: [{:eex, "migration.exs", migration_path(schema)}], else: [] + + files = files_to_be_generated(schema) ++ migration_file Mix.Phoenix.copy_from(paths, "priv/templates/phx.gen.schema", binding, files) - if schema.migration? do - migration_dir = - cond do - migration_dir = opts[:migration_dir] -> - migration_dir + schema + end - opts[:repo] -> - repo_name = repo |> Module.split() |> List.last() |> Macro.underscore() - Mix.Phoenix.context_app_path(ctx_app, "priv/#{repo_name}/migrations/") + defp migration_path(%Schema{context_app: ctx_app, repo: repo, opts: opts, table: table}) do + migration_dir = + cond do + migration_dir = opts[:migration_dir] -> + migration_dir - true -> - Mix.Phoenix.context_app_path(ctx_app, "priv/repo/migrations/") - end + opts[:repo] -> + repo_name = repo |> Module.split() |> List.last() |> Macro.underscore() + Mix.Phoenix.context_app_path(ctx_app, "priv/#{repo_name}/migrations/") - migration_path = Path.join(migration_dir, "#{timestamp()}_create_#{schema.table}.exs") + true -> + Mix.Phoenix.context_app_path(ctx_app, "priv/repo/migrations/") + end - Mix.Phoenix.copy_from paths, "priv/templates/phx.gen.schema", binding, [ - {:eex, "migration.exs", migration_path}, - ] - end + Path.join(migration_dir, "#{timestamp()}_create_#{table}.exs") + end + defp format_files(%Schema{} = schema) do + files_to_format(schema) |> Mix.Phoenix.maybe_format() schema end @doc false + def files_to_format(%Schema{generate?: false}), do: [] + def files_to_format(%Schema{} = schema), do: [schema.file, migration_path(schema)] + + @doc false + def print_shell_instructions(%Schema{generate?: false}), do: :ok + def print_shell_instructions(%Schema{} = schema) do if schema.migration? do Mix.shell().info """ @@ -262,6 +280,7 @@ defmodule Mix.Tasks.Phx.Gen.Schema do args end end + def validate_args!(_, help) do help.raise_with_help "Invalid arguments" end diff --git a/test/mix/tasks/phx.gen.html_test.exs b/test/mix/tasks/phx.gen.html_test.exs index 450e0599b7..0b4c4e1ead 100644 --- a/test/mix/tasks/phx.gen.html_test.exs +++ b/test/mix/tasks/phx.gen.html_test.exs @@ -331,6 +331,7 @@ defmodule Mix.Tasks.Phx.Gen.HtmlTest do test "with a matching plural and singular term", config do in_tmp_project(config.test, fn -> Gen.Html.run(~w(Tracker Series series value:integer)) + assert_file("lib/phoenix_web/controllers/series_controller.ex", fn file -> assert file =~ "render(conn, :index, series_collection: series)" end) @@ -399,58 +400,60 @@ defmodule Mix.Tasks.Phx.Gen.HtmlTest do describe "inside umbrella" do test "without context_app generators config uses web dir", config do in_tmp_umbrella_project(config.test, fn -> - Application.put_env(:phoenix, :generators, context_app: nil) - Gen.Html.run(~w(Accounts User users name:string)) + with_generator_env([context_app: nil], fn -> + Gen.Html.run(~w(Accounts User users name:string)) - assert_file("lib/phoenix/accounts.ex") - assert_file("lib/phoenix/accounts/user.ex") + assert_file("lib/phoenix/accounts.ex") + assert_file("lib/phoenix/accounts/user.ex") - assert_file("lib/phoenix_web/controllers/user_controller.ex", fn file -> - assert file =~ "defmodule PhoenixWeb.UserController" - assert file =~ "use PhoenixWeb, :controller" - end) + assert_file("lib/phoenix_web/controllers/user_controller.ex", fn file -> + assert file =~ "defmodule PhoenixWeb.UserController" + assert file =~ "use PhoenixWeb, :controller" + end) - assert_file("lib/phoenix_web/controllers/user_html.ex", fn file -> - assert file =~ "defmodule PhoenixWeb.UserHTML" - end) + assert_file("lib/phoenix_web/controllers/user_html.ex", fn file -> + assert file =~ "defmodule PhoenixWeb.UserHTML" + end) - assert_file("test/phoenix_web/controllers/user_controller_test.exs", fn file -> - assert file =~ "defmodule PhoenixWeb.UserControllerTest" + assert_file("test/phoenix_web/controllers/user_controller_test.exs", fn file -> + assert file =~ "defmodule PhoenixWeb.UserControllerTest" + end) end) end) end test "raises with false context_app", config do in_tmp_umbrella_project(config.test, fn -> - Application.put_env(:phoenix, :generators, context_app: false) - - assert_raise Mix.Error, ~r/no context_app configured/, fn -> - Gen.Html.run(~w(Accounts User users name:string)) - end + with_generator_env([context_app: false], fn -> + assert_raise Mix.Error, ~r/no context_app configured/, fn -> + Gen.Html.run(~w(Accounts User users name:string)) + end + end) end) end test "with context_app generators config does not use web dir", config do in_tmp_umbrella_project(config.test, fn -> File.mkdir!("another_app") - Application.put_env(:phoenix, :generators, context_app: {:another_app, "another_app"}) - Gen.Html.run(~w(Accounts User users name:string)) + with_generator_env([context_app: {:another_app, "another_app"}], fn -> + Gen.Html.run(~w(Accounts User users name:string)) - assert_file("another_app/lib/another_app/accounts.ex") - assert_file("another_app/lib/another_app/accounts/user.ex") + assert_file("another_app/lib/another_app/accounts.ex") + assert_file("another_app/lib/another_app/accounts/user.ex") - assert_file("lib/phoenix/controllers/user_controller.ex", fn file -> - assert file =~ "defmodule Phoenix.UserController" - assert file =~ "use Phoenix, :controller" - end) + assert_file("lib/phoenix/controllers/user_controller.ex", fn file -> + assert file =~ "defmodule Phoenix.UserController" + assert file =~ "use Phoenix, :controller" + end) - assert_file("lib/phoenix/controllers/user_html.ex", fn file -> - assert file =~ "defmodule Phoenix.UserHTML" - end) + assert_file("lib/phoenix/controllers/user_html.ex", fn file -> + assert file =~ "defmodule Phoenix.UserHTML" + end) - assert_file("test/phoenix/controllers/user_controller_test.exs", fn file -> - assert file =~ "defmodule Phoenix.UserControllerTest" + assert_file("test/phoenix/controllers/user_controller_test.exs", fn file -> + assert file =~ "defmodule Phoenix.UserControllerTest" + end) end) end) end