Skip to content

Commit 82d500e

Browse files
Chao-Shun-ChengLUCI
authored andcommitted
sync: support post-sync hook in <repo-hooks>
Add support for a new hook type "post-sync" declared in the manifest using <repo-hooks>. This allows executing a script automatically after a successful `repo sync`. This is useful for initializing developer environments, installing project-wide Git hooks, generating configs, and other post-sync automation tasks. Example manifest usage: <project name="myorg/repo-hooks" path="hooks" revision="main" /> <repo-hooks in-project="myorg/repo-hooks" enabled-list="post-sync"> <hook name="post-sync" /> </repo-hooks> The hook script must be named `post-sync.py` and located at the root of the hook project. The post-sync hook does not block `repo sync`; if the script fails, the sync still completes successfully with a warning. Test: Added `post-sync.py` in hook project and verified it runs after `repo sync` Bug: b/421694721 Change-Id: I69f3158f0fc319d73a85028d6e90fea02c1dc8c8 Signed-off-by: Kenny Cheng <[email protected]> Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/480581 Reviewed-by: Scott Lee <[email protected]> Reviewed-by: Gavin Mak <[email protected]>
1 parent 21269c3 commit 82d500e

File tree

3 files changed

+58
-0
lines changed

3 files changed

+58
-0
lines changed

docs/repo-hooks.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,43 @@ def main(project_list, worktree_list=None, **kwargs):
133133
kwargs: Leave this here for forward-compatibility.
134134
"""
135135
```
136+
137+
### post-sync
138+
139+
This hook runs when `repo sync` completes without errors.
140+
141+
Note: This includes cases where no actual checkout may occur. The hook will still run.
142+
For example:
143+
- `repo sync -n` performs network fetches only and skips the checkout phase.
144+
- `repo sync <project>` only updates the specified project(s).
145+
- Partial failures may still result in a successful exit.
146+
147+
This hook is useful for post-processing tasks such as setting up git hooks,
148+
bootstrapping configuration files, or running project initialization logic.
149+
150+
The hook is defined using the existing `<repo-hooks>` manifest block and is
151+
optional. If the hook script fails or is missing, `repo sync` will still
152+
complete successfully, and the error will be printed as a warning.
153+
154+
Example:
155+
156+
```xml
157+
<project name="myorg/dev-tools" path="tools" revision="main" />
158+
<repo-hooks in-project="myorg/dev-tools" enabled-list="post-sync">
159+
<hook name="post-sync" />
160+
</repo-hooks>
161+
```
162+
163+
The `post-sync.py` file should be defined like:
164+
165+
```py
166+
def main(repo_topdir=None, **kwargs):
167+
"""Main function invoked directly by repo.
168+
169+
We must use the name "main" as that is what repo requires.
170+
171+
Args:
172+
repo_topdir: The absolute path to the top-level directory of the repo workspace.
173+
kwargs: Leave this here for forward-compatibility.
174+
"""
175+
```

hooks.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
# The API we've documented to hook authors. Keep in sync with repo-hooks.md.
2626
_API_ARGS = {
2727
"pre-upload": {"project_list", "worktree_list"},
28+
"post-sync": {"repo_topdir"},
2829
}
2930

3031

subcmds/sync.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ def _rlimit_nofile():
6868
from git_refs import HEAD
6969
from git_refs import R_HEADS
7070
import git_superproject
71+
from hooks import RepoHook
7172
import platform_utils
7273
from progress import elapsed_str
7374
from progress import jobs_str
@@ -623,6 +624,7 @@ def _Options(self, p, show_smart=True):
623624
action="store_true",
624625
help=optparse.SUPPRESS_HELP,
625626
)
627+
RepoHook.AddOptionGroup(p, "post-sync")
626628

627629
def _GetBranch(self, manifest_project):
628630
"""Returns the branch name for getting the approved smartsync manifest.
@@ -1847,6 +1849,21 @@ def Execute(self, opt, args):
18471849
except (KeyboardInterrupt, Exception) as e:
18481850
raise RepoUnhandledExceptionError(e, aggregate_errors=errors)
18491851

1852+
# Run post-sync hook only after successful sync
1853+
self._RunPostSyncHook(opt)
1854+
1855+
def _RunPostSyncHook(self, opt):
1856+
"""Run post-sync hook if configured in manifest <repo-hooks>."""
1857+
hook = RepoHook.FromSubcmd(
1858+
hook_type="post-sync",
1859+
manifest=self.manifest,
1860+
opt=opt,
1861+
abort_if_user_denies=False,
1862+
)
1863+
success = hook.Run(repo_topdir=self.client.topdir)
1864+
if not success:
1865+
print("Warning: post-sync hook reported failure.")
1866+
18501867
def _ExecuteHelper(self, opt, args, errors):
18511868
manifest = self.outer_manifest
18521869
if not opt.outer_manifest:

0 commit comments

Comments
 (0)