Skip to content

Commit

Permalink
Fix bug in doc Mix task and add tests for it
Browse files Browse the repository at this point in the history
  • Loading branch information
eksperimental committed Feb 13, 2024
1 parent 8470c85 commit f6e4c9e
Show file tree
Hide file tree
Showing 9 changed files with 578 additions and 415 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ ex_doc-*.tar

node_modules/
/test/fixtures/umbrella/_build/
/test/fixtures/single/_build/
/test/fixtures/single/doc/
/test/tmp/
/tmp/
/npm-debug.log
Expand Down
40 changes: 28 additions & 12 deletions lib/ex_doc/cli.ex
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,32 @@ defmodule ExDoc.CLI do
]
)

cond do
List.keymember?(opts, :version, 0) ->
IO.puts("ExDoc v#{ExDoc.version()}")
if List.keymember?(opts, :version, 0) do
IO.puts("ExDoc v#{ExDoc.version()}")
else
results = generate(args, opts, generator)
error_results = Enum.filter(results, &(elem(&1, 0) == :error))

opts[:warnings_as_errors] == true and ExDoc.Utils.warned?() ->
IO.puts(
:stderr,
"Doc generation failed due to warnings while using the --warnings-as-errors option"
)
if error_results == [] do
results
else
formatters = Enum.map(error_results, &elem(&1, 1).formatter)

exit({:shutdown, 1})
format_message =
case formatters do
[formatter] -> "#{formatter} format"
_ -> "#{Enum.join(formatters, ", ")} formats"
end

message =
"Documents have been generated, but generation for #{format_message} failed due to warnings while using the --warnings-as-errors option."

message_formatted = IO.ANSI.format([:red, message, :reset])

IO.puts(:stderr, message_formatted)

true ->
generate(args, opts, generator)
exit({:shutdown, 1})
end
end
end

Expand Down Expand Up @@ -82,7 +94,11 @@ defmodule ExDoc.CLI do
quiet? ||
IO.puts(IO.ANSI.format([:green, "View #{inspect(formatter)} docs at #{inspect(index)}"]))

index
if opts[:warnings_as_errors] == true and ExDoc.Utils.warned?() do
{:error, %{reason: :warnings_as_errors, formatter: formatter}}
else
{:ok, index}
end
end
end

Expand Down
54 changes: 40 additions & 14 deletions lib/mix/tasks/docs.ex
Original file line number Diff line number Diff line change
Expand Up @@ -400,26 +400,52 @@ defmodule Mix.Tasks.Docs do
|> normalize_formatters()
|> put_package(config)

Code.prepend_path(options[:source_beam])

for path <- Keyword.get_values(options, :paths),
path <- Path.wildcard(path) do
Code.prepend_path(path)
end

Mix.shell().info("Generating docs...")

for formatter <- options[:formatters] do
index = generator.(project, version, Keyword.put(options, :formatter, formatter))
Mix.shell().info([:green, "View #{inspect(formatter)} docs at #{inspect(index)}"])
results =
for formatter <- options[:formatters] do
index = generator.(project, version, Keyword.put(options, :formatter, formatter))
Mix.shell().info([:green, "View #{inspect(formatter)} docs at #{inspect(index)}"])

if cli_opts[:open] do
browser_open(index)
end

if cli_opts[:open] do
browser_open(index)
if options[:warnings_as_errors] == true and ExDoc.Utils.warned?() do
{:error, %{reason: :warnings_as_errors, formatter: formatter}}
else
{:ok, index}
end
end

if options[:warnings_as_errors] == true and ExDoc.Utils.warned?() do
Mix.shell().info([
:red,
"Doc generation failed due to warnings while using the --warnings-as-errors option"
])
error_results = Enum.filter(results, &(elem(&1, 0) == :error))

exit({:shutdown, 1})
else
index
end
if error_results == [] do
results
else
formatters = Enum.map(error_results, &elem(&1, 1).formatter)

format_message =
case formatters do
[formatter] -> "#{formatter} format"
_ -> "#{Enum.join(formatters, ", ")} formats"
end

message =
"Documents have been generated, but generation for #{format_message} failed due to warnings while using the --warnings-as-errors option."

message_formatted = IO.ANSI.format([:red, message, :reset])

