根据Jenkins官方文档，Jenkins的实际层级组织结构如下：

## Jenkins的实际层级结构

Jenkins在使用**Organization Folder**（组织文件夹）功能时，采用的层级结构为：

```
Organization Folder（组织）
  └── Repository/Project（仓库/项目）
        └── Branch（分支）
              └── Build（构建）
```

官方文档中明确展示的层级示例：

```
+--- GitHub Organization
     +--- Project 1
          +--- master
          +--- feature-branch-a
          +--- feature-branch-b
     +--- Project 2
          +--- master
          +--- pull-request-1
```

## 关键区别

"Projects → Repository"实际上在Jenkins中是同一层级的概念。 Jenkins使用以下术语：

- **Organization Folder**：对应GitHub Organization、Bitbucket Team、GitLab Organization等组织级别
- **Multibranch Pipeline Project**：对应单个代码仓库，会自动为该仓库的所有包含Jenkinsfile的分支创建构建任务
- **Branch**：具体的分支或Pull Request
- **Build**：针对某个分支的具体构建执行

## 实现逻辑

Jenkins通过以下机制实现这种层级：

1. **Multibranch Pipeline**自动扫描单个仓库，为每个包含Jenkinsfile的分支创建Pipeline任务
2. **Organization Folder**自动扫描整个组织，为每个符合条件的仓库创建Multibranch Pipeline项目
3. 当分支或仓库被创建/删除时，可以通过webhook或定期扫描自动更新Jenkins中的任务结构

因此，准确的表述应该是：**Organization → Repository(Project) → Branch → Build**，其中Repository和Project是等价的概念。


根据Jenkins官方文档和API最佳实践，您可以通过以下方式获取GitLab Organization Folder的所有分支和构建信息：

## 推荐方案：使用Tree参数的单次API调用

最高效的方式是使用`tree`参数，通过一次API调用获取所有数据：

```bash
https://<JENKINS_HOST>/job/<ORGANIZATION_FOLDER_NAME>/api/json?tree=jobs[name,url,jobs[name,url,builds[number,result,timestamp,duration,url]]]
```

### 参数说明

- **第一层`jobs`**：Organization Folder下的所有Repository（Multibranch Pipeline项目）
- **第二层`jobs`**：每个Repository下的所有Branch（分支作为子job存在）
- **`builds`**：每个Branch的构建历史

### 限制返回的构建数量

如果构建历史过多，可以限制返回数量（例如最近50次）：

```bash
https://<JENKINS_HOST>/job/<ORGANIZATION_FOLDER_NAME>/api/json?tree=jobs[name,url,jobs[name,url,builds[number,result,timestamp,duration,url]{0,50}]]
```

`{0,50}`表示只返回最近50次构建。

## API调用结构层次

基于Organization Folder的结构，API调用路径遵循以下层级：

1. **Organization Folder** → `/job/<FOLDER_NAME>`
2. **Repository (Multibranch Pipeline)** → `/job/<FOLDER_NAME>/job/<REPO_NAME>`
3. **Branch** → `/job/<FOLDER_NAME>/job/<REPO_NAME>/job/<BRANCH_NAME>`
4. **Build** → `/job/<FOLDER_NAME>/job/<REPO_NAME>/job/<BRANCH_NAME>/<BUILD_NUMBER>`

## 完整示例

假设您的Organization Folder名为`CMII-UAV-Cloud-Backend-GITLAB`：

```bash
# 获取所有仓库、分支和最近50次构建
curl -u username:api_token \
  "https://<JENKINS_HOST>/job/CMII-UAV-Cloud-Backend-GITLAB/api/json?tree=jobs[name,url,jobs[name,url,builds[number,result,timestamp,duration,url]{0,50}]]"
```

## 性能优化建议

1. **避免使用`depth`参数**：`depth`会返回大量不必要的数据，建议使用`tree`参数精确指定所需字段
2. **限制构建数量**：使用`{0,N}`语法限制每个分支返回的构建数量
3. **按需获取字段**：只请求必要的字段，减少数据传输量


