集成 API
GitHub 集成管理相关的 API 端点。
端点概览
| 方法 | 端点 | 描述 | 认证 |
|---|---|---|---|
| GET | /integrations/github/install-url | 获取安装 URL | ✅ |
| GET | /integrations/github/callback | 安装回调 | ✅ |
| GET | /integrations/github/installations | 安装列表 | ✅ |
| GET | /integrations/github/installations/{id} | 安装详情 | ✅ |
| POST | /integrations/github/installations/{id}/sync | 同步安装 | ✅ |
| GET | /integrations/github/installations/{id}/repositories | 已导入仓库 | ✅ |
| GET | /integrations/github/installations/{id}/remote-repositories | 远程仓库列表 | ✅ |
获取安装 URL
GET /api/v1/integrations/github/install-url
获取 GitHub App 安装链接。
请求
http
GET /api/v1/integrations/github/install-url?state=custom_state
Authorization: Bearer <token>查询参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
state | string | ❌ | CSRF 防护状态码 |
响应
成功 (200 OK):
json
{
"install_url": "https://github.com/apps/sentinel-app/installations/new"
}使用流程
- 调用此端点获取安装 URL
- 重定向用户到该 URL
- 用户选择账户和仓库权限
- GitHub 重定向回 callback URL
- 调用 callback 端点完成安装
示例
typescript
const getInstallUrl = async () => {
const response = await fetch('/api/v1/integrations/github/install-url', {
headers: { 'Authorization': `Bearer ${token}` },
});
const data = await response.json();
window.location.href = data.install_url;
};安装回调
GET /api/v1/integrations/github/callback
处理 GitHub App 安装回调。
请求
http
GET /api/v1/integrations/github/callback?installation_id=12345678&setup_action=install
Authorization: Bearer <token>查询参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
installation_id | integer | ✅ | GitHub 安装 ID |
setup_action | string | ❌ | 操作类型 (install/update) |
响应
成功 (200 OK):
json
{
"installation": {
"installation_id": 12345678,
"account_login": "octocat",
"account_type": "User",
"target_type": "User",
"repository_selection": "selected",
"permissions": {
"contents": "read",
"pull_requests": "write",
"metadata": "read"
},
"created_at": "2024-01-01T12:00:00Z",
"updated_at": "2024-01-01T12:00:00Z"
}
}Account/Target 类型:
User- 个人账户Organization- 组织账户
Repository 选择:
all- 所有仓库selected- 选定的仓库
安装列表
GET /api/v1/integrations/github/installations
获取当前用户的 GitHub App 安装列表。
请求
http
GET /api/v1/integrations/github/installations?limit=20&offset=0
Authorization: Bearer <token>查询参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
limit | integer | 20 | 每页数量 |
offset | integer | 0 | 偏移量 |
响应
成功 (200 OK):
json
{
"installations": [
{
"installation_id": 12345678,
"account_login": "octocat",
"account_type": "User",
"target_type": "User",
"repository_selection": "selected",
"permissions": {
"contents": "read",
"pull_requests": "write"
},
"suspended_at": null,
"last_synced_at": "2024-01-01T12:00:00Z",
"created_at": "2024-01-01T12:00:00Z",
"updated_at": "2024-01-01T12:00:00Z"
}
],
"total": 1
}示例
typescript
const listInstallations = async () => {
const response = await fetch('/api/v1/integrations/github/installations', {
headers: { 'Authorization': `Bearer ${token}` },
});
return response.json();
};安装详情
GET /api/v1/integrations/github/installations/{id}
获取特定安装的详细信息。
请求
http
GET /api/v1/integrations/github/installations/12345678
Authorization: Bearer <token>响应
成功 (200 OK):
返回安装对象,字段同安装列表。
错误响应:
404 Not Found: 安装不存在或无权访问
同步安装
POST /api/v1/integrations/github/installations/{id}/sync
从 GitHub 同步安装信息(权限、仓库列表等)。
请求
http
POST /api/v1/integrations/github/installations/12345678/sync
Authorization: Bearer <token>响应
成功 (200 OK):
返回更新后的安装对象。
使用场景
- 用户在 GitHub 上修改了仓库权限
- 添加或移除了仓库访问权限
- 需要刷新安装状态
示例
typescript
const syncInstallation = async (installationId: number) => {
const response = await fetch(
`/api/v1/integrations/github/installations/${installationId}/sync`,
{
method: 'POST',
headers: { 'Authorization': `Bearer ${token}` },
}
);
return response.json();
};已导入仓库
GET /api/v1/integrations/github/installations/{id}/repositories
获取该安装下已导入到 Sentinel 的仓库列表。
请求
http
GET /api/v1/integrations/github/installations/12345678/repositories?limit=50
Authorization: Bearer <token>查询参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
limit | integer | 50 | 每页数量 |
offset | integer | 0 | 偏移量 |
响应
成功 (200 OK):
json
{
"repositories": [
{
"repository_id": "650e8400-e29b-41d4-a716-446655440000",
"project_id": "550e8400-e29b-41d4-a716-446655440000",
"external_id": "123456789",
"owner": "octocat",
"name": "Hello-World",
"full_name": "octocat/Hello-World",
"clone_url": "https://github.com/octocat/Hello-World.git",
"default_branch": "main",
"visibility": "public",
"enabled": true,
"created_at": "2024-01-01T12:00:00Z"
}
],
"total": 1
}远程仓库列表
GET /api/v1/integrations/github/installations/{id}/remote-repositories
从 GitHub 获取该安装可访问的仓库列表(未导入的)。
请求
http
GET /api/v1/integrations/github/installations/12345678/remote-repositories?page=1&per_page=30
Authorization: Bearer <token>查询参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
page | integer | 1 | 页码 |
per_page | integer | 30 | 每页数量 (最大100) |
响应
成功 (200 OK):
json
{
"repositories": [
{
"external_id": "123456789",
"owner": "octocat",
"name": "Hello-World",
"full_name": "octocat/Hello-World",
"clone_url": "https://github.com/octocat/Hello-World.git",
"default_branch": "main",
"visibility": "public",
"private": false,
"imported": false,
"imported_repository_id": null
},
{
"external_id": "987654321",
"owner": "octocat",
"name": "Spoon-Knife",
"full_name": "octocat/Spoon-Knife",
"clone_url": "https://github.com/octocat/Spoon-Knife.git",
"default_branch": "main",
"visibility": "public",
"private": false,
"imported": true,
"imported_repository_id": "650e8400-e29b-41d4-a716-446655440000"
}
],
"total_count": 2
}说明:
imported: 是否已导入到 Sentinelimported_repository_id: 已导入时的仓库 ID
使用场景
用于仓库选择界面:
- 显示所有可访问的仓库
- 标记哪些已导入
- 允许用户选择导入新仓库
示例
typescript
const listRemoteRepositories = async (
installationId: number,
page = 1,
perPage = 30
) => {
const response = await fetch(
`/api/v1/integrations/github/installations/${installationId}/remote-repositories?page=${page}&per_page=${perPage}`,
{
headers: { 'Authorization': `Bearer ${token}` },
}
);
return response.json();
};
// 过滤未导入的仓库
const getUnimportedRepos = async (installationId: number) => {
const { repositories } = await listRemoteRepositories(installationId);
return repositories.filter(repo => !repo.imported);
};数据模型
Installation 对象
typescript
interface GithubInstallation {
installation_id: number; // GitHub 安装 ID
account_login: string; // 账户名称
account_type: 'User' | 'Organization'; // 账户类型
target_type: 'User' | 'Organization'; // 目标类型
repository_selection: 'all' | 'selected'; // 仓库选择
permissions: Record<string, string>; // 权限映射
suspended_at?: string; // 暂停时间
last_synced_at?: string; // 最后同步时间
created_at: string; // 创建时间
updated_at: string; // 更新时间
}RemoteRepository 对象
typescript
interface RemoteRepository {
external_id: string; // GitHub 仓库 ID
owner: string; // 所有者
name: string; // 仓库名
full_name: string; // 完整名称
clone_url: string; // 克隆 URL
default_branch: string; // 默认分支
visibility: string; // 可见性
private: boolean; // 是否私有
imported: boolean; // 是否已导入
imported_repository_id?: string; // 导入后的 ID
}GitHub App 权限
Sentinel GitHub App 需要以下权限:
| 权限 | 级别 | 用途 |
|---|---|---|
| Contents | read | 读取代码内容 |
| Pull requests | write | 评论 PR,发布审查结果 |
| Metadata | read | 读取仓库元数据 |
| Webhooks | read/write | 管理 Webhook |
最佳实践
1. 定期同步
typescript
const syncAllInstallations = async () => {
const { installations } = await listInstallations();
await Promise.all(
installations.map(inst =>
syncInstallation(inst.installation_id)
)
);
};
// 每小时同步一次
setInterval(syncAllInstallations, 60 * 60 * 1000);2. 仓库导入向导
typescript
const importWizard = async (installationId: number, projectId: string) => {
// 1. 获取远程仓库
const { repositories } = await listRemoteRepositories(installationId);
// 2. 过滤未导入的
const unimported = repositories.filter(r => !r.imported);
// 3. 用户选择
const selected = await showSelectionDialog(unimported);
// 4. 批量导入
for (const repo of selected) {
await importRepository(projectId, {
external_id: repo.external_id,
installation_id: installationId,
owner: repo.owner,
name: repo.name,
clone_url: repo.clone_url,
default_branch: repo.default_branch,
visibility: repo.visibility,
});
}
};3. 权限检查
typescript
const hasRequiredPermissions = (installation: GithubInstallation) => {
const required = ['contents', 'pull_requests', 'metadata'];
return required.every(perm =>
installation.permissions[perm] === 'read' ||
installation.permissions[perm] === 'write'
);
};安装流程
1. 用户点击"Connect GitHub"
↓
2. 获取安装 URL
↓
3. 重定向到 GitHub
↓
4. 用户授权 App
↓
5. GitHub 回调到 callback URL
↓
6. 前端调用 callback 端点
↓
7. 安装记录创建完成
↓
8. 显示可导入的仓库列表相关端点
- 仓库 API - 导入仓库
- Webhook API - 自动触发机制