Skip to content

集成 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>

查询参数:

参数类型必填说明
statestring❌CSRF 防护状态码

响应 ​

成功 (200 OK):

json
{
  "install_url": "https://github.com/apps/sentinel-app/installations/new"
}

使用流程 ​

  1. 调用此端点获取安装 URL
  2. 重定向用户到该 URL
  3. 用户选择账户和仓库权限
  4. GitHub 重定向回 callback URL
  5. 调用 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_idinteger✅GitHub 安装 ID
setup_actionstring❌操作类型 (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>

查询参数:

参数类型默认值说明
limitinteger20每页数量
offsetinteger0偏移量

响应 ​

成功 (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>

查询参数:

参数类型默认值说明
limitinteger50每页数量
offsetinteger0偏移量

响应 ​

成功 (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>

查询参数:

参数类型默认值说明
pageinteger1页码
per_pageinteger30每页数量 (最大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: 是否已导入到 Sentinel
  • imported_repository_id: 已导入时的仓库 ID

使用场景 ​

用于仓库选择界面:

  1. 显示所有可访问的仓库
  2. 标记哪些已导入
  3. 允许用户选择导入新仓库

示例 ​

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 需要以下权限:

权限级别用途
Contentsread读取代码内容
Pull requestswrite评论 PR,发布审查结果
Metadataread读取仓库元数据
Webhooksread/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. 显示可导入的仓库列表

相关端点 ​


相关文档 ​

Released under the MIT License.