sdk_generate/internal/push/gitea.go

349 lines
8.4 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package push
import (
"encoding/base64"
"fmt"
"sync"
"time"
"code.gitea.io/sdk/gitea"
)
var (
// 全局客户端实例(单例)
defaultClient *GiteaClient
once sync.Once
initErr error
)
// GiteaClient Gitea 客户端封装
type GiteaClient struct {
client *gitea.Client
}
// RepoConfig 仓库配置
type RepoConfig struct {
Name string // 仓库名称
Description string // 仓库描述
Private bool // 是否私有false 为公共仓库
AutoInit bool // 是否自动初始化
Gitignores string // .gitignore 模板,如 "Go", "Python"
License string // 许可证,如 "MIT", "Apache-2.0"
Readme string // README 模板,如 "Default"
}
// FileConfig 文件配置
type FileConfig struct {
Path string // 文件路径,如 "main.go"
Content string // 文件内容(原始字符串)
Message string // 提交信息
Branch string // 分支名,为空则使用默认分支
}
// TagConfig Tag 配置
type TagConfig struct {
TagName string // tag 名称,如 "v1.0.0"
Message string // tag 说明
}
// GetClient 获取全局客户端实例(单例模式)
func GetClient() (*GiteaClient, error) {
//if defaultClient == nil {
// once.Do(func() {
// defaultClient, initErr = NewGiteaClient(
// "https://gitea.cdlsxd.cn/api/v1",
// "rzy_lsxd_2026",
// )
// })
// if initErr != nil {
// return nil, initErr
// }
//}
return defaultClient, nil
}
// NewGiteaClient 创建 Gitea 客户端实例
func NewGiteaClient(url, token string) (*GiteaClient, error) {
client, err := gitea.NewClient(url, gitea.SetToken(token))
if err != nil {
return nil, fmt.Errorf("创建 Gitea 客户端失败: %v", err)
}
defaultClient = &GiteaClient{
client: client,
}
return defaultClient, nil
}
// CreateRepo 创建仓库(支持个人和组织)
func (g *GiteaClient) CreateRepo(cfg RepoConfig, orgName ...string) (*gitea.Repository, error) {
if g.client == nil {
return nil, fmt.Errorf("客户端未初始化")
}
opts := gitea.CreateRepoOption{
Name: cfg.Name,
Description: cfg.Description,
Private: cfg.Private,
AutoInit: cfg.AutoInit,
Gitignores: cfg.Gitignores,
License: cfg.License,
//Readme: cfg.Readme,
}
var repo *gitea.Repository
var err error
// 如果传入了组织名,则为组织创建仓库
if len(orgName) > 0 && orgName[0] != "" {
repo, _, err = g.client.CreateOrgRepo(orgName[0], opts)
if err != nil {
return nil, fmt.Errorf("为组织 %s 创建仓库失败: %v", orgName[0], err)
}
} else {
repo, _, err = g.client.CreateRepo(opts)
if err != nil {
return nil, fmt.Errorf("创建仓库失败: %v", err)
}
}
return repo, nil
}
// PushFile 推送单个文件
func (g *GiteaClient) PushFile(owner, repoName string, fileCfg FileConfig) error {
if g.client == nil {
return fmt.Errorf("客户端未初始化")
}
// Base64 编码文件内容
contentBase64 := base64.StdEncoding.EncodeToString([]byte(fileCfg.Content))
opts := gitea.CreateFileOptions{
FileOptions: gitea.FileOptions{
Message: fileCfg.Message,
BranchName: fileCfg.Branch,
},
Content: contentBase64,
}
_, _, err := g.client.CreateFile(owner, repoName, fileCfg.Path, opts)
if err != nil {
return fmt.Errorf("推送文件 %s 失败: %v", fileCfg.Path, err)
}
return nil
}
// PushFiles 批量推送多个文件
func (g *GiteaClient) PushFiles(owner, repoName string, files []FileConfig) error {
if g.client == nil {
return fmt.Errorf("客户端未初始化")
}
for _, file := range files {
if err := g.PushFile(owner, repoName, file); err != nil {
return err
}
}
return nil
}
// CreateTag 创建标签
func (g *GiteaClient) CreateTag(owner, repoName string, tagCfg TagConfig) (*gitea.Tag, error) {
if g.client == nil {
return nil, fmt.Errorf("客户端未初始化")
}
opts := gitea.CreateTagOption{
TagName: tagCfg.TagName,
Message: tagCfg.Message,
}
tag, _, err := g.client.CreateTag(owner, repoName, opts)
if err != nil {
return nil, fmt.Errorf("创建标签 %s 失败: %v", tagCfg.TagName, err)
}
return tag, nil
}
// CreateRepoAndPush 创建仓库并推送代码(完整流程)
func (g *GiteaClient) CreateRepoAndPush(cfg RepoConfig, files []FileConfig, tagCfg *TagConfig, orgName ...string) error {
if g.client == nil {
return fmt.Errorf("客户端未初始化")
}
// 1. 创建仓库
repo, err := g.CreateRepo(cfg, orgName...)
if err != nil {
return err
}
// 等待仓库初始化完成
if cfg.AutoInit {
fmt.Println("⏳ 等待仓库初始化...")
time.Sleep(2 * time.Second)
}
// 2. 推送代码
if len(files) > 0 {
fmt.Println("📤 开始推送文件...")
if err := g.PushFiles(repo.Owner.UserName, repo.Name, files); err != nil {
return err
}
}
// 3. 创建标签(如果需要)
if tagCfg != nil && tagCfg.TagName != "" {
fmt.Println("🏷️ 创建标签...")
if _, err := g.CreateTag(repo.Owner.UserName, repo.Name, *tagCfg); err != nil {
return err
}
}
fmt.Println("🎉 全部操作完成!")
return nil
}
// ==================== 便捷函数(使用全局单例) ====================
// CreateRepoQuick 使用全局客户端快速创建仓库
func CreateRepoQuick(cfg RepoConfig, orgName ...string) (*gitea.Repository, error) {
client, err := GetClient()
if err != nil {
return nil, err
}
return client.CreateRepo(cfg, orgName...)
}
// PushFileQuick 使用全局客户端快速推送文件
func PushFileQuick(owner, repoName string, fileCfg FileConfig) error {
client, err := GetClient()
if err != nil {
return err
}
return client.PushFile(owner, repoName, fileCfg)
}
// PushFilesQuick 使用全局客户端快速批量推送文件
func PushFilesQuick(owner, repoName string, files []FileConfig) error {
client, err := GetClient()
if err != nil {
return err
}
return client.PushFiles(owner, repoName, files)
}
// CreateTagQuick 使用全局客户端快速创建标签
func CreateTagQuick(owner, repoName string, tagCfg TagConfig) (*gitea.Tag, error) {
client, err := GetClient()
if err != nil {
return nil, err
}
return client.CreateTag(owner, repoName, tagCfg)
}
// PushQuick 使用全局客户端快速完整推送
func PushQuick(repoName, description string, files []FileConfig, tagCfg *TagConfig, orgName ...string) error {
client, err := GetClient()
if err != nil {
return err
}
cfg := RepoConfig{
Name: repoName,
Description: description,
Private: false,
AutoInit: true,
Gitignores: "Go",
License: "MIT",
Readme: "Default",
}
return client.CreateRepoAndPush(cfg, files, tagCfg, orgName...)
}
// ==================== 示例 ====================
// ExampleUsage 使用示例
func ExampleUsage() {
// 准备文件
files := []FileConfig{
{
Path: "main.go",
Content: `package main\n\nimport "fmt"\n\nfunc main() {\n\tfmt.Println("Hello, Gitea!")\n}\n`,
Message: "添加主程序",
Branch: "main",
},
{
Path: "README.md",
Content: `# Auto Created Repo\n\nThis repo is created by Gitea API.`,
Message: "添加 README",
Branch: "main",
},
}
tagCfg := &TagConfig{
TagName: "v1.0.0",
Message: "首次发布",
}
// 方式1使用快捷函数自动使用全局单例
err := PushQuick("my-auto-repo", "通过 API 自动创建的公共仓库", files, tagCfg)
if err != nil {
fmt.Printf("❌ 操作失败: %v\n", err)
}
// 方式2手动获取客户端实例更灵活
client, err := GetClient()
if err != nil {
fmt.Printf("获取客户端失败: %v\n", err)
return
}
// 创建私有仓库
cfg := RepoConfig{
Name: "private-repo",
Description: "私有仓库",
Private: true,
AutoInit: true,
}
// 为组织创建仓库
err = client.CreateRepoAndPush(cfg, files, nil, "my-org")
if err != nil {
fmt.Printf("❌ 操作失败: %v\n", err)
}
// 方式3单独使用各个功能
// 只创建仓库
repoCfg := RepoConfig{
Name: "test-repo",
Private: false,
AutoInit: true,
}
repo, err := CreateRepoQuick(repoCfg)
if err != nil {
fmt.Printf("创建仓库失败: %v\n", err)
}
// 只推送文件
err = PushFileQuick(repo.Owner.UserName, repo.Name, FileConfig{
Path: "test.txt",
Content: "Hello World",
Message: "添加测试文件",
Branch: "main",
})
if err != nil {
fmt.Printf("推送文件失败: %v\n", err)
}
// 只创建标签
_, err = CreateTagQuick(repo.Owner.UserName, repo.Name, TagConfig{
TagName: "v0.1.0",
Message: "测试版本",
})
if err != nil {
fmt.Printf("创建标签失败: %v\n", err)
}
}