Repository: phoenixframework/phoenix
Pull request #3604 (2019-11-06 23:47:02)

Fix 404 on "Using MySQL" link
Using the `.html` file extension here led to a 404 when trying to access the "Using MySQL" section of the readme.


Patch:
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 6a0128722..f58ab774f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -207,7 +207,7 @@ of beginning users because expert users have more tools at their disposal to
 help themselves.
 
 The general pattern we use for presenting information is to first introduce a
-small, discreet topic, then write a small amount of code to demonstrate the
+small, discrete topic, then write a small amount of code to demonstrate the
 concept, then verify that the code worked.
 
 In this way, we build from small, easily digestible concepts into more complex
diff --git a/guides/ecto.md b/guides/ecto.md
index bde6f1715..3846e1242 100644
--- a/guides/ecto.md
+++ b/guides/ecto.md
@@ -11,7 +11,7 @@ Newly generated Phoenix projects include Ecto with the PostgreSQL adapter by def
 
 For a thorough, general guide for Ecto, check out the [Ecto getting started guide](https://hexdocs.pm/ecto/getting-started.html). For an overview of all Ecto specific mix tasks for Phoenix, see the [mix tasks guide](phoenix_mix_tasks.html#ecto-specific-mix-tasks).
 
-This guide assumes that we have generated our new application with Ecto integration and that we will be using PostgreSQL. For instructions on switching to MySQL, please see the [Using MySQL](ecto.html#using-mysql) section.
+This guide assumes that we have generated our new application with Ecto integration and that we will be using PostgreSQL. For instructions on switching to MySQL, please see the [Using MySQL](#using-mysql) section.
 
 The default Postgres configuration has a superuser account with username 'postgres' and the password 'postgres'. If you take a look at the file `config/dev.exs`, you'll see that Phoenix works off this assumption. If you don't have this account already setup on your machine, you can connect to your postgres instance by typing `psql` and then entering the following commands:
 
diff --git a/guides/errors.md b/guides/errors.md
index fb5536ec3..a4de46e96 100644
--- a/guides/errors.md
+++ b/guides/errors.md
@@ -72,7 +72,7 @@ defmodule Phoenix.Router do
 end
 ```
 
-Plug provides a protocol called `Plug.Exception` specifically for adding a status to exception structs.
+Plug provides a protocol called `Plug.Exception` where we are able to customize the status and add actions that exception structs can returns on the debug error page.
 
 If we wanted to supply a status of 404 for an `Ecto.NoResultsError`, we could do it by defining an implementation for the `Plug.Exception` protocol like this:
 
@@ -83,3 +83,20 @@ end
 ```
 
 Note that this is just an example: Phoenix [already does this](https://github.com/phoenixframework/phoenix_ecto/blob/master/lib/phoenix_ecto/plug.ex) for `Ecto.NoResultsError`, so you don't have to.
+
+#### Actions
+
+Actions are functions that can be triggered by the error page, it is basically a list of maps defining a `label` and a `handler` to be executed.
+It is rendered in the error page as a collection of buttons and follows the format of: `[%{label: String.t(), handler: {module(), function :: atom(), args :: []}}]`.
+
+If we wanted to return some actions for an `Ecto.NoResultsError` we would implement `Plug.Exception` like this:
+
+```elixir
+defimpl Plug.Exception, for: Ecto.NoResultsError do
+  def status(_exception), do: 404
+  def actions(_exception), do: [%{
+      label: "Run seeds",
+      handler: {Code, :eval_file, "priv/repo/seeds.exs"}
+    }]
+end
+```
\ No newline at end of file
diff --git a/guides/phoenix_mix_tasks.md b/guides/phoenix_mix_tasks.md
index ba4ffc4ee..7d8989592 100644
--- a/guides/phoenix_mix_tasks.md
+++ b/guides/phoenix_mix_tasks.md
@@ -874,7 +874,7 @@ defmodule Mix.Tasks.Hello.Greeting do
   """
 
   def run(_args) do
-    Mix.shell.info("Greetings from the Hello Phoenix Application!")
+    Mix.shell().info("Greetings from the Hello Phoenix Application!")
   end
 
   # We can define other functions as needed here.
@@ -892,7 +892,7 @@ The `@shortdoc` module attribute holds a string which will describe our task whe
 
 `@moduledoc` serves the same function that it does in any module. It's where we can put long-form documentation and doctests, if we have any.
 
-The `run/1` function is the critical heart of any mix task. It's the function that does all the work when users invoke our task. In ours, all we do is send a greeting from our app, but we can implement our `run/1` function to do whatever we need it to. Note that `Mix.shell.info/1` is the preferred way to print text back out to the user.
+The `run/1` function is the critical heart of any mix task. It's the function that does all the work when users invoke our task. In ours, all we do is send a greeting from our app, but we can implement our `run/1` function to do whatever we need it to. Note that `Mix.shell().info/1` is the preferred way to print text back out to the user.
 
 Of course, our task is just a module, so we can define other private functions as needed to support our `run/1` function.
 
@@ -928,7 +928,7 @@ If you want to make your new mix task to use your application's infrastructure,
   . . .
   def run(_args) do
     Mix.Task.run("app.start")
-    Mix.shell.info("Now I have access to Repo and other goodies!")
+    Mix.shell().info("Now I have access to Repo and other goodies!")
   end
   . . .
 ```
diff --git a/installer/lib/mix/tasks/phx.new.ex b/installer/lib/mix/tasks/phx.new.ex
index b46929f22..53f7e7b0a 100644
--- a/installer/lib/mix/tasks/phx.new.ex
+++ b/installer/lib/mix/tasks/phx.new.ex
@@ -98,7 +98,7 @@ defmodule Mix.Tasks.Phx.New do
              gettext: :boolean, umbrella: :boolean, verbose: :boolean]
 
   def run([version]) when version in ~w(-v --version) do
-    Mix.shell.info("Phoenix v#{@version}")
+    Mix.shell().info("Phoenix v#{@version}")
   end
 
   def run(argv) do
@@ -142,7 +142,7 @@ defmodule Mix.Tasks.Phx.New do
 
   defp prompt_to_install_deps(%Project{} = project, generator, path) do
     path = Map.fetch!(project, path)
-    install? = Mix.shell.yes?("\nFetch and install dependencies?")
+    install? = Mix.shell().yes?("\nFetch and install dependencies?")
     cd_step = ["$ cd #{relative_app_path(path)}"]
 
     maybe_cd(path, fn ->
@@ -204,7 +204,7 @@ defmodule Mix.Tasks.Phx.New do
   end
 
   defp print_webpack_info(_project, _gen) do
-    Mix.shell.info """
+    Mix.shell().info """
     Phoenix uses an optional assets build tool called webpack
     that requires node.js and npm. Installation instructions for
     node.js, which includes npm, can be found at http://nodejs.org.
@@ -216,7 +216,7 @@ defmodule Mix.Tasks.Phx.New do
   end
 
   defp print_missing_steps(steps) do
-    Mix.shell.info """
+    Mix.shell().info """
 
     We are almost there! The following steps are missing:
 
@@ -226,7 +226,7 @@ defmodule Mix.Tasks.Phx.New do
 
   defp print_ecto_info(Web), do: :ok
   defp print_ecto_info(_gen) do
-    Mix.shell.info """
+    Mix.shell().info """
     Then configure your database in config/dev.exs and run:
 
         $ mix ecto.create
@@ -234,14 +234,14 @@ defmodule Mix.Tasks.Phx.New do
   end
 
   defp print_mix_info(Ecto) do
-    Mix.shell.info """
+    Mix.shell().info """
     You can run your app inside IEx (Interactive Elixir) as:
 
         $ iex -S mix
     """
   end
   defp print_mix_info(_gen) do
-    Mix.shell.info """
+    Mix.shell().info """
     Start your Phoenix app with:
 
         $ mix phx.server
@@ -273,8 +273,8 @@ defmodule Mix.Tasks.Phx.New do
   end
 
   defp cmd(%Project{} = project, cmd) do
-    Mix.shell.info [:green, "* running ", :reset, cmd]
-    case Mix.shell.cmd(cmd, cmd_opts(project)) do
+    Mix.shell().info [:green, "* running ", :reset, cmd]
+    case Mix.shell().cmd(cmd, cmd_opts(project)) do
       0 ->
         []
       _ ->
@@ -326,7 +326,7 @@ defmodule Mix.Tasks.Phx.New do
   end
 
   defp check_directory_existence!(path) do
-    if File.dir?(path) and not Mix.shell.yes?("The directory #{path} already exists. Are you sure you want to continue?") do
+    if File.dir?(path) and not Mix.shell().yes?("The directory #{path} already exists. Are you sure you want to continue?") do
       Mix.raise "Please select another directory for installation."
     end
   end
diff --git a/installer/templates/phx_single/mix.exs b/installer/templates/phx_single/mix.exs
index 6f539d93f..567f90a4a 100644
--- a/installer/templates/phx_single/mix.exs
+++ b/installer/templates/phx_single/mix.exs
@@ -38,7 +38,7 @@ defmodule <%= app_module %>.MixProject do
   defp deps do
     [
       <%= phoenix_dep %>,<%= if ecto do %>
-      {:phoenix_ecto, "~> 4.0"},
+      {:phoenix_ecto, "~> 4.1"},
       {:ecto_sql, "~> 3.1"},
       {<%= inspect adapter_app %>, ">= 0.0.0"},<% end %><%= if html do %>
       {:phoenix_html, "~> 2.11"},
diff --git a/installer/templates/phx_web/endpoint.ex b/installer/templates/phx_web/endpoint.ex
index 4ebc796ec..8efd62e8c 100644
--- a/installer/templates/phx_web/endpoint.ex
+++ b/installer/templates/phx_web/endpoint.ex
@@ -20,7 +20,8 @@ defmodule <%= endpoint_module %> do
   if code_reloading? do<%= if html do %>
     socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket
     plug Phoenix.LiveReloader<% end %>
-    plug Phoenix.CodeReloader
+    plug Phoenix.CodeReloader<%= if ecto do %>
+    plug Phoenix.Ecto.CheckRepoStatus, otp_app: :<%= web_app_name %><% end %>
   end
 
   plug Plug.RequestId
diff --git a/lib/mix/phoenix.ex b/lib/mix/phoenix.ex
index c65691402..47a9e0a11 100644
--- a/lib/mix/phoenix.ex
+++ b/lib/mix/phoenix.ex
@@ -144,7 +144,7 @@ defmodule Mix.Phoenix do
 
   defp app_base(app) do
     case Application.get_env(app, :namespace, app) do
-      ^app -> app |> to_string |> Phoenix.Naming.camelize()
+      ^app -> app |> to_string() |> Phoenix.Naming.camelize()
       mod  -> mod |> inspect()
     end
   end
@@ -153,16 +153,16 @@ defmodule Mix.Phoenix do
   Returns the OTP app from the Mix project configuration.
   """
   def otp_app do
-    Mix.Project.config |> Keyword.fetch!(:app)
+    Mix.Project.config() |> Keyword.fetch!(:app)
   end
 
   @doc """
   Returns all compiled modules in a project.
   """
   def modules do
-    Mix.Project.compile_path
+    Mix.Project.compile_path()
     |> Path.join("*.beam")
-    |> Path.wildcard
+    |> Path.wildcard()
     |> Enum.map(&beam_to_module/1)
   end
 
@@ -324,14 +324,14 @@ defmodule Mix.Phoenix do
     case Enum.filter(file_paths, &File.exists?(&1)) do
       [] -> :ok
       conflicts ->
-        Mix.shell.info"""
+        Mix.shell().info"""
         The following files conflict with new files to be generated:
 
         #{conflicts |> Enum.map(&"  * #{&1}") |> Enum.join("\n")}
 
         See the --web option to namespace similarly named resources
         """
-        unless Mix.shell.yes?("Proceed with interactive overwrite?") do
+        unless Mix.shell().yes?("Proceed with interactive overwrite?") do
           System.halt()
         end
     end
diff --git a/lib/mix/tasks/phx.digest.clean.ex b/lib/mix/tasks/phx.digest.clean.ex
index 55ac8b09a..5ec2e5d46 100644
--- a/lib/mix/tasks/phx.digest.clean.ex
+++ b/lib/mix/tasks/phx.digest.clean.ex
@@ -49,9 +49,9 @@ defmodule Mix.Tasks.Phx.Digest.Clean do
         # true. In case it's not true, build structure is mostly a no-op, so we
         # are fine.
         Mix.Project.build_structure()
-        Mix.shell.info [:green, "Clean complete for #{inspect output_path}"]
+        Mix.shell().info [:green, "Clean complete for #{inspect output_path}"]
       {:error, :invalid_path} ->
-        Mix.shell.error "The output path #{inspect output_path} does not exist"
+        Mix.shell().error "The output path #{inspect output_path} does not exist"
     end
   end
 end
diff --git a/lib/mix/tasks/phx.digest.ex b/lib/mix/tasks/phx.digest.ex
index c0f8d3062..9b5ae270a 100644
--- a/lib/mix/tasks/phx.digest.ex
+++ b/lib/mix/tasks/phx.digest.ex
@@ -51,9 +51,9 @@ defmodule Mix.Tasks.Phx.Digest do
         # build_embedded set to true. In case it's not true,
         # build structure is mostly a no-op, so we are fine.
         Mix.Project.build_structure()
-        Mix.shell.info [:green, "Check your digested files at #{inspect output_path}"]
+        Mix.shell().info [:green, "Check your digested files at #{inspect output_path}"]
       {:error, :invalid_path} ->
-        Mix.shell.error "The input path #{inspect input_path} does not exist"
+        Mix.shell().error "The input path #{inspect input_path} does not exist"
     end
   end
 end
diff --git a/lib/mix/tasks/phx.ex b/lib/mix/tasks/phx.ex
index 9ddf6a90d..d460df13c 100644
--- a/lib/mix/tasks/phx.ex
+++ b/lib/mix/tasks/phx.ex
@@ -20,10 +20,10 @@ defmodule Mix.Tasks.Phx do
 
   defp general() do
     Application.ensure_all_started(:phoenix)
-    Mix.shell.info "Phoenix v#{Application.spec(:phoenix, :vsn)}"
-    Mix.shell.info "Productive. Reliable. Fast."
-    Mix.shell.info "A productive web framework that does not compromise speed or maintainability."
-    Mix.shell.info "\nAvailable tasks:\n"
+    Mix.shell().info "Phoenix v#{Application.spec(:phoenix, :vsn)}"
+    Mix.shell().info "Productive. Reliable. Fast."
+    Mix.shell().info "A productive web framework that does not compromise speed or maintainability."
+    Mix.shell().info "\nAvailable tasks:\n"
     Mix.Tasks.Help.run(["--search", "phx."])
   end
 end
diff --git a/lib/mix/tasks/phx.gen.channel.ex b/lib/mix/tasks/phx.gen.channel.ex
index 5179f5ab6..420b13774 100644
--- a/lib/mix/tasks/phx.gen.channel.ex
+++ b/lib/mix/tasks/phx.gen.channel.ex
@@ -42,7 +42,7 @@ defmodule Mix.Tasks.Phx.Gen.Channel do
       {:eex, "channel_test.exs", Path.join(test_prefix, "channels/#{binding[:path]}_channel_test.exs")},
     ]
 
-    Mix.shell.info """
+    Mix.shell().info """
 
     Add the channel to your `#{Mix.Phoenix.web_path(context_app, "channels/user_socket.ex")}` handler, for example:
 
diff --git a/lib/mix/tasks/phx.gen.context.ex b/lib/mix/tasks/phx.gen.context.ex
index 4ac4f049e..19aea6c47 100644
--- a/lib/mix/tasks/phx.gen.context.ex
+++ b/lib/mix/tasks/phx.gen.context.ex
@@ -77,7 +77,7 @@ defmodule Mix.Tasks.Phx.Gen.Context do
 
   @doc false
   def run(args) do
-    if Mix.Project.umbrella? do
+    if Mix.Project.umbrella?() do
       Mix.raise "mix phx.gen.context can only be run inside an application directory"
     end
 
@@ -171,7 +171,7 @@ defmodule Mix.Tasks.Phx.Gen.Context do
     if String.contains?(file, content_to_inject) do
       :ok
     else
-      Mix.shell.info([:green, "* injecting ", :reset, Path.relative_to_cwd(file_path)])
+      Mix.shell().info([:green, "* injecting ", :reset, Path.relative_to_cwd(file_path)])
 
       file
       |> String.trim_trailing()
@@ -247,7 +247,7 @@ defmodule Mix.Tasks.Phx.Gen.Context do
       function_count = Context.function_count(context)
       file_count = Context.file_count(context)
 
-      Mix.shell.info """
+      Mix.shell().info """
       You are generating into an existing context.
 
       The #{inspect context.module} context currently has #{function_count} functions and \
@@ -264,7 +264,7 @@ defmodule Mix.Tasks.Phx.Gen.Context do
 
       If you are not sure, prefer creating a new context over adding to the existing one.
       """
-      unless Mix.shell.yes?("Would you like to proceed?") do
+      unless Mix.shell().yes?("Would you like to proceed?") do
         System.halt()
       end
     end
diff --git a/lib/mix/tasks/phx.gen.html.ex b/lib/mix/tasks/phx.gen.html.ex
index 826b8585b..40405f842 100644
--- a/lib/mix/tasks/phx.gen.html.ex
+++ b/lib/mix/tasks/phx.gen.html.ex
@@ -102,7 +102,7 @@ defmodule Mix.Tasks.Phx.Gen.Html do
 
   @doc false
   def run(args) do
-    if Mix.Project.umbrella? do
+    if Mix.Project.umbrella?() do
       Mix.raise "mix phx.gen.html can only be run inside an application directory"
     end
 
@@ -161,7 +161,7 @@ defmodule Mix.Tasks.Phx.Gen.Html do
   @doc false
   def print_shell_instructions(%Context{schema: schema, context_app: ctx_app} = context) do
     if schema.web_namespace do
-      Mix.shell.info """
+      Mix.shell().info """
 
       Add the resource to your #{schema.web_namespace} :browser scope in #{Mix.Phoenix.web_path(ctx_app)}/router.ex:
 
@@ -172,7 +172,7 @@ defmodule Mix.Tasks.Phx.Gen.Html do
           end
       """
     else
-      Mix.shell.info """
+      Mix.shell().info """
 
       Add the resource to your browser scope in #{Mix.Phoenix.web_path(ctx_app)}/router.ex:
 
diff --git a/lib/mix/tasks/phx.gen.json.ex b/lib/mix/tasks/phx.gen.json.ex
index b42e9606b..f6b28da2e 100644
--- a/lib/mix/tasks/phx.gen.json.ex
+++ b/lib/mix/tasks/phx.gen.json.ex
@@ -102,7 +102,7 @@ defmodule Mix.Tasks.Phx.Gen.Json do
 
   @doc false
   def run(args) do
-    if Mix.Project.umbrella? do
+    if Mix.Project.umbrella?() do
       Mix.raise "mix phx.gen.json can only be run inside an application directory"
     end
 
@@ -159,7 +159,7 @@ defmodule Mix.Tasks.Phx.Gen.Json do
   @doc false
   def print_shell_instructions(%Context{schema: schema, context_app: ctx_app} = context) do
     if schema.web_namespace do
-      Mix.shell.info """
+      Mix.shell().info """
 
       Add the resource to your #{schema.web_namespace} :api scope in #{Mix.Phoenix.web_path(ctx_app)}/router.ex:
 
@@ -170,7 +170,7 @@ defmodule Mix.Tasks.Phx.Gen.Json do
           end
       """
     else
-      Mix.shell.info """
+      Mix.shell().info """
 
       Add the resource to your :api scope in #{Mix.Phoenix.web_path(ctx_app)}/router.ex:
 
diff --git a/lib/mix/tasks/phx.gen.presence.ex b/lib/mix/tasks/phx.gen.presence.ex
index d392c18da..e36389ced 100644
--- a/lib/mix/tasks/phx.gen.presence.ex
+++ b/lib/mix/tasks/phx.gen.presence.ex
@@ -41,7 +41,7 @@ defmodule Mix.Tasks.Phx.Gen.Presence do
 
     Mix.Phoenix.copy_from paths(), "priv/templates/phx.gen.presence", binding, files
 
-    Mix.shell.info """
+    Mix.shell().info """
 
     Add your new module to your supervision tree,
     in lib/#{otp_app}/application.ex:
diff --git a/lib/mix/tasks/phx.gen.schema.ex b/lib/mix/tasks/phx.gen.schema.ex
index ec422e594..fc87d5761 100644
--- a/lib/mix/tasks/phx.gen.schema.ex
+++ b/lib/mix/tasks/phx.gen.schema.ex
@@ -162,7 +162,7 @@ defmodule Mix.Tasks.Phx.Gen.Schema do
   @doc false
   def print_shell_instructions(%Schema{} = schema) do
     if schema.migration? do
-      Mix.shell.info """
+      Mix.shell().info """
 
       Remember to update your repository by running migrations:
 
diff --git a/lib/mix/tasks/phx.gen.secret.ex b/lib/mix/tasks/phx.gen.secret.ex
index aa43f0f25..2bbe426d3 100644
--- a/lib/mix/tasks/phx.gen.secret.ex
+++ b/lib/mix/tasks/phx.gen.secret.ex
@@ -14,7 +14,7 @@ defmodule Mix.Tasks.Phx.Gen.Secret do
 
   @doc false
   def run([]),    do: run(["64"])
-  def run([int]), do: int |> parse!() |> random_string() |> Mix.shell.info()
+  def run([int]), do: int |> parse!() |> random_string() |> Mix.shell().info()
   def run([_|_]), do: invalid_args!()
 
   defp parse!(int) do
diff --git a/lib/mix/tasks/phx.routes.ex b/lib/mix/tasks/phx.routes.ex
index d08ce007f..862522b36 100644
--- a/lib/mix/tasks/phx.routes.ex
+++ b/lib/mix/tasks/phx.routes.ex
@@ -38,7 +38,7 @@ defmodule Mix.Tasks.Phx.Routes do
 
     router_mod
     |> ConsoleFormatter.format(endpoint(opts[:endpoint], base))
-    |> Mix.shell.info()
+    |> Mix.shell().info()
   end
 
   defp endpoint(nil, base) do
diff --git a/lib/mix/tasks/phx.server.ex b/lib/mix/tasks/phx.server.ex
index 426f5291f..6db1b3ba5 100644
--- a/lib/mix/tasks/phx.server.ex
+++ b/lib/mix/tasks/phx.server.ex
@@ -40,6 +40,6 @@ defmodule Mix.Tasks.Phx.Server do
   end
 
   defp iex_running? do
-    Code.ensure_loaded?(IEx) and IEx.started?
+    Code.ensure_loaded?(IEx) and IEx.started?()
   end
 end
diff --git a/lib/phoenix/channel.ex b/lib/phoenix/channel.ex
index a30d5c572..bb9df984e 100644
--- a/lib/phoenix/channel.ex
+++ b/lib/phoenix/channel.ex
@@ -198,7 +198,7 @@ defmodule Phoenix.Channel do
   ## Subscribing to external topics
 
   Sometimes you may need to programmatically subscribe a socket to external
-  topics in addition to the the internal `socket.topic`. For example,
+  topics in addition to the internal `socket.topic`. For example,
   imagine you have a bidding system where a remote client dynamically sets
   preferences on products they want to receive bidding notifications on.
   Instead of requiring a unique channel process and topic per
diff --git a/lib/phoenix/code_reloader/proxy.ex b/lib/phoenix/code_reloader/proxy.ex
index 764eb519e..fc203606f 100644
--- a/lib/phoenix/code_reloader/proxy.ex
+++ b/lib/phoenix/code_reloader/proxy.ex
@@ -37,7 +37,7 @@ defmodule Phoenix.CodeReloader.Proxy do
         put_chars(from, reply, apply(m, f, as), output)
 
       {:io_request, _from, _reply, _request} = msg ->
-        send(Process.group_leader, msg)
+        send(Process.group_leader(), msg)
         {:noreply, output}
 
       _ ->
@@ -46,7 +46,7 @@ defmodule Phoenix.CodeReloader.Proxy do
   end
 
   defp put_chars(from, reply, chars, output) do
-    send(Process.group_leader, {:io_request, from, reply, {:put_chars, chars}})
+    send(Process.group_leader(), {:io_request, from, reply, {:put_chars, chars}})
     {:noreply, output <> IO.chardata_to_string(chars)}
   end
 end
diff --git a/lib/phoenix/code_reloader/server.ex b/lib/phoenix/code_reloader/server.ex
index fc87baa2e..cb72bc061 100644
--- a/lib/phoenix/code_reloader/server.ex
+++ b/lib/phoenix/code_reloader/server.ex
@@ -40,8 +40,8 @@ defmodule Phoenix.CodeReloader.Server do
   end
 
   def handle_call(:check_symlinks, _from, checked?) do
-    if not checked? and Code.ensure_loaded?(Mix.Project) and not Mix.Project.umbrella? do
-      priv_path = "#{Mix.Project.app_path}/priv"
+    if not checked? and Code.ensure_loaded?(Mix.Project) and not Mix.Project.umbrella?() do
+      priv_path = "#{Mix.Project.app_path()}/priv"
 
       case :file.read_link(priv_path) do
         {:ok, _} ->
@@ -50,10 +50,12 @@ defmodule Phoenix.CodeReloader.Server do
         {:error, _} ->
           if can_symlink?() do
             File.rm_rf(priv_path)
-            Mix.Project.build_structure
+            Mix.Project.build_structure()
           else
-            Logger.warn "Phoenix is unable to create symlinks. Phoenix' code reloader will run " <>
-                        "considerably faster if symlinks are allowed." <> os_symlink(:os.type)
+            Logger.warn(
+              "Phoenix is unable to create symlinks. Phoenix' code reloader will run " <>
+                "considerably faster if symlinks are allowed." <> os_symlink(:os.type())
+            )
           end
       end
     end
@@ -65,7 +67,7 @@ defmodule Phoenix.CodeReloader.Server do
     compilers = endpoint.config(:reloadable_compilers)
     reloadable_apps = endpoint.config(:reloadable_apps) || default_reloadable_apps()
     backup = load_backup(endpoint)
-    froms  = all_waiting([from], endpoint)
+    froms = all_waiting([from], endpoint)
 
     {res, out} =
       proxy_io(fn ->
@@ -74,8 +76,9 @@ defmodule Phoenix.CodeReloader.Server do
         catch
           :exit, {:shutdown, 1} ->
             :error
+
           kind, reason ->
-            IO.puts Exception.format(kind, reason, System.stacktrace)
+            IO.puts(Exception.format(kind, reason, System.stacktrace()))
             :error
         end
       end)
@@ -84,6 +87,7 @@ defmodule Phoenix.CodeReloader.Server do
       case res do
         :ok ->
           :ok
+
         :error ->
           write_backup(backup)
           {:error, out}
@@ -103,17 +107,19 @@ defmodule Phoenix.CodeReloader.Server do
   end
 
   defp default_reloadable_apps() do
-    if Mix.Project.umbrella? do
-      Enum.map(Mix.Dep.Umbrella.cached, &(&1.app))
+    if Mix.Project.umbrella?() do
+      Enum.map(Mix.Dep.Umbrella.cached(), & &1.app)
     else
       [Mix.Project.config()[:app]]
     end
   end
 
   defp os_symlink({:win32, _}),
-    do: " On Windows, the lack of symlinks may even cause empty assets to be served. " <>
+    do:
+      " On Windows, the lack of symlinks may even cause empty assets to be served. " <>
         "Luckily, you can address this issue by starting your Windows terminal at least " <>
         "once with \"Run as Administrator\" and then running your Phoenix application."
+
   defp os_symlink(_),
     do: ""
 
@@ -140,12 +146,14 @@ defmodule Phoenix.CodeReloader.Server do
     |> :code.which()
     |> read_backup()
   end
+
   defp read_backup(path) when is_list(path) do
     case File.read(path) do
       {:ok, binary} -> {:ok, path, binary}
       _ -> :error
     end
   end
+
   defp read_backup(_path), do: :error
 
   defp write_backup({:ok, path, file}), do: File.write!(path, file)
@@ -160,27 +168,29 @@ defmodule Phoenix.CodeReloader.Server do
   end
 
   defp mix_compile({:module, Mix.Task}, compilers, apps_to_reload) do
-    mix_compile_deps(Mix.Dep.cached, apps_to_reload, compilers)
+    mix_compile_deps(Mix.Dep.cached(), apps_to_reload, compilers)
     mix_compile_project(Mix.Project.config()[:app], apps_to_reload, compilers)
   end
+
   defp mix_compile({:error, _reason}, _, _) do
     raise "the Code Reloader is enabled but Mix is not available. If you want to " <>
-          "use the Code Reloader in production or inside an escript, you must add " <>
-          ":mix to your applications list. Otherwise, you must disable code reloading " <>
-          "in such environments"
+            "use the Code Reloader in production or inside an escript, you must add " <>
+            ":mix to your applications list. Otherwise, you must disable code reloading " <>
+            "in such environments"
   end
 
   defp mix_compile_deps(deps, apps_to_reload, compilers) do
     for dep <- deps, dep.app in apps_to_reload do
-      Mix.Dep.in_dependency dep, fn _ ->
+      Mix.Dep.in_dependency(dep, fn _ ->
         mix_compile_unless_stale_config(compilers)
-      end
+      end)
     end
 
     :ok
   end
 
   defp mix_compile_project(nil, _, _), do: :ok
+
   defp mix_compile_project(app, apps_to_reload, compilers) do
     if app in apps_to_reload do
       mix_compile_unless_stale_config(compilers)
@@ -190,8 +200,8 @@ defmodule Phoenix.CodeReloader.Server do
   end
 
   defp mix_compile_unless_stale_config(compilers) do
-    manifests = Mix.Tasks.Compile.Elixir.manifests
-    configs   = Mix.Project.config_files
+    manifests = Mix.Tasks.Compile.Elixir.manifests()
+    configs = Mix.Project.config_files()
 
     case Mix.Utils.extract_stale(configs, manifests) do
       [] ->
@@ -199,18 +209,18 @@ defmodule Phoenix.CodeReloader.Server do
 
       files ->
         raise """
-        could not compile application: #{Mix.Project.config[:app]}.
+        could not compile application: #{Mix.Project.config()[:app]}.
 
         You must restart your server after changing the following config or lib files:
 
           * #{Enum.map_join(files, "\n  * ", &Path.relative_to_cwd/1)}
 
         """
-     end
-   end
+    end
+  end
 
   defp mix_compile(compilers) do
-    all = Mix.Project.config[:compilers] || Mix.compilers
+    all = Mix.Project.config()[:compilers] || Mix.compilers()
 
     compilers =
       for compiler <- compilers, compiler in all do
@@ -220,7 +230,7 @@ defmodule Phoenix.CodeReloader.Server do
 
     # We call build_structure mostly for Windows so new
     # assets in priv are copied to the build directory.
-    Mix.Project.build_structure
+    Mix.Project.build_structure()
     results = Enum.map(compilers, &Mix.Task.run("compile.#{&1}", []))
 
     # Results are either {:ok, _} | {:error, _}, {:noop, _} or
@@ -240,11 +250,11 @@ defmodule Phoenix.CodeReloader.Server do
   end
 
   defp consolidate_protocols? do
-    Mix.Project.config[:consolidate_protocols]
+    Mix.Project.config()[:consolidate_protocols]
   end
 
   defp proxy_io(fun) do
-    original_gl = Process.group_leader
+    original_gl = Process.group_leader()
     {:ok, proxy_gl} = Proxy.start()
     Process.group_leader(self(), proxy_gl)
 
diff --git a/lib/phoenix/endpoint.ex b/lib/phoenix/endpoint.ex
index a0e212866..81ebff427 100644
--- a/lib/phoenix/endpoint.ex
+++ b/lib/phoenix/endpoint.ex
@@ -139,7 +139,7 @@ defmodule Phoenix.Endpoint do
       will be referenced from `System.get_env("HOST")` at runtime.
 
       The `:scheme` option accepts `"http"` and `"https"` values. Default value
-      is infered from top level `:http` or `:https` option. It is useful
+      is inferred from top level `:http` or `:https` option. It is useful
       when hosting Phoenix behind a load balancer or reverse proxy and
       terminating SSL there.
 
@@ -183,7 +183,7 @@ defmodule Phoenix.Endpoint do
           ]
 
     * `:pubsub_server` - the name of the pubsub server to use in channels
-      and via the Endpoint broadcast funtions. The PubSub server is typically
+      and via the Endpoint broadcast functions. The PubSub server is typically
       started in your supervision tree.
 
   ### Adapter configuration
diff --git a/lib/phoenix/endpoint/cowboy2_handler.ex b/lib/phoenix/endpoint/cowboy2_handler.ex
index 50fcadcf0..c478c75c4 100644
--- a/lib/phoenix/endpoint/cowboy2_handler.ex
+++ b/lib/phoenix/endpoint/cowboy2_handler.ex
@@ -46,7 +46,7 @@ defmodule Phoenix.Endpoint.Cowboy2Handler do
     end
   catch
     :error, value ->
-      case System.stacktrace do
+      case System.stacktrace() do
         # Maybe the handler is not available because the code is being recompiled.
         # Sync with the code reloader and retry once.
         [{^endpoint, :__handler__, _, _} | _] when value == :undef and retry? ->
diff --git a/lib/phoenix/exceptions.ex b/lib/phoenix/exceptions.ex
index 52c7ed150..a3c6b13e6 100644
--- a/lib/phoenix/exceptions.ex
+++ b/lib/phoenix/exceptions.ex
@@ -66,4 +66,5 @@ end
 
 defimpl Plug.Exception, for: Phoenix.ActionClauseError do
   def status(_), do: 400
+  def actions(_), do: []
 end
diff --git a/lib/phoenix/socket.ex b/lib/phoenix/socket.ex
index b7e1d166d..8c219cbeb 100644
--- a/lib/phoenix/socket.ex
+++ b/lib/phoenix/socket.ex
@@ -77,7 +77,7 @@ defmodule Phoenix.Socket do
 
     * `:partitions` - each channel is spawned under a supervisor.
       This option controls how many supervisors will be spawned
-      to handlle channels. Defaults to the number of cores.
+      to handle channels. Defaults to the number of cores.
 
   ## Garbage collection
 
diff --git a/mix.exs b/mix.exs
index 9a01e7995..21ec926c9 100644
--- a/mix.exs
+++ b/mix.exs
@@ -12,7 +12,7 @@ defmodule Phoenix.MixProject do
       package: package(),
       lockfile: lockfile(),
       preferred_cli_env: [docs: :docs],
-      consolidate_protocols: Mix.env != :test,
+      consolidate_protocols: Mix.env() != :test,
       xref: [
         exclude: [
           Ecto.Type,
@@ -23,7 +23,7 @@ defmodule Phoenix.MixProject do
           Plug.Cowboy
         ]
       ],
-      elixirc_paths: elixirc_paths(Mix.env),
+      elixirc_paths: elixirc_paths(Mix.env()),
       name: "Phoenix",
       docs: docs(),
       aliases: aliases(),


Test patch:
diff --git a/installer/test/phx_new_test.exs b/installer/test/phx_new_test.exs
index fc126583a..feab93a83 100644
--- a/installer/test/phx_new_test.exs
+++ b/installer/test/phx_new_test.exs
@@ -133,6 +133,7 @@ defmodule Mix.Tasks.Phx.NewTest do
       assert_file "phx_blog/test/support/data_case.ex", ~r"defmodule PhxBlog.DataCase"
       assert_file "phx_blog/lib/phx_blog_web.ex", ~r"defmodule PhxBlogWeb"
       assert_file "phx_blog/priv/repo/migrations/.formatter.exs", ~r"import_deps: \[:ecto_sql\]"
+      assert_file "phx_blog/lib/phx_blog_web/endpoint.ex", ~r"plug Phoenix.Ecto.CheckRepoStatus, otp_app: :phx_blog"
 
       # Install dependencies?
       assert_received {:mix_shell, :yes?, ["\nFetch and install dependencies?"]}
@@ -178,6 +179,9 @@ defmodule Mix.Tasks.Phx.NewTest do
       # No Ecto
       config = ~r/config :phx_blog, PhxBlog.Repo,/
       refute File.exists?("phx_blog/lib/phx_blog/repo.ex")
+      assert_file "phx_blog/lib/phx_blog_web/endpoint.ex", fn file ->
+        refute file =~ "plug Phoenix.Ecto.CheckRepoStatus, otp_app: :phx_blog"
+      end
 
       # No gettext
       refute_file "phx_blog/lib/phx_blog_web/gettext.ex"
diff --git a/lib/phoenix/test/conn_test.ex b/lib/phoenix/test/conn_test.ex
index 54e4b0e1c..783921378 100644
--- a/lib/phoenix/test/conn_test.ex
+++ b/lib/phoenix/test/conn_test.ex
@@ -369,7 +369,7 @@ defmodule Phoenix.ConnTest do
   end
 
   @doc """
-  Asserts the given status code, that we have an text response and
+  Asserts the given status code, that we have a text response and
   returns the response body if one was set or sent.
 
   ## Examples
@@ -384,7 +384,7 @@ defmodule Phoenix.ConnTest do
   end
 
   @doc """
-  Asserts the given status code, that we have an json response and
+  Asserts the given status code, that we have a json response and
   returns the decoded JSON response if one was set or sent.
 
   ## Examples
@@ -542,7 +542,7 @@ defmodule Phoenix.ConnTest do
   end
 
   @doc """
-  Calls the Endpoint and and the given Router pipelines.
+  Calls the Endpoint and the given Router pipelines.
 
   See `bypass_through/1`.
   """
diff --git a/test/mix/tasks/phx.new_test.exs b/test/mix/tasks/phx.new_test.exs
index 68e6aadd8..ca8b26999 100644
--- a/test/mix/tasks/phx.new_test.exs
+++ b/test/mix/tasks/phx.new_test.exs
@@ -52,7 +52,7 @@ defmodule Mix.Tasks.Phx.NewTest do
           Mix.Task.run "compile", ["--no-deps-check"]
           assert_received {:mix_shell, :info, ["Generated phx_blog app"]}
           refute_received {:mix_shell, :info, ["Generated phoenix app"]}
-          Mix.shell.flush()
+          Mix.shell().flush()
 
           # Adding a new template touches file (through mix)
           File.touch! "lib/phx_blog_web/views/layout_view.ex", @epoch
diff --git a/test/phoenix/view_test.exs b/test/phoenix/view_test.exs
index 51bf7a7fa..cd52ca03b 100644
--- a/test/phoenix/view_test.exs
+++ b/test/phoenix/view_test.exs
@@ -29,7 +29,7 @@ defmodule Phoenix.ViewTest do
     catch
       _, _ ->
         info = [file: 'test/fixtures/templates/show.html.eex', line: 1]
-        assert {MyApp.View, :"show.html", 1, info} in System.stacktrace
+        assert {MyApp.View, :"show.html", 1, info} in System.stacktrace()
     else
       _ ->
         flunk "expected rendering to raise"