用户可通过该项目便捷地与 GitCode API 交互,实现仓库、问题、拉取请求等管理操作。提供异步 API 客户端、类型安全模型、自动重试机制及直观的命令行界面,支持 token 认证与配置持久化。【此简介由AI生成】
当前访问频次受限,请登录后继续访问
gckit
适用于 Python 的 GitCode API 客户端与命令行界面。
这是一个用于 GitCode API 的 Python 客户端库和命令行界面。它提供了异步接口,可用于操作仓库、问题、拉取请求、分支和用户。项目仓库:https://gitcode.com/pimenovdmitry/gckit。
特性
- 异步 API 客户端:基于
httpx构建的异步 GitCode 客户端 - V4 + V5 API 支持:分别为不同的 GitCode API 版本提供 V5Client 和 V4Client
- 类型安全模型:针对仓库、分支、问题、拉取请求、发布、标签、Webhook 和内容的类型化数据类模型
- 带退避策略的重试:遇到速率限制和服务器错误时自动重试
- 根级 CLI 命令:直接命令,如
gckit repo ...、gckit issue ...和gckit auth ... - 认证支持:基于令牌的认证,配置文件持久化存储
- 搜索功能:搜索仓库、问题和用户
- MCP 服务器:将所有 CLI 命令公开为 MCP 工具,供 opencode.ai 等 AI 代理使用(
gckit mcp)
API 客户端
gckit 通过单独的客户端类支持两个 GitCode API 版本:
V5Client:使用 v5 API(/repos/{owner}/{repo}/...),采用 Bearer 令牌认证。这是默认客户端,为保持向后兼容性,也可通过Client使用。V4Client:使用 v4 GitLab 兼容 API(/projects/{owner}%2F{repo}/...),采用 PRIVATE-TOKEN 认证。当需要使用仅在 v4 版本中可用的端点时,请使用此客户端。
from gckit import V5Client, V4Client
# v5 API (default)
async with V5Client(token='your-token') as client:
user = await client.user('username')
# v4 API (GitLab-compatible) — for v4-only endpoints
async with V4Client(token='your-token') as client:
discussions = await client.repo('owner', 'repo').pulls.discussions(42)
两个客户端共享相同的重试、日志记录和错误处理基础架构。
安装
开发环境安装:
git clone https://gitcode.com/pimenovdmitry/gckit.git
cd gckit
uv sync --extra dev
从检出的仓库中运行 CLI,命令如下:
./scripts/gckit --help
辅助脚本期望项目虚拟环境位于 .venv。
认证
首先,从您的账户设置获取 GitCode 访问令牌。然后进行认证:
# Save token for future use
gckit auth login <your-token>
# Check authentication status
gckit auth status
# Show the authenticated user
gckit auth whoami
# Remove saved token
gckit auth logout
CLI 的令牌查找优先级如下:
--tokenGITCODE_TOKENGITCODE_ACCESS_TOKEN~/.config/gitcode/credentials
示例:
gckit --token <your-token> repo list
export GITCODE_TOKEN=<your-token>
export GITCODE_ACCESS_TOKEN=<your-token>
CLI 用法
默认 CLI 输出会打开 Textual 应用,供用户进行交互式操作。人工可读输出需要 TTY 环境。在非 TTY 会话中,请使用 --json 或 --yaml 参数以获取适合自动化的机器可读输出。
全局选项:
gckit --token <token> --debug ...
./scripts/gckit --token <token> --debug ...
gckit --help-all
如果在列表式命令中省略 --page,CLI 会自动分页遍历所有可用结果。
交互式 TUI
当命令有可浏览的行时,列表式的人性化输出会打开一个交互式 Textual 表格。使用 ↑/↓ 移动,Enter 打开所选行,Esc 返回,q 或 Ctrl+C 退出,r 重试加载失败的详情。表头显示部分名称和行数;详情屏幕在后台加载相关数据时,会保持主要项目可见。
可对仓库、分支、问题、拉取请求、标签、发布、搜索结果、用户和仓库内容目录项进行深度导航。问题和拉取请求详情屏幕会明确显示空的相关部分,并呈现部分相关数据加载失败的情况,而非将其隐藏。
命令
在交互式终端中运行时,人性化可读的命令会启动 Textual 应用:
$ gckit issue get owner/repo 123
# Opens an interactive Textual issue view.
自动化和重定向输出应明确要求结构化格式:
gckit issue get owner/repo 123 --json
gckit pr get owner/repo 456 --issues --yaml
在没有 TTY 或结构化输出标志的情况下,人工命令会快速失败,而非将面向屏幕的输出写入管道。
# Authentication
gckit auth login <token>
gckit auth logout
gckit auth status
gckit auth whoami
gckit auth whoami --json
gckit auth whoami --yaml
# Repositories
gckit repo list [owner]
gckit repo list [owner] --page 1 --per-page 50
gckit repo list [owner] --json
gckit repo list [owner] --yaml
gckit repo info <owner/repo>
gckit repo info <owner/repo> --json
gckit repo info <owner/repo> --yaml
gckit repo create <name> --description "demo" --private --auto-init
gckit repo create <name> --json
gckit repo create <name> --yaml
gckit repo update <owner/repo> --name "new-name" --description "new desc"
gckit repo update <owner/repo> --v4 --visibility public # --v4 routes through V4Client
gckit repo delete <owner/repo> --yes
gckit repo fork <owner/repo> --organization my-org
gckit repo forks <owner/repo>
gckit repo stargazers <owner/repo>
gckit repo subscribers <owner/repo>
gckit repo contributors <owner/repo>
gckit repo languages <owner/repo>
gckit repo activity <owner/repo>
gckit repo transfer <owner/repo> <new_owner> --yes
gckit repo archive <owner/repo> --yes
gckit repo unarchive <owner/repo>
gckit repo settings get <owner/repo>
gckit repo settings update <owner/repo> --has-issues/--no-has-issues
gckit repo pr-settings get <owner/repo>
gckit repo pr-settings update <owner/repo> --merge-method merge
gckit repo push-config get <owner/repo>
gckit repo push-config set <owner/repo> --restrict-push/--no-restrict-push
gckit repo transition get <owner/repo>
gckit repo transition set <owner/repo> --enable-transition/--no-enable-transition
gckit repo module <owner/repo> --enable-module/--no-enable-module
gckit repo reviewer <owner/repo> --enable-reviewer --reviewer-count 3
gckit repo member update <owner/repo> <username> --permission admin
gckit repo roles <owner/repo>
gckit repo file-list <owner/repo>
gckit repo blob <owner/repo> <sha>
gckit repo raw <owner/repo> <path>
gckit repo trees <owner/repo> <sha>
gckit repo upload-image <owner/repo> <file>
gckit repo upload-file <owner/repo> <file>
# Branches
gckit branch list <owner/repo>
gckit branch list <owner/repo> --page 1 --per-page 50
gckit branch list <owner/repo> --json
gckit branch list <owner/repo> --yaml
# Content
gckit content get <owner/repo> <path>
gckit content get <owner/repo> <path> --ref develop
gckit content get <owner/repo> <path> --json
gckit content get <owner/repo> <path> --yaml
gckit content create <owner/repo> <path> --message "Add file" --content "Hello" --branch main
gckit content create <owner/repo> <path> --message "Add file" --content "Hello" --json
gckit content update <owner/repo> <path> --message "Update" --content "new" --sha <sha> --branch main
gckit content update <owner/repo> <path> --message "Update" --content "new" --sha <sha> --yaml
gckit content delete <owner/repo> <path> --message "Remove" --sha <sha> --yes
# Webhooks
gckit hook list <owner/repo>
gckit hook list <owner/repo> --page 1 --per-page 50
gckit hook list <owner/repo> --json
gckit hook list <owner/repo> --yaml
gckit hook get <owner/repo> <id>
gckit hook get <owner/repo> <id> --json
gckit hook get <owner/repo> <id> --yaml
gckit hook create <owner/repo> --url https://example.com/hook --events push,pull_request
gckit hook create <owner/repo> --url https://example.com/hook --events push --secret mys3cret --content-type json --insecure-ssl --json
gckit hook update <owner/repo> <id> --events push,pull_request
gckit hook update <owner/repo> <id> --url https://example.com/new-hook --active/--no-active --json
gckit hook delete <owner/repo> <id> --yes
gckit hook test <owner/repo> <id>
gckit hook test <owner/repo> <id> --json
# Tags
gckit tag list <owner/repo>
gckit tag list <owner/repo> --page 1 --per-page 50
gckit tag list <owner/repo> --json
gckit tag list <owner/repo> --yaml
gckit tag create <owner/repo> <tag_name> --ref main --message "v1.0.0"
gckit tag create <owner/repo> <tag_name> --ref main --json
# Releases
gckit release list <owner/repo>
gckit release list <owner/repo> --page 1 --per-page 50
gckit release list <owner/repo> --json
gckit release list <owner/repo> --yaml
gckit release create <owner/repo> <tag_name> --name "v1.0.0" --body "Release notes" --draft --prerelease
gckit release create <owner/repo> <tag_name> --name "v1.0.0" --json
# Issues
gckit issue list <owner/repo>
gckit issue list <owner/repo> --state all --page 1 --per-page 50
gckit issue list <owner/repo> --json
gckit issue list <owner/repo> --yaml
gckit issue get <owner/repo> <number>
gckit issue get <owner/repo> <number> --pull-requests
gckit issue get <owner/repo> <number> --comments --related-branches
gckit issue get <owner/repo> <number> --json
gckit issue get <owner/repo> <number> --yaml
gckit issue comments list <owner/repo> <number>
gckit issue branches list <owner/repo> <number>
gckit issue labels add <owner/repo> <number> bug "help wanted"
gckit issue labels add <owner/repo> <number> bug --json
gckit issue operate-logs <owner/repo> <number>
gckit issue create <owner/repo> <title> --body "details"
gckit issue create <owner/repo> <title> --json
gckit issue update <owner/repo> <number> --title "new title" --body "details"
gckit issue update <owner/repo> <number> --json
gckit issue close <owner/repo> <number>
gckit issue close <owner/repo> <number> --json
gckit issue close <owner/repo> <number> --yaml
gckit issue reopen <owner/repo> <number>
gckit issue reopen <owner/repo> <number> --json
gckit issue reopen <owner/repo> <number> --yaml
gckit issue pulls <owner/repo> <number>
gckit issue pulls <owner/repo> <number> --json
gckit issue pulls <owner/repo> <number> --yaml
gckit issue export <owner/repo> ./issues-export
gckit issue export <owner/repo> ./issues-export --state all --page 1 --per-page 50
# Issues — extended operations
gckit issue comments create <owner/repo> <number> --body "comment text"
gckit issue comments create <owner/repo> <number> --body "text" --json
gckit issue comments update <owner/repo> <number> <comment_id> --body "updated text"
gckit issue comments update <owner/repo> <number> <comment_id> --body "text" --yaml
gckit issue comments delete <owner/repo> <number> <comment_id> --yes
gckit issue comments delete <owner/repo> <number> <comment_id> --yes --json
gckit issue branches set <owner/repo> <number> <branch_name>...
gckit issue branches set <owner/repo> <number> main develop --json
gckit issue mine
gckit issue mine --state all --page 1 --per-page 50
gckit issue mine --json
gckit issue mine --yaml
# Pull Requests
gckit pr list <owner/repo>
gckit pr list <owner/repo> --state all --page 1 --per-page 50
gckit pr list <owner/repo> --search "Change-Id: I<change-id>"
gckit pr list <owner/repo> --json
gckit pr list <owner/repo> --yaml
gckit pr owner <owner> list
gckit pr owner <owner> list --state all --search "Change-Id: I<change-id>"
gckit pr owner <owner> list --json
gckit pr owner <owner> list --yaml
gckit pr get <owner/repo> <number>
gckit pr get <owner/repo> <number> --issues --comments --files --commits --merge-status
gckit pr get <owner/repo> <number> --json
gckit pr create <owner/repo> <title> --head feature --base main --body "details"
gckit pr create <owner/repo> <title> --head feature --base main --head-repo fork-owner --body "Cross-fork PR"
gckit pr create <owner/repo> <title> --yaml
gckit pr merge <owner/repo> <number> --merge-method squash --title "Merge title" --message "Merge body"
gckit pr merge <owner/repo> <number> --json
gckit pr merge <owner/repo> <number> --yaml
gckit pr close <owner/repo> <number>
gckit pr close <owner/repo> <number> --yaml
# Pull Requests — extended operations
gckit pr update <owner/repo> <number> --title "new title" --body "description"
gckit pr update <owner/repo> <number> --title "new title" --json
gckit pr comments create <owner/repo> <number> --body "comment text"
gckit pr comments create <owner/repo> <number> --body "inline review" --path src/file.py --commit-id abc123
gckit pr comments create <owner/repo> <number> --body "comment" --json
gckit pr comments update <owner/repo> <number> <comment_id> --body "updated text"
gckit pr comments update <owner/repo> <number> <comment_id> --body "text" --yaml
gckit pr comments delete <owner/repo> <number> <comment_id> --yes
gckit pr comments delete <owner/repo> <number> <comment_id> --yes --json
gckit pr review create <owner/repo> <number> --body "LGTM" --event APPROVED
gckit pr review create <owner/repo> <number> --body "needs work" --event REQUEST_CHANGES --json
gckit pr operate-logs <owner/repo> <number>
gckit pr operate-logs <owner/repo> <number> --json
gckit pr link <owner/repo> <number> <issue_number>...
gckit pr link <owner/repo> <number> 42 43 44 --json
gckit pr unlink <owner/repo> <number> <issue_number> --yes
gckit pr unlink <owner/repo> <number> 42 --yes --yaml
# Pull Requests — discussions (V4Client, v4 GitLab API)
gckit pr discussions <owner/repo> <number>
gckit pr discussions <owner/repo> <number> --per-page 50 --json
gckit pr discussions <owner/repo> <number> --yaml
# Search
gckit search repos <query>
gckit search repos <query> --sort stars --order desc --page 1 --json
gckit search issues <query>
gckit search issues <query> --sort created --order asc --yaml
gckit search users <query>
gckit search users <query> --sort followers --json
# Users
gckit user <username>
gckit user <username> --json
gckit user <username> --yaml
MCP 服务器
gckit 附带了一个 Model Context Protocol(MCP)服务器,该服务器提供基于 CLI 和仅 API 的工具。这使得 AI 代理(如 opencode.ai)能够通过标准工具界面与 GitCode 仓库、问题、PR 等进行交互。
启动服务器
gckit mcp
服务器采用标准输入输出(stdio)传输方式,不会向标准输出(stdout)打印任何内容,仅通过标准输入(stdin)监听 MCP JSON-RPC 消息。这是 AI 智能体集成的标准协议。
可用工具
MCP 服务器在 11 个资源组中提供了 92 个工具:
| 组 | 工具数量 | 描述 |
|---|---|---|
| auth | 1 | whoami |
| repo | 33 | list, info, create, delete, update, fork, forks, stargazers, subscribers, contributors, languages, activity, transfer, archive, unarchive, settings (get/update), pr-settings (get/update), push-config (get/set), transition (get/set), module, reviewer, member update, roles, file-list, blob, raw, trees, upload-image, upload-file |
| branch | 1 | list |
| content | 5 | get, create, update, delete, readme |
| hook | 6 | list, get, create, update, delete, test |
| issue | 16 | list, get, create, update, close, reopen, mine, pulls, comments (list/create/update/delete), labels add, operate-logs, branches (list/set) |
| pr | 21 | list, get, create, merge, close, update, comments (create/update/delete), review create, operate-logs, link, unlink, discussions (list/get/create/reply/note update/note delete/resolve), owner list |
| release | 3 | list, create, update |
| tag | 2 | list, create |
| search | 3 | repos, issues, users |
| user | 1 | Fetch user by username |
破坏性操作(delete、close、unlink)在其工具描述前会加上 [DESTRUCTIVE] 前缀,以便 AI 智能体在执行前进行标记。
身份验证
MCP 服务器通过与 CLI 相同的链来解析令牌:
GITCODE_TOKEN环境变量~/.config/gitcode/credentials(通过gckit auth login保存)
您也可以在工具调用中直接将令牌作为 token 参数传递(大多数 MCP 客户端支持此方式)。
针对 opencode.ai 的配置
要在 opencode.ai 中使用 gckit 作为 MCP 工具提供方,请将其添加到 .opencode/opencode.json:
{
// gckit MCP server — 92 tools for GitCode API
"mcp": {
"gckit": {
"type": "local",
"command": ["gckit", "mcp"],
"enabled": true,
"timeout": 30000
}
}
}
确保在环境中设置了 GITCODE_TOKEN,或者在启动代理前运行了 gckit auth login。
API 用法
Client 是 V5Client 的别名。两者可以互换使用。
import asyncio
from gckit import Client
from gckit.gitcode import GitCodeError, NotFoundError
from gckit.gitcode._retry import RetryConfig
async def main() -> None:
async with Client(
token='your-token',
retry_config=RetryConfig(max_retries=5, backoff_factor=2.0, initial_delay=1.0),
) as client:
user = await client.user('username')
print(f'{user.login}: {user.name}')
current_user = await client.get_current_user()
print(current_user.login)
repos = await client.list_repos(owner='organization', per_page=50)
for repo in repos:
print(f'{repo.full_name}: {repo.description}')
async for repo in client.iter_repos(owner='organization', per_page=100):
print(repo.full_name)
repo_resource = client.repo('owner', 'repository')
repo = await repo_resource.get_info()
print(repo.default_branch)
branches = await repo_resource.branches.list(per_page=50)
issues = await repo_resource.issues.list(state='open', per_page=50)
prs = await repo_resource.pulls.list(state='open', per_page=50)
for branch in branches:
print(branch.name)
for issue in issues:
print(f'#{issue.number}: {issue.title}')
for pr in prs:
print(f'#{pr.number}: {pr.title}')
# Tags
tags = await repo_resource.tags.list(per_page=50)
async for tag in repo_resource.tags.iter_all():
print(tag.name)
# Releases
releases = await repo_resource.releases.list(per_page=50)
new_release = await repo_resource.releases.create(
tag_name='v1.0.0',
name='Version 1.0.0',
body='Release notes',
)
# Content
readme = await repo_resource.content.get_readme()
file_content = await repo_resource.content.get('src/main.py')
dir_listing = await repo_resource.content.get('src')
created = await repo_resource.content.create(
'new_file.py',
message='Add file',
content='print("hello")',
branch='main',
)
updated = await repo_resource.content.update(
'README.md',
message='Update README',
content='# Updated',
sha='abc123',
branch='main',
)
await repo_resource.content.delete(
'old_file.py',
message='Remove file',
sha='def456',
branch='main',
)
# Webhooks
hooks = await repo_resource.hooks.list()
async for hook in repo_resource.hooks.iter_all():
print(f'Hook {hook.id}: {hook.url}')
new_hook = await repo_resource.hooks.create(
'https://example.com/hook',
['push', 'pull_request'],
config={'content_type': 'json', 'secret': 's3cret'},
)
print(f'Created hook {new_hook.id}')
updated_hook = await repo_resource.hooks.update(
new_hook.id, events=['push']
)
print(f'Updated hook {updated_hook.id}')
result = await repo_resource.hooks.test(new_hook.id)
print(f'Test result: {result}')
await repo_resource.hooks.delete(new_hook.id)
# Search
repo_results = await client.search_repositories('gckit', sort='stars', order='desc')
issue_results = await client.search_issues('bug', state='open')
user_results = await client.search_users('alice', sort='followers')
created_issue = await repo_resource.issues.create(
title='Bug report',
body='Something is wrong',
)
await repo_resource.issues.comments(created_issue.number)
await repo_resource.issues.related_branches(created_issue.number)
await repo_resource.issues.pull_requests(created_issue.number)
created_pr = await repo_resource.pulls.create(
title='Fix bug',
head='fix-branch',
base='main',
body='Fixes the reported bug.',
)
await repo_resource.pulls.issues(created_pr.number)
try:
await client.user('nonexistent-user')
except NotFoundError:
print('User not found')
except GitCodeError as exc:
print(f'API error: {exc}')
asyncio.run(main())
对于仅 v4 版本的端点(如 PR 讨论),请使用 V4Client:
import asyncio
from gckit import V4Client
async def main() -> None:
async with V4Client(token='your-token') as client:
repo = client.repo('owner', 'repository')
# PR discussions (v4 GitLab-compatible API)
discussions = await repo.pulls.discussions(42)
for discussion in discussions:
print(f'Discussion: {discussion.id}')
# Update a repo through v4 API (e.g. visibility)
updated = await repo.update(visibility='public')
print(f'Updated: {updated.name}')
asyncio.run(main())
开发
设置开发环境
git clone https://gitcode.com/pimenovdmitry/gckit.git
cd gckit
./scripts/setup-dev.sh
该脚本会安装依赖项、预提交钩子,还可选择为 direnv 自动激活功能创建 .envrc 文件,并验证设置是否正确。若要跳过交互式提示或直接运行命令行界面:
uv sync --extra dev
uv run pre-commit install
./scripts/gckit --help
运行测试
uv run pytest
uv run pytest --cov=gckit
uv run pytest tests/unit/
uv run pytest tests/integration/ -m integration
uv run pytest tests/quality/test_unit_functional_overlap.py::test_unit_tests_do_not_duplicate_functional_coverage
uv run pytest -k "test_user"
默认情况下,pytest 会从 pyproject.toml 中读取配置 -m 'not slow and not real_api',因此执行 uv run pytest 会包含单元测试和模拟集成测试。实时 real_api 测试保持独立,必须显式指定才能运行。若要针对模拟集成测试覆盖率,可使用 uv run pytest tests/integration/ -m integration;若要使用默认标记选择运行集成文件,可执行 uv run pytest tests/integration/。
重复单元测试重叠检查(tests/quality/test_unit_functional_overlap.py::test_unit_tests_do_not_duplicate_functional_coverage)会将每个单元测试的覆盖率与功能测试覆盖率进行比较。如果检查报告某个单元测试已被功能测试完全覆盖,请删除该冗余单元测试,而非将其移至 tests/integration/ 目录。
CLI 测试涵盖全局选项(--token、--debug)、repo 等直接根命令、用于人工输出的 Textual 启动和非 TTY 拒绝机制,以及输出/分页标志,包括 --page、--per-page、--state、--json、--yaml、--pull-requests、--comments、--related-branches、--issues、--files、--commits 和 --merge-status。
代码质量
uv run ty check
uv run ruff check
uv run ruff check --fix
uv run ruff format
uv run ruff format --check
API 发现
除了已文档化的 v5 REST API 外,GitCode 还公开了多个 API 版本和网关。
| API | 基础 URL | 路径格式 | 文档 |
|---|---|---|---|
| v5 REST | api.gitcode.com/api/v5 |
/repos/{owner}/{repo}/... |
docs.gitcode.com |
| v4 GitLab | api.gitcode.com/api/v4 |
/projects/{owner}%2F{repo}/merge_requests/... |
未文档化 |
| Web API | web-api.gitcode.com |
内部(SPA) | 未文档化 |
查找隐藏端点的方法
-
JS 包:SPA 会加载包含 API 路径的供应商代码块:
curl -sL https://gitcode.com | grep -oP 'assets/index-[^.]+\.js' | head -1 # 然后在 JS 中搜索 API 模式: curl -s https://cdn-static.gitcode.com/assets/index-*.js | grep -oP '/api/v\\d/[^"]+' | sort -u -
API 版本探测:如果 v5 没有所需端点,可以尝试使用相同的 token 访问 v4、v3、v1:
curl -s --header "PRIVATE-TOKEN: $GITCODE_TOKEN" \ "https://api.gitcode.com/api/v4/projects/{owner}%2F{repo}/merge_requests/{iid}/discussions" -
域名变体:
api.gitcode.com与web-api.gitcode.com -
路径格式变体:GitHub 风格(
/repos/o/r/pulls/n)与 GitLab 风格(/projects/o%2Fr/merge_requests/n) -
资源名称变体:
pulls与merge_requests,单数与复数(/review与/reviews)
示例:pr discussions 功能是通过在 JS 包中找到 diff_review_record_list 发现的,然后探测 API 版本(v4 可行),接着切换到 GitLab 路径格式(/projects/{owner}%2F{repo}/merge_requests/{iid}/discussions)。
许可证
MIT 许可证 - 详情参见 LICENSE 文件。
项目介绍
用户可通过该项目便捷地与 GitCode API 交互,实现仓库、问题、拉取请求等管理操作。提供异步 API 客户端、类型安全模型、自动重试机制及直观的命令行界面,支持 token 认证与配置持久化。【此简介由AI生成】
定制我的领域