IO.puts(:stderr, message_formatted)

exit({:shutdown, 1})
end
end

Expand Down
167 changes: 83 additions & 84 deletions test/ex_doc/cli_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ defmodule ExDoc.CLITest do

@ebin "_build/test/lib/ex_doc/ebin"

defp run(args) do
defp run(args, generator \\ &{&1, &2, &3}, io_device \\ :stdio) do
# TODO: Use with_io on Elixir v1.13
io =
capture_io(fn ->
send(self(), ExDoc.CLI.main(args, &{&1, &2, &3}))
capture_io(io_device, fn ->
send(self(), ExDoc.CLI.main(args, generator))
end)

assert_receive response
Expand All @@ -20,115 +20,113 @@ defmodule ExDoc.CLITest do
{[html, epub], _io} = run(["ExDoc", "1.2.3", @ebin])

assert html ==
{"ExDoc", "1.2.3",
[
formatter: "html",
formatters: ["html", "epub"],
apps: [:ex_doc],
source_beam: @ebin
]}
{:ok,
{"ExDoc", "1.2.3",
[
formatter: "html",
formatters: ["html", "epub"],
apps: [:ex_doc],
source_beam: @ebin
]}}

assert epub ==
{"ExDoc", "1.2.3",
[
formatter: "epub",
formatters: ["html", "epub"],
apps: [:ex_doc],
source_beam: @ebin
]}
{:ok,
{"ExDoc", "1.2.3",
[
formatter: "epub",
formatters: ["html", "epub"],
apps: [:ex_doc],
source_beam: @ebin
]}}
end

test "formatter option" do
{[epub, html], _io} = run(["ExDoc", "1.2.3", @ebin, "-f", "epub", "-f", "html"])

assert epub ==
{"ExDoc", "1.2.3",
[
formatter: "epub",
formatters: ["epub", "html"],
apps: [:ex_doc],
source_beam: @ebin
]}
{:ok,
{"ExDoc", "1.2.3",
[
formatter: "epub",
formatters: ["epub", "html"],
apps: [:ex_doc],
source_beam: @ebin
]}}

assert html ==
{"ExDoc", "1.2.3",
[
formatter: "html",
formatters: ["epub", "html"],
apps: [:ex_doc],
source_beam: @ebin
]}
{:ok,
{"ExDoc", "1.2.3",
[
formatter: "html",
formatters: ["epub", "html"],
apps: [:ex_doc],
source_beam: @ebin
]}}
end

test "version" do
{_, io} = run(["--version"])
assert io == "ExDoc v#{ExDoc.version()}\n"
assert io =~ "ExDoc v#{ExDoc.version()}\n"

{_, io} = run(["--version"])
assert io == "ExDoc v#{ExDoc.version()}\n"
assert io =~ "ExDoc v#{ExDoc.version()}\n"
end

describe "--warnings-as-errors" do
@describetag :warnings

test "exits with code 0 when no warnings" do
test "exits with 0 when there are warnings and --warnings-as-errors flag is not set" do
ExDoc.Utils.unset_warned()

{[html, epub], _io} = run(["ExDoc", "1.2.3", @ebin, "--warnings-as-errors"])

assert html ==
{"ExDoc", "1.2.3",
[
formatter: "html",
formatters: ["html", "epub"],
apps: [:ex_doc],
source_beam: @ebin,
warnings_as_errors: true
]}

assert epub ==
{"ExDoc", "1.2.3",
[
formatter: "epub",
formatters: ["html", "epub"],
apps: [:ex_doc],
source_beam: @ebin,
warnings_as_errors: true
]}
end
Mix.Project.in_project(:single, "test/fixtures/single", fn _mod ->
source_beam = "_build/test/lib/single/ebin"

test "exits with 1 when there is a warning" do
ExDoc.Utils.set_warned()
fun = fn ->
run(
["Single", "1.2.3", source_beam, "--formatter=html"],
&ExDoc.generate_docs/3,
:stderr
)
end

fun = fn ->
run(["ExDoc", "1.2.3", @ebin, "--warnings-as-errors"])
end
{[_html], io} = fun.()

io =
capture_io(:stderr, fn ->
assert catch_exit(fun.()) == {:shutdown, 1}
end)
assert io =~
~s|documentation references function \"Single.bar/0\" but it is undefined or private|

assert io =~
"Doc generation failed due to warnings while using the --warnings-as-errors option\n"
# TODO: remove check when we require Elixir v1.16
if Version.match?(System.version(), ">= 1.16.0-rc") do
assert io =~ ~S|moduledoc `Single.bar/0`|
assert io =~ ~S|doc `Single.bar/0`|
end
end)
end

test "exits with 1 when there are multiple warnings" do
ExDoc.Utils.set_warned()
ExDoc.Utils.set_warned()
ExDoc.Utils.set_warned()
test "exits with 1 when there are warnings with --warnings-as-errors flag" do
ExDoc.Utils.unset_warned()

fun = fn ->
run(["ExDoc", "1.2.3", @ebin, "--warnings-as-errors"])
end
Mix.Project.in_project(:single, "test/fixtures/single", fn _mod ->
source_beam = "_build/test/lib/single/ebin"

io =
capture_io(:stderr, fn ->
assert catch_exit(fun.()) == {:shutdown, 1}
end)
fun = fn ->
run(
["Single", "1.2.3", source_beam, "--formatter=html", "--warnings-as-errors"],
&ExDoc.generate_docs/3,
:stderr
)
end

assert io =~
"Doc generation failed due to warnings while using the --warnings-as-errors option\n"
# fun.()

io =
capture_io(:stderr, fn ->
assert catch_exit(fun.()) == {:shutdown, 1}
end)

assert io =~
"Documents have been generated, but generation for html format failed due to warnings " <>
"while using the --warnings-as-errors option."
end)
end
end

Expand Down Expand Up @@ -156,7 +154,7 @@ defmodule ExDoc.CLITest do
--canonical http://example.com/project
)

