Skip to content

Commit cdacc39

Browse files
committed
Add --warnings-as-errors flag for non-zero exit code
1 parent fcfd2b9 commit cdacc39

File tree

10 files changed

+115
-31
lines changed

10 files changed

+115
-31
lines changed

lib/ex_doc/application.ex

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ defmodule ExDoc.Application do
1717
match?("makeup_" <> _, Atom.to_string(app)),
1818
do: Application.ensure_all_started(app)
1919

20-
Supervisor.start_link([ExDoc.Refs], strategy: :one_for_one)
20+
children = [
21+
ExDoc.Refs,
22+
ExDoc.WarningCounter
23+
]
24+
25+
Supervisor.start_link(children, strategy: :one_for_one)
2126
end
2227
end

lib/ex_doc/cli.ex

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,25 @@ defmodule ExDoc.CLI do
2626
package: :string,
2727
proglang: :string,
2828
source_ref: :string,
29-
version: :boolean
29+
version: :boolean,
30+
warnings_as_errors: :boolean
3031
]
3132
)
3233

33-
if List.keymember?(opts, :version, 0) do
34-
print_version()
35-
else
36-
generate(args, opts, generator)
34+
cond do
35+
List.keymember?(opts, :version, 0) ->
36+
print_version()
37+
38+
opts[:warnings_as_errors] == true and ExDoc.WarningCounter.count() > 0 ->
39+
IO.puts(
40+
:stderr,
41+
"Doc generation failed due to warnings while using the --warnings-as-errors option"
42+
)
43+
44+
exit({:shutdown, ExDoc.WarningCounter.count()})
45+
46+
true ->
47+
generate(args, opts, generator)
3748
end
3849
end
3950

