🛠️ 创建 / 编辑 / 列表模型
pkg/domain 中用于包管理(创建、编辑、更新)与包列表/流行包查询的结构体。这些类型同时充当 API 请求体与响应体,对应 Packagist 的 https://packagist.org/api/... 写接口与 https://packagist.org/packages/list.json 读接口。
类型总览
| 类型 | 角色 | 是否需要凭据 |
|---|---|---|
PackageCreateRequest / PackageCreateResponse | 创建包 | ✅ 需要 |
PackageEditRequest / PackageEditResponse | 编辑包 | ✅ 需要 |
PackageUpdateRequest / PackageUpdateResponse | 更新包 | ✅ 需要 |
PackageListResponse | 包名列表 | ❌ 公开 |
PackageListWithDataResponse / PackageData | 带附加数据的包列表 | ❌ 公开 |
PopularPackagesResponse / PopularPackage | 流行包列表 | ❌ 公开 |
写操作需要 API 凭据
创建/编辑/更新包属于写操作,必须通过 client.WithAPICredentials(username, apiToken) 提供凭据,否则会被 Packagist 拒绝。
✏️ 创建包
PackageCreateRequest
go
type PackageCreateRequest struct {
Repository string `json:"repository"`
}| 字段 | 类型 | 说明 |
|---|---|---|
Repository | string | 要提交的包的仓库 URL(如 https://github.com/symfony/console) |
PackageCreateResponse
go
type PackageCreateResponse struct {
Status string `json:"status"`
}| 字段 | 类型 | 说明 |
|---|---|---|
Status | string | 操作状态(如 success) |
📝 编辑包
PackageEditRequest
go
type PackageEditRequest struct {
Repository string `json:"repository"`
}| 字段 | 类型 | 说明 |
|---|---|---|
Repository | string | 新的仓库 URL,用于替换该包原有的仓库地址 |
PackageEditResponse
go
type PackageEditResponse struct {
Status string `json:"status"`
}| 字段 | 类型 | 说明 |
|---|---|---|
Status | string | 操作状态 |
创建 vs 编辑
- 创建(
CreatePackage):向 Packagist 注册一个新包,只需传仓库 URL。 - 编辑(
EditPackage):修改已有包的仓库地址,需同时指定包名(在方法参数中)和新仓库 URL。 - 更新(
UpdatePackage):触发 Packagist 重新抓取某包的元数据,通常不改变仓库地址。
🔄 更新包
PackageUpdateRequest
go
type PackageUpdateRequest struct {
Repository string `json:"repository"`
}| 字段 | 类型 | 说明 |
|---|---|---|
Repository | string | 要触发更新的包名或仓库标识 |
PackageUpdateResponse
go
type PackageUpdateResponse struct {
Status string `json:"status"`
Jobs []string `json:"jobs,omitempty"`
}| 字段 | 类型 | 说明 |
|---|---|---|
Status | string | 操作状态 |
Jobs | []string | 触发的后台作业 ID 列表(可用来轮询更新进度) |
📋 包名列表
PackageListResponse
对应 https://packagist.org/packages/list.json,返回 Packagist 中所有包名。
go
type PackageListResponse struct {
PackageNames []string `json:"packageNames"`
}| 字段 | 类型 | 说明 |
|---|---|---|
PackageNames | []string | 包名列表 |
📋 带附加数据的包列表
PackageListWithDataResponse
对应 https://packagist.org/packages/list.json?fields[]=repository&fields[]=type,返回包名到附加数据的映射。
go
type PackageListWithDataResponse struct {
Packages map[string]PackageData `json:"package"`
}| 字段 | 类型 | 说明 |
|---|---|---|
Packages | map[string]PackageData | 包信息映射,键为包名,值为附加数据 |
PackageData
go
type PackageData struct {
Type string `json:"type,omitempty"`
Repository string `json:"repository,omitempty"`
Abandoned interface{} `json:"abandoned,omitempty"`
}| 字段 | 类型 | 说明 |
|---|---|---|
Type | string | 包类型(如 library) |
Repository | string | 仓库 URL |
Abandoned | interface{} | 是否废弃:可为 bool(false/true)或 string(推荐替代包名) |
Abandoned 是联合类型
Abandoned 在 JSON 中既可能是布尔值也可能是字符串:
false/true:表示未废弃 / 已废弃(无替代包)"vendor/replacement":已废弃,并推荐迁移到该替代包
因此 Go 端用 interface{} 接收。使用时需做类型断言:
go
switch v := data.Abandoned.(type) {
case bool:
if v { fmt.Println("已废弃,无替代包") }
case string:
fmt.Printf("已废弃,替代包: %s\n", v)
}⭐ 流行包
PopularPackagesResponse
对应 https://packagist.org/explore/popular.json,返回流行包列表。
go
type PopularPackagesResponse struct {
Packages []PopularPackage `json:"packages"`
Total int `json:"total"`
Next string `json:"next,omitempty"`
}| 字段 | 类型 | 说明 |
|---|---|---|
Packages | []PopularPackage | 流行包信息列表 |
Total | int | 总流行包数 |
Next | string | 下一页 URL,没有则为空 |
PopularPackage
go
type PopularPackage struct {
Name string `json:"name"`
Description string `json:"description"`
URL string `json:"url"`
Downloads int `json:"downloads"`
Favers int `json:"favers"`
}| 字段 | 类型 | 说明 |
|---|---|---|
Name | string | 包名 |
Description | string | 包描述 |
URL | string | 包页面 URL |
Downloads | int | 下载次数 |
Favers | int | 收藏次数 |
与 SearchResult 的区别
PopularPackage 的字段几乎与 domain.SearchResult 一致,但语义不同:前者来自「流行包」榜单(按收藏/下载排序),后者来自关键词搜索。两者独立定义以便各自演进。
🚀 示例
创建包(需凭据)
go
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/scagogogo/composer-skills/pkg/client"
"github.com/scagogogo/composer-skills/pkg/domain"
)
func main() {
c := client.NewComposerClient(30*time.Second,
client.WithAPICredentials("your-username", "your-api-token"),
)
resp, err := c.CreatePackage(context.Background(), &domain.PackageCreateRequest{
Repository: "https://github.com/your-org/your-package",
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("创建结果: %s\n", resp.Status)
}列出带附加数据的包
go
list, _ := c.ListPackagesWithData([]string{"repository", "type"})
for name, data := range list.Packages {
fmt.Printf("%s type=%s repo=%s\n", name, data.Type, data.Repository)
}获取流行包
go
popular, _ := c.ListPopularPackages(20)
for _, p := range popular.Packages {
fmt.Printf("%-30s ★%-6d 下载:%d\n", p.Name, p.Favers, p.Downloads)
}📚 相关文档
- 🔙 返回 Domain 概览
- 📦 包详情字段 → package.md
- 📊 下载统计 → statistics.md