ref:main
Coverage: 0.0%
0/13 lines covered
1
# Copyright 2026 Cole Christensen
2
#
3
# Licensed under the Apache License, Version 2.0 (the "License");
4
# you may not use this file except in compliance with the License.
5
# You may obtain a copy of the License at
6
#
7
# http://www.apache.org/licenses/LICENSE-2.0
8
#
9
# Unless required by applicable law or agreed to in writing, software
10
# distributed under the License is distributed on an "AS IS" BASIS,
11
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
# See the License for the specific language governing permissions and
13
# limitations under the License.
14
15
defmodule Mix.Tasks.LicenseCheck do
16
@moduledoc """
17
Checks that all .ex and .exs source files contain the Apache 2.0 license header.
18
19
## Usage
20
21
mix license_check
22
23
Returns exit code 1 if any files are missing the header.
24
"""
25
@shortdoc "Verify Apache 2.0 license headers on all source files"
26
27
use Mix.Task
28
29
@expected_first_line "# Copyright 2026 Cole Christensen"
30
31
@impl Mix.Task
32
def run(_args) do
33
files =
34
(Path.wildcard("lib/**/*.ex") ++
35
Path.wildcard("test/**/*.ex") ++
36
Path.wildcard("test/**/*.exs") ++
37
["mix.exs"])
38
|> Enum.filter(&File.exists?/1)
39
40
missing =
41
Enum.filter(files, fn file ->
42
case File.open(file, [:read, :utf8]) do
43
{:ok, device} ->
44
first_line = IO.read(device, :line) |> String.trim_trailing()
45
File.close(device)
46
first_line != @expected_first_line
47
48
{:error, _} ->
49
true
50
end
51
end)
52
53
if missing == [] do
54
Mix.shell().info("All #{length(files)} files have license headers.")
55
else
56
Mix.shell().error("Missing license header in #{length(missing)} file(s):")
57
58
Enum.each(missing, fn file ->
59
Mix.shell().error(" #{file}")
60
end)
61
62
Mix.raise("License check failed. Add the Apache 2.0 header to the files listed above.")
63
end
64
end
65
end
66
67