Presubmit.Rule (presubmit v0.2.2)

Copy Markdown View Source

One named check over a change set.

check is a function of the commit (and, for configurable rules, the options the rule set was given) that returns :ok or raises Presubmit.Violation. Rules are grouped into rule sets (Presubmit.RuleSet) and run by Presubmit.Runner.

A rule may declare the change-set sources it applies to; outside them it is skipped. no_fixup is the canonical case: fixup! commits are meant to exist locally and be autosquashed, so the rule applies to committed revisions (:head, :rev) and not to the index a hook is checking.

Rules skip autosquash commits, those whose subject starts fixup!, squash! or amend! (Presubmit.Message.autosquash/1). Such a commit's message and diff are not what lands: git rebase --autosquash folds them into an earlier commit, and the rules check that commit as it ends up. A rule about autosquash commits themselves declares on_autosquash: :check; no_fixup does, so a range that still holds one fails.

A rule's severity is :error (a violation fails the run) or :warn (it is reported but does not fail). Its scope, when set, restricts the change set to files matching a pattern before the check runs, so one configuration can apply different rules to different parts of a repository.

A commit may exempt itself with trailers, as in Chromium: No-Presubmit: true skips every rule, and Presubmit-Skip: pure_move, max_files skips the named ones. The exemption is part of the commit and is reported on every run, which is the point — unlike git commit --no-verify, it leaves a trace and CI sees the same decision.

Summary

Functions

Rule ids a commit's Presubmit-Skip: trailers name, or :all for No-Presubmit: true.

Runs the rule against commit.

Types

check()

@type check() ::
  (Presubmit.Commit.t() -> :ok | {:skip, String.t()})
  | (Presubmit.Commit.t(), keyword() -> :ok | {:skip, String.t()})

outcome()

@type outcome() ::
  :pass
  | {:fail, String.t()}
  | {:skip, String.t()}
  | {:error, Exception.t(), Exception.stacktrace()}

t()

@type t() :: %Presubmit.Rule{
  check: check(),
  id: atom(),
  name: String.t(),
  on_autosquash: :skip | :check,
  opts: keyword(),
  scope: term(),
  set: module() | nil,
  severity: term(),
  sources: [atom()] | nil
}

Functions

exemptions(commit)

@spec exemptions(Presubmit.Commit.t()) :: :all | [atom()]

Rule ids a commit's Presubmit-Skip: trailers name, or :all for No-Presubmit: true.

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

@spec new(atom(), String.t(), check(), keyword()) :: t()

Builds a rule.

run(rule, commit)

@spec run(t(), Presubmit.Commit.t()) :: outcome()

Runs the rule against commit.

A Presubmit.Violation is a failure. A skip is: a Presubmit.NoMessageError (a message rule against the index or working tree), a check returning {:skip, reason} (nothing configured), an autosquash commit (unless the rule declares on_autosquash: :check), or a change set outside the rule's sources. Any other exception is reported as an error rather than crashing the run.