{[{project, version, opts}], _io} = run(args)
{[{:ok, {project, version, opts}}], _io} = run(args)
assert project == "ExDoc"
assert version == "1.2.3"

Expand Down Expand Up @@ -187,7 +185,7 @@ defmodule ExDoc.CLITest do
test "loading" do
File.write!("test.exs", ~s([extras: ["README.md"], formatters: ["html"]]))

{[{project, version, opts}], _io} =
{[{:ok, {project, version, opts}}], _io} =
run(["ExDoc", "--extra-section", "Guides", "1.2.3", @ebin, "-c", "test.exs"])

assert project == "ExDoc"
Expand All @@ -208,7 +206,7 @@ defmodule ExDoc.CLITest do
test "switches take precedence over config" do
File.write!("test.exs", ~s([logo: "config_logo.png", formatters: ["html"]]))

{[{project, version, opts}], _io} =
{[{:ok, {project, version, opts}}], _io} =
run([
"ExDoc",
"--logo",
Expand Down Expand Up @@ -254,7 +252,8 @@ defmodule ExDoc.CLITest do
test "loading" do
File.write!("test.config", ~s({extras, [<<"README.md">>]}. {formatters, [<<"html">>]}.))

{[{project, version, opts}], _io} = run(["ExDoc", "1.2.3", @ebin, "-c", "test.config"])
{[{:ok, {project, version, opts}}], _io} =
run(["ExDoc", "1.2.3", @ebin, "-c", "test.config"])

assert project == "ExDoc"
assert version == "1.2.3"
Expand Down
3 changes: 2 additions & 1 deletion test/ex_doc/formatter/html_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@ defmodule ExDoc.Formatter.HTMLTest do
generate_docs(doc_config(context, skip_undefined_reference_warnings_on: []))
end)

assert out =~ ~s|documentation references function "Warnings.bar/0" but|
assert out =~
~s|documentation references function "Warnings.bar/0" but it is undefined or private|

# TODO: remove check when we require Elixir v1.16
if Version.match?(System.version(), ">= 1.16.0-rc") do
Expand Down
10 changes: 10 additions & 0 deletions test/fixtures/single/lib/single.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
defmodule Single do
@moduledoc """
moduledoc `Single.bar/0`
"""

@doc """
doc `Single.bar/0`
"""
def foo(), do: :foo
end
Loading

0 comments on commit f6e4c9e

Please sign in to comment.