Presubmit.RuleSet behaviour (presubmit v0.2.2)

Copy Markdown View Source

A module that groups related rules, so a configuration can enable a whole area of policy with one entry.

defmodule MyApp.CommitRules do
  use Presubmit.RuleSet

  import Presubmit.Query
  import Presubmit.Assertions

  rule :no_todo, "no TODO without an issue reference", fn commit ->
    refute_added_lines(commit, ~r/TODO(?!\(#\d+\))/, in: ~r{^lib/})
  end

  rule :subject, "subject matches the configured pattern", fn commit, opts ->
    assert_subject(commit, Keyword.fetch!(opts, :subject))
  end
end

In .presubmit.exs a rule set is named by module, optionally with only:/except: to select rules, warn: to make some of them report without failing, in: to restrict the set to changes under a path pattern, and any other options the rules read:

[
  Presubmit.Rules.Phoenix,
  {Presubmit.Rules.Ecto, except: [:migrations_reversible]},
  {Presubmit.Rules.Elixir, warn: [:specs]},
  {Presubmit.Rules.ExUnit, in: ~r{^apps/core/}},
  {MyApp.CommitRules, subject: ~r/^\[\w+\] /}
]

Summary

Types

What applicable?/2 consults: which modules are loaded, which apps the examined tree depends on, and which files it contains.

{app_or_apps, module}: any of the apps declared or locked, or the module loaded.

A rule set as it appears in configuration.

Callbacks

A one-line description of the set, for mix presubmit --list.

What must be present for the set to be enabled by default. {app, module} is satisfied when module is loaded in the VM or app (any of a list) is declared in the examined tree's mix.exs or present in its mix.lock; {:file, path} when the tree has that file.

The rules in the set, configured with opts.

Functions

Whether every requirement of module is satisfied under env, with the reasons: {:ok, reasons} or {:missing, reasons}.

Expands a configuration entry into rules, applying only:, except:, warn:, and in: and passing the remaining options to the set.

Declares a rule. check is a function of the commit, or of the commit and the set's options. attrs may give sources:, the change-set sources the rule applies to ([:head, :rev] for rules that only make sense on a commit); elsewhere it is skipped. It may give on_autosquash: :check for a rule that checks fixup!/squash!/amend! commits, which every other rule skips (see Presubmit.Rule).

Types

env()

@type env() :: %{
  loaded?: (module() -> boolean()),
  deps: [atom()],
  file?: (Path.t() -> boolean())
}

What applicable?/2 consults: which modules are loaded, which apps the examined tree depends on, and which files it contains.

requirement()

@type requirement() :: {atom() | [atom()], module()} | {:file, Path.t()}

{app_or_apps, module}: any of the apps declared or locked, or the module loaded.

spec()

@type spec() :: module() | {module(), keyword()}

A rule set as it appears in configuration.

Callbacks

description()

@callback description() :: String.t()

A one-line description of the set, for mix presubmit --list.

requires()

@callback requires() :: [requirement()]

What must be present for the set to be enabled by default. {app, module} is satisfied when module is loaded in the VM or app (any of a list) is declared in the examined tree's mix.exs or present in its mix.lock; {:file, path} when the tree has that file.

rules(keyword)

@callback rules(keyword()) :: [Presubmit.Rule.t()]

The rules in the set, configured with opts.

Functions

applicable?(module, env)

@spec applicable?(module(), env()) :: {:ok, [String.t()]} | {:missing, [String.t()]}

Whether every requirement of module is satisfied under env, with the reasons: {:ok, reasons} or {:missing, reasons}.

expand(module)

@spec expand(spec()) :: [Presubmit.Rule.t()]

Expands a configuration entry into rules, applying only:, except:, warn:, and in: and passing the remaining options to the set.

rule(id, name, check, attrs \\ [])

(macro)

Declares a rule. check is a function of the commit, or of the commit and the set's options. attrs may give sources:, the change-set sources the rule applies to ([:head, :rev] for rules that only make sense on a commit); elsewhere it is skipped. It may give on_autosquash: :check for a rule that checks fixup!/squash!/amend! commits, which every other rule skips (see Presubmit.Rule).