1 # AOSP Presubmit Hooks 2 3 [TOC] 4 5 This repo holds hooks that get run by repo during the upload phase. They 6 perform various checks automatically such as running linters on your code. 7 8 Note: Currently all hooks are disabled by default. Each repo must explicitly 9 turn on any hook it wishes to enforce. 10 11 ## Usage 12 13 Normally these execute automatically when you run `repo upload`. If you want to 14 run them by hand, you can execute `pre-upload.py` directly. By default, that 15 will scan the active repo and process all commits that haven't yet been merged. 16 See its help for more info. 17 18 ### Bypassing 19 20 Sometimes you might want to bypass the upload checks. While this is **strongly 21 discouraged** (often failures you add will affect others and block them too), 22 sometimes there are valid reasons for this. You can simply use the option 23 `--no-verify` when running `repo upload` to skip all upload checks. This will 24 skip **all** checks and not just specific ones. It should be used only after 25 having run & evaluated the upload output previously. 26 27 # Config Files 28 29 There are two types of config files: 30 * Repo project-wide settings (e.g. all of AOSP). These set up defaults for all 31 projects that are checked out via a single manifest. 32 * Project-local settings (e.g. a single .git repo). These control settings for 33 the local project you're working on. 34 35 The merging of these config files control the hooks/checks that get run when 36 running `repo upload`. 37 38 ## GLOBAL-PREUPLOAD.cfg 39 40 These are the manifest-wide defaults and can be located in two places: 41 * `.repo/manifests/GLOBAL-PREUPLOAD.cfg`: The manifest git repo. 42 Simply check this in to the manifest git repo and you're done. 43 * `GLOBAL-PREUPLOAD.cfg`: The top level of the repo checkout. 44 For manifests that don't have a project checked out at the top level, 45 you can use repo's `<copyfile>` directive. 46 47 These config files will be loaded first before stacking `PREUPLOAD.cfg` 48 settings on top. 49 50 ## PREUPLOAD.cfg 51 52 This file are checked in the top of a specific git repository. Stacking them 53 in subdirectories (to try and override parent settings) is not supported. 54 55 ## Example 56 57 ``` 58 [Options] 59 ignore_merged_commits = true 60 61 [Hook Scripts] 62 name = script --with args ${PREUPLOAD_FILES} 63 64 [Builtin Hooks] 65 cpplint = true 66 67 [Builtin Hooks Options] 68 cpplint = --filter=-x ${PREUPLOAD_FILES} 69 70 [Tool Paths] 71 clang-format = /usr/bin/clang-format 72 ``` 73 74 ## Environment 75 76 Hooks are executed in the top directory of the git repository. All paths should 77 generally be relative to that point. 78 79 A few environment variables are set so scripts don't need to discover things. 80 81 * `REPO_PROJECT`: The name of the project. 82 e.g. `platform/tools/repohooks` 83 * `REPO_PATH`: The path to the project relative to the root. 84 e.g. `tools/repohooks` 85 * `REPO_REMOTE`: The name of the git remote. 86 e.g. `aosp`. 87 * `REPO_LREV`: The name of the remote revision, translated to a local tracking 88 branch. This is typically latest commit in the remote-tracking branch. 89 e.g. `ec044d3e9b608ce275f02092f86810a3ba13834e` 90 * `REPO_RREV`: The remote revision. 91 e.g. `master` 92 * `PREUPLOAD_COMMIT`: The commit that is currently being checked. 93 e.g. `1f89dce0468448fa36f632d2fc52175cd6940a91` 94 95 ## Placeholders 96 97 A few keywords are recognized to pass down settings. These are **not** 98 environment variables, but are expanded inline. Files with whitespace and 99 such will be expanded correctly via argument positions, so do not try to 100 force your own quote handling. 101 102 * `${PREUPLOAD_FILES}`: List of files to operate on. 103 * `${PREUPLOAD_COMMIT}`: Commit hash. 104 * `${PREUPLOAD_COMMIT_MESSAGE}`: Commit message. 105 106 Some variables are available to make it easier to handle OS differences. These 107 are automatically expanded for you: 108 109 * `${REPO_ROOT}`: The absolute path of the root of the repo checkout. 110 * `${BUILD_OS}`: The string `darwin-x86` for macOS and the string `linux-x86` 111 for Linux/x86. 112 113 ## [Options] 114 115 This section allows for setting options that affect the overall behavior of the 116 pre-upload checks. The following options are recognized: 117 118 * `ignore_merged_commits`: If set to `true`, the hooks will not run on commits 119 that are merged. Hooks will still run on the merge commit itself. 120 121 ## [Hook Scripts] 122 123 This section allows for completely arbitrary hooks to run on a per-repo basis. 124 125 The key can be any name (as long as the syntax is valid), as can the program 126 that is executed. The key is used as the name of the hook for reporting purposes, 127 so it should be at least somewhat descriptive. 128 129 ``` 130 [Hook Scripts] 131 my_first_hook = program --gogog ${PREUPLOAD_FILES} 132 another_hook = funtimes --i-need "some space" ${PREUPLOAD_FILES} 133 some_fish = linter --ate-a-cat ${PREUPLOAD_FILES} 134 some_cat = formatter --cat-commit ${PREUPLOAD_COMMIT} 135 some_dog = tool --no-cat-in-commit-message ${PREUPLOAD_COMMIT_MESSAGE} 136 ``` 137 138 ## [Builtin Hooks] 139 140 This section allows for turning on common/builtin hooks. There are a bunch of 141 canned hooks already included geared towards AOSP style guidelines. 142 143 * `checkpatch`: Run commits through the Linux kernel's `checkpatch.pl` script. 144 * `clang_format`: Run git-clang-format against the commit. The default style is 145 `file`. 146 * `commit_msg_bug_field`: Require a valid `Bug:` line. 147 * `commit_msg_changeid_field`: Require a valid `Change-Id:` Gerrit line. 148 * `commit_msg_test_field`: Require a `Test:` line. 149 * `cpplint`: Run through the cpplint tool (for C++ code). 150 * `gofmt`: Run Go code through `gofmt`. 151 * `google_java_format`: Run Java code through 152 [`google-java-format`](https://github.com/google/google-java-format) 153 * `jsonlint`: Verify JSON code is sane. 154 * `pylint`: Run Python code through `pylint`. 155 * `xmllint`: Run XML code through `xmllint`. 156 157 Note: Builtin hooks tend to match specific filenames (e.g. `.json`). If no 158 files match in a specific commit, then the hook will be skipped for that commit. 159 160 ``` 161 [Builtin Hooks] 162 # Turn on cpplint checking. 163 cpplint = true 164 # Turn off gofmt checking. 165 gofmt = false 166 ``` 167 168 ## [Builtin Hooks Options] 169 170 Used to customize the behavior of specific `[Builtin Hooks]`. Any arguments set 171 here will be passed directly to the linter in question. This will completely 172 override any existing default options, so be sure to include everything you need 173 (especially `${PREUPLOAD_FILES}` -- see below). 174 175 Quoting is handled naturally. i.e. use `"a b c"` to pass an argument with 176 whitespace. 177 178 See [Placeholders](#Placeholders) for variables you can expand automatically. 179 180 ``` 181 [Builtin Hooks Options] 182 # Pass more filter args to cpplint. 183 cpplint = --filter=-x ${PREUPLOAD_FILES} 184 ``` 185 186 ## [Tool Paths] 187 188 Some builtin hooks need to call external executables to work correctly. By 189 default it will call those tools from the user's `$PATH`, but the paths of those 190 executables can be overridden through `[Tool Paths]`. This is helpful to 191 provide consistent behavior for developers across different OS and Linux 192 distros/versions. The following tools are recognized: 193 194 * `clang-format`: used for the `clang_format` builtin hook. 195 * `cpplint`: used for the `cpplint` builtin hook. 196 * `git-clang-format`: used for the `clang_format` builtin hook. 197 * `gofmt`: used for the `gofmt` builtin hook. 198 * `google-java-format`: used for the `google_java_format` builtin hook. 199 * `google-java-format-diff`: used for the `google_java_format` builtin hook. 200 * `pylint`: used for the `pylint` builtin hook. 201 202 See [Placeholders](#Placeholders) for variables you can expand automatically. 203 204 ``` 205 [Tool Paths] 206 # Pass absolute paths. 207 clang-format = /usr/bin/clang-format 208 # Or paths relative to the top of the git project. 209 clang-format = prebuilts/bin/clang-format 210 # Or paths relative to the repo root. 211 clang-format = ${REPO_ROOT}/prebuilts/clang/host/${BUILD_OS}/clang-stable/bin/clang-format 212 ``` 213 214 # Hook Developers 215 216 These are notes for people updating the `pre-upload.py` hook itself: 217 218 * Don't worry about namespace collisions. The `pre-upload.py` script is loaded 219 and exec-ed in its own context. The only entry-point that matters is `main`. 220 * New hooks can be added in `rh/hooks.py`. Be sure to keep the list up-to-date 221 with the documentation in this file. 222 223 ### Warnings 224 225 If the return code of a hook is 77, then it is assumed to be a warning. The 226 output will be printed to the terminal, but uploading will still be allowed 227 without a bypass being required. 228 229 ## TODO/Limitations 230 231 * `pylint` should support per-directory pylintrc files. 232 * Some checkers operate on the files as they exist in the filesystem. This is 233 not easy to fix because the linters require not just the modified file but the 234 entire repo in order to perform full checks. e.g. `pylint` needs to know what 235 other modules exist locally to verify their API. We can support this case by 236 doing a full checkout of the repo in a temp dir, but this can slow things down 237 a lot. Will need to consider a `PREUPLOAD.cfg` knob. 238 * We need to add `pylint` tool to the AOSP manifest and use that local copy 239 instead of relying on the version that is in $PATH. 240 * Should make file extension filters configurable. All hooks currently declare 241 their own list of files like `.cc` and `.py` and `.xml`. 242 * Add more checkers. 243 * `clang-check`: Runs static analyzers against code. 244 * License checking (like require AOSP header). 245 * Whitespace checking (trailing/tab mixing/etc...). 246 * Long line checking. 247 * Commit message checks (correct format/BUG/TEST/SOB tags/etc...). 248 * Markdown (gitiles) validator. 249 * Spell checker. 250