git-repohooks: setup CQ for new repo

Bug: b/400763202
Test: `./recipes/recipes.py test train`
Change-Id: I345c9baf76acd4c7d060e522de94cd861f85f5c9
diff --git a/generated/commit-queue.cfg b/generated/commit-queue.cfg
index 595b72b..9560d51 100644
--- a/generated/commit-queue.cfg
+++ b/generated/commit-queue.cfg
@@ -111,6 +111,38 @@
   }
 }
 config_groups {
+  name: "git-repohooks_repo"
+  gerrit {
+    url: "https://gerrit-review.googlesource.com"
+    projects {
+      name: "git-repohooks"
+      ref_regexp: "refs/heads/.+"
+    }
+  }
+  verifiers {
+    gerrit_cq_ability {
+      committer_list: "googlers"
+      dry_run_access_list: "all"
+      new_patchset_run_access_list: "all"
+    }
+    tryjob {
+      builders {
+        name: "gerrit/try/Verify git-repohooks CL"
+        mode_allowlist: "DRY_RUN"
+        mode_allowlist: "FULL_RUN"
+        mode_allowlist: "NEW_PATCHSET_RUN"
+      }
+      retry_config {
+        single_quota: 1
+        global_quota: 2
+        failure_weight: 100
+        transient_failure_weight: 1
+        timeout_weight: 100
+      }
+    }
+  }
+}
+config_groups {
   name: "luci-config_repo"
   gerrit {
     url: "https://gerrit-review.googlesource.com"
diff --git a/generated/cr-buildbucket.cfg b/generated/cr-buildbucket.cfg
index f72176a..58b8dd9 100644
--- a/generated/cr-buildbucket.cfg
+++ b/generated/cr-buildbucket.cfg
@@ -56,6 +56,27 @@
       }
     }
     builders {
+      name: "Verify git-repohooks CL"
+      swarming_host: "chromium-swarm.appspot.com"
+      dimensions: "cpu:x86-64"
+      dimensions: "os:Ubuntu"
+      dimensions: "pool:luci.gerrit.try"
+      exe {
+        cipd_package: "infra/recipe_bundles/gerrit.googlesource.com/luci-config"
+        cipd_version: "refs/heads/main"
+        cmd: "luciexe"
+      }
+      properties:
+        '{'
+        '  "recipe": "git-repohooks"'
+        '}'
+      service_account: "gerrit-luci-try-builder@gerritcodereview-ci.iam.gserviceaccount.com"
+      experiments {
+        key: "luci.recipes.use_python3"
+        value: 100
+      }
+    }
+    builders {
       name: "Verify luci-test CL"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "cpu:x86-64"
diff --git a/main.star b/main.star
index 86b5a5e..dab7a0c 100755
--- a/main.star
+++ b/main.star
@@ -116,5 +116,6 @@
 # Per-repo configurations
 exec("//repos/gerrit.star")
 exec("//repos/git-repo.star")
+exec("//repos/git-repohooks.star")
 exec("//repos/luci-config.star")
 exec("//repos/luci-test.star")
diff --git a/recipes/README.recipes.md b/recipes/README.recipes.md
index 85d53fe..353baa4 100644
--- a/recipes/README.recipes.md
+++ b/recipes/README.recipes.md
@@ -5,6 +5,7 @@
 **[Recipes](#Recipes)**
   * [gerrit](#recipes-gerrit)
   * [git-repo](#recipes-git-repo)
+  * [git-repohooks](#recipes-git-repohooks)
   * [luci-test](#recipes-luci-test)
 ## Recipes
 
@@ -26,6 +27,18 @@
 Generate a gclient configuration to check out git-repo.
 
 Return: (config) A gclient recipe module configuration.
+### *recipes* / [git-repohooks](/recipes/recipes/git-repohooks.py)
+
+[DEPS](/recipes/recipes/git-repohooks.py#15): [depot\_tools/bot\_update][depot_tools/recipe_modules/bot_update], [depot\_tools/gclient][depot_tools/recipe_modules/gclient], [recipe\_engine/buildbucket][recipe_engine/recipe_modules/buildbucket], [recipe\_engine/context][recipe_engine/recipe_modules/context], [recipe\_engine/path][recipe_engine/recipe_modules/path], [recipe\_engine/step][recipe_engine/recipe_modules/step]
+
+
+— **def [RunSteps](/recipes/recipes/git-repohooks.py#40)(api):**
+
+— **def [gclient\_config](/recipes/recipes/git-repohooks.py#27)(api):**
+
+Generate a gclient configuration to check out git-repohooks.
+
+Return: (config) A gclient recipe module configuration.
 ### *recipes* / [luci-test](/recipes/recipes/luci-test.py)
 
 [DEPS](/recipes/recipes/luci-test.py#9): [depot\_tools/gerrit][depot_tools/recipe_modules/gerrit], [depot\_tools/gsutil][depot_tools/recipe_modules/gsutil], [fuchsia/git\_checkout][fuchsia/recipe_modules/git_checkout], [infra/zip][infra/recipe_modules/zip], [recipe\_engine/buildbucket][recipe_engine/recipe_modules/buildbucket], [recipe\_engine/context][recipe_engine/recipe_modules/context], [recipe\_engine/file][recipe_engine/recipe_modules/file], [recipe\_engine/json][recipe_engine/recipe_modules/json], [recipe\_engine/nodejs][recipe_engine/recipe_modules/nodejs], [recipe\_engine/path][recipe_engine/recipe_modules/path], [recipe\_engine/step][recipe_engine/recipe_modules/step]
diff --git a/recipes/recipes/git-repohooks.expected/basic.json b/recipes/recipes/git-repohooks.expected/basic.json
new file mode 100644
index 0000000..3ef72b9
--- /dev/null
+++ b/recipes/recipes/git-repohooks.expected/basic.json
@@ -0,0 +1,174 @@
+[
+  {
+    "cmd": [
+      "vpython3",
+      "RECIPE_REPO[depot_tools]/gerrit_client.py",
+      "changes",
+      "--host",
+      "https://chromium-review.googlesource.com",
+      "--json_file",
+      "/path/to/tmp/json",
+      "--limit",
+      "1",
+      "-p",
+      "change=123456",
+      "-o",
+      "ALL_REVISIONS",
+      "-o",
+      "DOWNLOAD_COMMANDS",
+      "--verbose"
+    ],
+    "env": {
+      "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "git-repohooks:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "gerrit fetch current CL info",
+    "timeout": 480,
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@json.output@[@@@",
+      "@@@STEP_LOG_LINE@json.output@  {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"branch\": \"main\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"owner\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"John Doe\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"revisions\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"184ebe53805e102605d11f6b143486d15c23a09c\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"_number\": \"7\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"ref\": \"refs/changes/56/123456/7\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    }@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@]@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[depot_tools::bot_update]/resources/bot_update.py",
+      "--spec-path",
+      "cache_dir = '[CACHE]/git'\nsolutions = [{'deps_file': '.DEPS.git', 'managed': True, 'name': 'git-repohooks', 'url': 'https://gerrit.googlesource.com/git-repohooks'}]",
+      "--patch_root",
+      "git-repohooks",
+      "--revision_mapping_file",
+      "{}",
+      "--git-cache-dir",
+      "[CACHE]/git",
+      "--cleanup-dir",
+      "[CLEANUP]/bot_update",
+      "--output_json",
+      "/path/to/tmp/json",
+      "--patch_ref",
+      "https://chromium.googlesource.com/git-repohooks@refs/heads/main:refs/changes/56/123456/7",
+      "--revision",
+      "git-repohooks@refs/heads/main",
+      "--refs",
+      "refs/heads/main"
+    ],
+    "env": {
+      "DEPOT_TOOLS_REPORT_BUILD": "git-repohooks/try/builder/8945511751514863184",
+      "GIT_BACKENDINFO": "1",
+      "GIT_DAPPER_TRACE": "1",
+      "GIT_HTTP_LOW_SPEED_LIMIT": "102400",
+      "GIT_HTTP_LOW_SPEED_TIME": "1800",
+      "GIT_SSH_COMMAND": "ssh -o SendEnv=GIT_DAPPER_TRACE -o SendEnv=GIT_BACKENDINFO",
+      "GIT_TRACE2_EVENT": "[CLEANUP]/trace2-event",
+      "GIT_TRACE_CURL": "[CLEANUP]/trace-curl",
+      "GIT_TRACE_CURL_NO_DATA": "1",
+      "GIT_TRACE_PACKET": "[CLEANUP]/trace-packet"
+    },
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "git-repohooks:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "bot_update",
+    "~followup_annotations": [
+      "@@@STEP_TEXT@Some step text@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"did_run\": true,@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"fixed_revisions\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"git-repohooks\": \"HEAD\"@@@",
+      "@@@STEP_LOG_LINE@json.output@  },@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"manifest\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"git-repohooks\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"repository\": \"https://fake.org/git-repohooks.git\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"revision\": \"b6c460c58dc15a96b9398a97188dd17d3dc8006e\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    }@@@",
+      "@@@STEP_LOG_LINE@json.output@  },@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"patch_root\": \"git-repohooks\",@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"got_revision\": \"b6c460c58dc15a96b9398a97188dd17d3dc8006e\"@@@",
+      "@@@STEP_LOG_LINE@json.output@  },@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"root\": \"git-repohooks\",@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"source_manifest\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"directories\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"git-repohooks\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"git_checkout\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"repo_url\": \"https://fake.org/git-repohooks.git\",@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"revision\": \"b6c460c58dc15a96b9398a97188dd17d3dc8006e\"@@@",
+      "@@@STEP_LOG_LINE@json.output@        }@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"version\": 0@@@",
+      "@@@STEP_LOG_LINE@json.output@  },@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"step_text\": \"Some step text\"@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@SET_BUILD_PROPERTY@got_revision@\"b6c460c58dc15a96b9398a97188dd17d3dc8006e\"@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "run_tests",
+      "-vv"
+    ],
+    "cwd": "[START_DIR]/git-repohooks",
+    "luci_context": {
+      "realm": {
+        "name": "git-repohooks:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Run tests"
+  },
+  {
+    "name": "$result"
+  }
+]
\ No newline at end of file
diff --git a/recipes/recipes/git-repohooks.py b/recipes/recipes/git-repohooks.py
new file mode 100644
index 0000000..c823973
--- /dev/null
+++ b/recipes/recipes/git-repohooks.py
@@ -0,0 +1,53 @@
+# Copyright (C) 2025 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+DEPS = [
+    'recipe_engine/buildbucket',
+    'recipe_engine/step',
+    'recipe_engine/path',
+    'recipe_engine/context',
+    'depot_tools/bot_update',
+    'depot_tools/gclient',
+]
+
+PYTHON_VERSION_COMPATIBILITY = 'PY3'
+
+
+def gclient_config(api):
+    """Generate a gclient configuration to check out git-repohooks.
+
+    Return: (config) A gclient recipe module configuration.
+    """
+    cfg = api.gclient.make_config()
+    soln = cfg.solutions.add()
+    soln.name = 'git-repohooks'
+    soln.url = 'https://gerrit.googlesource.com/git-repohooks'
+    soln.revision = 'HEAD'
+    return cfg
+
+
+def RunSteps(api):
+    cl = api.buildbucket.build.input.gerrit_changes[0]
+    project_name = cl.project
+    assert project_name == 'git-repohooks', f'unknown project: "{project_name}"'
+
+    api.bot_update.ensure_checkout(gclient_config=gclient_config(api))
+
+    with api.context(cwd=api.path.start_dir / project_name):
+        # TODO(b/266734831): Use tox to run tests.
+        api.step('Run tests', ['vpython3', 'run_tests', '-vv'])
+
+
+def GenTests(api):
+    yield (api.test('basic') + api.buildbucket.try_build(project='git-repohooks'))
diff --git a/repos/git-repohooks.star b/repos/git-repohooks.star
new file mode 100644
index 0000000..62bb99a
--- /dev/null
+++ b/repos/git-repohooks.star
@@ -0,0 +1,58 @@
+# This is configuration for LUCI for the git-repohooks repo
+# https://gerrit.googlesource.com/git-repohooks
+
+# Set up Swarming permissions (for LED).
+luci.binding(
+    realm = "try",
+    roles = "role/swarming.taskTriggerer",
+    groups = "mdb/git-repo-try-build-access",
+)
+
+luci.binding(
+    realm = "pools/try",
+    roles = "role/swarming.poolUser",
+    groups = "mdb/git-repo-try-build-access",
+)
+
+luci.builder(
+    name = "Verify git-repohooks CL",
+    bucket = "try",
+    executable = luci.recipe(
+        name = "git-repohooks",
+    ),
+    service_account = "gerrit-luci-try-builder@gerritcodereview-ci.iam.gserviceaccount.com",
+    dimensions = {
+        "os": "Ubuntu",
+        "cpu": "x86-64",
+        "pool": "luci.gerrit.try",
+    },
+)
+
+luci.cq_group(
+    name = "git-repohooks_repo",
+    acls = [
+        acl.entry(
+            roles = [acl.CQ_DRY_RUNNER, acl.CQ_NEW_PATCHSET_RUN_TRIGGERER],
+            groups = "all",
+        ),
+        acl.entry(
+            acl.CQ_COMMITTER,
+            groups = "googlers",
+        ),
+    ],
+    watch = cq.refset(
+        repo = "https://gerrit.googlesource.com/git-repohooks",
+        refs = ["refs/heads/.+"],
+    ),
+)
+
+luci.cq_tryjob_verifier(
+    builder = "try/Verify git-repohooks CL",
+    cq_group = "git-repohooks_repo",
+    # Add NEW_PATCHSET_RUN to the defaults DRY_RUN and FULL_RUN
+    mode_allowlist = [
+        cq.MODE_DRY_RUN,
+        cq.MODE_FULL_RUN,
+        cq.MODE_NEW_PATCHSET_RUN,
+    ],
+)