diff options
| author | Kenny Cheng <chao.shun.cheng.tw@gmail.com> | 2025-06-02 21:55:04 +0800 |
|---|---|---|
| committer | LUCI <gerrit-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2025-07-01 16:11:50 -0700 |
| commit | 82d500eb7aa93f9bff66a4358a08d2ba2d599550 (patch) | |
| tree | 60d2003fa946943a13bfb9a96bd88bb60167c57f | |
| parent | 21269c3eedc428610a5cab1494b2459a7e939fc7 (diff) | |
| download | git-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.md | 40 | ||||
| -rw-r--r-- | hooks.py | 1 | ||||
| -rw-r--r-- | subcmds/sync.py | 17 |
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 | |||
| 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 | ``` | ||
| @@ -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 | |||
| 68 | from git_refs import HEAD | 68 | from git_refs import HEAD |
| 69 | from git_refs import R_HEADS | 69 | from git_refs import R_HEADS |
| 70 | import git_superproject | 70 | import git_superproject |
| 71 | from hooks import RepoHook | ||
| 71 | import platform_utils | 72 | import platform_utils |
| 72 | from progress import elapsed_str | 73 | from progress import elapsed_str |
| 73 | from progress import jobs_str | 74 | from 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: |
