summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKenny Cheng <chao.shun.cheng.tw@gmail.com>2025-06-02 21:55:04 +0800
committerLUCI <gerrit-scoped@luci-project-accounts.iam.gserviceaccount.com>2025-07-01 16:11:50 -0700
commit82d500eb7aa93f9bff66a4358a08d2ba2d599550 (patch)
tree60d2003fa946943a13bfb9a96bd88bb60167c57f
parent21269c3eedc428610a5cab1494b2459a7e939fc7 (diff)
downloadgit-repo-82d500eb7aa93f9bff66a4358a08d2ba2d599550.tar.gz
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 <chao.shun.cheng.tw@gmail.com> Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/480581 Reviewed-by: Scott Lee <ddoman@google.com> Reviewed-by: Gavin Mak <gavinmak@google.com>
-rw-r--r--docs/repo-hooks.md40
-rw-r--r--hooks.py1
-rw-r--r--subcmds/sync.py17
3 files changed, 58 insertions, 0 deletions
diff --git a/docs/repo-hooks.md b/docs/repo-hooks.md
index cbb1aac7..a56f261c 100644
--- a/docs/repo-hooks.md
+++ b/docs/repo-hooks.md
@@ -133,3 +133,43 @@ def main(project_list, worktree_list=None, **kwargs):
133 kwargs: Leave this here for forward-compatibility. 133 kwargs: Leave this here for forward-compatibility.
134 """ 134 """
135``` 135```
136
137### post-sync
138
139This hook runs when `repo sync` completes without errors.
140
141Note: This includes cases where no actual checkout may occur. The hook will still run.
142For 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
147This hook is useful for post-processing tasks such as setting up git hooks,
148bootstrapping configuration files, or running project initialization logic.
149
150The hook is defined using the existing `<repo-hooks>` manifest block and is
151optional. If the hook script fails or is missing, `repo sync` will still
152complete successfully, and the error will be printed as a warning.
153
154Example:
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
163The `post-sync.py` file should be defined like:
164
165```py
166def 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```
diff --git a/hooks.py b/hooks.py
index f940e3f5..fc31a5ef 100644
--- a/hooks.py
+++ b/hooks.py
@@ -25,6 +25,7 @@ from git_refs import HEAD
25# The API we've documented to hook authors. Keep in sync with repo-hooks.md. 25# The API we've documented to hook authors. Keep in sync with repo-hooks.md.
26_API_ARGS = { 26_API_ARGS = {
27 "pre-upload": {"project_list", "worktree_list"}, 27 "pre-upload": {"project_list", "worktree_list"},
28 "post-sync": {"repo_topdir"},
28} 29}
29 30
30 31
diff --git a/subcmds/sync.py b/subcmds/sync.py
index 20d75dc8..250925f4 100644
--- a/subcmds/sync.py
+++ b/subcmds/sync.py
@@ -68,6 +68,7 @@ from git_config import GetUrlCookieFile
68from git_refs import HEAD 68from git_refs import HEAD
69from git_refs import R_HEADS 69from git_refs import R_HEADS
70import git_superproject 70import git_superproject
71from hooks import RepoHook
71import platform_utils 72import platform_utils
72from progress import elapsed_str 73from progress import elapsed_str
73from progress import jobs_str 74from progress import jobs_str
@@ -623,6 +624,7 @@ later is required to fix a server side protocol bug.
623 action="store_true", 624 action="store_true",
624 help=optparse.SUPPRESS_HELP, 625 help=optparse.SUPPRESS_HELP,
625 ) 626 )
627 RepoHook.AddOptionGroup(p, "post-sync")
626 628
627 def _GetBranch(self, manifest_project): 629 def _GetBranch(self, manifest_project):
628 """Returns the branch name for getting the approved smartsync manifest. 630 """Returns the branch name for getting the approved smartsync manifest.
@@ -1847,6 +1849,21 @@ later is required to fix a server side protocol bug.
1847 except (KeyboardInterrupt, Exception) as e: 1849 except (KeyboardInterrupt, Exception) as e:
1848 raise RepoUnhandledExceptionError(e, aggregate_errors=errors) 1850 raise RepoUnhandledExceptionError(e, aggregate_errors=errors)
1849 1851
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
1850 def _ExecuteHelper(self, opt, args, errors): 1867 def _ExecuteHelper(self, opt, args, errors):
1851 manifest = self.outer_manifest 1868 manifest = self.outer_manifest
1852 if not opt.outer_manifest: 1869 if not opt.outer_manifest: