diff options
Diffstat (limited to 'docs')
-rw-r--r-- | docs/manifest-format.txt | 23 | ||||
-rw-r--r-- | docs/repo-hooks.md | 105 |
2 files changed, 117 insertions, 11 deletions
diff --git a/docs/manifest-format.txt b/docs/manifest-format.txt index 2a07f199..77784099 100644 --- a/docs/manifest-format.txt +++ b/docs/manifest-format.txt | |||
@@ -27,11 +27,12 @@ following DTD: | |||
27 | remove-project*, | 27 | remove-project*, |
28 | project*, | 28 | project*, |
29 | extend-project*, | 29 | extend-project*, |
30 | repo-hooks?)> | 30 | repo-hooks?, |
31 | include*)> | ||
31 | 32 | ||
32 | <!ELEMENT notice (#PCDATA)> | 33 | <!ELEMENT notice (#PCDATA)> |
33 | 34 | ||
34 | <!ELEMENT remote (EMPTY)> | 35 | <!ELEMENT remote EMPTY> |
35 | <!ATTLIST remote name ID #REQUIRED> | 36 | <!ATTLIST remote name ID #REQUIRED> |
36 | <!ATTLIST remote alias CDATA #IMPLIED> | 37 | <!ATTLIST remote alias CDATA #IMPLIED> |
37 | <!ATTLIST remote fetch CDATA #REQUIRED> | 38 | <!ATTLIST remote fetch CDATA #REQUIRED> |
@@ -39,7 +40,7 @@ following DTD: | |||
39 | <!ATTLIST remote review CDATA #IMPLIED> | 40 | <!ATTLIST remote review CDATA #IMPLIED> |
40 | <!ATTLIST remote revision CDATA #IMPLIED> | 41 | <!ATTLIST remote revision CDATA #IMPLIED> |
41 | 42 | ||
42 | <!ELEMENT default (EMPTY)> | 43 | <!ELEMENT default EMPTY> |
43 | <!ATTLIST default remote IDREF #IMPLIED> | 44 | <!ATTLIST default remote IDREF #IMPLIED> |
44 | <!ATTLIST default revision CDATA #IMPLIED> | 45 | <!ATTLIST default revision CDATA #IMPLIED> |
45 | <!ATTLIST default dest-branch CDATA #IMPLIED> | 46 | <!ATTLIST default dest-branch CDATA #IMPLIED> |
@@ -47,7 +48,7 @@ following DTD: | |||
47 | <!ATTLIST default sync-c CDATA #IMPLIED> | 48 | <!ATTLIST default sync-c CDATA #IMPLIED> |
48 | <!ATTLIST default sync-s CDATA #IMPLIED> | 49 | <!ATTLIST default sync-s CDATA #IMPLIED> |
49 | 50 | ||
50 | <!ELEMENT manifest-server (EMPTY)> | 51 | <!ELEMENT manifest-server EMPTY> |
51 | <!ATTLIST manifest-server url CDATA #REQUIRED> | 52 | <!ATTLIST manifest-server url CDATA #REQUIRED> |
52 | 53 | ||
53 | <!ELEMENT project (annotation*, | 54 | <!ELEMENT project (annotation*, |
@@ -66,32 +67,32 @@ following DTD: | |||
66 | <!ATTLIST project clone-depth CDATA #IMPLIED> | 67 | <!ATTLIST project clone-depth CDATA #IMPLIED> |
67 | <!ATTLIST project force-path CDATA #IMPLIED> | 68 | <!ATTLIST project force-path CDATA #IMPLIED> |
68 | 69 | ||
69 | <!ELEMENT annotation (EMPTY)> | 70 | <!ELEMENT annotation EMPTY> |
70 | <!ATTLIST annotation name CDATA #REQUIRED> | 71 | <!ATTLIST annotation name CDATA #REQUIRED> |
71 | <!ATTLIST annotation value CDATA #REQUIRED> | 72 | <!ATTLIST annotation value CDATA #REQUIRED> |
72 | <!ATTLIST annotation keep CDATA "true"> | 73 | <!ATTLIST annotation keep CDATA "true"> |
73 | 74 | ||
74 | <!ELEMENT copyfile (EMPTY)> | 75 | <!ELEMENT copyfile EMPTY> |
75 | <!ATTLIST copyfile src CDATA #REQUIRED> | 76 | <!ATTLIST copyfile src CDATA #REQUIRED> |
76 | <!ATTLIST copyfile dest CDATA #REQUIRED> | 77 | <!ATTLIST copyfile dest CDATA #REQUIRED> |
77 | 78 | ||
78 | <!ELEMENT linkfile (EMPTY)> | 79 | <!ELEMENT linkfile EMPTY> |
79 | <!ATTLIST linkfile src CDATA #REQUIRED> | 80 | <!ATTLIST linkfile src CDATA #REQUIRED> |
80 | <!ATTLIST linkfile dest CDATA #REQUIRED> | 81 | <!ATTLIST linkfile dest CDATA #REQUIRED> |
81 | 82 | ||
82 | <!ELEMENT extend-project (EMPTY)> | 83 | <!ELEMENT extend-project EMPTY> |
83 | <!ATTLIST extend-project name CDATA #REQUIRED> | 84 | <!ATTLIST extend-project name CDATA #REQUIRED> |
84 | <!ATTLIST extend-project path CDATA #IMPLIED> | 85 | <!ATTLIST extend-project path CDATA #IMPLIED> |
85 | <!ATTLIST extend-project groups CDATA #IMPLIED> | 86 | <!ATTLIST extend-project groups CDATA #IMPLIED> |
86 | 87 | ||
87 | <!ELEMENT remove-project (EMPTY)> | 88 | <!ELEMENT remove-project EMPTY> |
88 | <!ATTLIST remove-project name CDATA #REQUIRED> | 89 | <!ATTLIST remove-project name CDATA #REQUIRED> |
89 | 90 | ||
90 | <!ELEMENT repo-hooks (EMPTY)> | 91 | <!ELEMENT repo-hooks EMPTY> |
91 | <!ATTLIST repo-hooks in-project CDATA #REQUIRED> | 92 | <!ATTLIST repo-hooks in-project CDATA #REQUIRED> |
92 | <!ATTLIST repo-hooks enabled-list CDATA #REQUIRED> | 93 | <!ATTLIST repo-hooks enabled-list CDATA #REQUIRED> |
93 | 94 | ||
94 | <!ELEMENT include (EMPTY)> | 95 | <!ELEMENT include EMPTY> |
95 | <!ATTLIST include name CDATA #REQUIRED> | 96 | <!ATTLIST include name CDATA #REQUIRED> |
96 | ]> | 97 | ]> |
97 | 98 | ||
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 @@ | |||
1 | # repo hooks | ||
2 | |||
3 | [TOC] | ||
4 | |||
5 | Repo provides a mechanism to hook specific stages of the runtime with custom | ||
6 | python modules. All the hooks live in one git project which is checked out by | ||
7 | the manifest (specified during `repo init`), and the manifest itself defines | ||
8 | which hooks are registered. | ||
9 | |||
10 | These are useful to run linters, check formatting, and run quick unittests | ||
11 | before allowing a step to proceed (e.g. before uploading a commit to Gerrit). | ||
12 | |||
13 | A complete example can be found in the Android project. It can be easily | ||
14 | re-used by any repo based project and is not specific to Android.<br> | ||
15 | https://android.googlesource.com/platform/tools/repohooks | ||
16 | |||
17 | ## Approvals | ||
18 | |||
19 | When a hook is processed the first time, the user is prompted for approval. | ||
20 | We don't want to execute arbitrary code without explicit consent. For manifests | ||
21 | fetched via secure protocols (e.g. https://), the user is prompted once. For | ||
22 | insecure protocols (e.g. http://), the user is prompted whenever the registered | ||
23 | repohooks project is updated and a hook is triggered. | ||
24 | |||
25 | ## Manifest Settings | ||
26 | |||
27 | For the full syntax, see the [repo manifest format](./manifest-format.txt). | ||
28 | |||
29 | Here's a short example from | ||
30 | [Android](https://android.googlesource.com/platform/manifest/+/master/default.xml). | ||
31 | The `<project>` line checks out the repohooks git repo to the local | ||
32 | `tools/repohooks/` path. The `<repo-hooks>` line says to look in the project | ||
33 | with the name `platform/tools/repohooks` for hooks to run during the | ||
34 | `pre-upload` phase. | ||
35 | |||
36 | ```xml | ||
37 | <project path="tools/repohooks" name="platform/tools/repohooks" /> | ||
38 | <repo-hooks in-project="platform/tools/repohooks" enabled-list="pre-upload" /> | ||
39 | ``` | ||
40 | |||
41 | ## Source Layout | ||
42 | |||
43 | The repohooks git repo should have a python file with the same name as the hook. | ||
44 | So if you want to support the `pre-upload` hook, you'll need to create a file | ||
45 | named `pre-upload.py`. Repo will dynamically load that module when processing | ||
46 | the hook and then call the `main` function in it. | ||
47 | |||
48 | Hooks should have their `main` accept `**kwargs` for future compatibility. | ||
49 | |||
50 | ## Runtime | ||
51 | |||
52 | Hook return values are ignored. | ||
53 | |||
54 | Any uncaught exceptions from the hook will cause the step to fail. This is | ||
55 | intended as a fallback safety check though rather than the normal flow. If | ||
56 | you want your hook to trigger a failure, it should call `sys.exit()` (after | ||
57 | displaying relevant diagnostics). | ||
58 | |||
59 | Output (stdout & stderr) are not filtered in any way. Hooks should generally | ||
60 | not be too verbose. A short summary is nice, and some status information when | ||
61 | long running operations occur, but long/verbose output should be used only if | ||
62 | the hook ultimately fails. | ||
63 | |||
64 | The hook runs from the top level of the git repo where the operation is started. | ||
65 | e.g. If you're in the git repo `src/foo/`, that is where the hook runs, even if | ||
66 | the `repo` command was started from a subdir like `src/foo/bar/`. | ||
67 | |||
68 | Python's `sys.path` is modified so that the top of repohooks directory comes | ||
69 | first. This should help simplify the hook logic to easily allow importing of | ||
70 | local modules. | ||
71 | |||
72 | Repo does not modify the state of the git checkout. This means that the hooks | ||
73 | might be running in a dirty git repo with many commits and checked out to the | ||
74 | latest one. If the hook wants to operate on specific git commits, it needs to | ||
75 | manually discover the list of pending commits, extract the diff/commit, and | ||
76 | then check it directly. Hooks should not normally modify the active git repo | ||
77 | (such as checking out a specific commit to run checks) without first prompting | ||
78 | the user. Although user interaction is discouraged in the common case, it can | ||
79 | be useful when deploying automatic fixes. | ||
80 | |||
81 | ## Hooks | ||
82 | |||
83 | Here are all the points available for hooking. | ||
84 | |||
85 | ### pre-upload | ||
86 | |||
87 | This hook runs when people run `repo upload`. | ||
88 | |||
89 | The `pre-upload.py` file should be defined like: | ||
90 | |||
91 | ```py | ||
92 | def main(project_list, worktree_list=None, **kwargs): | ||
93 | """Main function invoked directly by repo. | ||
94 | |||
95 | We must use the name "main" as that is what repo requires. | ||
96 | |||
97 | Args: | ||
98 | project_list: List of projects to run on. | ||
99 | worktree_list: A list of directories. It should be the same length as | ||
100 | project_list, so that each entry in project_list matches with a | ||
101 | directory in worktree_list. If None, we will attempt to calculate | ||
102 | the directories automatically. | ||
103 | kwargs: Leave this here for forward-compatibility. | ||
104 | """ | ||
105 | ``` | ||