🛠️ 包管理
对 Packagist 上的包执行写操作:创建、编辑、更新(触发重新抓取)。这三个方法都需要 API 凭证(Packagist 用户名 + API token),用于把你的仓库注册到 Packagist 或在仓库地址变更后更新注册。
需要凭证
三个方法都要求客户端通过 WithAPICredentials 配置了用户名与 API token,否则直接返回错误 "API credentials are required for ..."。凭证会作为 URL 查询参数发出,请从环境变量读取,勿硬编码。
何时使用
- 🛠️ 发布新包:把你的 GitHub/GitLab 仓库注册到 Packagist,让它开始抓取版本。
- 📦 仓库迁移:包的源码仓库地址变了,用
EditPackage更新注册的仓库 URL。 - 🔄 强制刷新:仓库已推新 tag 但 Packagist 还没更新,用
UpdatePackage触发重新抓取。 - 🤖 自动化发布流水线:发版后自动通知 Packagist 更新。
数据模型
请求与响应结构定义在 pkg/domain/create_package.go。
PackageCreateRequest / Response
type PackageCreateRequest struct {
Repository string `json:"repository"`
}
type PackageCreateResponse struct {
Status string `json:"status"`
}| 字段 | 类型 | 说明 |
|---|---|---|
PackageCreateRequest.Repository | string | 要注册的仓库 URL(如 https://github.com/vendor/package) |
PackageCreateResponse.Status | string | 操作状态,如 success |
PackageEditRequest / Response
type PackageEditRequest struct {
Repository string `json:"repository"`
}
type PackageEditResponse struct {
Status string `json:"status"`
}| 字段 | 类型 | 说明 |
|---|---|---|
PackageEditRequest.Repository | string | 新的仓库 URL |
PackageEditResponse.Status | string | 操作状态 |
PackageUpdateRequest / Response
type PackageUpdateRequest struct {
Repository string `json:"repository"`
}
type PackageUpdateResponse struct {
Status string `json:"status"`
Jobs []string `json:"jobs,omitempty"`
}| 字段 | 类型 | 说明 |
|---|---|---|
PackageUpdateRequest.Repository | string | 要更新的仓库 URL |
PackageUpdateResponse.Status | string | 操作状态 |
PackageUpdateResponse.Jobs | []string | 触发的后台作业 ID 列表,可用于跟踪抓取进度 |
CreatePackage
🛠️ 在 Packagist 上创建(注册)一个新包。对应 POST https://packagist.org/api/create-package?username={user}&apiToken={token}。
签名
func (c *ComposerClient) CreatePackage(ctx context.Context, request *domain.PackageCreateRequest) (*domain.PackageCreateResponse, error)参数
| 参数 | 类型 | 说明 |
|---|---|---|
ctx | context.Context | 上下文,用于超时与取消 |
request | *domain.PackageCreateRequest | 含 Repository 仓库 URL |
返回值
| 值 | 类型 | 说明 |
|---|---|---|
| 结果 | *domain.PackageCreateResponse | 含 Status |
| 错误 | error | 凭证缺失、HTTP 失败、非 200、JSON 解析失败时返回 |
示例
package main
import (
"context"
"fmt"
"log"
"os"
"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(
os.Getenv("PACKAGIST_USERNAME"),
os.Getenv("PACKAGIST_API_TOKEN"),
),
)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
resp, err := c.CreatePackage(ctx, &domain.PackageCreateRequest{
Repository: "https://github.com/myorg/my-package",
})
if err != nil {
log.Fatalf("创建包失败: %v", err)
}
fmt.Printf("状态: %s\n", resp.Status)
}非空错误信息
当 resp.StatusCode != 200 时,SDK 会把响应体作为字符串塞进 error("failed to create package: %s"),便于看到 Packagist 返回的具体原因(如「仓库已被其他包注册」)。
EditPackage
🛠️ 编辑已存在包的仓库地址。对应 PUT https://packagist.org/api/packages/{name}?username={user}&apiToken={token}。
签名
func (c *ComposerClient) EditPackage(ctx context.Context, packageName string, request *domain.PackageEditRequest) (*domain.PackageEditResponse, error)参数
| 参数 | 类型 | 说明 |
|---|---|---|
ctx | context.Context | 上下文 |
packageName | string | 要编辑的包名(vendor/package) |
request | *domain.PackageEditRequest | 含新的 Repository 仓库 URL |
返回值
| 值 | 类型 | 说明 |
|---|---|---|
| 结果 | *domain.PackageEditResponse | 含 Status |
| 错误 | error | 凭证缺失、HTTP 失败、非 200、JSON 解析失败时返回 |
示例
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
resp, err := c.EditPackage(ctx, "myorg/my-package", &domain.PackageEditRequest{
Repository: "https://github.com/myorg/my-package-new-location",
})
if err != nil {
log.Fatalf("编辑包失败: %v", err)
}
fmt.Printf("状态: %s\n", resp.Status)仓库迁移场景
当你的包源码从 GitHub 迁移到 GitLab(或换 org)后,包的 composer.json 里的仓库地址会变。用 EditPackage 把 Packagist 注册的仓库 URL 改成新地址,之后 Packagist 会从新仓库抓取版本。
UpdatePackage
🛠️ 触发 Packagist 重新抓取指定仓库(强制更新)。对应 POST https://packagist.org/api/update-package?username={user}&apiToken={token}。
签名
func (c *ComposerClient) UpdatePackage(ctx context.Context, request *domain.PackageUpdateRequest) (*domain.PackageUpdateResponse, error)参数
| 参数 | 类型 | 说明 |
|---|---|---|
ctx | context.Context | 上下文 |
request | *domain.PackageUpdateRequest | 含 Repository 仓库 URL |
返回值
| 值 | 类型 | 说明 |
|---|---|---|
| 结果 | *domain.PackageUpdateResponse | 含 Status 与 Jobs(后台作业 ID) |
| 错误 | error | 凭证缺失、HTTP 失败、非 200、JSON 解析失败时返回 |
示例
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
resp, err := c.UpdatePackage(ctx, &domain.PackageUpdateRequest{
Repository: "https://github.com/myorg/my-package",
})
if err != nil {
log.Fatalf("更新包失败: %v", err)
}
fmt.Printf("状态: %s\n", resp.Status)
fmt.Printf("作业: %v\n", resp.Jobs)何时用 Update vs Edit
- EditPackage:改仓库地址本身(包指向了不同的源码仓库)。
- UpdatePackage:仓库地址没变,但想让 Packagist 立刻重新抓取(如刚 push 了新 tag,等不及自动抓取)。
UpdatePackage 返回的 Jobs 是 Packagist 后台抓取作业的 ID,可用于跟踪抓取是否完成。
进阶
三个写操作对比
| 方法 | HTTP | 路径 | 作用 |
|---|---|---|---|
CreatePackage | POST | /api/create-package | 注册新包 |
EditPackage | PUT | /api/packages/{name} | 修改包的仓库地址 |
UpdatePackage | POST | /api/update-package | 触发重新抓取 |
自动化发布流水线
典型的「打 tag → 发布」流水线片段:
// 1. 推送 tag 后触发 Packagist 更新
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
resp, err := c.UpdatePackage(ctx, &domain.PackageUpdateRequest{
Repository: "https://github.com/myorg/my-package",
})
if err != nil {
log.Printf("触发更新失败: %v\n", err)
return
}
log.Printf("已触发更新,作业: %v\n", resp.Jobs)
// 2. 轮询 GetPackage 确认新版本已收录
for i := 0; i < 10; i++ {
time.Sleep(15 * time.Second)
info, err := c.GetPackage("myorg/my-package")
if err == nil {
if _, ok := info.Package.Versions["v1.2.3"]; ok {
log.Println("新版本已收录")
break
}
}
}🔗 相关
- 🔌 凭证配置见 WithAPICredentials。
- 📦 确认更新结果见 GetPackage / GetPackageChanges。