• Home
Name Date Size #Lines LOC

..--

rh/04-Jul-2025-4,6773,349

tools/04-Jul-2025-18,08713,506

.gitignoreD04-Jul-20256 21

OWNERSD04-Jul-2025195 119

PREUPLOAD.cfgD04-Jul-2025825 2018

README.mdD04-Jul-202513.7 KiB350276

pre-upload.pyD04-Jul-202523.4 KiB658514

README.md

1# AOSP Preupload Hooks
2
3This repo holds hooks that get run by [repo] during the upload phase.  They
4perform various checks automatically such as running linters on your code.
5
6Note: Currently all hooks are disabled by default.  Each repo must explicitly
7turn on any hook it wishes to enforce.
8
9[TOC]
10
11## Usage
12
13Normally these execute automatically when you run `repo upload`.  If you want to
14run them by hand, you can execute `pre-upload.py` directly.  By default, that
15will scan the active repo and process all commits that haven't yet been merged.
16See its help for more info.
17
18### Bypassing
19
20Sometimes you might want to bypass the upload checks.  While this is **strongly
21discouraged** (often failures you add will affect others and block them too),
22sometimes there are valid reasons for this.  You can simply use the option
23`--ignore-hooks` when running `repo upload` to ignore all hook errors.
24This will ignore **all** hook errors and not just specific ones.
25
26# Config Files
27
28There are two types of config files:
29* Repo project-wide settings (e.g. all of AOSP).  These set up defaults for all
30  projects that are checked out via a single manifest.
31* Project-local settings (e.g. a single .git repo).  These control settings for
32  the local project you're working on.
33
34The merging of these config files control the hooks/checks that get run when
35running `repo upload`.
36
37## GLOBAL-PREUPLOAD.cfg
38
39These are the manifest-wide defaults and can be located in two places:
40* `.repo/manifests/GLOBAL-PREUPLOAD.cfg`: The manifest git repo.
41  Simply check this in to the manifest git repo and you're done.
42* `GLOBAL-PREUPLOAD.cfg`: The top level of the repo checkout.
43  For manifests that don't have a project checked out at the top level,
44  you can use repo's `<copyfile>` directive.
45
46These config files will be loaded first before stacking `PREUPLOAD.cfg`
47settings on top.
48
49## PREUPLOAD.cfg
50
51This file is checked in the top of a specific git repository.  Stacking them
52in subdirectories (to try and override parent settings) is not supported.
53
54## Example
55
56```
57# Per-project `repo upload` hook settings.
58# https://android.googlesource.com/platform/tools/repohooks
59
60[Options]
61ignore_merged_commits = true
62
63[Hook Scripts]
64name = script --with args ${PREUPLOAD_FILES}
65
66[Builtin Hooks]
67cpplint = true
68
69[Builtin Hooks Options]
70cpplint = --filter=-x ${PREUPLOAD_FILES}
71
72[Tool Paths]
73clang-format = /usr/bin/clang-format
74```
75
76## Environment
77
78Hooks are executed in the top directory of the git repository.  All paths should
79generally be relative to that point.
80
81A few environment variables are set so scripts don't need to discover things.
82
83* `REPO_PROJECT`: The name of the project.
84   e.g. `platform/tools/repohooks`
85* `REPO_PATH`: The path to the project relative to the root.
86   e.g. `tools/repohooks`
87* `REPO_REMOTE`: The name of the git remote.
88   e.g. `aosp`.
89* `REPO_LREV`: The name of the remote revision, translated to a local tracking
90   branch. This is typically latest commit in the remote-tracking branch.
91   e.g. `ec044d3e9b608ce275f02092f86810a3ba13834e`
92* `REPO_RREV`: The remote revision.
93   e.g. `master`
94* `PREUPLOAD_COMMIT`: The commit that is currently being checked.
95   e.g. `1f89dce0468448fa36f632d2fc52175cd6940a91`
96
97## Placeholders
98
99A few keywords are recognized to pass down settings.  These are **not**
100environment variables, but are expanded inline.  Files with whitespace and
101such will be expanded correctly via argument positions, so do not try to
102force your own quote handling.
103
104* `${PREUPLOAD_FILES}`: List of files to operate on.
105* `${PREUPLOAD_FILES_PREFIXED}`: A list of files to operate on.
106   Any string preceding/attached to the keyword ${PREUPLOAD_FILES_PREFIXED}
107   will be repeated for each file automatically. If no string is preceding/attached
108   to the keyword, the previous argument will be repeated before each file.
109* `${PREUPLOAD_COMMIT}`: Commit hash.
110* `${PREUPLOAD_COMMIT_MESSAGE}`: Commit message.
111
112Some variables are available to make it easier to handle OS differences.  These
113are automatically expanded for you:
114
115* `${REPO_PATH}`: The path to the project relative to the root.
116  e.g. `tools/repohooks`
117* `${REPO_PROJECT}`: The name of the project.
118  e.g. `platform/tools/repohooks`
119* `${REPO_ROOT}`: The absolute path of the root of the repo checkout.  If the
120  project is in a submanifest, this points to the root of the submanifest.
121* `${REPO_OUTER_ROOT}`: The absolute path of the root of the repo checkout.
122  This always points to the root of the overall repo checkout.
123* `${BUILD_OS}`: The string `darwin-x86` for macOS and the string `linux-x86`
124  for Linux/x86.
125
126### Examples
127
128Here are some examples of using the placeholders.
129Consider this sample config file.
130```
131[Hook Scripts]
132lister = ls ${PREUPLOAD_FILES}
133checker prefix = check --file=${PREUPLOAD_FILES_PREFIXED}
134checker flag = check --file ${PREUPLOAD_FILES_PREFIXED}
135```
136
137With a commit that changes `path1/file1` and `path2/file2`, then this will run
138programs with the arguments:
139* `['ls', 'path1/file1', 'path2/file2']`
140* `['check', '--file=path1/file1', '--file=path2/file2']`
141* `['check', '--file', 'path1/file1', '--file', 'path2/file2']`
142
143## [Options]
144
145This section allows for setting options that affect the overall behavior of the
146pre-upload checks.  The following options are recognized:
147
148* `ignore_merged_commits`: If set to `true`, the hooks will not run on commits
149  that are merged.  Hooks will still run on the merge commit itself.
150
151## [Hook Scripts]
152
153This section allows for completely arbitrary hooks to run on a per-repo basis.
154
155The key can be any name (as long as the syntax is valid), as can the program
156that is executed. The key is used as the name of the hook for reporting purposes,
157so it should be at least somewhat descriptive.
158
159Whitespace in the key name is OK!
160
161The keys must be unique as duplicates will silently clobber earlier values.
162
163You do not need to send stderr to stdout.  The tooling will take care of
164merging them together for you automatically.
165
166```
167[Hook Scripts]
168my first hook = program --gogog ${PREUPLOAD_FILES}
169another hook = funtimes --i-need "some space" ${PREUPLOAD_FILES}
170some fish = linter --ate-a-cat ${PREUPLOAD_FILES}
171some cat = formatter --cat-commit ${PREUPLOAD_COMMIT}
172some dog = tool --no-cat-in-commit-message ${PREUPLOAD_COMMIT_MESSAGE}
173```
174
175## [Builtin Hooks]
176
177This section allows for turning on common/builtin hooks.  There are a bunch of
178canned hooks already included geared towards AOSP style guidelines.
179
180* `aidl_format`: Run AIDL files (.aidl) through `aidl-format`.
181* `aosp_license`: Check if all new-added file have valid AOSP license headers.
182* `android_test_mapping_format`: Validate TEST_MAPPING files in Android source
183  code. Refer to go/test-mapping for more details.
184* `bpfmt`: Run Blueprint files (.bp) through `bpfmt`.
185* `checkpatch`: Run commits through the Linux kernel's `checkpatch.pl` script.
186* `clang_format`: Run git-clang-format against the commit. The default style is
187  `file`.
188* `commit_msg_bug_field`: Require a valid `Bug:` line.
189* `commit_msg_changeid_field`: Require a valid `Change-Id:` Gerrit line.
190* `commit_msg_prebuilt_apk_fields`: Require badging and build information for
191  prebuilt APKs.
192* `commit_msg_relnote_field_format`: Check for possible misspellings of the
193  `Relnote:` field and that multiline release notes are properly formatted with
194  quotes.
195* `commit_msg_relnote_for_current_txt`: Check that CLs with changes to
196  current.txt or public_plus_experimental_current.txt also contain a
197  `Relnote:` field in the commit message.
198* `commit_msg_test_field`: Require a `Test:` line.
199* `cpplint`: Run through the cpplint tool (for C++ code).
200* `gofmt`: Run Go code through `gofmt`.
201* `google_java_format`: Run Java code through
202  [`google-java-format`](https://github.com/google/google-java-format).
203  Supports an additional option --include-dirs, which if specified will limit
204  enforcement to only files under the specified directories.
205* `jsonlint`: Verify JSON code is sane.
206* `ktfmt`: Run Kotlin code through `ktfmt`. Supports an additional option
207  --include-dirs, which if specified will limit enforcement to only files under
208  the specified directories.
209* `pylint`: Alias of `pylint3`.
210* `pylint2`: Ignored for compatibility with old configs.
211* `pylint3`: Run Python code through `pylint` using Python 3.
212* `rustfmt`: Run Rust code through `rustfmt`.
213* `xmllint`: Run XML code through `xmllint`.
214
215Note: Builtin hooks tend to match specific filenames (e.g. `.json`).  If no
216files match in a specific commit, then the hook will be skipped for that commit.
217
218```
219[Builtin Hooks]
220# Turn on cpplint checking.
221cpplint = true
222# Turn off gofmt checking.
223gofmt = false
224```
225
226## [Builtin Hooks Options]
227
228Used to customize the behavior of specific `[Builtin Hooks]`.  Any arguments set
229here will be passed directly to the linter in question.  This will completely
230override any existing default options, so be sure to include everything you need
231(especially `${PREUPLOAD_FILES}` -- see below).
232
233Quoting is handled naturally.  i.e. use `"a b c"` to pass an argument with
234whitespace.
235
236See [Placeholders](#Placeholders) for variables you can expand automatically.
237
238```
239[Builtin Hooks Options]
240# Pass more filter args to cpplint.
241cpplint = --filter=-x ${PREUPLOAD_FILES}
242```
243
244## [Builtin Hooks Exclude Paths]
245
246*** note
247This section can only be added to the repo project-wide settings
248[GLOBAL-PREUPLOAD.cfg](#GLOBAL_PREUPLOAD_cfg).
249***
250
251Used to explicitly exclude some projects when processing a hook. With this
252section, it is possible to define a hook that should apply to the majority of
253projects except a few.
254
255An entry must completely match the project's `REPO_PATH`. The paths can use the
256[shell-style wildcards](https://docs.python.org/library/fnmatch.html) and
257quotes. For advanced cases, it is possible to use a [regular
258expression](https://docs.python.org/howto/regex.html) by using the `^` prefix.
259
260```
261[Builtin Hooks Exclude Paths]
262# Run cpplint on all projects except ones under external/ and vendor/.
263# The "external" and "vendor" projects, if they exist, will still run cpplint.
264cpplint = external/* vendor/*
265
266# Run rustfmt on all projects except ones under external/.  All projects under
267# hardware/ will be excluded except for ones starting with hardware/google (due to
268# the negative regex match).
269rustfmt = external/ ^hardware/(!?google)
270```
271
272## [Tool Paths]
273
274Some builtin hooks need to call external executables to work correctly.  By
275default it will call those tools from the user's `$PATH`, but the paths of those
276executables can be overridden through `[Tool Paths]`.  This is helpful to
277provide consistent behavior for developers across different OS and Linux
278distros/versions.  The following tools are recognized:
279
280* `aidl-format`: used for the `aidl_format` builtin hook.
281* `android-test-mapping-format`: used for the `android_test_mapping_format`
282  builtin hook.
283* `bpfmt`: used for the `bpfmt` builtin hook.
284* `clang-format`: used for the `clang_format` builtin hook.
285* `cpplint`: used for the `cpplint` builtin hook.
286* `git-clang-format`: used for the `clang_format` builtin hook.
287* `gofmt`: used for the `gofmt` builtin hook.
288* `google-java-format`: used for the `google_java_format` builtin hook.
289* `google-java-format-diff`: used for the `google_java_format` builtin hook.
290* `ktfmt`: used for the `ktfmt` builtin hook.
291* `pylint`: used for the `pylint` builtin hook.
292* `rustfmt`: used for the `rustfmt` builtin hook.
293
294See [Placeholders](#Placeholders) for variables you can expand automatically.
295
296```
297[Tool Paths]
298# Pass absolute paths.
299clang-format = /usr/bin/clang-format
300# Or paths relative to the top of the git project.
301clang-format = prebuilts/bin/clang-format
302# Or paths relative to the repo root.
303clang-format = ${REPO_ROOT}/prebuilts/clang/host/${BUILD_OS}/clang-stable/bin/clang-format
304```
305
306# Hook Developers
307
308These are notes for people updating the `pre-upload.py` hook itself:
309
310* Don't worry about namespace collisions.  The `pre-upload.py` script is loaded
311  and exec-ed in its own context.  The only entry-point that matters is `main`.
312* New hooks can be added in `rh/hooks.py`.  Be sure to keep the list up-to-date
313  with the documentation in this file.
314* Python versions
315  * Code loaded & run by end users (i.e. during `repo upload`) should stick to
316    older versions of Python.  We expect users to run on a variety of platforms
317    where Python is not the latest (e.g. Ubuntu LTS that is years behind).  We
318    currently require **Python 3.6**.  This aligns with [repo's supported Python
319    versions](https://gerrit.googlesource.com/git-repo/+/HEAD/docs/python-support.md).
320  * Code only run by repohooks developers may use much newer versions of Python
321    to keep things simple, especially as we don't readily test older versions.
322
323## Warnings
324
325If the return code of a hook is 77, then it is assumed to be a warning.  The
326output will be printed to the terminal, but uploading will still be allowed
327without a bypass being required.
328
329# TODO/Limitations
330
331* Some checkers operate on the files as they exist in the filesystem.  This is
332  not easy to fix because the linters require not just the modified file but the
333  entire repo in order to perform full checks.  e.g. `pylint` needs to know what
334  other modules exist locally to verify their API.  We can support this case by
335  doing a full checkout of the repo in a temp dir, but this can slow things down
336  a lot.  Will need to consider a `PREUPLOAD.cfg` knob.
337* We need to add `pylint` tool to the AOSP manifest and use that local copy
338  instead of relying on the version that is in $PATH.
339* Should make file extension filters configurable.  All hooks currently declare
340  their own list of files like `.cc` and `.py` and `.xml`.
341* Add more checkers.
342  * `clang-check`: Runs static analyzers against code.
343  * Whitespace checking (trailing/tab mixing/etc...).
344  * Long line checking.
345  * Commit message checks (correct format/BUG/TEST/SOB tags/etc...).
346  * Markdown (gitiles) validator.
347  * Spell checker.
348
349[repo]: https://gerrit.googlesource.com/git-repo/
350