mirror of
https://gitea.com/gitea/gitea-mcp.git
synced 2025-08-23 14:23:05 +00:00
Add release and tags related funcions (#25)
Reviewed-on: https://gitea.com/gitea/gitea-mcp/pulls/25 Reviewed-by: hiifong Mr <i@hiif.ong> Co-authored-by: yp05327 <576951401@qq.com> Co-committed-by: yp05327 <576951401@qq.com>
This commit is contained in:
@@ -154,6 +154,15 @@ The Gitea MCP Server supports the following tools:
|
||||
| create_branch | Branch | Create a new branch |
|
||||
| delete_branch | Branch | Delete a branch |
|
||||
| list_branches | Branch | List all branches in a repository |
|
||||
| create_release | Release | Create a new release in a repository |
|
||||
| delete_release | Release | Delete a release from a repository |
|
||||
| get_release | Release | Get a release |
|
||||
| get_latest_release | Release | Get the latest release in a repository |
|
||||
| list_releases | Release | List all releases in a repository |
|
||||
| create_tag | Tag | Create a new tag |
|
||||
| delete_tag | Tag | Delete a tag |
|
||||
| get_tag | Tag | Get a tag |
|
||||
| list_tags | Tag | List all tags in a repository |
|
||||
| list_repo_commits | Commit | List all commits in a repository |
|
||||
| get_file_content | File | Get the content and metadata of a file |
|
||||
| create_file | File | Create a new file |
|
||||
|
@@ -154,6 +154,15 @@ Gitea MCP 服务器支持以下工具:
|
||||
| create_branch | 分支 | 创建一个新分支 |
|
||||
| delete_branch | 分支 | 删除一个分支 |
|
||||
| list_branches | 分支 | 列出仓库中的所有分支 |
|
||||
| create_release | 版本发布 | 创建一个新版本发布 |
|
||||
| delete_release | 版本发布 | 删除一个版本发布 |
|
||||
| get_release | 版本发布 | 获取一个版本发布 |
|
||||
| get_latest_release | 版本发布 | 获取最新的版本发布 |
|
||||
| list_releases | 版本发布 | 列出所有版本发布 |
|
||||
| create_tag | 标签 | 创建一个新标签 |
|
||||
| delete_tag | 标签 | 删除一个标签 |
|
||||
| get_tag | 标签 | 获取一个标签 |
|
||||
| list_tags | 标签 | 列出所有标签 |
|
||||
| list_repo_commits | 提交 | 列出仓库中的所有提交 |
|
||||
| get_file_content | 文件 | 获取文件的内容和元数据 |
|
||||
| create_file | 文件 | 创建一个新文件 |
|
||||
|
@@ -144,7 +144,6 @@ cp gitea-mcp /usr/local/bin/
|
||||
## ✅ 可用工具
|
||||
|
||||
Gitea MCP 伺服器支持以下工具:
|
||||
|
||||
| 工具 | 範圍 | 描述 |
|
||||
| :--------------------------: | :------: | :--------------------------: |
|
||||
| get_my_user_info | 用戶 | 獲取已認證用戶的信息 |
|
||||
@@ -154,6 +153,15 @@ Gitea MCP 伺服器支持以下工具:
|
||||
| create_branch | 分支 | 創建一個新分支 |
|
||||
| delete_branch | 分支 | 刪除一個分支 |
|
||||
| list_branches | 分支 | 列出倉庫中的所有分支 |
|
||||
| create_release | 版本發布 | 創建一個新版本發布 |
|
||||
| delete_release | 版本發布 | 刪除一個版本發布 |
|
||||
| get_release | 版本發布 | 獲取一個版本發布 |
|
||||
| get_latest_release | 版本發布 | 獲取最新的版本發布 |
|
||||
| list_releases | 版本發布 | 列出所有版本發布 |
|
||||
| create_tag | 標籤 | 創建一個新標籤 |
|
||||
| delete_tag | 標籤 | 刪除一個標籤 |
|
||||
| get_tag | 標籤 | 獲取一個標籤 |
|
||||
| list_tags | 標籤 | 列出所有標籤 |
|
||||
| list_repo_commits | 提交 | 列出倉庫中的所有提交 |
|
||||
| get_file_content | 文件 | 獲取文件的內容和元數據 |
|
||||
| create_file | 文件 | 創建一個新文件 |
|
||||
|
230
operation/repo/release.go
Normal file
230
operation/repo/release.go
Normal file
@@ -0,0 +1,230 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
||||
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
||||
"gitea.com/gitea/gitea-mcp/pkg/log"
|
||||
"gitea.com/gitea/gitea-mcp/pkg/ptr"
|
||||
"gitea.com/gitea/gitea-mcp/pkg/to"
|
||||
"github.com/mark3labs/mcp-go/mcp"
|
||||
)
|
||||
|
||||
const (
|
||||
CreateReleaseToolName = "create_release"
|
||||
DeleteReleaseToolName = "delete_release"
|
||||
GetReleaseToolName = "get_release"
|
||||
GetLatestReleaseToolName = "get_latest_release"
|
||||
ListReleasesToolName = "list_releases"
|
||||
)
|
||||
|
||||
var (
|
||||
CreateReleaseTool = mcp.NewTool(
|
||||
CreateReleaseToolName,
|
||||
mcp.WithDescription("Create release"),
|
||||
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
|
||||
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
|
||||
mcp.WithString("tag_name", mcp.Required(), mcp.Description("tag name")),
|
||||
mcp.WithString("target", mcp.Required(), mcp.Description("target commitish")),
|
||||
mcp.WithString("title", mcp.Required(), mcp.Description("release title")),
|
||||
mcp.WithBoolean("is_draft", mcp.Description("Whether the release is draft"), mcp.DefaultBool(false)),
|
||||
mcp.WithBoolean("is_pre_release", mcp.Description("Whether the release is pre-release"), mcp.DefaultBool(false)),
|
||||
)
|
||||
|
||||
DeleteReleaseTool = mcp.NewTool(
|
||||
DeleteReleaseToolName,
|
||||
mcp.WithDescription("Delete release"),
|
||||
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
|
||||
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
|
||||
mcp.WithNumber("id", mcp.Required(), mcp.Description("release id")),
|
||||
)
|
||||
|
||||
GetReleaseTool = mcp.NewTool(
|
||||
GetReleaseToolName,
|
||||
mcp.WithDescription("Get release"),
|
||||
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
|
||||
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
|
||||
mcp.WithNumber("id", mcp.Required(), mcp.Description("release id")),
|
||||
)
|
||||
|
||||
GetLatestReleaseTool = mcp.NewTool(
|
||||
GetLatestReleaseToolName,
|
||||
mcp.WithDescription("Get latest release"),
|
||||
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
|
||||
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
|
||||
)
|
||||
|
||||
ListReleasesTool = mcp.NewTool(
|
||||
ListReleasesToolName,
|
||||
mcp.WithDescription("List releases"),
|
||||
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
|
||||
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
|
||||
mcp.WithBoolean("is_draft", mcp.Description("Whether the release is draft"), mcp.DefaultBool(false)),
|
||||
mcp.WithBoolean("is_pre_release", mcp.Description("Whether the release is pre-release"), mcp.DefaultBool(false)),
|
||||
mcp.WithNumber("page", mcp.Description("page number"), mcp.DefaultNumber(1), mcp.Min(1)),
|
||||
mcp.WithNumber("pageSize", mcp.Description("page size"), mcp.DefaultNumber(20), mcp.Min(1)),
|
||||
)
|
||||
)
|
||||
|
||||
// To avoid return too many tokens, we need to provide at least information as possible
|
||||
// llm can call get release to get more information
|
||||
type ListReleaseResult struct {
|
||||
ID int64 `json:"id"`
|
||||
TagName string `json:"tag_name"`
|
||||
Target string `json:"target_commitish"`
|
||||
Title string `json:"title"`
|
||||
IsDraft bool `json:"draft"`
|
||||
IsPrerelease bool `json:"prerelease"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
PublishedAt time.Time `json:"published_at"`
|
||||
}
|
||||
|
||||
func CreateReleaseFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
log.Debugf("Called CreateReleasesFn")
|
||||
owner, ok := req.Params.Arguments["owner"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("owner is required")
|
||||
}
|
||||
repo, ok := req.Params.Arguments["repo"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("repo is required")
|
||||
}
|
||||
tagName, ok := req.Params.Arguments["tag_name"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("tag_name is required")
|
||||
}
|
||||
target, ok := req.Params.Arguments["target"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("target is required")
|
||||
}
|
||||
title, ok := req.Params.Arguments["title"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("title is required")
|
||||
}
|
||||
isDraft, _ := req.Params.Arguments["is_draft"].(bool)
|
||||
isPreRelease, _ := req.Params.Arguments["is_pre_release"].(bool)
|
||||
|
||||
_, _, err := gitea.Client().CreateRelease(owner, repo, gitea_sdk.CreateReleaseOption{
|
||||
TagName: tagName,
|
||||
Target: target,
|
||||
Title: title,
|
||||
IsDraft: isDraft,
|
||||
IsPrerelease: isPreRelease,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create release error: %v", err)
|
||||
}
|
||||
|
||||
return mcp.NewToolResultText("Release Created"), nil
|
||||
}
|
||||
|
||||
func DeleteReleaseFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
log.Debugf("Called DeleteReleaseFn")
|
||||
owner, ok := req.Params.Arguments["owner"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("owner is required")
|
||||
}
|
||||
repo, ok := req.Params.Arguments["repo"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("repo is required")
|
||||
}
|
||||
id, ok := req.Params.Arguments["id"].(float64)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("id is required")
|
||||
}
|
||||
|
||||
_, err := gitea.Client().DeleteRelease(owner, repo, int64(id))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("delete release error: %v", err)
|
||||
}
|
||||
|
||||
return to.TextResult("Release deleted successfully")
|
||||
}
|
||||
|
||||
func GetReleaseFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
log.Debugf("Called GetReleaseFn")
|
||||
owner, ok := req.Params.Arguments["owner"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("owner is required")
|
||||
}
|
||||
repo, ok := req.Params.Arguments["repo"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("repo is required")
|
||||
}
|
||||
id, ok := req.Params.Arguments["id"].(float64)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("id is required")
|
||||
}
|
||||
|
||||
release, _, err := gitea.Client().GetRelease(owner, repo, int64(id))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get release error: %v", err)
|
||||
}
|
||||
|
||||
return to.TextResult(release)
|
||||
}
|
||||
|
||||
func GetLatestReleaseFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
log.Debugf("Called GetLatestReleaseFn")
|
||||
owner, ok := req.Params.Arguments["owner"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("owner is required")
|
||||
}
|
||||
repo, ok := req.Params.Arguments["repo"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("repo is required")
|
||||
}
|
||||
|
||||
release, _, err := gitea.Client().GetLatestRelease(owner, repo)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get latest release error: %v", err)
|
||||
}
|
||||
|
||||
return to.TextResult(release)
|
||||
}
|
||||
|
||||
func ListReleasesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
log.Debugf("Called ListReleasesFn")
|
||||
owner, ok := req.Params.Arguments["owner"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("owner is required")
|
||||
}
|
||||
repo, ok := req.Params.Arguments["repo"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("repo is required")
|
||||
}
|
||||
isDraft, _ := req.Params.Arguments["is_draft"].(bool)
|
||||
isPreRelease, _ := req.Params.Arguments["is_pre_release"].(bool)
|
||||
page, _ := req.Params.Arguments["page"].(float64)
|
||||
pageSize, _ := req.Params.Arguments["pageSize"].(float64)
|
||||
|
||||
releases, _, err := gitea.Client().ListReleases(owner, repo, gitea_sdk.ListReleasesOptions{
|
||||
ListOptions: gitea_sdk.ListOptions{
|
||||
Page: int(page),
|
||||
PageSize: int(pageSize),
|
||||
},
|
||||
IsDraft: ptr.To(isDraft),
|
||||
IsPreRelease: ptr.To(isPreRelease),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list releases error: %v", err)
|
||||
}
|
||||
|
||||
results := make([]ListReleaseResult, len(releases))
|
||||
for _, release := range releases {
|
||||
results = append(results, ListReleaseResult{
|
||||
ID: release.ID,
|
||||
TagName: release.TagName,
|
||||
Target: release.Target,
|
||||
Title: release.Title,
|
||||
IsDraft: release.IsDraft,
|
||||
IsPrerelease: release.IsPrerelease,
|
||||
CreatedAt: release.CreatedAt,
|
||||
PublishedAt: release.PublishedAt,
|
||||
})
|
||||
}
|
||||
return to.TextResult(results)
|
||||
}
|
@@ -70,6 +70,19 @@ func RegisterTool(s *server.MCPServer) {
|
||||
s.AddTool(DeleteBranchTool, DeleteBranchFn)
|
||||
s.AddTool(ListBranchesTool, ListBranchesFn)
|
||||
|
||||
// Release
|
||||
s.AddTool(CreateReleaseTool, CreateReleaseFn)
|
||||
s.AddTool(DeleteReleaseTool, DeleteReleaseFn)
|
||||
s.AddTool(GetReleaseTool, GetReleaseFn)
|
||||
s.AddTool(GetLatestReleaseTool, GetLatestReleaseFn)
|
||||
s.AddTool(ListReleasesTool, ListReleasesFn)
|
||||
|
||||
// Tag
|
||||
s.AddTool(CreateTagTool, CreateTagFn)
|
||||
s.AddTool(DeleteTagTool, DeleteTagFn)
|
||||
s.AddTool(GetTagTool, GetTagFn)
|
||||
s.AddTool(ListTagsTool, ListTagsFn)
|
||||
|
||||
// Commit
|
||||
s.AddTool(ListRepoCommitsTool, ListRepoCommitsFn)
|
||||
}
|
||||
|
174
operation/repo/tag.go
Normal file
174
operation/repo/tag.go
Normal file
@@ -0,0 +1,174 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
||||
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
||||
"gitea.com/gitea/gitea-mcp/pkg/log"
|
||||
"gitea.com/gitea/gitea-mcp/pkg/to"
|
||||
"github.com/mark3labs/mcp-go/mcp"
|
||||
)
|
||||
|
||||
const (
|
||||
CreateTagToolName = "create_tag"
|
||||
DeleteTagToolName = "delete_tag"
|
||||
GetTagToolName = "get_tag"
|
||||
ListTagsToolName = "list_tags"
|
||||
)
|
||||
|
||||
var (
|
||||
CreateTagTool = mcp.NewTool(
|
||||
CreateTagToolName,
|
||||
mcp.WithDescription("Create tag"),
|
||||
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
|
||||
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
|
||||
mcp.WithString("tag_name", mcp.Required(), mcp.Description("tag name")),
|
||||
mcp.WithString("target", mcp.Description("target commitish"), mcp.DefaultString("")),
|
||||
mcp.WithString("message", mcp.Description("tag message"), mcp.DefaultString("")),
|
||||
)
|
||||
|
||||
DeleteTagTool = mcp.NewTool(
|
||||
DeleteTagToolName,
|
||||
mcp.WithDescription("Delete tag"),
|
||||
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
|
||||
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
|
||||
mcp.WithString("tag_name", mcp.Required(), mcp.Description("tag name")),
|
||||
)
|
||||
|
||||
GetTagTool = mcp.NewTool(
|
||||
GetTagToolName,
|
||||
mcp.WithDescription("Get tag"),
|
||||
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
|
||||
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
|
||||
mcp.WithString("tag_name", mcp.Required(), mcp.Description("tag name")),
|
||||
)
|
||||
|
||||
ListTagsTool = mcp.NewTool(
|
||||
ListTagsToolName,
|
||||
mcp.WithDescription("List tags"),
|
||||
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
|
||||
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
|
||||
mcp.WithNumber("page", mcp.Description("page number"), mcp.DefaultNumber(1), mcp.Min(1)),
|
||||
mcp.WithNumber("pageSize", mcp.Description("page size"), mcp.DefaultNumber(20), mcp.Min(1)),
|
||||
)
|
||||
)
|
||||
|
||||
// To avoid return too many tokens, we need to provide at least information as possible
|
||||
// llm can call get tag to get more information
|
||||
type ListTagResult struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Commit *gitea_sdk.CommitMeta `json:"commit"`
|
||||
// message may be a long text, so we should not provide it here
|
||||
}
|
||||
|
||||
func CreateTagFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
log.Debugf("Called CreateTagFn")
|
||||
owner, ok := req.Params.Arguments["owner"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("owner is required")
|
||||
}
|
||||
repo, ok := req.Params.Arguments["repo"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("repo is required")
|
||||
}
|
||||
tagName, ok := req.Params.Arguments["tag_name"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("tag_name is required")
|
||||
}
|
||||
target, _ := req.Params.Arguments["target"].(string)
|
||||
message, _ := req.Params.Arguments["message"].(string)
|
||||
|
||||
_, _, err := gitea.Client().CreateTag(owner, repo, gitea_sdk.CreateTagOption{
|
||||
TagName: tagName,
|
||||
Target: target,
|
||||
Message: message,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create tag error: %v", err)
|
||||
}
|
||||
|
||||
return mcp.NewToolResultText("Tag Created"), nil
|
||||
}
|
||||
|
||||
func DeleteTagFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
log.Debugf("Called DeleteTagFn")
|
||||
owner, ok := req.Params.Arguments["owner"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("owner is required")
|
||||
}
|
||||
repo, ok := req.Params.Arguments["repo"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("repo is required")
|
||||
}
|
||||
tagName, ok := req.Params.Arguments["tag_name"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("tag_name is required")
|
||||
}
|
||||
|
||||
_, err := gitea.Client().DeleteTag(owner, repo, tagName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("delete tag error: %v", err)
|
||||
}
|
||||
|
||||
return to.TextResult("Tag deleted")
|
||||
}
|
||||
|
||||
func GetTagFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
log.Debugf("Called GetTagFn")
|
||||
owner, ok := req.Params.Arguments["owner"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("owner is required")
|
||||
}
|
||||
repo, ok := req.Params.Arguments["repo"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("repo is required")
|
||||
}
|
||||
tagName, ok := req.Params.Arguments["tag_name"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("tag_name is required")
|
||||
}
|
||||
|
||||
tag, _, err := gitea.Client().GetTag(owner, repo, tagName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get tag error: %v", err)
|
||||
}
|
||||
|
||||
return to.TextResult(tag)
|
||||
}
|
||||
|
||||
func ListTagsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
log.Debugf("Called ListTagsFn")
|
||||
owner, ok := req.Params.Arguments["owner"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("owner is required")
|
||||
}
|
||||
repo, ok := req.Params.Arguments["repo"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("repo is required")
|
||||
}
|
||||
page, _ := req.Params.Arguments["page"].(float64)
|
||||
pageSize, _ := req.Params.Arguments["pageSize"].(float64)
|
||||
|
||||
tags, _, err := gitea.Client().ListRepoTags(owner, repo, gitea_sdk.ListRepoTagsOptions{
|
||||
ListOptions: gitea_sdk.ListOptions{
|
||||
Page: int(page),
|
||||
PageSize: int(pageSize),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list tags error: %v", err)
|
||||
}
|
||||
|
||||
results := make([]ListTagResult, 0, len(tags))
|
||||
for _, tag := range tags {
|
||||
results = append(results, ListTagResult{
|
||||
ID: tag.ID,
|
||||
Name: tag.Name,
|
||||
Commit: tag.Commit,
|
||||
})
|
||||
}
|
||||
return to.TextResult(results)
|
||||
}
|
Reference in New Issue
Block a user