@@ -140,27 +151,28 @@ defmodule ExDoc.CLI do
140151
ex_doc "Project" "1.0.0" "_build/dev/lib/project/ebin" -c "docs.exs"
141152
142153
Options:
143-
PROJECT Project name
144-
VERSION Version number
145-
BEAMS Path to compiled beam files
146-
-n, --canonical Indicate the preferred URL with rel="canonical" link element
147-
-c, --config Give configuration through a file instead of a command line.
148-
See "Custom config" section below for more information.
149-
-f, --formatter Docs formatter to use (html or epub), default: "html"
150-
-p, --homepage-url URL to link to for the site name
151-
--paths Prepends the given path to Erlang code path. The path might contain a glob
152-
pattern but in that case, remember to quote it: --paths "_build/dev/lib/*/ebin".
153-
This option can be given multiple times
154-
--language Identify the primary language of the documents, its value must be
155-
a valid [BCP 47](https://tools.ietf.org/html/bcp47) language tag, default: "en"
156-
-l, --logo Path to the image logo of the project (only PNG or JPEG accepted)
157-
The image size will be 64x64 and copied to the assets directory
158-
-m, --main The entry-point page in docs, default: "api-reference"
159-
--package Hex package name
160-
--source-ref Branch/commit/tag used for source link inference, default: "master"
161-
-u, --source-url URL to the source code
162-
-o, --output Path to output docs, default: "doc"
163-
-v, --version Print ExDoc version
154+
PROJECT Project name
155+
VERSION Version number
156+
BEAMS Path to compiled beam files
157+
-n, --canonical Indicate the preferred URL with rel="canonical" link element
158+
-c, --config Give configuration through a file instead of a command line.
159+
See "Custom config" section below for more information.
160+
-f, --formatter Docs formatter to use (html or epub), default: "html"
161+
-p, --homepage-url URL to link to for the site name
162+
--paths Prepends the given path to Erlang code path. The path might contain a glob
163+
pattern but in that case, remember to quote it: --paths "_build/dev/lib/*/ebin".
164+
This option can be given multiple times
165+
--language Identify the primary language of the documents, its value must be
166+
a valid [BCP 47](https://tools.ietf.org/html/bcp47) language tag, default: "en"
167+
-l, --logo Path to the image logo of the project (only PNG or JPEG accepted)
168+
The image size will be 64x64 and copied to the assets directory
169+
-m, --main The entry-point page in docs, default: "api-reference"
170+
--package Hex package name
171+
--source-ref Branch/commit/tag used for source link inference, default: "master"
172+
-u, --source-url URL to the source code
173+
-o, --output Path to output docs, default: "doc"
174+
-v, --version Print ExDoc version
175+
--warnings-as-errors Exit with non-zero status if doc generation has one or more warnings
164176
165177
## Custom config
166178

lib/ex_doc/config.ex

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ defmodule ExDoc.Config do
4343
version: nil,
4444
authors: nil,
4545
skip_undefined_reference_warnings_on: [],
46-
package: nil
46+
package: nil,
47+
warnings_as_errors: false
4748

4849
@type t :: %__MODULE__{
4950
apps: [atom()],
@@ -78,6 +79,7 @@ defmodule ExDoc.Config do
7879
version: nil | String.t(),
7980
authors: nil | [String.t()],
8081
skip_undefined_reference_warnings_on: [String.t()],
81-
package: :atom | nil
82+
package: :atom | nil,
83+
warnings_as_errors: boolean()
8284
}
8385
end

lib/ex_doc/language.ex

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ defmodule ExDoc.Language do
135135
def get(:erlang, _module), do: {:ok, ExDoc.Language.Erlang}
136136

137137
def get(language, module) when is_atom(language) and is_atom(module) do
138+
ExDoc.WarningCounter.increment()
139+
138140
IO.warn(
139141
"skipping module #{module}, reason: unsupported language (#{language})",
140142
[]

lib/ex_doc/markdown/earmark.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ defmodule ExDoc.Markdown.Earmark do
5252
defp print_messages(messages, options) do
5353
for {severity, line, message} <- messages do
5454
file = options[:file]
55+
ExDoc.WarningCounter.increment()
5556
IO.warn("#{inspect(__MODULE__)} (#{severity}) #{file}:#{line} #{message}", [])
5657
end
5758
end

lib/ex_doc/retriever.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ defmodule ExDoc.Retriever do
8181
docs
8282

8383
{:error, reason} ->
84+
ExDoc.WarningCounter.increment()
8485
IO.warn("skipping module #{inspect(module)}, reason: #{reason}", [])
8586
false
8687
end

lib/ex_doc/warning_counter.ex

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
defmodule ExDoc.WarningCounter do
2+
@moduledoc false
3+
4+
use Agent
5+
6+
def start_link(_opts) do
7+
Agent.start_link(fn -> 0 end, name: __MODULE__)
8+
end
9+
10+
def count do
11+
Agent.get(__MODULE__, & &1)
12+
end
13+
14+
def increment do
15+
Agent.update(__MODULE__, &(&1 + 1))
16+
end
17+
end

lib/mix/tasks/docs.ex

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ defmodule Mix.Tasks.Docs do
2121
* `--language` - Specifies the language to annotate the
2222
EPUB output in valid [BCP 47](https://tools.ietf.org/html/bcp47)
2323
24+
* `--warnings-as-errors` - Exits with non-zero exit code if any warnings are found
25+
2426
The command line options have higher precedence than the options
2527
specified in your `mix.exs` file below.
2628
@@ -299,7 +301,8 @@ defmodule Mix.Tasks.Docs do
299301
canonical: :string,
300302
formatter: :keep,
301303
language: :string,
302-
output: :string
304+
output: :string,
305+
warnings_as_errors: :boolean
303306
]
304307

305308
@aliases [n: :canonical, f: :formatter, o: :output]
@@ -349,7 +352,17 @@ defmodule Mix.Tasks.Docs do
349352
for formatter <- get_formatters(options) do
350353
index = generator.(project, version, Keyword.put(options, :formatter, formatter))
351354
Mix.shell().info([:green, "View #{inspect(formatter)} docs at #{inspect(index)}"])
352-
index
355+
356+
if options[:warnings_as_errors] == true and ExDoc.WarningCounter.count() > 0 do
357+
Mix.shell().info([
358+
:red,
359+
"Doc generation failed due to warnings while using the --warnings-as-errors option"
360+
])
361+
362+
exit({:shutdown, ExDoc.WarningCounter.count()})
363+
else
364+
index
365+
end
353366
end
354367
end
355368

test/ex_doc/cli_test.exs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,28 @@ defmodule ExDoc.CLITest do
2323
end) == "ExDoc v#{ExDoc.version()}\n"
2424
end
2525

26+
describe "--warnings-as-errors" do
27+
test "exits with 0 with no warnings" do
28+
assert {"ExDoc", "1.2.3", [_, _, warnings_as_errors: true]} =
29+
run(["ExDoc", "1.2.3", @ebin, "--warnings-as-errors"])
30+
end
31+
32+
test "exits with 1 with warnings" do
33+
fun = fn ->
34+
io =
35+
capture_io(:stderr, fn ->
36+
assert {"ExDoc", "1.2.3", [_, _, warnings_as_errors: true]} =
37+
run(["ExDoc", "1.2.3", @ebin, "--warnings-as-errors"])
38+
end)
39+
40+
assert io =~
41+
"Doc generation failed due to warnings while using the --warnings-as-errors option\n"
42+
end
43+
44+
assert catch_exit(fun.()) == {:shutdown, 1}
45+
end
46+
end
47+
2648
test "too many arguments" do
2749
fun = fn ->
2850
run(["ExDoc", "1.2.3", "/", "kaboom"])

test/mix/tasks/docs_test.exs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,4 +181,13 @@ defmodule Mix.Tasks.DocsTest do
181181
] = run([], app: :umbrella, apps_path: "apps/", docs: [ignore_apps: [:foo]])
182182
end)
183183
end
184+
185+
test "accepts warnings_as_errors in :warnings_as_errors" do
186+
assert [
187+
{"ex_doc", "dev",
188+
[formatter: "html", deps: _, apps: _, source_beam: _, warnings_as_errors: true]},
189+
{"ex_doc", "dev",
190+
[formatter: "epub", deps: _, apps: _, source_beam: _, warnings_as_errors: true]}
191+
] = run([], app: :ex_doc, docs: [warnings_as_errors: true])
192+
end
184193
end

0 commit comments

Comments
 (0)