summaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
authorRichard Maw <richard.maw@gmail.com>2017-04-08 15:25:53 +0100
committerRichard Maw <richard.maw@gmail.com>2017-04-10 22:02:32 +0100
commit17f73b454311ef232c29e85d9eacde7941dd8097 (patch)
tree94d143e6856c538b538ab2a017d088574f98e84e /doc
parent5f6e47a211da9e5c4816faad082f6dd7ab9d37d7 (diff)
downloadgitano-17f73b454311ef232c29e85d9eacde7941dd8097.tar.gz
Add section on git hooksrichardmaw/githookdoc
Diffstat (limited to 'doc')
-rw-r--r--doc/admin/000.mdwn136
1 files changed, 136 insertions, 0 deletions
diff --git a/doc/admin/000.mdwn b/doc/admin/000.mdwn
index 1de5ca4..c80e4cd 100644
--- a/doc/admin/000.mdwn
+++ b/doc/admin/000.mdwn
@@ -433,6 +433,142 @@ so you can split up your rules:
# Branches must not be tags
deny "Branches may only be commits" [ref prefix refs/heads/] [newtype exact commit]
+# Git Hook scripts
+
+Gitano administrators may create, or delegate creation of
+[Lua][lua] scripts to take action or provide further authentication
+when content is pushed to a repository.
+
+These [Lua][lua] scripts are sandboxed using [Supple][supple],
+to make it safer to run user-defined code.
+
+## How to add a hook
+
+Hooks are stored in the `gitano-admin.git` repository
+and the `refs/gitano/admin` branch of each other repository,
+so that there can be traceability of who is responsible for each hook.
+
+Global hooks in `gitano-admin.git` are loaded
+from the `global-hooks` subdirectory.
+Per-repository hooks in the `refs/gitano/admin` branch
+are loaded from the `hooks` subdirectory.
+
+In both cases hooks are loaded from a file named after the hook
+as defined by [githooks(5)][] suffixed with `.lua`.
+
+Currently the only hooks that are supported are:
+
+1. pre-receive
+2. update
+3. post-receive
+
+So a global pre-receive hook would be in the file `global-hooks/pre-receive.lua`
+and a per-repository post-receive hook would be in `hooks/post-receive.lua`.
+
+## APIs available to hooks
+
+1. `log.$level(...)` to emit text at that log level.
+ $level can be one of:
+
+ 1. `state`
+ 2. `crit` or `critical`
+ 3. `err` or `error`
+ 4. `warn` or `warning`
+ 5. `chat`
+ 6. `info`
+ 7. `debug`
+ 8. `ddebug` or `deepdebug`
+
+2. `fetch(url, headers, body, content_type)` during post-receive hooks.
+
+3. A `repo` object as the first parameter to per-repository hooks,
+ with the following methods:
+
+ ------------------------------------ ----------------------------------------------------------------------------
+ `:get(sha1ish)` Get the contents of a git object from anything matching [gitrevisions(7)][].
+ `:get_config(confname)` Get the value confname from the repo config if it is a single value
+ `:get_config_list(confname)` Get the value confname from the repo config if it is a list value
+ `:check_signature(obj, keyringname)` Check whether `obj` is an object signed by a key in keyring `keyringname`.
+ ------------------------------------ ----------------------------------------------------------------------------
+
+ Objects returned from `get` are [gall][] objects.
+ Refer to [gall's API documentation][gall-api] for details.
+
+4. An `actor` table in the global environment,
+ containing the following indices:
+
+ -------- --------------------------------------------------------------
+ username Gitano username of user doing the push.
+ keytag Name of the ssh key the user is pushing with.
+ source "ssh", "http" or "git" depending on the protocol used to push.
+ realname Real name of user from user configuration.
+ email E-Mail of user from user configuration.
+ -------- --------------------------------------------------------------
+
+5. The `refname`, `oldsha` and `newsha` as the third to fifth parameters
+ during per-repository update hooks, as described in [githooks(5)][].
+
+ Checking whether the master ref is deleted would be accomplished by:
+
+ local _, refname, oldsha, newsha = ...
+ if refname == "refs/heads/master" and newsha == ("0"):rep(40) then
+ log.state("Master deleted")
+ end
+
+6. For pre-receive or post-receive per-repository hooks as the third parameter,
+ a table indexed by the `refnames` being modified
+ containing tables of the `oldsha` and `newsha` indexed
+ either at positional indices `1` and `2`,
+ or by name `oldsha` and `newsha`.
+ Checking whether the master ref is deleted would be accomplished by:
+
+ local _, updates = ...
+ if (updates["refs/heads/master"] or {}).newsha == ("0"):rep(40) then
+ log.state("Master deleted")
+ end
+
+7. Global hooks work the same as per-repository hooks,
+ except their first parameter is instead a callable function
+ which will run the per-repository hook when called,
+ so global hooks may either replace or augment per-repository hooks.
+
+ To unconditionally run some global hook code and then call a local hook
+ your global hook would be structured something like:
+
+ -- Example global-hooks/update.lua
+ local hookf, repo, refname, oldsha, newsha = ...
+ -- Do stuff with repo/refname/oldsha/newsha here
+ --
+ -- And finally (optionally) tail-chain through to the per-repo hook
+ return hookf(repo, refname, oldsha, newsha)
+
+ To unconditionally ignore update hooks and log why:
+
+ -- Example global-hooks/update.lua
+ local hookf, repo, refname, oldsha, newsha = ...
+ local treeish = repo:get("refs/gitano/admin").sha
+ if repo:get(treeish..":hooks/update.lua") then
+ log.state("Update hooks are disabled")
+ end
+
+ To provide a default if a hook is not defined:
+
+ -- Example global-hooks/update.lua
+ local hookf, repo, refname, oldsha, newsha = ...
+ local treeish = repo:get("refs/gitano/admin").sha
+ if repo:get(treeish..":hooks/update.lua") then
+ return hookf(repo, refname, oldsha, newsha)
+ end
+ -- Do stuff with repo/refname/oldsha/newsha here
+
+
+[lua]: https://www.lua.org/
+[supple]: https://www.gitano.org.uk/supple/
+[githooks(5)]: https://git-scm.com/docs/githooks
+[gitrevisions(7)]: https://git-scm.com/docs/gitrevisions
+[gall]: https://www.gitano.org.uk/gall/
+[gall-api]: file:///usr/share/doc/lua-gall-doc/html/index.html
+
# Backup and restore of a Gitano instance
When gitano-setup is run, the admin needs to specify a Unix user in