Repository: phoenixframework/phoenix (elixir)

Issue:
Support --context-app option for phx.gen.schema
To be consistent with _phx.gen.html_ options, please support _--context-app_ option as well as _context module_ parameter for _phx.gen.schema_ generator(and other applicable generators too?).

Thank you.


Pull request description:
Add support for context_app with schema generator
Adds context_app support for generating schema files based on `:context_app` in the config and `--context_app` in the CLI.

Fixes #2699

Patch:
diff --git a/lib/mix/phoenix.ex b/lib/mix/phoenix.ex
index 3e73a1356..d804046c2 100644
--- a/lib/mix/phoenix.ex
+++ b/lib/mix/phoenix.ex
@@ -276,6 +276,9 @@ defmodule Mix.Phoenix do
         via cli option:
 
             mix phx.gen.[task] --context-app some_app
+
+        Note: cli option only works when `context_app` is not set to `false`
+        in the config.
         """
       {app, _path} ->
         {:ok, app}
diff --git a/lib/mix/tasks/phx.gen.schema.ex b/lib/mix/tasks/phx.gen.schema.ex
index fd5168035..e572e1436 100644
--- a/lib/mix/tasks/phx.gen.schema.ex
+++ b/lib/mix/tasks/phx.gen.schema.ex
@@ -16,6 +16,17 @@ defmodule Mix.Tasks.Phx.Gen.Schema do
 
   The generated migration can be skipped with `--no-migration`.
 
+  ## Contexts
+
+  Your schemas can be generated and added to a separate OTP app. Make sure your configuration is
+  properly setup or manually specify the context app with the `--context-app` option with the CLI.
+
+      # Via config
+      config :marketing_web, :generators, context_app: :marketing
+
+      # Via CLI
+      mix phx.gen.schema Blog.Post blog_posts title:string views:integer --context-app marketing
+
   ## Attributes
 
   The resource fields are given using `name:type` syntax
@@ -82,7 +93,7 @@ defmodule Mix.Tasks.Phx.Gen.Schema do
   alias Mix.Phoenix.Schema
 
   @switches [migration: :boolean, binary_id: :boolean, table: :string,
-             web: :string]
+             web: :string, context_app: :string]
 
   @doc false
   def run(args) do
@@ -110,12 +121,22 @@ defmodule Mix.Tasks.Phx.Gen.Schema do
   def build(args, parent_opts, help \\ __MODULE__) do
     {schema_opts, parsed, _} = OptionParser.parse(args, switches: @switches)
     [schema_name, plural | attrs] = validate_args!(parsed, help)
-    opts = Keyword.merge(parent_opts, schema_opts)
+
+    opts =
+      parent_opts
+      |> Keyword.merge(schema_opts)
+      |> put_context_app(schema_opts[:context_app])
+
     schema = Schema.new(schema_name, plural, attrs, opts)
 
     schema
   end
 
+  defp put_context_app(opts, nil), do: opts
+  defp put_context_app(opts, string) do
+    Keyword.put(opts, :context_app, String.to_atom(string))
+  end
+
   @doc false
   def files_to_be_generated(%Schema{} = schema) do
     [{:eex, "schema.ex", schema.file}]


Test patch:
diff --git a/test/mix/tasks/phx.gen.schema_test.exs b/test/mix/tasks/phx.gen.schema_test.exs
index b67ff3359..a2da949f3 100644
--- a/test/mix/tasks/phx.gen.schema_test.exs
+++ b/test/mix/tasks/phx.gen.schema_test.exs
@@ -268,4 +268,38 @@ defmodule Mix.Tasks.Phx.Gen.SchemaTest do
       end
     end
   end
+
+  describe "inside umbrella" do
+    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.Schema.run(~w(Blog.Post blog_posts title:string))
+        end
+      end
+    end
+
+    test "with context_app set to nil", config do
+      in_tmp_umbrella_project config.test, fn ->
+        Application.put_env(:phoenix, :generators, context_app: nil)
+
+        Gen.Schema.run(~w(Blog.Post blog_posts title:string))
+
+        assert_file "lib/phoenix/blog/post.ex"
+        assert [_] = Path.wildcard("priv/repo/migrations/*_create_blog_posts.exs")
+      end
+    end
+
+    test "with context_app", config do
+      in_tmp_umbrella_project config.test, fn ->
+        Application.put_env(:phoenix, :generators, context_app: {:another_app, "another_app"})
+
+        Gen.Schema.run(~w(Blog.Post blog_posts title:string))
+
+        assert_file "another_app/lib/another_app/blog/post.ex"
+        assert [_] = Path.wildcard("another_app/priv/repo/migrations/*_create_blog_posts.exs")
+      end
+    end
+  end
 end