From ddc5a0b14c4720d3b52b1b6cd16afc771e407b7e Mon Sep 17 00:00:00 2001 From: xbghc <58060018+xbghc@users.noreply.github.com> Date: Wed, 22 Oct 2025 18:47:48 +0800 Subject: [PATCH 1/6] docs: refresh gitcode-api guides --- docs/gitcode-actions/index.md | 111 +++++++- docs/gitcode-api/index.md | 200 ++++---------- docs/gitcode-api/issue.md | 195 ++++--------- docs/gitcode-api/pr.md | 185 +++---------- docs/gitcode-api/repo.md | 501 ++++------------------------------ docs/gitcode-api/user.md | 178 ++++-------- 6 files changed, 362 insertions(+), 1008 deletions(-) diff --git a/docs/gitcode-actions/index.md b/docs/gitcode-actions/index.md index 7a822e5..b5b6bc4 100644 --- a/docs/gitcode-actions/index.md +++ b/docs/gitcode-actions/index.md @@ -4,9 +4,15 @@ title: GitCode Actions 工具库 # @xbghc/gitcode-actions(GitCode Actions 工具库) -提供 GitCode 平台的自动化工作流和 GitHub Actions 集成功能。 +提供 GitCode 平台的自动化工作流、容器编排以及 AI 评论助手等能力。 -包路径:`packages/core` +包路径:`packages/gitcode-actions` + +主要能力分为三大类: + +- **事件监听器**:`watchPullRequest`、`watchIssues` 可持续轮询仓库事件并触发回调。 +- **容器与构建工具**:`createPrContainer`、`testShaBuild`、`chat` 等帮助在隔离环境中执行构建或对话任务。 +- **AI 评论助手**:`watchAiMentions`/`runAiMentionsOnce` 监听 `@AI` 等提及并自动生成回复。 ## 功能 @@ -57,11 +63,16 @@ prWatcher.start(); - `onClosed`: PR 关闭时触发。 - `onMerged`: PR 合并时触发。 - `onComment`: PR 有新评论时触发。 +- `commentType`: 仅监听指定类型的评论,支持 `diff_comment` 与 `pr_comment`,默认同时监听。 - `intervalSec`: 检查间隔时间(秒),默认为 5。 - `container`: 传入对象以启用内置容器管理(传 `false` 禁用)。 - `onContainerCreated`: 容器创建后触发。 - `onContainerRemoved`: 容器删除后触发。 +监视器的状态会持久化到 `~/.gitcode/watchers/prs/*.json`,便于在进程重启后延续最近一次的基线数据。可调用 `runOnce()` 进行单次轮询,或 `stop()` 停止后台定时任务。 + +`container` 对象支持 `image`、`env`、`autoRemove` 三个字段,对应 `ContainerOptions` 定义,可覆盖默认镜像或注入额外环境变量。 + **返回值:** - 返回一个 `PullRequestWatcher` 实例,该实例提供以下方法: @@ -98,12 +109,16 @@ issueWatcher.start(); // await issueWatcher.runOnce(); ``` -可通过 `issueQuery`/`commentQuery` 控制拉取范围,例如 `per_page`、`state` 等。 +可通过 `issueQuery`/`commentQuery` 控制拉取范围,例如 `per_page`、`state` 等。默认 `intervalSec` 为 5 秒,可按需调整。 + +监视器会把最后一次看到的评论 ID 保存在 `~/.gitcode/watchers/issues/*.json` 中,避免重复触发回调。`runOnce()` 可在不启动后台定时任务的情况下执行一次检测。 ### AI 评论助手 `watchAiMentions` 会同时监听 Issue 评论与 PR 评论。当新增评论中包含指定标记(默认为 `@AI`)时,会收集 Issue 标题、描述、历史评论等上下文,并将拼装后的提示语传入 `chat`。当 AI 调用成功且生成了内容时,会自动在对应的 Issue 或 PR 下创建回复评论。 +若只需在脚本中执行一次检测与回复,可使用 `runAiMentionsOnce`,它会串行执行一次 Issue/PR 轮询并立即处理所有检测到的提及。 + ```ts import { watchAiMentions } from '@xbghc/gitcode-actions'; import { GitcodeClient } from '@xbghc/gitcode-api'; @@ -130,8 +145,11 @@ const aiWatcher = watchAiMentions(client, 'https://gitcode.com/owner/repo.git', 可通过以下选项自定义行为: - `mention`: 触发标记,默认 `@AI` -- `buildPrompt(context)`: 自定义提示语内容 +- `buildPrompt(context)`: 自定义提示语内容,可复用导出的 `defaultPromptBuilder` - `issueIntervalSec` / `prIntervalSec`: Issue 与 PR 轮询频率 +- `issueQuery` / `issueCommentQuery`: 控制轮询 Issue 及其评论的筛选条件 +- `prCommentType`: 限定监听的 PR 评论类型(`diff_comment` 或 `pr_comment`) +- `chatOptions`: 传给 `chat` 的容器选项(如 `sha`、`keepContainer` 等) - `chatExecutor`: 自定义 chat 执行器,默认使用内置 `chat` - `includeIssueComments` / `includePullRequestComments`: 控制监听的评论类型 - `replyWithComment`: 是否自动在 Issue/PR 下回复评论,默认 `true` @@ -141,9 +159,11 @@ const aiWatcher = watchAiMentions(client, 'https://gitcode.com/owner/repo.git', 若只希望监听但不自动回复,可设置 `replyWithComment: false`;如需对回复内容进行包装,例如附带原评论引用,可通过 `buildReplyBody` 返回自定义文本。 -默认提示语会包含仓库、Issue 与评论上下文,并明确要求 AI 使用中文进行回复。 +默认提示语(`defaultPromptBuilder`)会包含仓库、Issue/PR 与评论上下文,并明确要求 AI 使用中文进行回复。 -## 工作原理 +AI 监听器内部复用 `watchIssues` 与 `watchPullRequest`,因此同样会在 `~/.gitcode/watchers` 下持久化基线数据,避免重复处理历史评论。 + +## PR 监控工作原理 - 按指定间隔检查 PR 列表(默认 5 秒) - 检测 PR 状态变化(新建、关闭、合并) @@ -151,9 +171,11 @@ const aiWatcher = watchAiMentions(client, 'https://gitcode.com/owner/repo.git', - 自动触发相应的回调函数 - 使用 `client.pr.list()` 获取 PR 数据 -## PR 构建容器 +## 容器与构建工具 + +提供在隔离的 Docker 容器中构建和测试 PR、运行 Claude Code 对话、验证提交可构建性的能力。 -提供在隔离的 Docker 容器中构建和测试 PR 的能力。 +### PR 构建容器 ```ts import { @@ -226,6 +248,7 @@ if (container) { 容器内可访问以下环境变量: - `PR_BASE_REPO_URL`、`PR_HEAD_REPO_URL` +- `PR_REPO_URL`(与 `PR_BASE_REPO_URL` 一致,便于脚本统一读取) - `PR_BASE_SHA`、`PR_HEAD_SHA` - 若设置,所有以 `ANTHROPIC_` 开头的 Claude 相关变量都会被转发 @@ -262,6 +285,73 @@ console.log('文件已复制到容器内:', targetPath); - 若需要重命名文件,可传入完整的目标路径,例如 `/tmp/workspace/output.log`。 - 目录同样支持复制,若希望重命名目录,可使用不带结尾 `/` 的路径(如 `/tmp/workspace/build-cache`)。 - 该方法会自动在容器中创建缺失的父目录,并在必要时执行重命名操作。 +- 若复制过程中出现问题,会抛出 `CopyToContainerError` 以便上层捕获处理。 + +### testShaBuild:提交构建预检 + +`testShaBuild(repoUrl, sha, options)` 会按顺序在临时容器中执行克隆、校验 SHA、检出、项目诊断以及依赖安装,帮助在合并前快速判断某个提交是否具备构建条件。 + +```ts +import { testShaBuild } from '@xbghc/gitcode-actions'; + +const result = await testShaBuild('https://gitcode.com/owner/repo.git', 'main', { + nodeVersion: '20', + verbose: true, +}); + +if (!result.success) { + console.error(result.error); + console.dir(result.diagnostics, { depth: null }); +} +``` + +预检流水线包含以下步骤: + +1. `prepareImage`:拉取或复用指定版本的 Node.js 镜像。 +2. `createWorkspaceContainer`:创建带有持久日志的工作容器。 +3. `cloneRepo`:将仓库克隆至 `/tmp/workspace`。 +4. `verifySha` 与 `checkoutSha`:确认目标提交/分支存在并检出。 +5. `checkProjectFiles`:执行基础文件检查并通过 `collectDiagnostics` 解析 `package.json`、`pnpm-lock.yaml` 等信息。 +6. `installDependencies`:使用 `corepack pnpm install` 安装依赖,内置 3 次指数退避重试。 + +`options` 支持: + +- `nodeVersion`: 使用的 Node.js 镜像版本,默认 `18`。 +- `verbose`: 输出容器执行过程的详细日志。 +- `keepContainer`: 是否在结束后保留容器以便排查。 + +返回的 `TestShaBuildResult` 提供结构化诊断: + +- `diagnostics.dockerAvailable`/`imagePullStatus`: 判断 Docker 是否可用以及镜像拉取状态。 +- `diagnostics.repoAccessible`: 是否成功克隆仓库。 +- `diagnostics.packageJsonExists`、`pnpmLockExists`、`isPnpmProject`: 项目元数据检查结果。 +- `diagnostics.steps`: 每个步骤的耗时、成功状态与错误摘要。 +- 若执行失败,`error` 字段会包含首个失败步骤的提示。 + +当输出为空导致诊断无法解析时,会抛出 `DiagnosticsCollectionError`;可捕获后追加上下文日志。 + +### 构建步骤工具 + +如需自定义流水线,可直接调用各个底层步骤: + +- `prepareImage(options)`: 校验镜像是否存在,不存在则拉取,失败时会抛出 `ImagePullError`。 +- `createWorkspaceContainer(options)`: 创建或复用带标签的工作容器,可通过 `reusable`、`repoUrl`、`branch` 在后续复用,异常时抛出 `ContainerCreationError`。 +- `cloneRepo(options)`: 克隆仓库到 `/tmp/workspace`。 +- `verifySha(options)`: 校验目标 SHA 是否存在;若失败会回退检测是否为分支名。 +- `checkoutSha(options)`: 检出指定 SHA 或分支。 +- `checkProjectFiles(options)`: 执行基础文件检测,返回 `ProjectCheckResult`(包含 `StepResult` 与 `ProjectDiagnostics`)。 +- `collectDiagnostics(output)`: 解析步骤输出,判断是否为 pnpm 项目。 +- `installDependencies(options)`: 根据项目的 `packageManager` 字段自动选择 pnpm 版本并进行安装,带指数退避重试。 +- `executeStep(options)`: 在容器内执行任意脚本并返回 `StepResult`,失败时抛出 `StepExecutionError`。 +- `cleanupPrContainers()`: 扫描并清理遗留的 PR 容器。 + +### 安装 CLI 工具 + +- `installClaudeCli(options)`: 在容器中全局安装 `@anthropic-ai/claude-code`。 +- `installGitcodeCli(options)`: 将本地 `@xbghc/gitcode-cli` 打包后复制进容器并全局安装。 +- `installCli({ name, script, ... })`: 统一的安装入口,可自定义安装脚本与名称。 + +所有安装工具都会复用 `executeStep`,并支持传入额外环境变量 (`env`) 与 `verbose` 日志输出。 ### 通过 Claude Code 进行对话 @@ -279,6 +369,9 @@ console.log(result.output); - `sha`: 目标提交或分支,默认 `dev` - `container`: 传入已有容器以复用,否则自动创建临时容器 +- `nodeVersion`: 自动创建容器时使用的 Node.js 版本,默认 `18` - `keepContainer`: 创建的临时容器是否保留,默认 `false` +- `verbose`: 是否输出调试日志 +- `npmRegistry` / `pnpmRegistry`: 自定义依赖安装时使用的镜像源 -调用过程中会自动转发宿主机上所有以 `ANTHROPIC_` 开头的环境变量,以便 Claude Code 正确认证。 +调用过程中会自动转发宿主机上所有以 `ANTHROPIC_` 开头的环境变量,以便 Claude Code 正确认证。函数返回 `ChatResult`,包含 `success`、`output`(成功时)与 `error`(失败时)等字段。当 `sha` 为 `dev` 且未显式传入容器时,会尝试复用共享的开发容器。 diff --git a/docs/gitcode-api/index.md b/docs/gitcode-api/index.md index abe1f9a..08051b4 100644 --- a/docs/gitcode-api/index.md +++ b/docs/gitcode-api/index.md @@ -1,173 +1,89 @@ --- -title: gitcode 工具库 +title: GitCode API 工具库 --- -# @xbghc/gitcode-api(工具库) +# @xbghc/gitcode-api(GitCode API 工具库) -提供 [GitCode API](https://docs.gitcode.com/docs/apis/) 访问与认证封装,以及 Git 远程地址解析工具。 +封装了访问 [GitCode REST API](https://docs.gitcode.com/docs/apis/) 所需的客户端、类型定义与 URL 构建工具,并附带常用的仓库地址解析与查询参数处理函数。 -包路径:`packages/gitcode` +- **包路径**:`packages/gitcode-api` +- **导出形式**:ESM(`import { GitcodeClient } from '@xbghc/gitcode-api'`) -## 导出内容 - -- `parseGitUrl(url: string): Remote | null` - - 解析 `https://gitcode.com/owner/repo(.git)` 或 `git@gitcode.com:owner/repo(.git)` 这类 URL。 -- `GitcodeClient` - - 轻量 HTTP 客户端,内置鉴权处理。 - - `getUserProfile()`:获取当前认证用户的个人资料信息。 - - `getSelfRepoPermissionRole(owner, repo)`:获取权限并归一化为 `admin | write | read | none`。 - - `listPullRequests(owner, repo, query?)`:获取仓库的 Pull Request 列表。 - - `createPullRequest(owner, repo, body)`:创建 Pull Request(支持字段:`title`、`head`、`base`、`body`、`issue`)。 - - `listPullRequestComments(url, prNumber, queryOptions?)`:获取指定 PR 的评论列表。 - - `listIssues(url, query?)`:获取仓库的 Issue 列表。 - - 也可通过模块方式调用:`client.repo.getSelfRepoPermissionRole()`、`client.pr.list()`、`client.pr.create()`、`client.pr.comments()`、`client.issue.list()` 等。 -- `GitcodeClientAuth` - - 通过 `client.auth` 提供本地令牌存储与加载。 -- `FileAuthStorage`、`defaultConfigPath()` - -更多 API: - -- 用户 API:见《[用户 API](./user.md)》。 -- Pull Requests:见《[Pull Requests API](./pr.md)》。 -- Issues:见《[Issues API](./issue.md)》。 - -## 公共类型 - -- `Remote`: 解析 Git 远程地址后的结果(`owner`、`repo`、`host?`)。 -- `RepoRole`: 仓库权限归一化结果,`'admin' | 'write' | 'read' | 'none'`。 -- `UserProfile`: 用户完整资料信息,包含 `id`、`login`、`name`、`email`、`avatar_url`、`followers`、`following`、`top_languages` 等字段。 -- `SelfPermissionResponse`: 当前用户在仓库的权限树响应;相关类型:`RoleInfo`、`PermissionPoint`、`ResourceNode`。 -- `ListPullsQuery`: PR 列表查询参数(常用:`state`、`page`、`per_page`、`head`、`base`、`sort`、`direction`)。 -- `ListPullsParams`: PR 列表路径参数(`owner`、`repo`、`query?`)。 -- `PullRequest`: PR 的完整字段表示(`id`、`number`、`title`、`state`、`user`、`head`、`base`、`created_at`、`updated_at`、`merged_at` 等)。 -- `ListPullsResponse`: `PullRequest[]`。 -- `CreatePullBody`: 创建 PR 的字段(`title?`、`head?`、`base?`、`body?`、`issue?`)。 -- `PRComment`: PR 评论的类型定义,包含 `id`、`body`、`user` 等字段。 -- `PRCommentQueryOptions`: PR 评论查询选项,支持 `comment_type`(`diff_comment` | `pr_comment`)。 -- `ListIssuesQuery`: Issue 列表查询参数(`state`、`labels`、`page`、`per_page`、`sort`)。 -- `ListIssuesParams`: Issue 列表路径参数(`owner`、`repo`、`query?`)。 -- `Issue`: Issue 的字段表示(`id`、`html_url`、`number`、`state`、`title`、`body`、`user`)。 -- `ListIssuesResponse`: `Issue[]`。 - -## 认证与请求 - -默认 API 基址:`https://gitcode.com/api/v5`,客户端固定使用请求头鉴权: - -- `Authorization: Bearer ` - -请求在网络连接失败时会自动重试 3 次,可通过 `retries` 选项自定义。 - -环境变量: - -- `GITCODE_TOKEN`:令牌(优先级高于磁盘存储) -- `GITCODE_HTTP_DEBUG`:开启 HTTP 调试日志,接受 `1`、`true`、`yes`、`on`、`debug` 等值 -- `GITCODE_HTTP_DEBUG_SHOW_SECRETS`:在调试日志中展示敏感头部(默认隐藏) - -**Token 读取优先级**: - -1. 环境变量 `GITCODE_TOKEN` -2. 本地配置文件 `~/.gitany/gitcode/config.json` - -### 认证使用示例 +## 快速开始 ```ts -import { GitCodeClient } from '@xbghc/gitcode-api'; +import { GitcodeClient } from '@xbghc/gitcode-api'; -const client = new GitcodeClient(); -await client.auth.setToken('your_token', 'bearer'); +// 构造函数可直接接收 token(默认会读取 GITCODE_TOKEN 环境变量) +const client = new GitcodeClient(process.env.GITCODE_TOKEN); -const token = await client.auth.token(); // 获取 token(环境变量优先) -console.log(token); +// 也可以稍后通过 auth 模块设置 +client.auth.setToken('your-token'); -const me = await client.request('/user', 'GET'); +// 通过模块化分组访问不同资源 +const pulls = await client.pr.list('https://gitcode.com/owner/repo.git', { state: 'open' }); +const issues = await client.issue.list('https://gitcode.com/owner/repo.git', { per_page: 50 }); +const profile = await client.user.getProfile(); ``` -默认本地存储路径:`~/.gitany/gitcode/config.json` +### 请求总览 -### GitcodeClient 用法 +- 所有请求最终调用 `client.request(url, method, options)`。 +- `options.searchParams`:用于 GET 查询参数,自动序列化基础类型。 +- `options.json`:发送 JSON 请求体;如需原始体,可使用 `options.body`。 +- `options.retry`:控制 `got` 的重试策略(默认继承全局配置并追加 `POST`/`PUT` 重试支持)。 +- 内置 ETag 缓存,会在返回 `304` 时复用上次结果;可通过 `isNotModified(result)` 判断复用命中。 +- 设置环境变量 `GITCODE_HTTP_DEBUG=1` 可打印请求/响应日志,`GITCODE_HTTP_DEBUG_SHOW_SECRETS=1` 会取消 Header 脱敏。 -```ts -import { GitcodeClient } from '@xbghc/gitcode-api'; +## 主要导出 -const client = new GitcodeClient({ - token: process.env.GITCODE_TOKEN ?? null, -}); - -// 获取当前用户信息(GET /api/v5/user) -const profile = await client.getUserProfile(); - -// 获取当前用户在某仓库的权限(GET /repos/{owner}/{repo}/collaborators/self-permission) -const perm = await client.getSelfRepoPermission('owner', 'repo'); - -// 获取 PR 列表(GET /repos/{owner}/{repo}/pulls) -const pulls = await client.listPullRequests('owner', 'repo', { - state: 'open', - page: 1, - per_page: 20, -}); - -// 创建 PR(POST /repos/{owner}/{repo}/pulls) -const pr = await client.createPullRequest('owner', 'repo', { - title: '修复登录异常', - head: 'feat/login-fix', - base: 'main', - body: '补充说明:修复 Token 过期报错', - // 可选:关联 issue - issue: 123, -}); - -// 获取 PR 评论(GET /repos/{owner}/{repo}/pulls/{number}/comments) -const comments = await client.listPullRequestComments('https://gitcode.com/owner/repo.git', 123, { - comment_type: 'pr_comment', -}); - -// 获取 Issue 列表(GET /repos/{owner}/{repo}/issues) -const issues = await client.issue.list('https://gitcode.com/owner/repo.git', { state: 'open' }); -``` - -## Git URL 解析 +### 客户端 -```ts -import { parseGitUrl } from '@xbghc/gitcode-api'; +- `GitcodeClient`:带 `pr`、`issue`、`repo`、`user` 子模块以及 `auth` 管理器的核心客户端。 +- `GitcodeClientAuth`:轻量认证容器,提供 `setToken()` 与 `token()`,默认读取 `GITCODE_TOKEN`。 -parseGitUrl('https://gitcode.com/owner/repo.git'); -// => { host: 'gitcode.com', owner: 'owner', repo: 'repo' } - -parseGitUrl('git@gitcode.com:owner/repo.git'); -// => { host: 'gitcode.com', owner: 'owner', repo: 'repo' } -``` +### 工具函数 -## 变更说明 +- `parseGitUrl(url)`:解析 HTTPS/SSH 仓库地址,返回 `{ owner, repo, host? }`,无法解析时返回 `null`。 +- `toGitUrl(url)`:确保仓库地址带 `.git` 后缀(幂等)。 +- `toQuery(object)`:剔除 `undefined` 字段后输出可直接传给 `searchParams` 的对象。 +- `isNotModified(value)`:判断返回数据是否由 ETag 缓存复用。 +- `isObjectLike(value)`:判定对象-like 值(工具方法,在 HTTP 错误处理等场景使用)。 -### 2025-09-10 更新 +### API URL & Schema 构建器 -- **移除 shared 包**:项目结构简化,移除了 `@gitany/shared` 包依赖 -- **改进类型系统**: - - `getUserProfile()` 现在返回完整的 `UserProfile` 类型,包含丰富的用户信息字段 - - `PullRequest` 类型现在包含完整的 API 响应字段 - - `RepoRole` 类型直接在 gitcode 包中定义,不再依赖 shared 包 -- **功能增强**:客户端现在返回更完整的 API 响应数据,提供更多有用信息 +包入口导出全部 URL 构建函数与 Zod Schema,覆盖 PR、Issue、Repo、User 四大类资源。例如: -### 2025-09-11 更新 +- PR:`listPullsUrl`、`createPullUrl`、`prCommentsUrl`、`pullRequestSettingsUrl`、`createPrCommentUrl`、`prCountUrl` 等。 +- Issue:`listIssuesUrl`、`issueCommentsUrl`、`createIssueUrl`、`createIssueCommentUrl`、`getIssueUrl`、`updateIssueUrl` 等。 +- Repo:`repoSettingsUrl`、`repoEventsUrl`、`contributorsUrl`、`branchesUrl`、`commitsUrl`、`fileBlobUrl`、`compareUrl`、`webhooksUrl` 等。 +- User:`userProfileUrl`、`userNamespaceUrl`。 -- PR 列表、PR 评论和仓库权限接口的返回数据均通过 Zod 进行结构校验。 -- 自身权限接口在角色信息中保留 `cn_name` 字段以确保权限检测。 +### 类型定义(节选) -### 2025-09-12 更新 +- PR:`PullRequest`、`PullRequestSettings`、`PRComment`、`CreatedPrComment`、`PrCount`。 +- Issue:`Issue`、`IssueComment`、`CreatedIssue`、`CreatedIssueComment`、`IssueDetail`、`UpdatedIssue`、`UpdatedIssueComment`。 +- Repo:`RepoSettings`、`RepoEvents`、`Contributors`、`Branch`、`Branches`、`Commits`、`FileBlob`、`Compare`、`Webhook`、`Webhooks`。 +- User:`UserProfile`、`UserNamespace`、`UserSummary`。 +- 权限:`SelfPermissionResponse`、`RoleInfo`、`PermissionPoint`、`ResourceNode`、`RepoRole`。 -- 新增 Issue 列表 API 封装。 +## 模块概览 -### 2025-09-13 更新 +- `client.pr`:拉取/创建 PR、读取评论、创建评论、读取 PR 设置、统计 PR 数量等。详见《[Pull Requests API](./pr.md)》。 +- `client.issue`:列出、读取、创建、更新 Issue 以及管理 Issue 评论。详见《[Issues API](./issue.md)》。 +- `client.repo`:仓库权限、设置、事件流、贡献者、分支、提交、文件内容与 Webhook。详见《[仓库 API](./repo.md)》。 +- `client.user`:获取当前登录用户资料与命名空间信息。详见《[用户 API](./user.md)》。 -- 网络请求在连接失败时会自动重试 3 次,提高稳定性。 +## 认证与环境变量 -### 2025-09-17 更新 +- `GITCODE_TOKEN`:默认读取的访问令牌,可通过 `client.auth.setToken()` 动态覆盖。 +- `GITCODE_HTTP_DEBUG`:值为 `1/true/on/debug` 时输出调试日志。 +- `GITCODE_HTTP_DEBUG_SHOW_SECRETS`:调试日志中保留授权头。 -- `utils/http.ts` 迁移至 `got`,并将 `HttpRequestOptions` 的字段与其约定对齐: - - `query` 更名为 `searchParams` - - 推荐使用 `json` 传递 JSON 负载,仍可通过 `body` 发送原始数据 -- 由于字段名称调整,调用方需要同步更新对应参数。 +客户端使用 `Bearer` 头部发送 Token;未提供 Token 时,将以匿名方式访问公开资源。 -### 历史变更 +## 变更记录 -- 内部统一使用 `utils/http.ts` 的 `httpRequest` 进行网络请求,实现 URL 构建、头部合并、鉴权与错误处理的集中管理,并在 2025-09-17 起交由 `got` 处理重试与解析逻辑,同时保留基于 ETag 的缓存。 +- **2025-09-17**:HTTP 层迁移至 `got`,新增 ETag 缓存、重试与调试日志;请求选项重命名为 `searchParams`/`json`。 +- **2025-09-13**:补全仓库、PR、Issue 相关 API,并以 Zod 校验响应;新增 `client.issue.update()`、`client.pr.createComment()`、`client.pr.count()` 等封装。 +- **2025-09-12**:新增 Issue 读写接口与命名空间 API,`parseGitUrl`/`toGitUrl` 暴露给外部使用。 diff --git a/docs/gitcode-api/issue.md b/docs/gitcode-api/issue.md index e7a3531..9732eb2 100644 --- a/docs/gitcode-api/issue.md +++ b/docs/gitcode-api/issue.md @@ -4,7 +4,7 @@ title: Issues API # Issues -提供与 Issue 相关的类型与路径构建工具,并通过 `GitcodeClient` 暴露便捷方法。 +Issue 模块提供列表、读取、创建、更新以及评论管理等功能,并导出相应的 URL 构建函数与类型。 适用接口: @@ -12,170 +12,83 @@ title: Issues API - 评论:GET `/api/v5/repos/{owner}/{repo}/issues/{number}/comments` - 创建:POST `/api/v5/repos/{owner}/issues` - 创建评论:POST `/api/v5/repos/{owner}/{repo}/issues/{number}/comments` +- 获取详情:GET `/api/v5/repos/{owner}/{repo}/issues/{number}` +- 更新 Issue:PATCH `/api/v5/repos/{owner}/{repo}/issues/{number}` +- 更新评论:PATCH `/api/v5/repos/{owner}/{repo}/issues/comments/{comment_id}` -## 类型与导出 +## 导出与类型 -### 列表相关 +- `ListIssuesQuery`、`ListIssuesParams`、`Issue`、`ListIssuesResponse`。 +- `IssueCommentsQuery`、`IssueComment`、`IssueCommentsResponse`。 +- `CreateIssueBody`、`CreateIssueParams`、`CreatedIssue`。 +- `CreateIssueCommentBody`、`CreateIssueCommentParams`、`CreatedIssueComment`。 +- `IssueDetail`、`UpdateIssueBody`、`UpdateIssueParams`、`UpdatedIssue`、`UpdatedIssueComment`。 +- URL/Schema:`listIssuesUrl`、`issueCommentsUrl`、`createIssueUrl`、`createIssueCommentUrl`、`getIssueUrl`、`updateIssueUrl` 等。 -- `ListIssuesQuery`:Issue 列表查询参数(`state`、`labels`、`page`、`per_page`、`sort`)。 -- `ListIssuesParams`:包含 `owner`、`repo` 与可选 `query`。 -- `Issue`:Issue 的最小字段表示(`id`、`html_url`、`number`、`state`、`title`、`body`、`user`、`assignees`、`labels`、`created_at`、`updated_at`)。 -- `ListIssuesResponse`:`Issue[]`。 -- `IssueCommentsQuery`:Issue 评论查询参数(`page`、`per_page`)。 -- `IssueComment`:Issue 评论的最小字段表示(`id`、`comment_id?`、`body`、`user`、`created_at?`、`updated_at?`)。 -- `IssueCommentsResponse`:`IssueComment[]`。 -- `listIssuesUrl(owner, repo)`:构建列表接口绝对 URL。 -- `issueCommentsUrl(owner, repo, number)`:构建评论列表接口绝对 URL。 +所有条目均由包入口导出。 -### 创建相关 - -- `CreateIssueBody`:创建 Issue 的请求体(`repo`、`title`、`body`、`assignee`、`milestone`、`labels` 等)。 -- `CreateIssueParams`:包含 `owner` 与 `body`。 -- `CreatedIssue`:创建成功的 Issue 完整字段表示。 -- `CreateIssueCommentBody`:创建 Issue 评论的请求体(`body`)。 -- `CreateIssueCommentParams`:包含 `owner`、`repo`、`number` 与 `body`。 -- `CreatedIssueComment`:创建成功的 Issue 评论完整字段表示。 -- `createIssueUrl(owner)`:构建创建 Issue 接口绝对 URL。 -- `createIssueCommentUrl(owner, repo, number)`:构建创建 Issue 评论接口绝对 URL。 - -以上均从包入口 `@xbghc/gitcode-api` 导出。 - -## 使用示例 - -### 列表操作 - -```ts -import { GitcodeClient, listIssuesUrl } from '@xbghc/gitcode-api'; - -const client = new GitcodeClient({ token: process.env.GITCODE_TOKEN ?? null }); - -// 1) 列表 Issues(通过 options.query 传参) -const listUrl = listIssuesUrl('owner', 'repo'); -const issues = await client.request(listUrl, 'GET', { - query: { state: 'open', page: 1, per_page: 20, labels: 'bug', sort: 'updated' }, -}); - -// 也可通过模块方式调用: -const issues2 = await client.issue.list('https://gitcode.com/owner/repo.git', { - state: 'open', - sort: 'updated', -}); - -// 2) 列表 Issue 评论 -const comments = await client.issue.comments('https://gitcode.com/owner/repo.git', 42, { - page: 1, - per_page: 20, -}); -``` - -### 读取与更新操作 +## 客户端用法 ```ts import { GitcodeClient } from '@xbghc/gitcode-api'; -const client = new GitcodeClient(); +const repoUrl = 'https://gitcode.com/owner/repo.git'; +const client = new GitcodeClient(process.env.GITCODE_TOKEN); -// 1) 获取单个 Issue 详情 -const issueDetails = await client.issue.get('https://gitcode.com/owner/repo', 42); -console.log(issueDetails.title, issueDetails.state); +// 1) 列表 Issue 与评论 +const issues = await client.issue.list(repoUrl, { state: 'open', per_page: 30 }); +const comments = await client.issue.comments(repoUrl, 42, { per_page: 10 }); -// 2) 更新一个 Issue -const updatedIssue = await client.issue.update('https://gitcode.com/owner/repo', 42, { - title: '新的 Issue 标题', - body: '更新后的内容。', - state: 'closed', // 可选 -}); -console.log(`Issue #${updatedIssue.number} 已更新并关闭。`); -``` - -### 创建操作 +// 2) 获取与更新 Issue +const detail = await client.issue.get(repoUrl, 42); +const updated = await client.issue.update(repoUrl, 42, { body: `${detail.body}\n\n已确认。` }); -```ts -import { GitcodeClient } from '@xbghc/gitcode-api'; - -const client = new GitcodeClient(); - -// 1) 创建 Issue -const issue = await client.issue.create({ - owner: 'username', +// 3) 创建 Issue 与评论 +const createdIssue = await client.issue.create({ + owner: 'owner', body: { - repo: 'my-repo', + repo: 'repo', title: '发现一个 Bug', - body: '详细描述 bug 的复现步骤...', - assignee: 'developer-username', // 可选,单个用户名或逗号分隔的多个用户名 - milestone: 1, // 可选 - labels: 'bug,critical', // 可选 + body: '详细描述复现步骤', + assignee: 'user1,user2', }, }); -console.log(`Issue 创建成功: ${issue.html_url}`); - -// 1b) 创建 Issue(多个 assignees) -const issueMultiple = await client.issue.create({ - owner: 'username', - body: { - repo: 'my-repo', - title: '需要多人协作的任务', - body: '这个任务需要多个开发者共同完成...', - assignee: 'user1,user2,user3', // 多个用户名用逗号分隔 - }, +const createdComment = await client.issue.createComment({ + owner: 'owner', + repo: 'repo', + number: Number(createdIssue.number), + body: { body: '收到,我来跟进。' }, }); -console.log(`分配给: ${issueMultiple.assignees.map(a => a.login).join(', ')}`); - -// 2) 创建 Issue 评论 -const comment = await client.issue.createComment({ - owner: 'username', - repo: 'my-repo', - number: 123, - body: { - body: '我已经开始处理这个问题了。', - }, +// 4) 更新评论 +await client.issue.updateComment({ + owner: 'owner', + repo: 'repo', + comment_id: createdComment.id, + body: { body: '进度更新:已定位问题。' }, }); - -console.log(`评论创建成功,ID: ${comment.id}`); - -// 3) 更新 Issue 评论 -const updatedComment = await client.issue.updateComment({ - owner: 'username', - repo: 'my-repo', - comment_id: comment.id, - body: { - body: '这是更新后的评论内容。', - }, -}); -console.log(`评论 ${updatedComment.id} 已更新。`); ``` -## 说明 - -- 网络请求层统一由内部的 `utils/http.ts` 中的 `httpRequest` 处理,自 2025-09-17 起使用 `got` 并支持 `searchParams`/`json` 等标准化选项,同时通过 ETag 自动缓存未变更的响应。 -- 字段与返回值与 GitCode 文档保持一致的最小子集,返回结果会通过 Zod 进行结构校验。 - -### ⚠️ GitCode API 文档勘误 +### 直接使用 URL 构建器 -**关于 `assignee` vs `assignees` 的不对称设计**: +```ts +import { GitcodeClient, listIssuesUrl } from '@xbghc/gitcode-api'; -GitCode API 在请求参数和响应数据中使用了不同的字段格式: +const client = new GitcodeClient(); +const url = listIssuesUrl('owner', 'repo'); +const data = await client.request(url, 'GET', { + searchParams: { state: 'closed', labels: 'bug', per_page: 20 }, +}); +``` -**请求参数**(创建/更新 Issue): -- 字段名:`assignee`(单数) -- 类型:字符串 -- 格式:单个用户名或逗号分隔的多个用户名 -- 示例:`"user1"` 或 `"user1,user2,user3"` +## 注意事项 -**响应数据**(所有 Issue 接口): -- 字段名:`assignees`(复数) -- 类型:对象数组 -- 格式:每个对象包含完整的用户信息 +- GitCode 的创建/更新请求使用 `assignee`(单数字符串,多个用户名用逗号分隔),响应则返回 `assignees: UserSummary[]`。 +- `IssueDetail`/`UpdatedIssue` 包含完整的工作项字段,可用于看板同步。 +- 所有响应均经 Zod 校验,不符合结构会抛出异常。 -`assignees` 数组中的每个对象包含以下字段: -- `avatar_url?`: 头像 URL(可选) -- `html_url`: 用户主页 URL -- `id`: 用户 ID -- `login`: 用户登录名 -- `name`: 用户显示名称 +## 更新记录 -本库已根据实际 API 行为实现: -- `CreateIssueBody` 和 `UpdateIssueBody` 使用 `assignee: string`(请求格式) -- 响应 schema 使用 `assignees: UserSummary[]`(响应格式) +- **2025-09-13**:新增 Issue 更新、评论更新与详情获取封装。 +- **2025-09-12**:提供 Issue 创建与评论创建 API。 diff --git a/docs/gitcode-api/pr.md b/docs/gitcode-api/pr.md index 056c2f6..4859e94 100644 --- a/docs/gitcode-api/pr.md +++ b/docs/gitcode-api/pr.md @@ -4,173 +4,78 @@ title: Pull Requests API # Pull Requests(PR) -提供与 Pull Request 相关的类型与路径构建工具,并通过 `GitcodeClient` 暴露便捷方法。 +PR 模块封装了列表、创建、评论、设置以及统计等常见操作,同时提供对应的 URL 构建函数与 Zod Schema。 适用接口: - 列表:GET `/api/v5/repos/{owner}/{repo}/pulls` - 创建:POST `/api/v5/repos/{owner}/{repo}/pulls` -- 设置:GET `/api/v5/repos/{owner}/{repo}/pull_request_settings` - 评论:GET `/api/v5/repos/{owner}/{repo}/pulls/{number}/comments` - 创建评论:POST `/api/v5/repos/{owner}/{repo}/pulls/{number}/comments` +- 设置:GET `/api/v5/repos/{owner}/{repo}/pull_request_settings` +- 统计:GET `/api/v5/repos/{owner}/{repo}/pull_requests/count` + +## 导出与类型 + +- `ListPullsQuery`、`ListPullsParams`、`PullRequest`、`ListPullsResponse`。 +- `CreatePullBody`:创建 PR 的请求体字段。 +- `PRComment`、`PRCommentQueryOptions`、`CreatedPrComment`。 +- `PullRequestSettings`:仓库 PR 配置。 +- `PrCount`:PR 数量统计(按状态聚合)。 +- URL/Schema:`listPullsUrl`、`createPullUrl`、`prCommentsUrl`、`createPrCommentUrl`、`pullRequestSettingsUrl`、`prCountUrl` 及对应的 Schema。 + +以上均可从包入口 `@xbghc/gitcode-api` 引入。 -## 类型与导出 - -- `ListPullsQuery`:PR 列表查询参数(`state`、`page`、`per_page`、`head`、`base` 等)。 -- `ListPullsParams`:包含 `owner`、`repo` 与可选 `query`。 -- `Branch`:PR 分支信息结构(`label`、`ref`、`sha` 等)。 -- `PullRequest`:PR 的最小字段表示(`id`、`number`、`title`、`state`、`head`、`base` 等)。 -- `ListPullsResponse`:`PullRequest[]`。 -- `CreatePullBody`:创建 PR 可用字段(`title`、`head`、`base`、`body`、`issue`)。 -- `PullRequestSettings`:PR 设置信息(合并策略等)。 -- `PRComment`:PR 评论信息。 -- `PRCommentQueryOptions`:PR 评论查询参数。 -- `CreatePrCommentBody`:创建PR评论的请求体。 -- `CreatePrCommentParams`:创建PR评论的参数。 -- `CreatedPrComment`:已创建的PR评论。 -- `listPullsUrl(owner, repo)`:构建列表接口绝对 URL。 -- `createPullUrl(owner, repo)`:构建创建接口路径(绝对 URL)。 -- `pullRequestSettingsUrl(owner, repo)`:构建设置接口 URL。 -- `prCommentsUrl(owner, repo, number)`:构建评论接口 URL。 -- `createPrCommentUrl(owner, repo, prNumber)`:构建创建评论接口 URL。 - -以上均从包入口 `@xbghc/gitcode-api` 导出。其中 `createPullUrl` 使用默认常量 `API_BASE`(`https://gitcode.com/api/v5`)构建绝对 URL。 - -## 使用示例 +## 客户端用法 ```ts -import { GitcodeClient, listPullsUrl, createPullUrl, type CreatePullBody } from '@xbghc/gitcode-api'; +import { GitcodeClient } from '@xbghc/gitcode-api'; -const client = new GitcodeClient(); +const repoUrl = 'https://gitcode.com/owner/repo.git'; +const client = new GitcodeClient(process.env.GITCODE_TOKEN); -// 1) 列表 PR(通过 options.query 传参) -const listUrl = listPullsUrl('owner', 'repo'); -const pulls = await client.request(listUrl, 'GET', { - query: { state: 'open', page: 1, per_page: 20 }, -}); +// 1) 列表 PR(带查询参数) +const pulls = await client.pr.list(repoUrl, { state: 'open', per_page: 50 }); -// 2) 创建 PR(使用绝对 URL 构建) -const createPath = createPullUrl('owner', 'repo'); -const body: CreatePullBody = { +// 2) 创建 PR +await client.pr.create(repoUrl, { title: '修复登录异常', head: 'feat/login-fix', base: 'main', - body: '说明文本', - issue: 123, -}; -const pr = await client.request(createPath, 'POST', { body: JSON.stringify(body) }); -``` - -也可直接使用 `GitcodeClient` 提供的封装方法: + body: '补充说明', +}); -```ts -const repoUrl = 'https://gitcode.com/owner/repo'; -const pulls2 = await client.pr.list(repoUrl, { state: 'open' }); -const pr2 = await client.pr.create(repoUrl, { title: '修复', head: 'feat/x' }); -``` +// 3) 获取评论与创建评论 +const comments = await client.pr.comments(repoUrl, 123, { comment_type: 'pr_comment' }); +const created = await client.pr.createComment(repoUrl, 123, '这个修复看起来不错!'); -或使用模块方式调用: +// 4) 读取仓库的 PR 设置 +const settings = await client.pr.getSettings('owner', 'repo'); -```ts -const pulls3 = await client.pr.list(repoUrl, { state: 'open' }); -const pr3 = await client.pr.create(repoUrl, { title: '修复', head: 'feat/x' }); +// 5) 统计 PR 数量(open/merged/closed) +const count = await client.pr.count(repoUrl); +console.log(count.open, count.merged, count.closed); ``` -### 新增功能:PR 设置和评论 +### 直接使用 URL 构建器 ```ts -// 获取 PR 设置 -const settings = await client.pr.getSettings('owner', 'repo'); -console.log('允许合并提交:', settings.allow_merge_commits); +import { GitcodeClient, listPullsUrl } from '@xbghc/gitcode-api'; -// 获取 PR 评论 -const comments = await client.pr.comments(repoUrl, 123); -comments.forEach((comment) => { - console.log(comment.user.login, comment.body); +const client = new GitcodeClient(); +const url = listPullsUrl('owner', 'repo'); +const data = await client.request(url, 'GET', { + searchParams: { state: 'closed', per_page: 20 }, }); - -// 创建 PR 评论 -const comment = await client.pr.createComment(repoUrl, 123, '这个修复看起来不错!'); -console.log('评论创建成功:', comment.id); ``` -## 类型定义 +## Schema 说明 -### `PullRequestSettings` - -PR 设置信息: - -```typescript -interface PullRequestSettings { - allow_merge_commits: boolean; - allow_squash_commits: boolean; - allow_rebase_commits: boolean; - allow_updates_from_default_branch: boolean; - allow_worktree_inheritance: boolean; - allow_auto_close_on_conflict: boolean; -} -``` - -### `PRComment` - -PR 评论信息: - -```typescript -interface PRComment { - id: number; - user: { - login: string; - avatar_url?: string; - }; - body: string; - created_at: string; - updated_at: string; - html_url: string; -} -``` - -### `CreatePrCommentBody` - -创建 PR 评论的请求体: - -```typescript -interface CreatePrCommentBody { - /** 评论内容 */ - body: string; -} -``` - -### `CreatePrCommentParams` - -创建 PR 评论的参数: - -```typescript -interface CreatePrCommentParams { - /** 仓库 URL(HTTP 或 SSH) */ - url: string; - /** PR 编号 */ - number: number; - /** 评论数据 */ - body: CreatePrCommentBody; -} -``` - -### `CreatedPrComment` - -已创建的 PR 评论: - -```typescript -interface CreatedPrComment { - /** 评论 ID */ - id: number; - /** 评论内容 */ - body: string; -} -``` +- 所有响应均由 Zod 校验,类型字段与 GitCode API 文档保持一致。 +- `PRComment` 除基础字段外还包含 `position`、`diff_hunk` 等原始属性,便于对齐差异信息。 +- `PrCount` 结构:`{ open: number; merged: number; closed: number; total: number }`。 -## 说明 +## 更新记录 -- 网络请求层统一由内部的 `utils/http.ts` 中的 `httpRequest` 处理,自 2025-09-17 起使用 `got` 并支持 `searchParams`/`json` 等标准化选项,同时通过 ETag 自动缓存未变更的响应。 -- 字段与返回值与 GitCode 文档保持一致的最小子集,返回结果会通过 Zod 进行结构校验。 -- 2025-09-13 更新:新增 PR 设置和评论功能支持。 -- 2025-09-14 更新:新增 PR 创建评论功能支持。 +- **2025-09-13**:新增 PR 设置、评论创建与 PR 数量统计封装;所有响应经 Zod 校验。 +- **2025-09-17**:所有请求改用 `searchParams`/`json` 选项,并继承 HTTP 重试与调试日志能力。 diff --git a/docs/gitcode-api/repo.md b/docs/gitcode-api/repo.md index 25690b2..2049583 100644 --- a/docs/gitcode-api/repo.md +++ b/docs/gitcode-api/repo.md @@ -4,480 +4,73 @@ title: 仓库 API # 仓库 API -## 概述 +仓库模块聚合了权限、基础信息、事件、分支、提交、文件、对比分支及 Webhook 相关接口。所有响应都由 Zod 校验,以确保字段与 GitCode 返回一致。 -仓库 API 提供获取仓库设置、分支、提交历史、贡献者、文件内容和 Webhooks 等功能。 +## 客户端方法 -## 更新说明 - -**2025-09-13 更新**: 新增完整的仓库管理 API,包括设置、分支、提交、贡献者、文件操作和 Webhooks 管理功能。 - -## API 方法 - -### `getSettings(owner, repo)` - -获取仓库设置信息。 +```ts +import { GitcodeClient } from '@xbghc/gitcode-api'; -**API 端点**: `GET /api/v5/repos/{owner}/{repo}/repo_settings` +const client = new GitcodeClient(process.env.GITCODE_TOKEN); +const repoUrl = 'https://gitcode.com/owner/repo.git'; -**返回类型**: `RepoSettings` +// 权限 +const permission = await client.repo.getSelfRepoPermission(repoUrl); +const role = await client.repo.getSelfRepoPermissionRole(repoUrl); -```typescript -const client = new GitcodeClient(); +// 仓库配置与事件 const settings = await client.repo.getSettings('owner', 'repo'); -console.log(settings.default_branch); -``` - -### `getEvents(owner, repo)` - -获取仓库的活动事件。 - -**API 端点**: `GET /api/v5/repos/{owner}/{repo}/events` - -**返回类型**: `RepoEvent[]` - -```typescript -const client = new GitcodeClient(); const events = await client.repo.getEvents('owner', 'repo'); -events.forEach((event) => { - console.log(event.type, event.actor.login); -}); -``` - -### `getBranches(owner, repo)` - -获取仓库所有分支信息。 - -**API 端点**: `GET /api/v5/repos/{owner}/{repo}/branches` -**返回类型**: `Branch[]` - -```typescript -const client = new GitcodeClient(); +// 分支/提交 const branches = await client.repo.getBranches('owner', 'repo'); -branches.forEach((branch) => { - console.log(branch.name, branch.default); -}); -``` - -### `getBranch(owner, repo, branch)` - -获取特定分支的详细信息。 - -**API 端点**: `GET /api/v5/repos/{owner}/{repo}/branches/{branch}` - -**返回类型**: `Branch` - -```typescript -const client = new GitcodeClient(); const branch = await client.repo.getBranch('owner', 'repo', 'main'); -console.log(branch.commit.id); -``` - -### `getCommits(owner, repo)` - -获取仓库提交历史。 - -**API 端点**: `GET /api/v5/repos/{owner}/{repo}/commits` - -**返回类型**: `Commit[]` - -```typescript -const client = new GitcodeClient(); const commits = await client.repo.getCommits('owner', 'repo'); -commits.forEach((commit) => { - console.log(commit.sha, commit.commit.message); -}); -``` - -### `getContributors(owner, repo)` - -获取仓库贡献者列表。 - -**API 端点**: `GET /api/v5/repos/{owner}/{repo}/contributors` - -**返回类型**: `Contributor[]` - -```typescript -const client = new GitcodeClient(); -const contributors = await client.repo.getContributors('owner', 'repo'); -contributors.forEach((contributor) => { - console.log(contributor.name, contributor.contributions); -}); -``` - -### `getFileBlob(owner, repo, sha)` - -获取文件内容。 - -**API 端点**: `GET /api/v5/repos/{owner}/{repo}/git/blobs/{sha}` - -**返回类型**: `FileBlob` - -```typescript -const client = new GitcodeClient(); -const fileBlob = await client.repo.getFileBlob('owner', 'repo', 'abc123'); -console.log(fileBlob.content, fileBlob.encoding); -``` - -### `compare(owner, repo, base, head)` - -比较两个分支或提交之间的差异。 - -**API 端点**: `GET /api/v5/repos/{owner}/{repo}/compare/{base}...{head}` - -**返回类型**: `Compare` - -```typescript -const client = new GitcodeClient(); -const comparison = await client.repo.compare('owner', 'repo', 'main', 'feature'); -console.log(comparison.files.length); -``` - -### `getWebhooks(owner, repo)` - -获取仓库所有 Webhooks。 - -**API 端点**: `GET /api/v5/repos/{owner}/{repo}/hooks` - -**返回类型**: `Webhook[]` - -```typescript -const client = new GitcodeClient(); -const webhooks = await client.repo.getWebhooks('owner', 'repo'); -webhooks.forEach((webhook) => { - console.log(webhook.url, webhook.active); -}); -``` - -### `getWebhook(owner, repo, id)` - -获取特定的 Webhook 信息。 - -**API 端点**: `GET /api/v5/repos/{owner}/{repo}/hooks/{id}` - -**返回类型**: `Webhook` - -```typescript -const client = new GitcodeClient(); -const webhook = await client.repo.getWebhook('owner', 'repo', 123); -console.log(webhook.config); -``` -### `getSelfRepoPermission(url)` +// 文件与比较 +const blob = await client.repo.getFileBlob('owner', 'repo', 'abc123'); +const diff = await client.repo.compare('owner', 'repo', 'main', 'feature'); -获取当前认证用户在指定仓库的权限。 - -**API 端点**: `GET /api/v5/repos/{owner}/{repo}/collaborators/self-permission` - -**返回类型**: `SelfPermissionResponse` - -```typescript -const client = new GitcodeClient(); -// URL can be a full repo URL or just 'owner/repo' -const permission = await client.repo.getSelfRepoPermission('owner/repo'); -console.log(permission.role_name, permission.permissions); -``` - -### `getSelfRepoPermissionRole(url)` - -获取当前认证用户在指定仓库的角色名称。 - -**API 端点**: `GET /api/v5/repos/{owner}/{repo}/collaborators/self-permission` - -**返回类型**: `RepoRole` (string enum) - -```typescript -const client = new GitcodeClient(); -const role = await client.repo.getSelfRepoPermissionRole('owner/repo'); -console.log('User role:', role); // e.g., 'admin', 'write', 'read' -``` - -## 类型定义 - -### `RepoSettings` - -仓库设置信息: - -```typescript -interface RepoSettings { - default_branch?: string; - has_issues?: boolean; - has_wiki?: boolean; - has_pull_requests?: boolean; - has_projects?: boolean; - allow_squash_merge?: boolean; - allow_merge_commit?: boolean; - allow_rebase_merge?: boolean; - delete_branch_on_merge?: boolean; -} -``` - -### `Branch` - -分支信息: - -```typescript -interface Branch { - name: string; - commit: { - id: string; - message: string; - parent_ids: string[]; - authored_date: string; - author_name: string; - author_iam_id: string | null; - author_email: string; - author_user_name: string | null; - committed_date: string; - committer_name: string; - committer_email: string; - committer_user_name: string | null; - open_gpg_verified: any | null; - verification_status: any | null; - gpg_primary_key_id: any | null; - short_id: string; - created_at: string; - title: string; - author_avatar_url: string; - committer_avatar_url: string; - relate_url: string | null; - }; - merged: boolean; - protected: boolean; - developers_can_push: boolean; - developers_can_merge: boolean; - can_push: boolean; - default: boolean; -} +// Webhook +const hooks = await client.repo.getWebhooks('owner', 'repo'); +const hook = await client.repo.getWebhook('owner', 'repo', hooks[0]?.id ?? 0); ``` -### `Commit` - -提交信息: +## 导出与类型 -```typescript -interface Commit { - sha: string; - commit: { - author: { - name: string; - date: string; - email: string; - }; - committer: { - name: string; - date: string; - email: string; - }; - message: string; - tree: { - sha: string; - url: string; - }; - }; - author: { - name: string; - id: number; - login: string; - type: string; - }; - committer: { - name: string; - id: number; - login: string; - type: string; - }; - html_url: string; - url: string; -} -``` - -### `Contributor` +- 权限:`selfPermissionUrl`、`selfPermissionResponseSchema`、`RepoRole` 以及相关类型。 +- 仓库配置与事件:`repoSettingsUrl`、`repoEventsUrl`、`repoSettingsSchema`、`repoEventsSchema`。 +- 贡献者:`contributorsUrl`、`contributorsSchema`。 +- 分支:`branchesUrl`、`branchUrl`、`branchSchema`。 +- 提交:`commitsUrl`、`commitSchema`。 +- 文件:`fileBlobUrl`、`fileBlobSchema`。 +- 对比:`compareUrl`、`compareSchema`。 +- Webhook:`webhooksUrl`、`webhookUrl`、`webhookSchema`。 -贡献者信息: +所有 Schema 均可通过包入口引用,以复用在自定义客户端中。 -```typescript -interface Contributor { - name: string; - contributions: number; - email: string; -} -``` +## 选项与返回值 -### `FileBlob` +- `client.repo.getSelfRepoPermission(url): SelfPermissionResponse` — 解析远程地址(HTTP/SSH/`owner/repo`)并返回完整权限树。 +- `client.repo.getSelfRepoPermissionRole(url): RepoRole` — 在权限树基础上提取归一化角色(`'admin' | 'write' | 'read' | 'none'`)。 +- `client.repo.getSettings(owner, repo): RepoSettings` — 默认分支、合并策略、CI 等配置。 +- `client.repo.getEvents(owner, repo): RepoEvents` — 仓库事件时间线。 +- `client.repo.getContributors(owner, repo): Contributors` — 贡献者数组,包含提交次数与用户信息。 +- `client.repo.getBranches(owner, repo): Branches` — 所有分支信息(数组)。 +- `client.repo.getBranch(owner, repo, branch): Branch` — 指定分支的提交、保护状态等细节。 +- `client.repo.getCommits(owner, repo): Commits` — 最近提交列表。 +- `client.repo.getFileBlob(owner, repo, sha): FileBlob` — Git blob 内容(base64 编码及大小)。 +- `client.repo.compare(owner, repo, base, head): Compare` — 提交比较详情(含 `files`、`commits` 等)。 +- `client.repo.getWebhooks(owner, repo): Webhooks` — 仓库所有 Webhook。 +- `client.repo.getWebhook(owner, repo, id): Webhook` — 指定 Webhook 详情。 -文件内容信息: +## 注意事项 -```typescript -interface FileBlob { - sha: string; - size: number; - url: string; - content: string; - encoding: string; -} -``` +- 权限方法接受完整仓库 URL、`owner/repo` 或 `.git` 结尾地址,内部会调用 `parseGitUrl` 统一解析。 +- `getCommits`、`getEvents` 等接口直接返回 GitCode API 的原始分页结果(按默认分页大小)。如需更多数据,可自行拼接 `searchParams` 配合 `client.request` 与 URL 构建器使用。 +- `getFileBlob` 返回的 `content` 经过 base64 编码,需自行解码。 -### `Compare` +## 更新记录 -代码比较结果: - -```typescript -interface Compare { - base_commit: Commit; - merge_base_commit: Commit; - commits: Commit[]; - files: CompareFile[]; - truncated: number; -} - -interface CompareFile { - sha: string; - filename: string; - status: string; - additions: number; - deletions: number; - changes: number; - blob_url: string; - raw_url: string; - patch?: string; - truncated: number; -} -``` - -### `Webhook` - -Webhook 配置信息: - -```typescript -interface Webhook { - id: number; - url: string; - test_url: string; - ping_url: string; - name: string; - events: string[]; - active: boolean; - config: { - url: string; - content_type: string; - secret?: string; - insecure_ssl: string; - }; - updated_at: string; - created_at: string; - last_response?: { - code: any | null; - status: string; - message: string; - }; -} -``` - -## 使用示例 - -### 获取仓库基本信息 - -```typescript -import { GitcodeClient } from '@xbghc/gitcode-api'; - -const client = new GitcodeClient(); - -// 获取仓库设置 -const settings = await client.repo.getSettings('myorg', 'myrepo'); -console.log('默认分支:', settings.default_branch); - -// 获取分支列表 -const branches = await client.repo.getBranches('myorg', 'myrepo'); -console.log('分支数量:', branches.length); - -// 获取最新提交 -const commits = await client.repo.getCommits('myorg', 'myrepo'); -if (commits.length > 0) { - console.log('最新提交:', commits[0].commit.message); -} -``` - -### 获取仓库贡献者 - -```typescript -const contributors = await client.repo.getContributors('myorg', 'myrepo'); -console.log('贡献者统计:'); -contributors.forEach((contributor) => { - console.log(` ${contributor.name}: ${contributor.contributions} 次提交`); -}); -``` - -### 比较分支差异 - -```typescript -const comparison = await client.repo.compare('myorg', 'myrepo', 'main', 'feature'); -console.log(`发现 ${comparison.files.length} 个文件变更`); -comparison.files.forEach((file) => { - console.log(` ${file.filename}: +${file.additions} -${file.deletions}`); -}); -``` - -### 管理 Webhooks - -```typescript -const webhooks = await client.repo.getWebhooks('myorg', 'myrepo'); -console.log(`仓库有 ${webhooks.length} 个 Webhooks`); - -if (webhooks.length > 0) { - const webhook = await client.repo.getWebhook('myorg', 'myrepo', webhooks[0].id); - console.log('第一个 Webhook:', webhook.url); -} -``` - -## 响应示例 - -### 仓库设置响应 - -```json -{ - "default_branch": "main", - "has_issues": true, - "has_wiki": false, - "has_pull_requests": true, - "has_projects": true, - "allow_squash_merge": true, - "allow_merge_commit": true, - "allow_rebase_merge": true, - "delete_branch_on_merge": false -} -``` - -### 分支列表响应 - -```json -[ - { - "name": "main", - "commit": { - "id": "abc123...", - "message": "Initial commit", - "author_name": "John Doe", - "author_email": "john@example.com", - "authored_date": "2024-01-15T10:30:00Z" - }, - "default": true, - "protected": true - } -] -``` - -## 错误处理 - -```typescript -try { - const branches = await client.repo.getBranches('nonexistent', 'repo'); -} catch (error) { - if (error.message.includes('404')) { - console.error('仓库不存在'); - } else { - console.error('获取仓库信息失败:', error); - } -} -``` +- **2025-09-13**:新增仓库事件、分支、提交、文件、对比与 Webhook 等接口封装。 +- **2025-09-17**:所有请求支持 `searchParams`/`json` 选项并复用 HTTP 调试日志、重试机制。 diff --git a/docs/gitcode-api/user.md b/docs/gitcode-api/user.md index 4c971ef..21dd876 100644 --- a/docs/gitcode-api/user.md +++ b/docs/gitcode-api/user.md @@ -4,164 +4,98 @@ title: 用户 API # 用户 API -## 概述 +`@xbghc/gitcode-api` 的用户模块提供获取当前认证用户资料与命名空间的封装,所有响应都会通过 Zod 进行结构校验。 -用户 API 提供获取当前认证用户信息和命名空间的功能。 +## 快速开始 -## 更新说明 +```ts +import { GitcodeClient } from '@xbghc/gitcode-api'; -**2025-09-10 更新**: `getUserProfile()` 方法现在返回完整的 `UserProfile` 类型,直接包含所有用户信息字段,无需通过 `raw` 字段访问原始数据。这提供了更丰富的用户信息和更好的类型安全。 -**2025-09-11 更新**: `getUserProfile()` 现在使用 Zod 对返回数据进行结构校验,提升类型安全。 -**2025-09-13 更新**: 新增 `getUserNamespace()` 方法,支持获取用户命名空间信息。 +const client = new GitcodeClient(process.env.GITCODE_TOKEN); +const profile = await client.user.getProfile(); +const namespace = await client.user.getNamespace(); -## API 方法 +console.log('当前登录用户:', profile.login, '命名空间:', namespace.path); +``` -### `getUserProfile()` +- 若未在构造函数中提供 Token,可调用 `client.auth.setToken('token')`。 +- 用户端点默认使用 `Bearer` 鉴权。 -获取当前认证用户的个人资料信息。 +## API 方法 -**API 端点**: `GET /api/v5/user` +### `client.user.getProfile()` -**返回类型**: `UserProfile` - 完整的用户信息接口,包含丰富的用户资料字段 +- **端点**:`GET /api/v5/user` +- **返回值**:`UserProfile` +- **说明**:返回完整的用户资料(包含 `login`、`name`、`email?`、`company?`、`top_languages` 等字段)。 -```typescript -const client = new GitcodeClient(); +```ts const profile = await client.user.getProfile(); -console.log(profile); +console.log(profile.name, profile.followers); ``` -### `getUserNamespace()` - -获取当前用户的命名空间信息。 - -**API 端点**: `GET /api/v5/user/namespace` +### `client.user.getNamespace()` -**返回类型**: `UserNamespace` - 用户命名空间信息 +- **端点**:`GET /api/v5/user/namespace` +- **返回值**:`UserNamespace` +- **说明**:返回当前用户命名空间的路径、名称、类型等信息,常用于组织 Git 仓库路径。 -```typescript -const client = new GitcodeClient(); +```ts const namespace = await client.user.getNamespace(); -console.log(namespace); +console.log(namespace.id, namespace.path); ``` ## 类型定义 ### `UserProfile` -完整的用户信息接口,包含以下字段: - -```typescript +```ts interface UserProfile { - id: string; // 用户 ID - login: string; // 登录名 - name: string; // 用户名 - email?: string; // 邮箱(可选) - avatar_url: string; // 头像 URL - html_url: string; // 个人主页 URL - type: string; // 用户类型 - url: string; // API URL - bio?: string; // 个人简介(可选) - blog?: string; // 个人博客(可选) - company?: string; // 公司(可选) - followers: number; // 关注者数量 - following: number; // 关注中数量 - top_languages: string[]; // 常用编程语言 + id: string; + login: string; + name: string; + email?: string; + avatar_url: string; + html_url: string; + type: string; + url: string; + bio?: string; + blog?: string; + company?: string; + followers: number; + following: number; + top_languages: string[]; } ``` ### `UserNamespace` -用户命名空间信息接口: - -```typescript +```ts interface UserNamespace { - id: number; // 命名空间 ID - path: string; // 命名空间路径 - name: string; // 命名空间名称 - html_url: string; // 命名空间主页 URL - type: string; // 命名空间类型 + id: number; + path: string; + name: string; + html_url: string; + type: string; } ``` -现在直接返回完整的用户信息,无需通过 `raw` 字段访问原始数据。 - -## 使用示例 - -### 获取用户信息 - -```typescript -import { GitcodeClient } from '@xbghc/gitcode-api'; +## 错误处理 -const client = new GitcodeClient({ - token: process.env.GITCODE_TOKEN, -}); +- 未提供或提供错误的 Token 时将得到 `401 Unauthorized`。 +- 网络异常会被归一化,例如连接/响应超时分别提示 “连接 GitCode 服务器超时” 与 “等待 GitCode 响应超时”。 +- 其他 HTTP 错误会保留原始状态码与响应正文,便于排查。 +```ts try { - const profile = await client.getUserProfile(); - console.log('用户信息:', { - ID: profile.id, - 登录名: profile.login, - 用户名: profile.name, - 邮箱: profile.email, - 头像: profile.avatar_url, - 公司: profile.company, - 关注者: profile.followers, - 关注中: profile.following, - 常用语言: profile.top_languages, - }); + const profile = await client.user.getProfile(); + console.log(profile.login); } catch (error) { - console.error('获取用户信息失败:', error); + console.error('获取用户信息失败:', (error as Error).message); } ``` -### 结合认证使用 +## 更新记录 -```typescript -import { GitcodeClient } from '@xbghc/gitcode-api'; - -const client = new GitcodeClient(); -const profile = await client.getUserProfile(); -console.log('当前用户:', profile.name); -``` - -## 响应示例 - -```json -{ - "avatar_url": "https://gitcode.com/u/123/avatar", - "followers_url": "https://gitcode.com/api/v5/users/123/followers", - "html_url": "https://gitcode.com/u/123", - "id": "123", - "login": "username", - "name": "用户名", - "type": "User", - "url": "https://gitcode.com/api/v5/users/123", - "bio": "开发者", - "blog": "https://example.com", - "company": "公司名称", - "email": "user@example.com", - "followers": 42, - "following": 15, - "top_languages": ["TypeScript", "JavaScript", "Python"] -} -``` - -## 错误处理 - -当请求失败时,会抛出错误。常见的错误情况包括: - -- **401 Unauthorized**: Token 无效或过期 -- **403 Forbidden**: 权限不足 -- **网络错误**: 连接失败或超时 - -```typescript -try { - const profile = await client.getUserProfile(); -} catch (error) { - if (error.message.includes('401')) { - console.error('认证失败,请检查 Token'); - } else { - console.error('请求失败:', error.message); - } -} -``` +- **2025-09-13**:新增 `client.user.getNamespace()` 并为所有响应引入 Zod 校验。 +- **2025-09-10**:`client.user.getProfile()` 返回完整字段集合而非嵌套原始响应。 From 2b345e19ae0ef1941252cdfeb5b6887086e65f90 Mon Sep 17 00:00:00 2001 From: xbghc <58060018+xbghc@users.noreply.github.com> Date: Wed, 22 Oct 2025 19:08:23 +0800 Subject: [PATCH 2/6] docs: refresh root README --- README.md | 361 ++++++++++++++++-------------------------------------- 1 file changed, 104 insertions(+), 257 deletions(-) diff --git a/README.md b/README.md index 64946b9..d8abb6d 100644 --- a/README.md +++ b/README.md @@ -1,316 +1,163 @@ # GitAny Actions -一个现代化的 TypeScript monorepo,提供与 GitCode 平台集成的工具和库。 +GitAny Actions 是一个基于 pnpm 的 TypeScript monorepo,围绕 GitCode 平台提供 API 客户端、命令行工具、自动化工作流、容器工具链以及配套服务。代码与文档通过 VitePress 维护,默认使用 Node.js 22 运行时。 -## 项目概览 +## 核心包 -GitAny Actions 是一个 TypeScript 项目,提供以下核心功能: +| 包 | 说明 | +| --- | --- | +| `@xbghc/gitcode-api` | 强类型的 GitCode REST 客户端,封装用户、仓库、PR、Issue 等模块并提供响应缓存与重试策略。 | +| `@xbghc/gitcode-cli` | `gitcode` 命令行工具,支持认证、仓库/PR/Issue 查询与评论等交互式操作。 | +| `@xbghc/gitcode-actions` | 事件监听、容器编排与 AI 评论助手工具集,可用于构建自动化工作流。 | +| `@xbghc/gitcode-actions-server` | 基于 Express 的后端服务,对外暴露 GitCode API 转发与自动化能力。 | +| `@xbghc/gitcode-dashboard` | Vue 3 管理面板,封装 GitCode 仓库与 Issue 的可视化操作界面。 | +| `@xbghc/git-lib` | 轻量级 Git 命令包装器,提供仓库 URL 解析与跨平台子进程调用。 | -- **@xbghc/gitcode-cli**: 命令行界面工具,提供 `gitcode` 命令行接口 -- **@xbghc/gitcode-api**: GitCode API 客户端库,提供完整的 GitCode 平台集成 -- **@xbghc/git-lib**: Git 命令包装器,提供跨平台的 Git 操作支持 -- **@xbghc/gitcode-actions**: GitCode Actions - 自动化工作流和操作库 +## 环境要求 -## 快速开始 +- Node.js 22(可通过 `.nvmrc` 对齐版本要求) +- pnpm 10(workspace 使用 `pnpm@10.15.0`) +- Docker(`@xbghc/gitcode-actions` 的容器函数依赖 `dockerode` 与宿主 Docker daemon) +- GitCode 访问令牌(用于 API 与 CLI 调用) -### 安装 +## 快速开始 ```bash -# 克隆项目 +# 克隆仓库 git clone -cd gitany-actions +cd gitcode-actions # 安装依赖 pnpm install -# 构建项目 +# 构建所有包 pnpm build ``` -### 使用 CLI 工具 +常用 workspace 脚本: + +- `pnpm dev`:并行启动各包的开发模式 +- `pnpm lint` / `pnpm format`:ESLint 与 Prettier 检查 +- `pnpm clean`:清理各包的构建产物 +- `pnpm docs:dev | docs:build | docs:preview`:VitePress 文档调试、构建与预览 +- `pnpm dev:core` / `pnpm dev:server` / `pnpm dev:dashboard`:聚焦核心自动化、后端或前端开发 +- `pnpm d` / `pnpm d:git` / `pnpm d:docker`:构建后分别启动 GitCode、Git、Docker 集成演示脚本 + +## CLI 速览 + +`@xbghc/gitcode-cli` 在构建后提供 `gitcode` 可执行文件: ```bash -# 查看帮助 -gitcode --help +# 解析仓库 URL,输出结构化信息 +gitcode parse https://gitcode.com/owner/repo.git -# 用户认证 -gitcode auth login +# 使用环境变量令牌执行用户操作 +GITCODE_TOKEN=your-token gitcode user show +GITCODE_TOKEN=your-token gitcode user namespace -# 查看用户信息 -gitcode user show -gitcode user namespace +# 授权(设置当前进程的令牌) +gitcode auth set-token -# 仓库操作 -gitcode repo settings owner repo -gitcode repo branches owner repo -gitcode repo commits owner repo -gitcode repo contributors owner repo -gitcode repo webhooks owner repo -gitcode repo permission owner repo +# 仓库权限与信息 +gitcode repo permission https://gitcode.com/owner/repo.git +GITCODE_TOKEN=... gitcode repo info branches owner repo +GITCODE_TOKEN=... gitcode repo info webhooks owner repo # Pull Request 操作 -gitcode pr list https://gitcode.com/owner/repo -gitcode pr create https://gitcode.com/owner/repo --title "新功能" --head feature-branch -gitcode pr settings owner repo -gitcode pr comments 123 --repo owner/repo +gitcode pr list https://gitcode.com/owner/repo --state all +GITCODE_TOKEN=... gitcode pr create https://gitcode.com/owner/repo --title "新特性" --head feature-branch +GITCODE_TOKEN=... gitcode pr info settings owner repo +GITCODE_TOKEN=... gitcode pr comments 12 https://gitcode.com/owner/repo --commentType pr_comment # Issue 操作 -gitcode issue list https://gitcode.com/owner/repo -gitcode issue create --repo owner/repo --title "新 Issue" --body "这是内容" -gitcode issue view 42 https://gitcode.com/owner/repo -gitcode issue edit 42 --repo owner/repo --label bug -gitcode issue close 42 --repo owner/repo -gitcode issue reopen 42 --repo owner/repo +gitcode issue list https://gitcode.com/owner/repo --state closed +GITCODE_TOKEN=... gitcode issue create owner repo --title "Bug" --body "重现步骤" +GITCODE_TOKEN=... gitcode issue comment 42 --repo owner/repo "感谢反馈!" ``` -### 使用 API 库 +CLI 底层通过 `GitcodeClient` 发起请求,并在出错时提供统一的错误处理与 JSON 输出选项。 + +## API 客户端示例 -```typescript +```ts import { GitcodeClient } from '@xbghc/gitcode-api'; -const client = new GitcodeClient(); +const client = new GitcodeClient(process.env.GITCODE_TOKEN); -// 用户操作 -const user = await client.user.getProfile(); +const profile = await client.user.getProfile(); const namespace = await client.user.getNamespace(); -// 仓库操作 -const settings = await client.repo.getSettings('owner', 'repo'); -const branches = await client.repo.getBranches('owner', 'repo'); -const commits = await client.repo.getCommits('owner', 'repo'); +const repoSettings = await client.repo.getSettings('owner', 'repo'); const contributors = await client.repo.getContributors('owner', 'repo'); - -// PR 操作 -const pulls = await client.pr.list('https://gitcode.com/owner/repo'); -const prSettings = await client.pr.getSettings('owner', 'repo'); - -// Issue 操作 -const issues = await client.issue.list('https://gitcode.com/owner/repo'); +const prCount = await client.pr.count('https://gitcode.com/owner/repo'); +const issues = await client.issue.list('https://gitcode.com/owner/repo', { state: 'open' }); ``` -## 项目结构 +客户端模块化导出,可单独访问 `client.repo`, `client.pr`, `client.issue`, `client.user` 与 `client.auth`,并对响应执行 Zod 校验和 ETag 缓存。 -``` -packages/ -├── gitcode-cli/ # 命令行界面工具 -│ ├── src/ -│ │ ├── commands/ # CLI 命令实现 -│ │ └── index.ts # CLI 入口 -│ └── README.md -├── gitcode-api/ # GitCode API 客户端 -│ ├── src/ -│ │ ├── api/ # API 类型定义和 URL 构建 -│ │ ├── client/ # 客户端实现 -│ │ └── index.ts # 包入口 -│ └── README.md -├── git-lib/ # Git 命令包装器 -│ ├── src/ -│ │ ├── git.ts # Git 操作函数 -│ │ └── index.ts # 包入口 -│ └── README.md -└── gitcode-actions/ # GitCode Actions - 自动化工作流 - ├── src/ - │ ├── logger.ts # 日志工具 - │ └── index.ts # 包入口 - └── README.md - -docs/ # 项目文档 -├── gitcode-api/ # GitCode API 文档 -├── gitcode-cli/ # CLI 使用文档 -├── git-lib/ # Git 库文档 -└── gitcode-actions/ # GitCode Actions 文档 -``` - -## 开发 - -### 环境要求 - -- Node.js 18+ -- pnpm 8+ +## 自动化与容器工具 -### 开发命令 - -```bash -# 安装依赖 -pnpm install +`@xbghc/gitcode-actions` 聚焦构建自动化: -# 开发模式(并行监听) -pnpm dev - -# 构建所有包 -pnpm build - -# 代码检查和格式化 -pnpm lint -pnpm format - -# 清理构建产物 -pnpm clean - -# 运行测试 -pnpm test - -# 生成文档 -pnpm docs:dev # 启动文档服务器 -pnpm docs:build # 构建静态文档 -pnpm docs:preview # 预览构建的文档 -``` - -### 包特定命令 - -```bash -# 工作特定包 -pnpm --filter @xbghc/gitcode-cli dev -pnpm --filter @xbghc/gitcode-api build -pnpm --filter @xbghc/gitcode-actions dev -pnpm --filter @xbghc/git-lib build -``` - -## 认证配置 - -### 环境变量 - -```bash -export GITANY_TOKEN=your-token -export GITCODE_TOKEN=your-token -export GITCODE_API_BASE=https://gitcode.com/api/v5 -``` +- 事件监听:`watchPullRequest` 与 `watchIssues` 会持久化状态到 `~/.gitcode/watchers`,支持 `start()`、`stop()` 与单次 `runOnce()`。 +- AI 评论助手:`watchAiMentions` / `runAiMentionsOnce` 监听 `@AI` 等提及,结合 `defaultPromptBuilder` 与 `chat` 自动回复。 +- 容器工具链:提供 `createPrContainer`、`createWorkspaceContainer`、`testShaBuild`、`copyToContainer`、`collectDiagnostics` 等函数,用于拉起 PR 隔离环境、执行构建、采集日志并清理容器。 -### 配置文件 - -配置文件存储在 `~/.gitany/gitcode/config.json`: - -```json -{ - "token": "your-access-token", - "apiBase": "https://gitcode.com/api/v5" -} -``` - -## API 覆盖范围 - -### GitCode API 支持 - -✅ **用户 API** - -- 获取用户信息 (`/user`) -- 获取用户命名空间 (`/user/namespace`) - -✅ **仓库 API** - -- 仓库设置 (`client.repo.getSettings`) -- 仓库事件 (`client.repo.getEvents`) -- 分支管理 (`client.repo.getBranches`, `client.repo.getBranch`) -- 提交历史 (`client.repo.getCommits`) -- 贡献者 (`client.repo.getContributors`) -- 文件操作 (`client.repo.getFileBlob`) -- 代码比较 (`client.repo.compare`) -- WebHooks (`client.repo.getWebhooks`, `client.repo.getWebhook`) -- 仓库权限 (`client.repo.getSelfRepoPermission`) - -✅ **Pull Request API** - -- PR 列表 (`client.pr.list`) -- 创建 PR (`client.pr.create`) -- PR 评论 (`client.pr.comments`, `client.pr.createComment`) -- PR 设置 (`client.pr.getSettings`) - -✅ **Issue API** - -- Issue 列表 (`client.issue.list`) -- Issue 详情 (`client.issue.get`) -- 创建/更新 Issue (`client.issue.create`, `client.issue.update`) -- Issue 评论 (`client.issue.comments`, `client.issue.createComment`, `client.issue.updateComment`) - -## 类型安全 - -所有 API 响应都有完整的 TypeScript 类型定义,使用 Zod 进行运行时验证: - -```typescript -import { GitcodeClient, type UserProfile, type RepoSettings } from '@xbghc/gitcode-api'; - -const client = new GitcodeClient(); - -// 完全类型安全的 API 调用 -const user: UserProfile = await client.user.getProfile(); -const settings: RepoSettings = await client.repo.getSettings('owner', 'repo'); +```ts +import { GitcodeClient } from '@xbghc/gitcode-api'; +import { watchPullRequest, watchAiMentions, createPrContainer } from '@xbghc/gitcode-actions'; + +const client = new GitcodeClient(process.env.GITCODE_TOKEN!); + +watchPullRequest(client, 'https://gitcode.com/owner/repo', { + intervalSec: 10, + onOpen: (pr) => console.log(`PR #${pr.number} opened: ${pr.title}`), + onComment: (pr, comment) => console.log(`PR #${pr.number} 评论: ${comment.body}`), + container: { image: 'node:22-bookworm' }, +}).start(); + +watchAiMentions(client, 'https://gitcode.com/owner/repo', { + mention: '@AI', + chatOptions: { sha: 'dev', keepContainer: false }, +}); + +await createPrContainer('https://gitcode.com/owner/repo', { id: 1, number: 12 } as any, { + image: 'node:22-bookworm', + env: { NODE_ENV: 'test' }, +}); ``` -## 构建系统 - -- **Bundler**: esbuild 与 TypeScript -- **输出**: ESM 模块,包含 TypeScript 声明文件 -- **目标**: Node.js 18+ -- **包管理器**: pnpm 与工作空间 - -## 代码质量 - -- **TypeScript**: 严格模式,共享 `tsconfig.base.json` -- **ESLint**: `@typescript-eslint` 与自定义规则 -- **Prettier**: 2 空格缩进,分号,单引号 -- **命名规范**: - - 文件: 小写 (`client.ts`) - - 类型: `PascalCase` - - 函数/变量: `camelCase` +## 服务与前端 -## Git Hooks +- **Server**:`packages/server` 提供 Express 路由(Issue、PR、Repo 等),整合 GitCode Token 中间件并内置 Swagger 文档输出,支持 `.env` 配置与 `pnpm --filter @xbghc/gitcode-actions-server dev` 启动。 +- **Dashboard**:`packages/gitcode-dashboard` 基于 Vue 3 + Element Plus,调用 API 客户端实现仓库概览、Issue 与 PR 管理,可通过 `pnpm --filter @xbghc/gitcode-dashboard dev` 启动。 -- **Pre-commit**: 运行文档同步检查 (`scripts/check-docs-updated.mjs`) -- **Prepare**: 自动安装 Husky hooks +## 环境与认证 -## 清理 PR 容器 - -若在手动运行过程中需要清理残留或异常状态的 PR 容器,可执行: +可参考 `.env.example` 配置访问令牌与 API 基础地址: ```bash -pnpm --filter @xbghc/gitcode-actions cleanup +GITCODE_TOKEN=your-token +GITCODE_API_BASE=https://gitcode.com/api/v5 +GITCODE_AUTH_STYLE=bearer +GITCODE_HTTP_DEBUG=1 # 可选:输出请求调试信息 ``` -## 文档同步 - -项目强制要求文档与代码同步更新: +自动化与 CLI 默认使用 `~/.gitcode` 目录存储本地状态(容器标签亦以 `gitany.*` 前缀标识)。 -- 任何对 `packages/gitcode-api/src/*` 的更改都需要更新 `docs/gitcode-api/*` -- 任何对 `packages/gitcode-cli/src/*` 的更改都需要更新 `docs/gitcode-cli/*` -- 通过 GitHub Actions 强制执行 +## 文档与规范 -**绕过机制** (不推荐): - -```bash -SKIP_DOCS_CHECK=1 git commit -m "..." -``` +- 项目文档位于 `docs/`,使用 VitePress (`pnpm docs:*`) 构建。 +- 提交前会运行 `scripts/check-docs-updated.mjs`,要求 `packages/gitcode-api` 与 `packages/gitcode-cli` 的变更同步更新对应文档,可通过 `SKIP_DOCS_CHECK=1` 暂时跳过(不推荐)。 +- 统一代码风格:ESLint + Prettier,TypeScript 采用 `tsconfig.base.json` 中的严格配置。 ## 贡献指南 -1. Fork 项目 -2. 创建功能分支 (`git checkout -b feature/amazing-feature`) -3. 提交更改 (`git commit -m 'Add amazing feature'`) -4. 推送到分支 (`git push origin feature/amazing-feature`) -5. 创建 Pull Request - -请确保: - -- 代码通过所有检查 (`pnpm lint` 和 `pnpm build`) -- 更新相关文档 -- 添加适当的测试 +1. Fork 仓库并创建分支(`git checkout -b feature/awesome`)。 +2. 开发过程中保持文档同步,必要时更新 `docs/*`。 +3. 提交前运行 `pnpm lint`、`pnpm build`,并根据包需求运行额外测试或脚本。 +4. 通过 Pull Request 提交,并附带操作日志或截图(若涉及 CLI/UI 变更)。 ## 许可证 MIT - -## 支持 - -- 📧 邮箱: [support@example.com](mailto:support@example.com) -- 🐛 问题报告: [GitHub Issues](https://github.com/your-org/gitany-actions/issues) -- 📖 文档: [项目文档](https://github.com/your-org/gitany-actions/docs) - -## 更新日志 - -### v0.1.0 (2025-09-13) - -- ✨ 新增完整的 GitCode API 支持 -- ✨ 新增 CLI 工具:用户管理、仓库操作、PR 管理 -- ✨ 新增类型安全的 API 客户端 -- ✨ 新增文档同步检查机制 -- 🐛 修复认证相关问题 -- 📚 完善项目文档和 API 文档 From ee54c703c951e72ff9cfa1c27f9eebde5ec2d986 Mon Sep 17 00:00:00 2001 From: xbghc <58060018+xbghc@users.noreply.github.com> Date: Wed, 22 Oct 2025 19:08:30 +0800 Subject: [PATCH 3/6] chore: align GitCode Actions branding --- .env.example | 2 +- README.md | 4 ++-- docs/gitcode-cli/issue.md | 2 +- docs/index.md | 2 +- packages/gitcode-actions/src/index.ts | 2 +- scripts/.env.example | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.env.example b/.env.example index 7d676f2..81666aa 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,4 @@ -# GitAny / GitCode 访问令牌 +# GitCode Actions / GitCode 访问令牌 GITCODE_TOKEN=your-token # GitCode API 配置 diff --git a/README.md b/README.md index d8abb6d..31d99a3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# GitAny Actions +# GitCode Actions -GitAny Actions 是一个基于 pnpm 的 TypeScript monorepo,围绕 GitCode 平台提供 API 客户端、命令行工具、自动化工作流、容器工具链以及配套服务。代码与文档通过 VitePress 维护,默认使用 Node.js 22 运行时。 +GitCode Actions 是一个基于 pnpm 的 TypeScript monorepo,围绕 GitCode 平台提供 API 客户端、命令行工具、自动化工作流、容器工具链以及配套服务。代码与文档通过 VitePress 维护,默认使用 Node.js 22 运行时。 ## 核心包 diff --git a/docs/gitcode-cli/issue.md b/docs/gitcode-cli/issue.md index 45c47c7..8594189 100644 --- a/docs/gitcode-cli/issue.md +++ b/docs/gitcode-cli/issue.md @@ -4,7 +4,7 @@ title: Issue Commands # GitCode Issue Commands -GitAny CLI provides comprehensive GitCode issue management functionality with GitHub CLI-style commands and options. +GitCode CLI provides comprehensive GitCode issue management functionality with GitHub CLI-style commands and options. ## Available Commands diff --git a/docs/index.md b/docs/index.md index 40ec2f1..b61bf01 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2,7 +2,7 @@ title: 首页 --- -# GitAny Monorepo 文档 +# GitCode Actions Monorepo 文档 本仓库包含两个包: diff --git a/packages/gitcode-actions/src/index.ts b/packages/gitcode-actions/src/index.ts index 2eb68d7..ed8791a 100644 --- a/packages/gitcode-actions/src/index.ts +++ b/packages/gitcode-actions/src/index.ts @@ -1,5 +1,5 @@ /** - * GitAny Core Package + * GitCode Actions Core Package * */ diff --git a/scripts/.env.example b/scripts/.env.example index 267403d..1c410d7 100644 --- a/scripts/.env.example +++ b/scripts/.env.example @@ -3,7 +3,7 @@ # --- 全局设置 --- -# GitAny / GitCode 鉴权 +# GitCode Actions / GitCode 鉴权 GITANY_TOKEN= GITCODE_TOKEN= GITCODE_API_BASE=https://gitcode.com/api/v5 From 56117c6fdabaf0514c68eff4b78ca9576873215f Mon Sep 17 00:00:00 2001 From: xbghc <58060018+xbghc@users.noreply.github.com> Date: Wed, 22 Oct 2025 19:15:02 +0800 Subject: [PATCH 4/6] fix: resolve server middleware lint errors --- packages/server/src/middleware/auth.ts | 8 +++----- packages/server/src/middleware/error-handler.ts | 1 + 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/server/src/middleware/auth.ts b/packages/server/src/middleware/auth.ts index 4d5d63d..bb13f1c 100644 --- a/packages/server/src/middleware/auth.ts +++ b/packages/server/src/middleware/auth.ts @@ -1,11 +1,9 @@ import type { Request, Response, NextFunction } from 'express'; // 扩展 Express Request 类型以包含 gitcodeToken -declare global { - namespace Express { - interface Request { - gitcodeToken?: string; - } +declare module 'express-serve-static-core' { + interface Request { + gitcodeToken?: string; } } diff --git a/packages/server/src/middleware/error-handler.ts b/packages/server/src/middleware/error-handler.ts index fda7e35..5ca9c27 100644 --- a/packages/server/src/middleware/error-handler.ts +++ b/packages/server/src/middleware/error-handler.ts @@ -6,6 +6,7 @@ export function errorHandler( res: Response, _next: NextFunction ): void { + void _next; console.error('Error:', err); res.status(500).json({ From c097f5980adcf001685eb7cd15a7ab35574b922f Mon Sep 17 00:00:00 2001 From: xbghc <1774733158@qq.com> Date: Fri, 24 Oct 2025 16:06:11 +0800 Subject: [PATCH 5/6] =?UTF-8?q?chore:=20=E6=B7=BB=E5=8A=A0=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E6=A3=80=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/pr-checks.yml | 3 + package.json | 1 + packages/git-lib/package.json | 1 + packages/gitcode-actions/package.json | 1 + packages/gitcode-api/package.json | 1 + packages/gitcode-cli/package.json | 1 + packages/gitcode-dashboard/package.json | 1 + packages/server/package.json | 1 + packages/server/src/middleware/auth.ts | 100 +++++++++++++++--------- packages/server/src/routes/issue.ts | 49 ++++++------ packages/server/src/routes/pr.ts | 29 +++---- packages/server/src/routes/repo.ts | 19 ++--- 12 files changed, 116 insertions(+), 91 deletions(-) diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index 63abfbd..ebf2887 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -28,5 +28,8 @@ jobs: - name: Build run: pnpm build + - name: Type Check + run: pnpm typecheck + - name: Lint run: pnpm lint diff --git a/package.json b/package.json index 51c3b0c..edb5a71 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "dev": "pnpm -r --parallel dev", "lint": "eslint .", "format": "prettier --write .", + "typecheck": "pnpm -r typecheck", "clean": "pnpm -r clean", "docs:dev": "vitepress dev docs", "docs:build": "vitepress build docs", diff --git a/packages/git-lib/package.json b/packages/git-lib/package.json index 84419cb..81328d0 100644 --- a/packages/git-lib/package.json +++ b/packages/git-lib/package.json @@ -11,6 +11,7 @@ "scripts": { "dev": "tsx watch src/index.ts", "build": "node ./scripts/build.mjs", + "typecheck": "tsc --noEmit", "clean": "rm -rf dist tsconfig.tsbuildinfo", "lint": "eslint ." }, diff --git a/packages/gitcode-actions/package.json b/packages/gitcode-actions/package.json index f07092f..0f974a0 100644 --- a/packages/gitcode-actions/package.json +++ b/packages/gitcode-actions/package.json @@ -11,6 +11,7 @@ "scripts": { "dev": "tsx watch src/index.ts", "build": "tsc -b", + "typecheck": "tsc --noEmit", "clean": "rm -rf dist tsconfig.tsbuildinfo", "lint": "eslint .", "cleanup": "node ./scripts/cleanup.mjs", diff --git a/packages/gitcode-api/package.json b/packages/gitcode-api/package.json index 064ef67..7946da3 100644 --- a/packages/gitcode-api/package.json +++ b/packages/gitcode-api/package.json @@ -11,6 +11,7 @@ "scripts": { "dev": "tsx watch src/index.ts", "build": "tsc -b", + "typecheck": "tsc --noEmit", "clean": "rm -rf dist tsconfig.tsbuildinfo", "lint": "eslint ." }, diff --git a/packages/gitcode-cli/package.json b/packages/gitcode-cli/package.json index 75303ce..69a8b54 100644 --- a/packages/gitcode-cli/package.json +++ b/packages/gitcode-cli/package.json @@ -12,6 +12,7 @@ "scripts": { "dev": "tsx watch src/index.ts", "build": "node ./scripts/build.mjs", + "typecheck": "tsc --noEmit", "clean": "rm -rf dist tsconfig.tsbuildinfo", "lint": "eslint .", "start": "node dist/index.js" diff --git a/packages/gitcode-dashboard/package.json b/packages/gitcode-dashboard/package.json index 4a4d4d6..1dbe37e 100644 --- a/packages/gitcode-dashboard/package.json +++ b/packages/gitcode-dashboard/package.json @@ -7,6 +7,7 @@ "scripts": { "dev": "vite", "build": "vue-tsc --noEmit && vite build", + "typecheck": "vue-tsc --noEmit", "preview": "vite preview", "clean": "rm -rf dist node_modules/.vite" }, diff --git a/packages/server/package.json b/packages/server/package.json index 1eb2263..e2fed83 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -11,6 +11,7 @@ "scripts": { "dev": "tsx watch src/index.ts", "build": "tsc -b && cp src/swagger.yaml dist/swagger.yaml", + "typecheck": "tsc --noEmit", "start": "node dist/index.js", "clean": "rm -rf dist tsconfig.tsbuildinfo", "lint": "eslint ." diff --git a/packages/server/src/middleware/auth.ts b/packages/server/src/middleware/auth.ts index bb13f1c..4c9611d 100644 --- a/packages/server/src/middleware/auth.ts +++ b/packages/server/src/middleware/auth.ts @@ -1,53 +1,77 @@ -import type { Request, Response, NextFunction } from 'express'; +import type { Request, Response } from 'express'; -// 扩展 Express Request 类型以包含 gitcodeToken -declare module 'express-serve-static-core' { - interface Request { - gitcodeToken?: string; - } +/** + * 认证处理器类型 + * - req: Express Request 对象 + * - res: Express Response 对象 + * - token: 已验证的 GitCode Token + */ +type AuthenticatedHandler = ( + req: Request, + res: Response, + token: string +) => void | Promise; + +/** + * 从请求中提取 GitCode Token + */ +function extractToken(req: Request): string | null { + // 从请求头获取 TOKEN(支持多种格式) + const token = + req.headers['x-gitcode-token'] as string || + req.headers['authorization']?.replace(/^Bearer\s+/i, '') || + req.headers['x-auth-token'] as string; + + return token || null; } /** - * 认证中间件 + * 高阶函数:为路由处理器添加认证功能 * - 从请求头中获取 GitCode Token * - 生产环境必须提供 TOKEN * - 开发环境可以使用默认 TOKEN + * + * @param handler 需要认证的路由处理器,会接收 token 作为第三个参数 + * @returns Express 路由处理器 + * + * @example + * router.get('/path', withAuth(async (req, res, token) => { + * const client = createGitcodeClient(token); + * // ... + * })); */ -export function authMiddleware(req: Request, res: Response, next: NextFunction): void { - const isProduction = process.env.NODE_ENV === 'production'; +export function withAuth(handler: AuthenticatedHandler) { + return async (req: Request, res: Response): Promise => { + const isProduction = process.env.NODE_ENV === 'production'; - // 从请求头获取 TOKEN(支持多种格式) - let token = - req.headers['x-gitcode-token'] as string || - req.headers['authorization']?.replace(/^Bearer\s+/i, '') || - req.headers['x-auth-token'] as string; + let token = extractToken(req); - // 如果没有提供 TOKEN - if (!token) { - // 生产环境必须提供 TOKEN - if (isProduction) { - res.status(401).json({ - error: 'Unauthorized', - message: 'GitCode token is required. Please provide token in request header: X-GitCode-Token or Authorization', - }); - return; - } + // 如果没有提供 TOKEN + if (!token) { + // 生产环境必须提供 TOKEN + if (isProduction) { + res.status(401).json({ + error: 'Unauthorized', + message: 'GitCode token is required. Please provide token in request header: X-GitCode-Token or Authorization', + }); + return; + } - // 开发环境使用默认 TOKEN(从环境变量) - const defaultToken = process.env.GITCODE_TOKEN || process.env.DEFAULT_GITCODE_TOKEN; + // 开发环境使用默认 TOKEN(从环境变量) + const defaultToken = process.env.GITCODE_TOKEN || process.env.DEFAULT_GITCODE_TOKEN; - if (!defaultToken) { - res.status(401).json({ - error: 'Unauthorized', - message: 'No GitCode token provided and no default token configured', - }); - return; - } + if (!defaultToken) { + res.status(401).json({ + error: 'Unauthorized', + message: 'No GitCode token provided and no default token configured', + }); + return; + } - token = defaultToken; - } + token = defaultToken; + } - // 将 TOKEN 附加到请求对象 - req.gitcodeToken = token; - next(); + // 调用处理器并传入 token + await handler(req, res, token); + }; } diff --git a/packages/server/src/routes/issue.ts b/packages/server/src/routes/issue.ts index c450f90..e1a605e 100644 --- a/packages/server/src/routes/issue.ts +++ b/packages/server/src/routes/issue.ts @@ -1,23 +1,20 @@ -import { Router, type Request, type Response } from 'express'; +import { Router } from 'express'; import type { ListIssuesQuery } from '@xbghc/gitcode-api'; -import { authMiddleware } from '../middleware/auth.js'; +import { withAuth } from '../middleware/auth.js'; import { createGitcodeClient } from '../utils/gitcode-client.js'; export const issueRouter: Router = Router(); -// 应用认证中间件到所有路由 -issueRouter.use(authMiddleware); - /** * 获取 Issue 列表 * GET /api/repo/:owner/:repo/issues */ -issueRouter.get('/repo/:owner/:repo/issues', async (req: Request, res: Response) => { +issueRouter.get('/repo/:owner/:repo/issues', withAuth(async (req, res, token) => { try { const { owner, repo } = req.params; const { state, page, per_page, sort, labels } = req.query; - const client = createGitcodeClient(req.gitcodeToken!); + const client = createGitcodeClient(token); const repoUrl = `https://gitcode.com/${owner}/${repo}`; const query: ListIssuesQuery = {}; @@ -41,7 +38,7 @@ issueRouter.get('/repo/:owner/:repo/issues', async (req: Request, res: Response) message: error instanceof Error ? error.message : 'Unknown error', }); } -}); +})); /** * 探测 Issue 数量 @@ -50,11 +47,11 @@ issueRouter.get('/repo/:owner/:repo/issues', async (req: Request, res: Response) * 注意:由于 GitCode Issue API 不支持 only_count 参数, * 此端点通过多次请求来探测Issue数量 */ -issueRouter.get('/repo/:owner/:repo/issues/count', async (req: Request, res: Response) => { +issueRouter.get('/repo/:owner/:repo/issues/count', withAuth(async (req, res, token) => { try { const { owner, repo } = req.params; - const client = createGitcodeClient(req.gitcodeToken!); + const client = createGitcodeClient(token); const repoUrl = `https://gitcode.com/${owner}/${repo}`; // 探测各个状态的Issue数量 @@ -170,17 +167,17 @@ issueRouter.get('/repo/:owner/:repo/issues/count', async (req: Request, res: Res message: error instanceof Error ? error.message : 'Unknown error', }); } -}); +})); /** * 获取 Issue 详情 * GET /api/repo/:owner/:repo/issues/:number */ -issueRouter.get('/repo/:owner/:repo/issues/:number', async (req: Request, res: Response) => { +issueRouter.get('/repo/:owner/:repo/issues/:number', withAuth(async (req, res, token) => { try { const { owner, repo, number } = req.params; - const client = createGitcodeClient(req.gitcodeToken!); + const client = createGitcodeClient(token); const repoUrl = `https://gitcode.com/${owner}/${repo}`; const issue = await client.issue.get(repoUrl, Number(number)); @@ -197,13 +194,13 @@ issueRouter.get('/repo/:owner/:repo/issues/:number', async (req: Request, res: R message: error instanceof Error ? error.message : 'Unknown error', }); } -}); +})); /** * 创建 Issue * POST /api/repo/:owner/:repo/issues */ -issueRouter.post('/repo/:owner/:repo/issues', async (req: Request, res: Response) => { +issueRouter.post('/repo/:owner/:repo/issues', withAuth(async (req, res, token) => { try { const { owner, repo } = req.params; const { title, body, labels, assignees } = req.body; @@ -216,7 +213,7 @@ issueRouter.post('/repo/:owner/:repo/issues', async (req: Request, res: Response return; } - const client = createGitcodeClient(req.gitcodeToken!); + const client = createGitcodeClient(token); const issue = await client.issue.create({ owner, @@ -241,18 +238,18 @@ issueRouter.post('/repo/:owner/:repo/issues', async (req: Request, res: Response message: error instanceof Error ? error.message : 'Unknown error', }); } -}); +})); /** * 更新 Issue * PATCH /api/repo/:owner/:repo/issues/:number */ -issueRouter.patch('/repo/:owner/:repo/issues/:number', async (req: Request, res: Response) => { +issueRouter.patch('/repo/:owner/:repo/issues/:number', withAuth(async (req, res, token) => { try { const { owner, repo, number } = req.params; const { title, body, state, labels, assignees } = req.body; - const client = createGitcodeClient(req.gitcodeToken!); + const client = createGitcodeClient(token); const repoUrl = `https://gitcode.com/${owner}/${repo}`; const issue = await client.issue.update(repoUrl, Number(number), { @@ -275,17 +272,17 @@ issueRouter.patch('/repo/:owner/:repo/issues/:number', async (req: Request, res: message: error instanceof Error ? error.message : 'Unknown error', }); } -}); +})); /** * 获取 Issue 评论列表 * GET /api/repo/:owner/:repo/issues/:number/comments */ -issueRouter.get('/repo/:owner/:repo/issues/:number/comments', async (req: Request, res: Response) => { +issueRouter.get('/repo/:owner/:repo/issues/:number/comments', withAuth(async (req, res, token) => { try { const { owner, repo, number } = req.params; - const client = createGitcodeClient(req.gitcodeToken!); + const client = createGitcodeClient(token); const repoUrl = `https://gitcode.com/${owner}/${repo}`; const comments = await client.issue.comments(repoUrl, Number(number)); @@ -302,13 +299,13 @@ issueRouter.get('/repo/:owner/:repo/issues/:number/comments', async (req: Reques message: error instanceof Error ? error.message : 'Unknown error', }); } -}); +})); /** * 添加 Issue 评论 * POST /api/repo/:owner/:repo/issues/:number/comments */ -issueRouter.post('/repo/:owner/:repo/issues/:number/comments', async (req: Request, res: Response) => { +issueRouter.post('/repo/:owner/:repo/issues/:number/comments', withAuth(async (req, res, token) => { try { const { owner, repo, number } = req.params; const { body } = req.body; @@ -321,7 +318,7 @@ issueRouter.post('/repo/:owner/:repo/issues/:number/comments', async (req: Reque return; } - const client = createGitcodeClient(req.gitcodeToken!); + const client = createGitcodeClient(token); const comment = await client.issue.createComment({ owner, @@ -342,4 +339,4 @@ issueRouter.post('/repo/:owner/:repo/issues/:number/comments', async (req: Reque message: error instanceof Error ? error.message : 'Unknown error', }); } -}); +})); diff --git a/packages/server/src/routes/pr.ts b/packages/server/src/routes/pr.ts index dbbab33..89330b3 100644 --- a/packages/server/src/routes/pr.ts +++ b/packages/server/src/routes/pr.ts @@ -1,23 +1,20 @@ import { Router, type Request, type Response } from 'express'; import type { ListPullsQuery } from '@xbghc/gitcode-api'; -import { authMiddleware } from '../middleware/auth.js'; +import { withAuth } from '../middleware/auth.js'; import { createGitcodeClient } from '../utils/gitcode-client.js'; export const prRouter: Router = Router(); -// 应用认证中间件到所有路由 -prRouter.use(authMiddleware); - /** * 获取 PR 数量统计 * GET /api/repo/:owner/:repo/pulls/count * 注意:此路由必须在 /repo/:owner/:repo/pulls/:number 之前定义 */ -prRouter.get('/repo/:owner/:repo/pulls/count', async (req: Request, res: Response) => { +prRouter.get('/repo/:owner/:repo/pulls/count', withAuth(async (req, res, token) => { try { const { owner, repo } = req.params; - const client = createGitcodeClient(req.gitcodeToken!); + const client = createGitcodeClient(token); const repoUrl = `https://gitcode.com/${owner}/${repo}`; const count = await client.pr.count(repoUrl); @@ -34,18 +31,18 @@ prRouter.get('/repo/:owner/:repo/pulls/count', async (req: Request, res: Respons message: error instanceof Error ? error.message : 'Unknown error', }); } -}); +})); /** * 获取 PR 列表 * GET /api/repo/:owner/:repo/pulls */ -prRouter.get('/repo/:owner/:repo/pulls', async (req: Request, res: Response) => { +prRouter.get('/repo/:owner/:repo/pulls', withAuth(async (req, res, token) => { try { const { owner, repo } = req.params; const { state, page, per_page, sort, direction, head, base } = req.query; - const client = createGitcodeClient(req.gitcodeToken!); + const client = createGitcodeClient(token); const repoUrl = `https://gitcode.com/${owner}/${repo}`; const query: ListPullsQuery = {}; @@ -71,7 +68,7 @@ prRouter.get('/repo/:owner/:repo/pulls', async (req: Request, res: Response) => message: error instanceof Error ? error.message : 'Unknown error', }); } -}); +})); /** * 获取 PR 详情 @@ -99,11 +96,11 @@ prRouter.get('/repo/:owner/:repo/pulls/:number', async (req: Request, res: Respo * 获取 PR 评论列表 * GET /api/repo/:owner/:repo/pulls/:number/comments */ -prRouter.get('/repo/:owner/:repo/pulls/:number/comments', async (req: Request, res: Response) => { +prRouter.get('/repo/:owner/:repo/pulls/:number/comments', withAuth(async (req, res, token) => { try { const { owner, repo, number } = req.params; - const client = createGitcodeClient(req.gitcodeToken!); + const client = createGitcodeClient(token); const repoUrl = `https://gitcode.com/${owner}/${repo}`; const comments = await client.pr.comments(repoUrl, Number(number)); @@ -120,13 +117,13 @@ prRouter.get('/repo/:owner/:repo/pulls/:number/comments', async (req: Request, r message: error instanceof Error ? error.message : 'Unknown error', }); } -}); +})); /** * 添加 PR 评论 * POST /api/repo/:owner/:repo/pulls/:number/comments */ -prRouter.post('/repo/:owner/:repo/pulls/:number/comments', async (req: Request, res: Response) => { +prRouter.post('/repo/:owner/:repo/pulls/:number/comments', withAuth(async (req, res, token) => { try { const { owner, repo, number } = req.params; const { body } = req.body; @@ -139,7 +136,7 @@ prRouter.post('/repo/:owner/:repo/pulls/:number/comments', async (req: Request, return; } - const client = createGitcodeClient(req.gitcodeToken!); + const client = createGitcodeClient(token); const repoUrl = `https://gitcode.com/${owner}/${repo}`; const comment = await client.pr.createComment(repoUrl, Number(number), body); @@ -156,7 +153,7 @@ prRouter.post('/repo/:owner/:repo/pulls/:number/comments', async (req: Request, message: error instanceof Error ? error.message : 'Unknown error', }); } -}); +})); /** * 更新 PR 状态 diff --git a/packages/server/src/routes/repo.ts b/packages/server/src/routes/repo.ts index 4027c66..b874438 100644 --- a/packages/server/src/routes/repo.ts +++ b/packages/server/src/routes/repo.ts @@ -1,18 +1,15 @@ -import { Router, type Request, type Response } from 'express'; +import { Router } from 'express'; import type { ListPullsQuery, ListIssuesQuery } from '@xbghc/gitcode-api'; -import { authMiddleware } from '../middleware/auth.js'; +import { withAuth } from '../middleware/auth.js'; import { createGitcodeClient } from '../utils/gitcode-client.js'; export const repoRouter: Router = Router(); -// 应用认证中间件到所有路由 -repoRouter.use(authMiddleware); - /** * 获取仓库的 PR 列表 * POST /api/pulls */ -repoRouter.post('/pulls', async (req: Request, res: Response) => { +repoRouter.post('/pulls', withAuth(async (req, res, token) => { try { const { owner, repo, state, page, per_page, sort, direction, head, base } = req.body; @@ -23,7 +20,7 @@ repoRouter.post('/pulls', async (req: Request, res: Response) => { } // 使用用户提供的 token 创建客户端 - const client = createGitcodeClient(req.gitcodeToken!); + const client = createGitcodeClient(token); // 构造仓库 URL const repoUrl = `https://gitcode.com/${owner}/${repo}`; @@ -54,13 +51,13 @@ repoRouter.post('/pulls', async (req: Request, res: Response) => { message: error instanceof Error ? error.message : 'Unknown error', }); } -}); +})); /** * 获取仓库的 Issue 列表 * POST /api/issues */ -repoRouter.post('/issues', async (req: Request, res: Response) => { +repoRouter.post('/issues', withAuth(async (req, res, token) => { try { const { owner, repo, state, page, per_page, sort, labels } = req.body; @@ -71,7 +68,7 @@ repoRouter.post('/issues', async (req: Request, res: Response) => { } // 使用用户提供的 token 创建客户端 - const client = createGitcodeClient(req.gitcodeToken!); + const client = createGitcodeClient(token); // 构造仓库 URL const repoUrl = `https://gitcode.com/${owner}/${repo}`; @@ -100,4 +97,4 @@ repoRouter.post('/issues', async (req: Request, res: Response) => { message: error instanceof Error ? error.message : 'Unknown error', }); } -}); +})); From df817a71fb99d65c667c21d1f7a42be0065e9b90 Mon Sep 17 00:00:00 2001 From: xbghc <1774733158@qq.com> Date: Fri, 24 Oct 2025 16:18:49 +0800 Subject: [PATCH 6/6] fix: update import path for zhCn locale in App.vue --- packages/gitcode-dashboard/src/App.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gitcode-dashboard/src/App.vue b/packages/gitcode-dashboard/src/App.vue index d09ab83..2bb26c5 100644 --- a/packages/gitcode-dashboard/src/App.vue +++ b/packages/gitcode-dashboard/src/App.vue @@ -60,7 +60,7 @@