分析您的API调用性能问题，主要原因是**Jenkins需要遍历整个Organization Folder的所有仓库、分支和构建数据**，即使您只请求了前3条记录。 以下是性能瓶颈和优化方案：

## 性能瓶颈分析

### 主要问题

1. **一次性加载所有数据**：Jenkins API的`tree`参数在返回前必须先遍历整个数据树结构，即使使用`{0,3}`限制构建数量
2. **Organization Folder扫描开销**：每个多分支项目的分支发现和元数据加载都会产生大量I/O操作
3. **深层嵌套查询**：三层嵌套（Organization → Repository → Branch → Builds）导致指数级的数据查询

### 为什么`{0,3}`不起作用

`{0,3}`只限制**每个分支**返回的构建数量，但Jenkins仍需要：
- 遍历所有Repository
- 扫描每个Repository的所有分支
- 为每个分支加载元数据

## 高效解决方案

### 方案1：分层逐级获取（推荐）

不要一次性获取所有层级，而是分步骤获取：

#### 步骤1：获取所有Repository

```bash
curl -g -u username:token \
  "http://192.168.34.41:27081/job/CMII-UAV-Cloud-Backend-GITLAB/api/json?tree=jobs[name,url]"
```

返回速度快，只获取Repository列表。

#### 步骤2：并行获取每个Repository的分支

```bash
# 对每个Repository
curl -g -u username:token \
  "http://192.168.34.41:27081/job/CMII-UAV-Cloud-Backend-GITLAB/job/<REPO_NAME>/api/json?tree=jobs[name,url,lastBuild[number,result,timestamp,duration]]"
```

使用`lastBuild`只获取最新构建，而非所有构建历史。

#### 步骤3：按需获取具体分支的构建历史

```bash
curl -g -u username:token \
  "http://192.168.34.41:27081/job/CMII-UAV-Cloud-Backend-GITLAB/job/<REPO_NAME>/job/<BRANCH_NAME>/api/json?tree=builds[number,result,timestamp,duration]{0,10}"
```

### 方案2：只获取关键信息

如果只需要统计数据，使用最小化字段：

```bash
curl -g -u username:token \
  "http://192.168.34.41:27081/job/CMII-UAV-Cloud-Backend-GITLAB/api/json?tree=jobs[name,jobs[name,lastBuild[number,result,timestamp]]]"
```

关键优化点：
- 移除`url`字段（可自行构造）
- 只用`lastBuild`替代`builds[]`
- 减少返回字段数量

### 方案3：使用Python脚本异步并发获取

```python
import asyncio
import aiohttp
from aiohttp import BasicAuth

async def fetch_repos(session, base_url, auth):
    url = f"{base_url}/api/json?tree=jobs[name]"
    async with session.get(url, auth=auth) as resp:
        data = await resp.json()
        return [job['name'] for job in data.get('jobs', [])]

async def fetch_repo_branches(session, base_url, repo_name, auth):
    url = f"{base_url}/job/{repo_name}/api/json?tree=jobs[name,lastBuild[number,result,timestamp]]"
    async with session.get(url, auth=auth) as resp:
        data = await resp.json()
        return {
            'repo': repo_name,
            'branches': data.get('jobs', [])
        }

async def main():
    base_url = "http://192.168.34.41:27081/job/CMII-UAV-Cloud-Backend-GITLAB"
    auth = BasicAuth('zeaslity', '114f14f0c48fd9dfb4d3092426b0f72913')
    
    async with aiohttp.ClientSession() as session:
        # 1. 获取所有仓库
        repos = await fetch_repos(session, base_url, auth)
        print(f"找到 {len(repos)} 个仓库")
        
        # 2. 并发获取所有仓库的分支信息
        tasks = [fetch_repo_branches(session, base_url, repo, auth) for repo in repos]
        results = await asyncio.gather(*tasks)
        
        # 3. 输出结果
        for result in results:
            print(f"\n仓库: {result['repo']}")
            for branch in result['branches']:
                build = branch.get('lastBuild', {})
                if build != None:
                  print(f"  分支: {branch['name']}, 最新构建: #{build.get('number', 'N/A')}")

asyncio.run(main())
```

这个脚本将3分钟的串行请求压缩到数秒内。