sapling/eden/mononoke/hooks
Thomas Orozco 16384599a8 mononoke (+ rust/shed/async_unit): update async_unit to expect async fn's
Summary:
This allows code that is being exercised under async_unit to call into code
that expects a Tokio 0.2 environment (e.g. 0.2 timers).

Unfortunately, this requires turning off LSAN for the async_unit tests, since
it looks like LSAN and Tokio 0.2 don't work very well together, resulting in
LSAN reporting leaked memory for some TLS structures that were initialized by
tokio-preview (regardless of whether the Runtime is being dropped):
https://fb.workplace.com/groups/rust.language/permalink/3249964938385432/

Considering async_unit is effectively only used in Mononoke, and Mononoke
already turns off LSAN in tests for precisely this reason ... it's probably
reasonable to do the same here.

The main body of changes here is also about updating the majority of our
changes to stop calling wait(), and use this new async unit everywhere. This is
effectively a pretty big batch conversion of all of our tests to use async fns
instead of the former approaches. I've also updated a substantial number of
utility functions to be async fns.

A few notable changes here:

- Some pushrebase tests were pretty flaky — the race they look for isn't
  deterministic. I added some actual waiting (using pushrebase hooks) to make
  it more deterministic.  This is kinda copy pasted from the globalrev hook
  (where I had introduced this first), but this will do for now.
- The multiplexblob tests don't work at all with new futures, because they call
  `poll()` all over the place. I've updated them to new futures, which required
  a bit of reworking.
- I took out a couple tests in async unit that were broken anyway.

Reviewed By: StanislavGlebik

Differential Revision: D19902539

fbshipit-source-id: 352b4a531ef5fa855114c1dd8bb4d70ed967dd55
2020-02-18 01:55:00 -08:00
..
content-stores/src Manual synchronization of fbcode/eden and facebookexperimental/eden 2020-02-11 11:42:43 +01:00
hooks-tests/src mononoke (+ rust/shed/async_unit): update async_unit to expect async fn's 2020-02-18 01:55:00 -08:00
src mononoke (+ rust/shed/async_unit): update async_unit to expect async fn's 2020-02-18 01:55:00 -08:00
README.md mononoke: move the codebase under eden/ directory 2020-02-06 13:46:04 +01: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 must provide a short description of the failure, used to summarize this failure with other similar failures.
  • long_description (string or nil) If the hook was not satisfied, this should provide a long description of the failure with suggestions for how the user should approach fixing this hook failure. Mononoke will use description if this is not provided, but this message needs to stand alone (description is not automatically added to this message).

Here are some common properties of hooks:

The ctx argument passed to the hook function always has at least the following fields:

key description
config_strings (table of string) Contains string configs defined per repository config
config_ints (table of int) Contains int configs defined per repository config
regex_match(regex, string) (function) Returns a boolean indicating whether the string matches the supplied regex

The type 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
len() Returns a number that is the length of the file in bytes. (Only present if is_deleted() returns false.)
text() Returns a string containing the contents of the file, or nil if the file is binary or too large. (Only present if is_deleted() returns false.)
path_regex_match(regex) Returns a boolean indicating whether the file's path matches the supplied regex

PerChangeset

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

key description
info (table) Described below.
files (table) List of objects of type file, described above.
file_text(path) (function) Takes the relative path to a file in the repo and returns its contents, or nil if the file does not exist, is binary, or too large.
parse_commit_msg() (function) Returns a table with phabricator tags parsed.
is_valid_reviewer(user) (function) Returns whether a user can review the commit.

ctx.info is a table with the following fields:

key description
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 additional fields:

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