diff --git a/README.md b/README.md index e35f8e99..250d08e5 100644 --- a/README.md +++ b/README.md @@ -11,4 +11,6 @@ that you can put anywhere in your path. * Source: https://code.google.com/p/git-repo/ * Overview: https://source.android.com/source/developing.html * Docs: https://source.android.com/source/using-repo.html +* [repo Manifest Format](./docs/manifest-format.txt) +* [repo Hooks](./docs/repo-hooks.md) * [Submitting patches](./SUBMITTING_PATCHES.md) diff --git a/docs/repo-hooks.md b/docs/repo-hooks.md new file mode 100644 index 00000000..c8eb945f --- /dev/null +++ b/docs/repo-hooks.md @@ -0,0 +1,105 @@ +# repo hooks + +[TOC] + +Repo provides a mechanism to hook specific stages of the runtime with custom +python modules. All the hooks live in one git project which is checked out by +the manifest (specified during `repo init`), and the manifest itself defines +which hooks are registered. + +These are useful to run linters, check formatting, and run quick unittests +before allowing a step to proceed (e.g. before uploading a commit to Gerrit). + +A complete example can be found in the Android project. It can be easily +re-used by any repo based project and is not specific to Android.
+https://android.googlesource.com/platform/tools/repohooks + +## Approvals + +When a hook is processed the first time, the user is prompted for approval. +We don't want to execute arbitrary code without explicit consent. For manifests +fetched via secure protocols (e.g. https://), the user is prompted once. For +insecure protocols (e.g. http://), the user is prompted whenever the registered +repohooks project is updated and a hook is triggered. + +## Manifest Settings + +For the full syntax, see the [repo manifest format](./manifest-format.txt). + +Here's a short example from +[Android](https://android.googlesource.com/platform/manifest/+/master/default.xml). +The `` line checks out the repohooks git repo to the local +`tools/repohooks/` path. The `` line says to look in the project +with the name `platform/tools/repohooks` for hooks to run during the +`pre-upload` phase. + +```xml + + +``` + +## Source Layout + +The repohooks git repo should have a python file with the same name as the hook. +So if you want to support the `pre-upload` hook, you'll need to create a file +named `pre-upload.py`. Repo will dynamically load that module when processing +the hook and then call the `main` function in it. + +Hooks should have their `main` accept `**kwargs` for future compatibility. + +## Runtime + +Hook return values are ignored. + +Any uncaught exceptions from the hook will cause the step to fail. This is +intended as a fallback safety check though rather than the normal flow. If +you want your hook to trigger a failure, it should call `sys.exit()` (after +displaying relevant diagnostics). + +Output (stdout & stderr) are not filtered in any way. Hooks should generally +not be too verbose. A short summary is nice, and some status information when +long running operations occur, but long/verbose output should be used only if +the hook ultimately fails. + +The hook runs from the top level of the git repo where the operation is started. +e.g. If you're in the git repo `src/foo/`, that is where the hook runs, even if +the `repo` command was started from a subdir like `src/foo/bar/`. + +Python's `sys.path` is modified so that the top of repohooks directory comes +first. This should help simplify the hook logic to easily allow importing of +local modules. + +Repo does not modify the state of the git checkout. This means that the hooks +might be running in a dirty git repo with many commits and checked out to the +latest one. If the hook wants to operate on specific git commits, it needs to +manually discover the list of pending commits, extract the diff/commit, and +then check it directly. Hooks should not normally modify the active git repo +(such as checking out a specific commit to run checks) without first prompting +the user. Although user interaction is discouraged in the common case, it can +be useful when deploying automatic fixes. + +## Hooks + +Here are all the points available for hooking. + +### pre-upload + +This hook runs when people run `repo upload`. + +The `pre-upload.py` file should be defined like: + +```py +def main(project_list, worktree_list=None, **kwargs): + """Main function invoked directly by repo. + + We must use the name "main" as that is what repo requires. + + Args: + project_list: List of projects to run on. + worktree_list: A list of directories. It should be the same length as + project_list, so that each entry in project_list matches with a + directory in worktree_list. If None, we will attempt to calculate + the directories automatically. + kwargs: Leave this here for forward-compatibility. + """ +```