Creating AOSP Product Branches in Bulk Using the Gerrit REST API (Python)

In my previous post, I explained how to mirror AOSP Android 15 into gerrit.maksonlee.com with complete commit history and tags. Once all projects are imported, the next step in Android platform bring-up is to create a product-specific branch, for example, prj-0001-15-vanilla, across every repository.

Creating branches manually for hundreds of modules is tedious. In this post, I’ll show how to do it programmatically using the Gerrit REST API and Python, then update default.xml in platform/manifest to point to your Gerrit server and branch.


Authentication: OAuth for UI, HTTP Password for API

My Gerrit is configured with auth.type = OAUTH, so I log in via Keycloak.

However, OAuth login credentials do not work for the REST API.

Instead, you must generate an HTTP password from Gerrit:

Go to Settings → HTTP Credentials, generate a password, and use it along with your username in API calls.


Goal

  • Create a new branch prj-0001-15-vanilla across all AOSP projects
  • Point platform/manifest’s default.xml to:
    • refs/heads/prj-0001-15-vanilla
    • https://gerrit.maksonlee.com/ as the review server

Python Script: Create Branches in Bulk

import requests
import json

# --- Configuration ---
GERRIT_URL = "https://gerrit.maksonlee.com"
USERNAME = "maksonlee"
PASSWORD = "your_http_password"  # From Settings → HTTP Credentials
SOURCE_BRANCH = "android-15.0.0_r30"
NEW_BRANCH = "prj-0001-15-vanilla"

auth = (USERNAME, PASSWORD)

# --- Get all projects (handle Gerrit's anti-CSRF prefix) ---
resp = requests.get(f"{GERRIT_URL}/a/projects/?d", auth=auth)
if not resp.ok:
    raise RuntimeError(f"Failed to list projects: {resp.status_code} {resp.text}")

clean_text = resp.text.lstrip(")]}'\n")
projects = json.loads(clean_text).keys()

for project in projects:
    print(f" Processing {project}")
    project_encoded = project.replace("/", "%2F")

    # --- Check if source branch exists ---
    check_url = f"{GERRIT_URL}/a/projects/{project_encoded}/branches/{SOURCE_BRANCH}"
    check_resp = requests.get(check_url, auth=auth)
    if check_resp.status_code != 200:
        print(f" Source branch {SOURCE_BRANCH} not found, skipping.")
        continue

    # --- Create new branch ---
    new_branch_url = f"{GERRIT_URL}/a/projects/{project_encoded}/branches/{NEW_BRANCH}"
    payload = {"revision": f"refs/heads/{SOURCE_BRANCH}"}
    resp = requests.put(new_branch_url, auth=auth, json=payload)

    if resp.status_code == 201:
        print(f" Created {NEW_BRANCH}")
    elif resp.status_code == 409:
        print(f" Branch already exists")
    else:
        print(f" Failed (HTTP {resp.status_code}): {resp.text}")

Update platform/manifest with the New Branch

After creating the branches, update your platform/manifest repository’s default.xml:

From:

<remote  name="aosp"
         fetch=".."
         review="https://android-review.googlesource.com/" />
<default revision="refs/tags/android-15.0.0_r30"
         remote="aosp"
         sync-j="4" />

To:

<remote  name="aosp"
         fetch=".."
         review="https://gerrit.maksonlee.com/" />
<default revision="refs/heads/prj-0001-15-vanilla"
         remote="aosp"
         sync-j="4" />

Final Result

  • All projects now have a prj-0001-15-vanilla branch cloned from android-15.0.0_r30
  • Your manifest repo points to the new branch and your local Gerrit
  • Developers can now sync using:
repo init -u https://gerrit.maksonlee.com/platform/manifest -b prj-0001-15-vanilla
repo sync

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top