From de322091f79ef35a531b1e917c4a7640d2815f5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20F=C3=B6hring?= Date: Sat, 17 Feb 2024 15:23:58 +0100 Subject: [PATCH] Fix files_included not being honored by Runner when reading from stdin. Refs #1115 --- lib/credo.ex | 2 ++ lib/credo/check/runner.ex | 16 +++++++++++++++- lib/credo/sources.ex | 35 +++++++++++++++++++++++++++++++++++ test/credo/sources_test.exs | 17 +++++++++++++++++ 4 files changed, 69 insertions(+), 1 deletion(-) diff --git a/lib/credo.ex b/lib/credo.ex index 36e68d52d..84ded2ec0 100644 --- a/lib/credo.ex +++ b/lib/credo.ex @@ -31,6 +31,7 @@ defmodule Credo do |> WriteDebugReport.call([]) end + @doc false def run(argv_or_exec, files_that_changed) do argv_or_exec |> Execution.build(files_that_changed) @@ -38,5 +39,6 @@ defmodule Credo do |> WriteDebugReport.call([]) end + @doc false def version, do: @version end diff --git a/lib/credo/check/runner.ex b/lib/credo/check/runner.ex index e6f94f2b9..8be90be92 100644 --- a/lib/credo/check/runner.ex +++ b/lib/credo/check/runner.ex @@ -51,7 +51,21 @@ defmodule Credo.Check.Runner do # but it is necessary to avoid hitting the filesystem when reading from STDIN [%Credo.SourceFile{filename: filename}] = Execution.get_source_files(exec) - if filename in files_excluded do + file_included? = + if files_included != [] do + Credo.Sources.filename_matches?(filename, files_included) + else + true + end + + file_excluded? = + if files_excluded != [] do + Credo.Sources.filename_matches?(filename, files_excluded) + else + false + end + + if !file_included? || file_excluded? do :skip_run else [] diff --git a/lib/credo/sources.ex b/lib/credo/sources.ex index 10c0200af..92518ccd8 100644 --- a/lib/credo/sources.ex +++ b/lib/credo/sources.ex @@ -9,6 +9,41 @@ defmodule Credo.Sources do @default_sources_glob ~w(** *.{ex,exs}) @stdin_filename "stdin" + @doc false + def filename_matches?(filename, patterns) do + patterns + |> List.wrap() + |> Enum.any?(&match_filename_pattern(filename, &1)) + end + + defp match_filename_pattern(filename, pattern) when is_binary(pattern) do + if String.contains?(pattern, "*") do + matches_glob_naively?(filename, pattern) + else + String.starts_with?(filename, pattern) + end + end + + defp match_filename_pattern(filename, %Regex{} = pattern), do: String.match?(filename, pattern) + + defp match_filename_pattern(_, pattern), + do: raise("Expected String or Regex, got: #{inspect(pattern)}") + + # naively converts glob pattern to regex + # does not account for brace or tilde expansion or command substitution + # or anything other than * and ** + defp matches_glob_naively?(filename, pattern) do + pattern + |> String.replace("/", "\\/") + |> String.replace("**", ".+") + |> String.replace("*", "[^\/]+") + |> Regex.compile() + |> case do + {:ok, regex} -> String.match?(filename, regex) + _ -> raise "Compiling glob pattern to regex failed: #{inspect(pattern)}" + end + end + @doc """ Finds sources for a given `Credo.Execution`. diff --git a/test/credo/sources_test.exs b/test/credo/sources_test.exs index f1df91f80..441e1da83 100644 --- a/test/credo/sources_test.exs +++ b/test/credo/sources_test.exs @@ -293,4 +293,21 @@ defmodule Credo.SourcesTest do assert expected == Credo.Sources.find_in_dir(dir, ["*.ex"], [~r/.ex$/]) end + + test "it matches filenames given patterns" do + assert Credo.Sources.filename_matches?("lib/credo/check/runner.ex", [ + "lib/credo/check/runner.ex" + ]) + + assert Credo.Sources.filename_matches?("lib/credo/check.ex", ["lib/*/check.ex"]) + assert Credo.Sources.filename_matches?("lib/credo/check/runner.ex", ["lib/**/runner.ex"]) + assert Credo.Sources.filename_matches?("lib/credo/check/runner.ex", ["lib/**/*.ex"]) + + assert Credo.Sources.filename_matches?("lib/credo/check/foo.ex", ["lib/**/*.ex"]) + assert Credo.Sources.filename_matches?("lib/credo/check/foo.ex", [~r/.ex$/]) + + refute Credo.Sources.filename_matches?("lib/credo/check/runner.ex", ["lib/*/runner.ex"]) + refute Credo.Sources.filename_matches?("lib/credo/check/runner.ex", ["*.exs"]) + refute Credo.Sources.filename_matches?("lib/credo/check/runner.ex", [~r/.exs$/]) + end end