forked from Gitlink/gitlink-cli
165 lines
4.2 KiB
Markdown
165 lines
4.2 KiB
Markdown
# gitlink-cli 开发指南
|
||
|
||
## 环境准备
|
||
|
||
### 前置条件
|
||
- Go 1.22+(构建 CLI)
|
||
- Node.js 14+(npm 安装包,可选)
|
||
- Git
|
||
|
||
### 克隆与构建
|
||
|
||
```bash
|
||
git clone https://gitlink.org.cn/Gitlink/gitlink-cli.git
|
||
cd gitlink-cli
|
||
make build # 构建二进制
|
||
make install # 安装到 $GOPATH/bin
|
||
make test # 运行测试
|
||
make lint # 代码检查
|
||
```
|
||
|
||
## 项目结构
|
||
|
||
```
|
||
cmd/ # Cobra 命令定义
|
||
root.go # 根命令 + 全局 flags
|
||
auth/auth.go # 认证命令
|
||
api/api.go # Raw API 命令
|
||
config/config.go # 配置命令
|
||
cmdutil/ # 全局工具
|
||
internal/ # 内部包
|
||
auth/ # 登录、Token 存储
|
||
client/ # HTTP 客户端 + 分页
|
||
config/ # 配置文件管理
|
||
context/ # git remote 解析
|
||
output/ # 输出格式化
|
||
shortcuts/ # Shortcut 实现
|
||
common/ # 框架(types, runner, testutil)
|
||
_template/ # 开发模板
|
||
register.go # 注册入口
|
||
issue/ # Issue shortcuts(参考实现)
|
||
skills/ # AI Agent Skills
|
||
```
|
||
|
||
## 新增 Shortcut 指南
|
||
|
||
### 1. 创建域目录
|
||
|
||
```bash
|
||
mkdir -p shortcuts/mydomain
|
||
```
|
||
|
||
### 2. 实现 Shortcuts
|
||
|
||
参考 `shortcuts/_template/template.go` 或 `shortcuts/issue/issue.go`。
|
||
|
||
每个域需要实现 `Shortcuts()` 函数,返回 `[]*common.Shortcut` 列表:
|
||
|
||
```go
|
||
package mydomain
|
||
|
||
import "github.com/gitlink-org/gitlink-cli/shortcuts/common"
|
||
|
||
func Shortcuts() []*common.Shortcut {
|
||
return []*common.Shortcut{
|
||
{
|
||
Name: "list",
|
||
Description: "List resources",
|
||
Flags: []common.Flag{
|
||
{Name: "page", Short: "p", Usage: "Page number", Default: "1"},
|
||
},
|
||
Run: func(ctx *common.RuntimeContext) error {
|
||
if err := ctx.ResolveOwnerRepo(); err != nil {
|
||
return err
|
||
}
|
||
env, err := ctx.CallAPI("GET", ctx.RepoPath()+"/resources", nil)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
return ctx.Output(env)
|
||
},
|
||
},
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3. 注册域
|
||
|
||
在 `shortcuts/register.go` 中添加:
|
||
|
||
```go
|
||
import "github.com/gitlink-org/gitlink-cli/shortcuts/mydomain"
|
||
|
||
// 在 RegisterShortcuts 函数中:
|
||
common.MountShortcut(rootCmd, "mydomain", mydomain.Shortcuts())
|
||
```
|
||
|
||
### 4. 编写测试
|
||
|
||
参考 `shortcuts/issue/issue_test.go`,使用 `common.NewTestServer` 和 `common.NewTestContext`:
|
||
|
||
```go
|
||
package mydomain
|
||
|
||
import (
|
||
"net/http"
|
||
"testing"
|
||
"github.com/gitlink-org/gitlink-cli/shortcuts/common"
|
||
)
|
||
|
||
func TestMyDomainList(t *testing.T) {
|
||
server := common.NewTestServer(t, func(w http.ResponseWriter, r *http.Request) {
|
||
if r.Method == "GET" && r.URL.Path == "/owner/repo/resources.json" {
|
||
common.WriteJSON(t, w, map[string]interface{}{
|
||
"resources": []interface{}{},
|
||
})
|
||
} else {
|
||
t.Fatalf("unexpected: %s %s", r.Method, r.URL.Path)
|
||
}
|
||
})
|
||
defer server.Close()
|
||
|
||
ctx := common.NewTestContext(t, server, "owner", "repo", map[string]string{})
|
||
err := common.RunShortcut(t, Shortcuts(), "list", ctx)
|
||
if err != nil {
|
||
t.Fatalf("list failed: %v", err)
|
||
}
|
||
}
|
||
```
|
||
|
||
## API 约定
|
||
|
||
### v1 API 路径
|
||
Issue 相关操作使用 v1 路径:`/v1/{owner}/{repo}/issues`
|
||
其他操作使用:`/{owner}/{repo}/...`
|
||
|
||
### HTTP 方法映射
|
||
| 操作 | 方法 |
|
||
|------|------|
|
||
| 列表 | GET |
|
||
| 查看 | GET |
|
||
| 创建 | POST |
|
||
| 更新 | PATCH/PUT |
|
||
| 删除 | DELETE |
|
||
|
||
### 通用参数
|
||
- `--owner` / `--repo`:自动从 git remote 解析
|
||
- `--format`:输出格式(json/table/yaml)
|
||
- `--page` / `--limit`:分页
|
||
|
||
## 测试
|
||
|
||
```bash
|
||
make test # 运行所有测试
|
||
make test-cover # 运行测试并生成覆盖率报告
|
||
go test -v ./shortcuts/mydomain/ # 测试单个域
|
||
```
|
||
|
||
## 提交 PR 前检查清单
|
||
|
||
- [ ] `make test` 通过
|
||
- [ ] `make lint` 通过(或 `go vet ./...`)
|
||
- [ ] 新 Shortcut 已注册到 `register.go`
|
||
- [ ] 包含单元测试
|
||
- [ ] 帮助文档(Description、Flags Usage)已更新
|