feat(shortcut): add shortcuts/ignore
This commit is contained in:
parent
52b7093846
commit
17c555620b
10
README.md
10
README.md
|
|
@ -467,6 +467,16 @@ gitlink-cli pipeline +disable --owner Gitlink --repo forgeplus --id 7 --workflow
|
|||
gitlink-cli pipeline +delete --owner Gitlink --repo forgeplus --id 7 --dry-run
|
||||
```
|
||||
|
||||
### Ignore File Templates
|
||||
|
||||
```bash
|
||||
# List all available .gitignore templates
|
||||
gitlink-cli ignore +list
|
||||
|
||||
# Filter templates by name
|
||||
gitlink-cli ignore +list --name Go
|
||||
```
|
||||
|
||||
### Search
|
||||
|
||||
```bash
|
||||
|
|
|
|||
|
|
@ -445,6 +445,16 @@ gitlink-cli pipeline +disable --owner Gitlink --repo forgeplus --id 7 --workflow
|
|||
gitlink-cli pipeline +delete --owner Gitlink --repo forgeplus --id 7 --dry-run
|
||||
```
|
||||
|
||||
### 忽略文件模板
|
||||
|
||||
```bash
|
||||
# 列出所有可用的 .gitignore 模板
|
||||
gitlink-cli ignore +list
|
||||
|
||||
# 按名称筛选模板
|
||||
gitlink-cli ignore +list --name Go
|
||||
```
|
||||
|
||||
### 搜索
|
||||
|
||||
```bash
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
# Ignore shortcut
|
||||
|
||||
新增 `ignore` Shortcut 组,补齐 GitLink 忽略文件模板(`.gitignore`)查询:
|
||||
|
||||
- `ignore +list`
|
||||
|
||||
同时补充了单元测试、README 示例。
|
||||
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package ignore
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
|
||||
"github.com/gitlink-org/gitlink-cli/shortcuts/common"
|
||||
)
|
||||
|
||||
// Shortcuts returns ignore-file management shortcuts.
|
||||
//
|
||||
// These shortcuts provide access to the GitLink ignore-file registry,
|
||||
// which lists all available .gitignore templates supported by the platform.
|
||||
func Shortcuts() []*common.Shortcut {
|
||||
return []*common.Shortcut{
|
||||
{
|
||||
Name: "list",
|
||||
Description: "List available ignore-file templates",
|
||||
Flags: []common.Flag{
|
||||
{Name: "name", Short: "n", Usage: "Filter ignore templates by name"},
|
||||
},
|
||||
Run: runList,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func runList(ctx *common.RuntimeContext) error {
|
||||
q := url.Values{}
|
||||
if name := ctx.Arg("name"); name != "" {
|
||||
q.Set("name", name)
|
||||
}
|
||||
env, err := ctx.CallAPIWithQuery("GET", "/ignores", q)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ctx.Output(env)
|
||||
}
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
package ignore
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/gitlink-org/gitlink-cli/internal/client"
|
||||
"github.com/gitlink-org/gitlink-cli/shortcuts/common"
|
||||
)
|
||||
|
||||
func runShortcut(t *testing.T, server *httptest.Server, name string, args map[string]string) error {
|
||||
t.Helper()
|
||||
shortcut := findShortcut(t, name)
|
||||
ctx := &common.RuntimeContext{
|
||||
Client: &client.Client{HTTP: server.Client(), BaseURL: server.URL},
|
||||
Owner: "owner",
|
||||
Repo: "repo",
|
||||
Format: "json",
|
||||
Args: args,
|
||||
}
|
||||
if ctx.Args == nil {
|
||||
ctx.Args = map[string]string{}
|
||||
}
|
||||
return shortcut.Run(ctx)
|
||||
}
|
||||
|
||||
func findShortcut(t *testing.T, name string) *common.Shortcut {
|
||||
t.Helper()
|
||||
for _, s := range Shortcuts() {
|
||||
if s.Name == name {
|
||||
return s
|
||||
}
|
||||
}
|
||||
t.Fatalf("shortcut %q not found", name)
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeJSON(t *testing.T, w http.ResponseWriter, payload interface{}) {
|
||||
t.Helper()
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if err := json.NewEncoder(w).Encode(payload); err != nil {
|
||||
t.Fatalf("failed to write response: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIgnoreList(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
t.Fatalf("got method %s, want GET", r.Method)
|
||||
}
|
||||
if r.URL.Path != "/ignores.json" {
|
||||
t.Fatalf("got path %s, want /ignores.json", r.URL.Path)
|
||||
}
|
||||
if got := r.URL.Query().Get("name"); got != "" {
|
||||
t.Fatalf("expected no name filter, got %q", got)
|
||||
}
|
||||
writeJSON(t, w, map[string]interface{}{
|
||||
"ignores": []interface{}{
|
||||
map[string]interface{}{"id": 1, "name": "Go"},
|
||||
map[string]interface{}{"id": 2, "name": "Ada"},
|
||||
},
|
||||
})
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
if err := runShortcut(t, server, "list", map[string]string{}); err != nil {
|
||||
t.Fatalf("ignore list failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIgnoreListWithNameFilter(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
t.Fatalf("got method %s, want GET", r.Method)
|
||||
}
|
||||
if r.URL.Path != "/ignores.json" {
|
||||
t.Fatalf("got path %s, want /ignores.json", r.URL.Path)
|
||||
}
|
||||
if got := r.URL.Query().Get("name"); got != "Ada" {
|
||||
t.Fatalf("expected name=Ada, got %q", got)
|
||||
}
|
||||
writeJSON(t, w, map[string]interface{}{
|
||||
"ignores": []interface{}{
|
||||
map[string]interface{}{"id": 2, "name": "Ada"},
|
||||
},
|
||||
})
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
if err := runShortcut(t, server, "list", map[string]string{"name": "Ada"}); err != nil {
|
||||
t.Fatalf("ignore list with name filter failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIgnoreListHTTPError(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte("server error"))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
err := runShortcut(t, server, "list", map[string]string{})
|
||||
if err == nil {
|
||||
t.Fatal("expected error for HTTP 500")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIgnoreListEmptyResult(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/ignores.json" {
|
||||
t.Fatalf("got path %s, want /ignores.json", r.URL.Path)
|
||||
}
|
||||
writeJSON(t, w, map[string]interface{}{
|
||||
"ignores": []interface{}{},
|
||||
})
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
if err := runShortcut(t, server, "list", map[string]string{"name": "NONEXISTENT"}); err != nil {
|
||||
t.Fatalf("ignore list with empty result failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/gitlink-org/gitlink-cli/shortcuts/common"
|
||||
"github.com/gitlink-org/gitlink-cli/shortcuts/compare"
|
||||
"github.com/gitlink-org/gitlink-cli/shortcuts/health"
|
||||
"github.com/gitlink-org/gitlink-cli/shortcuts/ignore"
|
||||
"github.com/gitlink-org/gitlink-cli/shortcuts/issue"
|
||||
"github.com/gitlink-org/gitlink-cli/shortcuts/label"
|
||||
"github.com/gitlink-org/gitlink-cli/shortcuts/license"
|
||||
|
|
@ -49,6 +50,7 @@ func RegisterAll(root *cobra.Command, translators ...*i18n.Translator) {
|
|||
"compare": compare.Shortcuts(),
|
||||
"webhook": webhook.Shortcuts(tr),
|
||||
"health": health.Shortcuts(tr),
|
||||
"ignore": ignore.Shortcuts(),
|
||||
"workflow": workflow.Shortcuts(),
|
||||
}
|
||||
|
||||
|
|
@ -70,6 +72,7 @@ func RegisterAll(root *cobra.Command, translators ...*i18n.Translator) {
|
|||
"compare": "Compare branches, tags, or commits",
|
||||
"webhook": tr.T("cmd.webhook.short"),
|
||||
"health": "Project health data collection",
|
||||
"ignore": tr.T("cmd.ignore.short"),
|
||||
"workflow": "AI agent workflow analysis",
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ func TestRegisterAll(t *testing.T) {
|
|||
"repo", "issue", "label", "license", "pr", "release", "branch",
|
||||
"org", "user", "search", "ci", "workflow",
|
||||
"compare", "member", "milestone", "pipeline", "webhook",
|
||||
"health",
|
||||
"health", "ignore",
|
||||
}
|
||||
|
||||
groupSet := map[string]bool{}
|
||||
|
|
|
|||
Loading…
Reference in New Issue