sapling/hooks
Michael Bolin b83240eb52 Put together a doc to explain the contracts of hooks in Mononoke.
Summary:
This is based on my reading of the source code, so I may have gotten things
wrong. Feel free to editorialize!

By putting this in a doc, hopefully it makes it easier for us to reason about
the API at a high level. Obviously it would be great if we could keep this up
to date going forward.

Reviewed By: StanislavGlebik

Differential Revision: D10340604

fbshipit-source-id: 9f3e82d234842e06c52f8a8b4440f8e06c487c0b
2018-10-19 11:49:56 -07:00
..
src Expose is_sym_link function in hooks 2018-10-17 07:23:19 -07:00
Cargo.toml Add Cargo.toml files to crates. (#7) 2018-07-09 19:52:27 -07:00
README.md Put together a doc to explain the contracts of hooks in Mononoke. 2018-10-19 11:49:56 -07:00

Commit Hooks

This document explains how to author and configure commit hooks for Mononoke.

Overview

Two types of hooks are supported (note that both are pre-commit hooks):

  • PerChangeset runs once per changeset.
  • PerAddedOrModifiedFile runs once per added or modified file per changeset.

Individual hooks are declared as follows in the server.toml file that contains the configuration for a repo:

[[hooks]]
# The name of your hook. Must be unique within this file.
name="my_hook"

# Path to the Lua script that implements your hook.
# Relative paths are resolved relative to the root of the config repo.
path="my_hook.lua"

# This must be either "PerChangeset" or "PerAddedOrModifiedFile".
hook_type="PerAddedOrModifiedFile"

# The following property is optional.
# If specified and there is a line in the commit message that matches
# the specified value, then the hook is not run for that commit.
bypass_commit_string="@ignore-conflict-markers"

# The following property is optional.
# If specified, the hook can be bypassed by specifying `--pushvars KEY=VALUE`
# when running `hg push`.
bypass_pushvar="KEY=VALUE"

Enabled hooks must be declared in [[bookmark.hooks]]:

[[bookmarks.hooks]]
# Note how this matches the "name" property in [[hooks]].
hook_name="my_hook"

Here is an example of a hook to prevent Perl files from being checked in:

-- file my_hook.lua

function hook (ctx)
  if ctx.file.path:match("\\.perl$") then
    return false, "Boo: scary Perl!"
  else
    return true
end

Lua API

Your hook must be implemented in Lua. The entry point to your hook must be a global function named hook(). This function should return up to three values:

  • success (boolean) This should be true if the hook was satisfied and false if it was not. If this is true, then description and long_description must be nil.
  • description (string or nil) If the hook was not satisfied, this should provide a short description of the failure.
  • long_description (string or nil) If the hook was not satisfied, this should provide a long description of the failure.

Here are some common types:

file is a table with the following fields:

key description
path (string) Path to the file relative to the repo root.
is_added() Returns a boolean indicating whether the file was added as part of the changeset
is_deleted() Returns a boolean indicating whether the file was deleted as part of the changeset
is_modified() Returns a boolean indicating whether the file was modified as part of the changeset
contains_string(needle) Returns a boolean indicating whether the specified string needle is present in this file. (Only present if is_deleted() returns false.)
len() Returns a number that is the length of the file in bytes. (Only present if is_deleted() returns false.)
content() Returns a string containing the contents of the file. (Only present if is_deleted() returns false.)

PerChangeset

Your hook() function receives a single ctx argument, which is a table with the following fields:

key description
info (table) Described below.
files (table) List of objects of type file, described above.
file_content(path) (function) Takes the relative path to a file in the repo and returns its contents.

ctx.info is a table with the following fields:

key description
repo_name (string) Name of the repository.
author (string) The author of the changeset. This should be something like "Stanislau Hlebik <stash@fb.com>".
comments (string) The commit message.
parent1_hash (string or nil) p1 for the commit as a hex string, if it exists.
parent2_hash (string or nil) p2 for the commit as a hex string, if it exists.

PerAddedOrModifiedFile

Your hook() function receives a single ctx argument, which is a table with the following fields:

key description
info (table) Described below.
file (table) Object of type file, described above. (Note is_deleted() will return false.)

ctx.info is a table with the following fields:

key description
repo_name (string) Name of the repository.