forked from Gitlink/gitlink-cli
Merge remote-tracking branch 'origin/master' into baoerjun_branch
This commit is contained in:
commit
ba23bf11a4
|
|
@ -1,122 +0,0 @@
|
|||
package pm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
"github.com/gitlink-org/gitlink-cli/shortcuts/common"
|
||||
)
|
||||
|
||||
func Shortcuts() []*common.Shortcut {
|
||||
return []*common.Shortcut{
|
||||
{
|
||||
Name: "boards",
|
||||
Description: "List kanban boards",
|
||||
Flags: []common.Flag{
|
||||
{Name: "page", Short: "p", Usage: "Page number", Default: "1"},
|
||||
{Name: "limit", Short: "l", Usage: "Items per page", Default: "20"},
|
||||
},
|
||||
Run: func(ctx *common.RuntimeContext) error {
|
||||
return listPM(ctx, "/pm/dashboards")
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "sprints",
|
||||
Description: "List sprint issues",
|
||||
Flags: []common.Flag{
|
||||
{Name: "page", Short: "p", Usage: "Page number", Default: "1"},
|
||||
{Name: "limit", Short: "l", Usage: "Items per page", Default: "20"},
|
||||
},
|
||||
Run: func(ctx *common.RuntimeContext) error {
|
||||
return listPM(ctx, "/pm/sprint_issues")
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "weekly",
|
||||
Description: "List weekly reports",
|
||||
Flags: []common.Flag{
|
||||
{Name: "page", Short: "p", Usage: "Page number", Default: "1"},
|
||||
{Name: "limit", Short: "l", Usage: "Items per page", Default: "20"},
|
||||
},
|
||||
Run: func(ctx *common.RuntimeContext) error {
|
||||
return listPM(ctx, "/pm/weekly_issues")
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "tags",
|
||||
Description: "List PM issue tags",
|
||||
Flags: []common.Flag{
|
||||
{Name: "page", Short: "p", Usage: "Page number", Default: "1"},
|
||||
{Name: "limit", Short: "l", Usage: "Items per page", Default: "20"},
|
||||
},
|
||||
Run: func(ctx *common.RuntimeContext) error {
|
||||
return listPM(ctx, "/pm/issue_tags")
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "pipelines",
|
||||
Description: "List PM pipelines",
|
||||
Flags: []common.Flag{
|
||||
{Name: "page", Short: "p", Usage: "Page number", Default: "1"},
|
||||
{Name: "limit", Short: "l", Usage: "Items per page", Default: "20"},
|
||||
},
|
||||
Run: func(ctx *common.RuntimeContext) error {
|
||||
return listPM(ctx, "/pm/pipelines")
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "actions",
|
||||
Description: "List action run records",
|
||||
Flags: []common.Flag{
|
||||
{Name: "page", Short: "p", Usage: "Page number", Default: "1"},
|
||||
{Name: "limit", Short: "l", Usage: "Items per page", Default: "20"},
|
||||
},
|
||||
Run: func(ctx *common.RuntimeContext) error {
|
||||
return listPM(ctx, "/pm/action_runs")
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func listPM(ctx *common.RuntimeContext, endpoint string) error {
|
||||
if err := ctx.ResolveOwnerRepo(); err != nil {
|
||||
return err
|
||||
}
|
||||
projectID, err := fetchProjectID(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
q := url.Values{}
|
||||
q.Set("project_id", strconv.Itoa(projectID))
|
||||
q.Set("owner", ctx.Owner)
|
||||
q.Set("repo", ctx.Repo)
|
||||
q.Set("page", ctx.Arg("page"))
|
||||
q.Set("limit", ctx.Arg("limit"))
|
||||
env, err := ctx.CallAPIRawWithQuery("GET", endpoint, q)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ctx.Output(env)
|
||||
}
|
||||
|
||||
func fetchProjectID(ctx *common.RuntimeContext) (int, error) {
|
||||
env, err := ctx.CallAPI("GET", ctx.RepoPath(), nil)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("获取项目信息失败: %w", err)
|
||||
}
|
||||
data, ok := env.Data.(map[string]interface{})
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("无法解析项目信息")
|
||||
}
|
||||
if idFloat, ok := data["repo_id"].(float64); ok {
|
||||
return int(idFloat), nil
|
||||
}
|
||||
if idFloat, ok := data["project_id"].(float64); ok {
|
||||
return int(idFloat), nil
|
||||
}
|
||||
if idFloat, ok := data["id"].(float64); ok {
|
||||
return int(idFloat), nil
|
||||
}
|
||||
return 0, fmt.Errorf("项目 ID 未找到,请确认仓库是否存在")
|
||||
}
|
||||
|
|
@ -1,200 +0,0 @@
|
|||
package pm
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/gitlink-org/gitlink-cli/shortcuts/common"
|
||||
)
|
||||
|
||||
func TestFetchProjectID(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
response map[string]interface{}
|
||||
wantID int
|
||||
}{
|
||||
{"repo_id", map[string]interface{}{"repo_id": float64(100)}, 100},
|
||||
{"project_id", map[string]interface{}{"project_id": float64(200)}, 200},
|
||||
{"id", map[string]interface{}{"id": float64(300)}, 300},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
resp := tc.response
|
||||
server := common.NewTestServer(t, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == "GET" && r.URL.Path == "/owner/repo.json" {
|
||||
common.WriteJSON(t, w, resp)
|
||||
return
|
||||
}
|
||||
t.Fatalf("unexpected request: %s %s", r.Method, r.URL.Path)
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
ctx := common.NewTestContext(t, server, "owner", "repo", map[string]string{})
|
||||
id, err := fetchProjectID(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("fetchProjectID failed: %v", err)
|
||||
}
|
||||
if id != tc.wantID {
|
||||
t.Fatalf("got %d, want %d", id, tc.wantID)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFetchProjectIDNotFound(t *testing.T) {
|
||||
server := common.NewTestServer(t, func(w http.ResponseWriter, r *http.Request) {
|
||||
common.WriteJSON(t, w, map[string]interface{}{"name": "repo"})
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
ctx := common.NewTestContext(t, server, "owner", "repo", map[string]string{})
|
||||
_, err := fetchProjectID(ctx)
|
||||
if err == nil {
|
||||
t.Fatal("expected error for missing project ID")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPMBoards(t *testing.T) {
|
||||
server := common.NewTestServer(t, func(w http.ResponseWriter, r *http.Request) {
|
||||
switch {
|
||||
case r.Method == "GET" && r.URL.Path == "/owner/repo.json":
|
||||
common.WriteJSON(t, w, map[string]interface{}{"id": float64(123)})
|
||||
case r.Method == "GET" && r.URL.Path == "/pm/dashboards":
|
||||
common.WriteJSON(t, w, map[string]interface{}{
|
||||
"boards": []interface{}{
|
||||
map[string]interface{}{"id": 1, "name": "Sprint 1"},
|
||||
map[string]interface{}{"id": 2, "name": "Sprint 2"},
|
||||
},
|
||||
})
|
||||
default:
|
||||
t.Fatalf("unexpected request: %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(), "boards", ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("boards failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPMSprints(t *testing.T) {
|
||||
server := common.NewTestServer(t, func(w http.ResponseWriter, r *http.Request) {
|
||||
switch {
|
||||
case r.Method == "GET" && r.URL.Path == "/owner/repo.json":
|
||||
common.WriteJSON(t, w, map[string]interface{}{"id": float64(123)})
|
||||
case r.Method == "GET" && r.URL.Path == "/pm/sprint_issues":
|
||||
common.WriteJSON(t, w, map[string]interface{}{
|
||||
"issues": []interface{}{
|
||||
map[string]interface{}{"id": 10, "subject": "Task A"},
|
||||
},
|
||||
})
|
||||
default:
|
||||
t.Fatalf("unexpected request: %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(), "sprints", ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("sprints failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPMWeekly(t *testing.T) {
|
||||
server := common.NewTestServer(t, func(w http.ResponseWriter, r *http.Request) {
|
||||
switch {
|
||||
case r.Method == "GET" && r.URL.Path == "/owner/repo.json":
|
||||
common.WriteJSON(t, w, map[string]interface{}{"id": float64(123)})
|
||||
case r.Method == "GET" && r.URL.Path == "/pm/weekly_issues":
|
||||
common.WriteJSON(t, w, map[string]interface{}{
|
||||
"reports": []interface{}{
|
||||
map[string]interface{}{"id": 1, "title": "Week 21"},
|
||||
},
|
||||
})
|
||||
default:
|
||||
t.Fatalf("unexpected request: %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(), "weekly", ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("weekly failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPMTags(t *testing.T) {
|
||||
server := common.NewTestServer(t, func(w http.ResponseWriter, r *http.Request) {
|
||||
switch {
|
||||
case r.Method == "GET" && r.URL.Path == "/owner/repo.json":
|
||||
common.WriteJSON(t, w, map[string]interface{}{"id": float64(123)})
|
||||
case r.Method == "GET" && r.URL.Path == "/pm/issue_tags":
|
||||
common.WriteJSON(t, w, map[string]interface{}{
|
||||
"tags": []interface{}{
|
||||
map[string]interface{}{"id": 1, "name": "bug"},
|
||||
},
|
||||
})
|
||||
default:
|
||||
t.Fatalf("unexpected request: %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(), "tags", ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("tags failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPMPipelines(t *testing.T) {
|
||||
server := common.NewTestServer(t, func(w http.ResponseWriter, r *http.Request) {
|
||||
switch {
|
||||
case r.Method == "GET" && r.URL.Path == "/owner/repo.json":
|
||||
common.WriteJSON(t, w, map[string]interface{}{"id": float64(123)})
|
||||
case r.Method == "GET" && r.URL.Path == "/pm/pipelines":
|
||||
common.WriteJSON(t, w, map[string]interface{}{
|
||||
"pipelines": []interface{}{
|
||||
map[string]interface{}{"id": 1, "name": "CI"},
|
||||
},
|
||||
})
|
||||
default:
|
||||
t.Fatalf("unexpected request: %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(), "pipelines", ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("pipelines failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPMActions(t *testing.T) {
|
||||
server := common.NewTestServer(t, func(w http.ResponseWriter, r *http.Request) {
|
||||
switch {
|
||||
case r.Method == "GET" && r.URL.Path == "/owner/repo.json":
|
||||
common.WriteJSON(t, w, map[string]interface{}{"id": float64(123)})
|
||||
case r.Method == "GET" && r.URL.Path == "/pm/action_runs":
|
||||
common.WriteJSON(t, w, map[string]interface{}{
|
||||
"runs": []interface{}{
|
||||
map[string]interface{}{"id": 1, "status": "success"},
|
||||
},
|
||||
})
|
||||
default:
|
||||
t.Fatalf("unexpected request: %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(), "actions", ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("actions failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
|
@ -12,7 +12,6 @@ import (
|
|||
"github.com/gitlink-org/gitlink-cli/shortcuts/member"
|
||||
"github.com/gitlink-org/gitlink-cli/shortcuts/milestone"
|
||||
"github.com/gitlink-org/gitlink-cli/shortcuts/org"
|
||||
"github.com/gitlink-org/gitlink-cli/shortcuts/pm"
|
||||
"github.com/gitlink-org/gitlink-cli/shortcuts/pr"
|
||||
"github.com/gitlink-org/gitlink-cli/shortcuts/release"
|
||||
"github.com/gitlink-org/gitlink-cli/shortcuts/repo"
|
||||
|
|
@ -41,7 +40,6 @@ func RegisterAll(root *cobra.Command) {
|
|||
"webhook": webhook.Shortcuts(),
|
||||
"member": member.Shortcuts(),
|
||||
"snippet": snippet.Shortcuts(),
|
||||
"pm": pm.Shortcuts(),
|
||||
"wiki": wiki.Shortcuts(),
|
||||
}
|
||||
|
||||
|
|
@ -61,7 +59,6 @@ func RegisterAll(root *cobra.Command) {
|
|||
"webhook": "Webhook operations",
|
||||
"member": "Project member operations",
|
||||
"snippet": "Local code snippet management",
|
||||
"pm": "Project management (kanban, sprints, weekly reports)",
|
||||
"wiki": "Wiki operations",
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue