diff --git a/docs/repo-hooks.md b/docs/repo-hooks.md index cbb1aac7c..a56f261c7 100644 --- a/docs/repo-hooks.md +++ b/docs/repo-hooks.md @@ -133,3 +133,43 @@ def main(project_list, worktree_list=None, **kwargs): kwargs: Leave this here for forward-compatibility. """ ``` + +### post-sync + +This hook runs when `repo sync` completes without errors. + +Note: This includes cases where no actual checkout may occur. The hook will still run. +For example: +- `repo sync -n` performs network fetches only and skips the checkout phase. +- `repo sync ` only updates the specified project(s). +- Partial failures may still result in a successful exit. + +This hook is useful for post-processing tasks such as setting up git hooks, +bootstrapping configuration files, or running project initialization logic. + +The hook is defined using the existing `` manifest block and is +optional. If the hook script fails or is missing, `repo sync` will still +complete successfully, and the error will be printed as a warning. + +Example: + +```xml + + + + +``` + +The `post-sync.py` file should be defined like: + +```py +def main(repo_topdir=None, **kwargs): + """Main function invoked directly by repo. + + We must use the name "main" as that is what repo requires. + + Args: + repo_topdir: The absolute path to the top-level directory of the repo workspace. + kwargs: Leave this here for forward-compatibility. + """ +``` diff --git a/hooks.py b/hooks.py index f940e3f54..fc31a5ef9 100644 --- a/hooks.py +++ b/hooks.py @@ -25,6 +25,7 @@ from git_refs import HEAD # The API we've documented to hook authors. Keep in sync with repo-hooks.md. _API_ARGS = { "pre-upload": {"project_list", "worktree_list"}, + "post-sync": {"repo_topdir"}, } diff --git a/subcmds/sync.py b/subcmds/sync.py index 20d75dc89..250925f49 100644 --- a/subcmds/sync.py +++ b/subcmds/sync.py @@ -68,6 +68,7 @@ from git_config import GetUrlCookieFile from git_refs import HEAD from git_refs import R_HEADS import git_superproject +from hooks import RepoHook import platform_utils from progress import elapsed_str from progress import jobs_str @@ -623,6 +624,7 @@ later is required to fix a server side protocol bug. action="store_true", help=optparse.SUPPRESS_HELP, ) + RepoHook.AddOptionGroup(p, "post-sync") def _GetBranch(self, manifest_project): """Returns the branch name for getting the approved smartsync manifest. @@ -1847,6 +1849,21 @@ later is required to fix a server side protocol bug. except (KeyboardInterrupt, Exception) as e: raise RepoUnhandledExceptionError(e, aggregate_errors=errors) + # Run post-sync hook only after successful sync + self._RunPostSyncHook(opt) + + def _RunPostSyncHook(self, opt): + """Run post-sync hook if configured in manifest .""" + hook = RepoHook.FromSubcmd( + hook_type="post-sync", + manifest=self.manifest, + opt=opt, + abort_if_user_denies=False, + ) + success = hook.Run(repo_topdir=self.client.topdir) + if not success: + print("Warning: post-sync hook reported failure.") + def _ExecuteHelper(self, opt, args, errors): manifest = self.outer_manifest if not opt.outer_manifest: