diff --git a/lib/mix/tasks/git_ops.check_message.ex b/lib/mix/tasks/git_ops.check_message.ex index 785264b..d1c30a0 100644 --- a/lib/mix/tasks/git_ops.check_message.ex +++ b/lib/mix/tasks/git_ops.check_message.ex @@ -4,9 +4,15 @@ defmodule Mix.Tasks.GitOps.CheckMessage do @shortdoc "Check if a file's content follows the Conventional Commits spec" @moduledoc """ - Receives a file path and validates if it's content follows the Conventional Commits specification. + Validates a commit message against the Conventional Commits specification. + + Check a file containing a commit message using: mix git_ops.check_message + + or to check the most recent commit on the current branch: + + mix git_ops.check_message --head Logs an error if the commit message is not parse-able. @@ -17,6 +23,15 @@ defmodule Mix.Tasks.GitOps.CheckMessage do alias GitOps.Config @doc false + def run(["--head"]) do + message = + Config.repository_path() + |> Git.init!() + |> Git.log!(["-1", "--format=%s"]) + + validate(message) + end + def run([path]) do # Full paths do not need to be wrapped with repo root path = @@ -26,8 +41,17 @@ defmodule Mix.Tasks.GitOps.CheckMessage do Path.join(Config.repository_path(), path) end - message = File.read!(path) + path + |> File.read!() + |> validate() + end + + def run(_), do: error_exit("Invalid usage. See `mix help git_ops.check_message`") + @spec error_exit(String.t()) :: no_return + defp error_exit(message), do: raise(Mix.Error, message: message) + + defp validate(message) do case Commit.parse(message) do {:ok, _} -> :ok @@ -70,9 +94,4 @@ defmodule Mix.Tasks.GitOps.CheckMessage do """) end end - - def run(_), do: error_exit("Invalid usage. See `mix help git_ops.check_message`") - - @spec error_exit(String.t()) :: no_return - defp error_exit(message), do: raise(Mix.Error, message: message) end diff --git a/test/check_message_test.exs b/test/check_message_test.exs index b8d90cb..57e373e 100644 --- a/test/check_message_test.exs +++ b/test/check_message_test.exs @@ -2,7 +2,7 @@ Mix.shell(Mix.Shell.Process) defmodule GitOps.Mix.Tasks.Test.CheckMessageTest do - use ExUnit.Case + use ExUnit.Case, async: false alias Mix.Tasks.GitOps.CheckMessage @@ -17,6 +17,46 @@ defmodule GitOps.Mix.Tasks.Test.CheckMessageTest do CheckMessage.run(["path/to/nowhere"]) end end + + describe "with --head" do + setup do + repo_path = System.tmp_dir!() + |> Path.join("repo") + + repo = Git.init!(repo_path) + + Application.put_env(:git_ops, :repository_path, repo_path) + + on_exit(fn -> + Application.delete_env(:git_ops, :repository_path) + File.rm_rf!(repo_path) + + :ok + end) + + {:ok, repo: repo} + end + + test "it fails when the repo contains no commits" do + assert_raise(Git.Error, ~r/does not have any commits/, fn -> + CheckMessage.run(["--head"]) + end) + end + + test "it fails when the latest commit does not have a valid message", %{repo: repo} do + Git.commit!(repo, ["-m 'invalid message'", "--allow-empty"]) + + assert_raise(Mix.Error, ~r/Not a valid Conventional Commit message/, fn -> + CheckMessage.run(["--head"]) + end) + end + + test "it succeeds when the latest commit has a valid message", %{repo: repo} do + Git.commit!(repo, ["-m 'chore: counting toes'", "--allow-empty"]) + + assert :ok = CheckMessage.run(["--head"]) + end + end describe "with valid path" do setup do diff --git a/test/config_test.exs b/test/config_test.exs index e370524..47b3157 100644 --- a/test/config_test.exs +++ b/test/config_test.exs @@ -10,7 +10,7 @@ defmodule GitOps.Test.ConfigTest do Application.put_env(:git_ops, :changelog_file, "CUSTOM_CHANGELOG.md") Application.put_env(:git_ops, :manage_readme_version, true) Application.put_env(:git_ops, :types, custom: [header: "Custom"], docs: [hidden?: false]) - Application.put_env(:git_ops, :tags, [allowed: ["tag_1", "tag_2"], allow_untagged?: false]) + Application.put_env(:git_ops, :tags, allowed: ["tag_1", "tag_2"], allow_untagged?: false) Application.put_env(:git_ops, :version_tag_prefix, "v") end