Skip to content

Commit 7849f1b

Browse files
committed
Ensure single trailing newline in source files
Reduce future code churn by gating source files with a test that ensures tracked text files in the repository end with a single trailing newline (UNIX convention). Alternatives to enforce this without a test: An .editorconfig file at the root of the repository makes most editors automatically insert a final newline and trim trailing whitespace on save, preventing the problem at the source: root = true [*] insert_final_newline = true trim_trailing_whitespace = true end_of_line = lf charset = utf-8 A .gitattributes file makes Git itself flag whitespace issues in diffs, on apply, and on merge: * text=auto eol=lf whitespace=blank-at-eol,blank-at-eof Both files support per-path exceptions. In .editorconfig, a section like [*.png] can override any setting. In .gitattributes, paths can opt out with -whitespace or be marked as binary (e.g. "*.png binary").
1 parent bb81d88 commit 7849f1b

6 files changed

Lines changed: 41 additions & 4 deletions

File tree

.github/ISSUE_TEMPLATE/bug_report.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,6 @@ https://github.com/wojtekmach/mix_install_examples/blob/main/phoenix.exs
2424

2525
### Expected behavior
2626

27+
<!--
28+
Describe the expected behavior.
29+
-->

installer/templates/phx_assets/app.js.eex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,4 +87,4 @@ document.querySelectorAll("[role=alert][data-flash]").forEach((el) => {
8787
el.addEventListener("click", () => {
8888
el.setAttribute("hidden", "")
8989
})
90-
})<% end %><% end %>
90+
})<% end %><% end %>

installer/templates/phx_static/default.css

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2587,4 +2587,3 @@
25872587
transform: rotate(360deg);
25882588
}
25892589
}
2590-

installer/templates/phx_umbrella/config/test.exs.eex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@ config :phoenix_live_view,
1919

2020
# Sort query params output of verified routes for robust url comparisons
2121
config :phoenix,
22-
sort_verified_routes_query_params: true
22+
sort_verified_routes_query_params: true

test/phoenix/source_files_test.exs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
defmodule Phoenix.SourceFilesTest do
2+
use ExUnit.Case, async: true
3+
4+
@repo_root Path.expand("../..", __DIR__)
5+
@git_repo? File.dir?(Path.join(@repo_root, ".git")) and System.find_executable("git") != nil
6+
@excluded_exts ~w(.br .foo .gz .ico .lock .map .pem .png)
7+
@excluded_files ~w(test/fixtures/hello.txt)
8+
9+
@tag skip: if(not @git_repo?, do: "git or .git repository not available")
10+
test "all tracked text files in the repository end with a single newline" do
11+
{output, 0} = System.cmd("git", ["ls-files", "-z"], cd: @repo_root)
12+
13+
target_files =
14+
output
15+
|> String.split("\0", trim: true)
16+
|> Enum.reject(fn file ->
17+
file in @excluded_files or Enum.any?(@excluded_exts, &String.ends_with?(file, &1))
18+
end)
19+
|> Enum.map(&Path.expand(&1, @repo_root))
20+
|> Enum.filter(&File.regular?/1)
21+
22+
assert target_files != [], "No tracked files found in the repository"
23+
24+
offending =
25+
target_files
26+
|> Enum.reject(fn file ->
27+
content = File.read!(file)
28+
content == "" or content =~ ~r/\S\n\z/
29+
end)
30+
|> Enum.map(&Path.relative_to(&1, @repo_root))
31+
32+
assert offending == [],
33+
"Expected the following files to end with a single trailing newline:\n\n" <>
34+
Enum.map_join(offending, "\n", &" - #{&1}")
35+
end
36+
end

usage-rules/elixir.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,3 @@
5252
assert_receive {:DOWN, ^ref, :process, ^pid, :normal}
5353

5454
- Instead of sleeping to synchronize before the next call, **always** use `_ = :sys.get_state/1` to ensure the process has handled prior messages
55-

0 commit comments

Comments
 (0)