Merge pull request 'fix(repo): +tree 未指定 --ref 时遵循仓库默认分支(修复 main 默认分支仓库 404)' (#337) from Taoyouce/gitlink-cli:fix/repo-tree-default-branch into master
This commit is contained in:
commit
dd3783d998
|
|
@ -0,0 +1,25 @@
|
|||
# repo +tree 遵循仓库默认分支
|
||||
|
||||
## 背景
|
||||
|
||||
`repo +tree` 未指定 `--ref` 时把 ref 硬编码为 `master`,对默认分支是
|
||||
`main`(或其他名称)的仓库直接返回 `[-2] 你访问的文件不存在`
|
||||
(生产实测 `datawhalechina/paper-chart-tutorial`,默认分支 `main`)。
|
||||
平台 `sub_entries` API 在不带 `ref` 参数时会自动使用仓库默认分支。
|
||||
|
||||
## 变更
|
||||
|
||||
- `--ref` 未指定时不再发送 `ref` 参数(交由平台落到默认分支),flag 也不再
|
||||
声明 `master` 默认值。
|
||||
|
||||
## 验证
|
||||
|
||||
- `go test ./shortcuts/repo/`(默认 ref 断言改为「不携带 ref 参数」)
|
||||
- 生产 gitlink.org.cn 实测:默认分支为 `main` 与 `master` 的仓库均正常列出根目录。
|
||||
|
||||
## 追加:branch/pr/release 同类问题一并修复
|
||||
|
||||
- 新增 `RuntimeContext.DefaultBranch()`:读取仓库详情的 `default_branch`(缺失时回退 master)
|
||||
- `branch +create --from` / `pr +create --base` 未指定时回退到仓库默认分支(不再硬编码 master)
|
||||
- `release +create --target` 未指定时省略 `target_commitish`(平台自动落默认分支)
|
||||
- 生产实测(默认分支为 main 的仓库):`repo +tree` / `branch +create` / `release +create` 均成功
|
||||
|
|
@ -56,7 +56,7 @@ func Shortcuts(translators ...*i18n.Translator) []*common.Shortcut {
|
|||
Description: tr.T("cmd.branch.create.short"),
|
||||
Flags: []common.Flag{
|
||||
{Name: "name", Short: "n", Usage: tr.T("flag.branch.name"), Required: true},
|
||||
{Name: "from", Short: "f", Usage: tr.T("flag.branch.from"), Default: "master"},
|
||||
{Name: "from", Short: "f", Usage: tr.T("flag.branch.from")},
|
||||
},
|
||||
Run: func(ctx *common.RuntimeContext) error {
|
||||
if err := ctx.ResolveOwnerRepo(); err != nil {
|
||||
|
|
@ -65,7 +65,10 @@ func Shortcuts(translators ...*i18n.Translator) []*common.Shortcut {
|
|||
name, _ := ctx.RequireArg("name")
|
||||
from := ctx.Arg("from")
|
||||
if from == "" {
|
||||
from = "master"
|
||||
var err error
|
||||
if from, err = ctx.DefaultBranch(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
payload := map[string]interface{}{
|
||||
"new_branch_name": name,
|
||||
|
|
|
|||
|
|
@ -81,12 +81,23 @@ func TestBranchCreate(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestBranchCreateDefaultFrom(t *testing.T) {
|
||||
// When 'from' is not set, it defaults to "master"
|
||||
// When 'from' is not set, it falls back to the repository default branch.
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/v1/owner/repo/branches.json" {
|
||||
switch r.URL.Path {
|
||||
case "/owner/repo.json":
|
||||
writeJSON(w, map[string]interface{}{"default_branch": "main"})
|
||||
case "/v1/owner/repo/branches.json":
|
||||
var payload map[string]interface{}
|
||||
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
|
||||
t.Fatalf("decode payload: %v", err)
|
||||
}
|
||||
if payload["old_branch_name"] != "main" {
|
||||
t.Fatalf("expected old_branch_name to be default branch main, got %v", payload["old_branch_name"])
|
||||
}
|
||||
writeJSON(w, map[string]interface{}{"name": "feature-y"})
|
||||
default:
|
||||
t.Fatalf("unexpected path: %s", r.URL.Path)
|
||||
}
|
||||
writeJSON(w, map[string]interface{}{"name": "feature-y"})
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
|
|
|
|||
|
|
@ -105,6 +105,20 @@ func (ctx *RuntimeContext) OutputData(data interface{}) error {
|
|||
return output.Print(output.SuccessEnvelope(data, nil), ctx.Format)
|
||||
}
|
||||
|
||||
// DefaultBranch fetches the repository's default branch, falling back to "master".
|
||||
func (ctx *RuntimeContext) DefaultBranch() (string, error) {
|
||||
env, err := ctx.CallAPI("GET", ctx.RepoPath(), nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if data, ok := env.Data.(map[string]interface{}); ok {
|
||||
if branch, ok := data["default_branch"].(string); ok && branch != "" {
|
||||
return branch, nil
|
||||
}
|
||||
}
|
||||
return "master", nil
|
||||
}
|
||||
|
||||
// RepoPath returns the API path prefix for the current owner/repo.
|
||||
func (ctx *RuntimeContext) RepoPath() string {
|
||||
return fmt.Sprintf("/%s/%s", ctx.Owner, ctx.Repo)
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ func Shortcuts(translators ...*i18n.Translator) []*common.Shortcut {
|
|||
{Name: "title", Short: "t", Usage: tr.T("flag.pr.title"), Required: true},
|
||||
{Name: "body", Short: "b", Usage: tr.T("flag.pr.body")},
|
||||
{Name: "head", Usage: tr.T("flag.pr.head"), Required: true},
|
||||
{Name: "base", Usage: tr.T("flag.pr.base"), Default: "master"},
|
||||
{Name: "base", Usage: tr.T("flag.pr.base")},
|
||||
},
|
||||
Run: func(ctx *common.RuntimeContext) error {
|
||||
if err := ctx.ResolveOwnerRepo(); err != nil {
|
||||
|
|
@ -108,7 +108,10 @@ func Shortcuts(translators ...*i18n.Translator) []*common.Shortcut {
|
|||
head, _ := ctx.RequireArg("head")
|
||||
base := ctx.Arg("base")
|
||||
if base == "" {
|
||||
base = "master"
|
||||
var err error
|
||||
if base, err = ctx.DefaultBranch(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
payload := map[string]interface{}{
|
||||
"title": title,
|
||||
|
|
|
|||
|
|
@ -253,6 +253,10 @@ func TestPRCreate(t *testing.T) {
|
|||
func TestPRCreateNoBody(t *testing.T) {
|
||||
var payload map[string]interface{}
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == "/owner/repo.json" {
|
||||
writeJSON(t, w, map[string]interface{}{"default_branch": "main"})
|
||||
return
|
||||
}
|
||||
payload = decodeJSON(t, r)
|
||||
writeJSON(t, w, map[string]interface{}{"id": float64(43), "title": "feat: nob"})
|
||||
}))
|
||||
|
|
@ -268,6 +272,9 @@ func TestPRCreateNoBody(t *testing.T) {
|
|||
if _, ok := payload["body"]; ok {
|
||||
t.Fatal("body should not be in payload when not provided")
|
||||
}
|
||||
if payload["base"] != "main" {
|
||||
t.Fatalf("expected base to fall back to default branch main, got %v", payload["base"])
|
||||
}
|
||||
}
|
||||
|
||||
// --- view ---
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ func Shortcuts(translators ...*i18n.Translator) []*common.Shortcut {
|
|||
{Name: "tag", Short: "t", Usage: tr.T("flag.release.tag"), Required: true},
|
||||
{Name: "name", Short: "n", Usage: tr.T("flag.release.name"), Required: true},
|
||||
{Name: "body", Short: "b", Usage: tr.T("flag.release.body")},
|
||||
{Name: "target", Usage: tr.T("flag.release.target"), Default: "master"},
|
||||
{Name: "target", Usage: tr.T("flag.release.target")},
|
||||
{Name: "prerelease", Usage: tr.T("flag.release.prerelease"), Default: "false"},
|
||||
{Name: "draft", Usage: "Mark as draft (true/false)", Default: "false"},
|
||||
{Name: "attachment-ids", Usage: "Comma-separated attachment IDs"},
|
||||
|
|
|
|||
|
|
@ -135,21 +135,19 @@ func Shortcuts(translators ...*i18n.Translator) []*common.Shortcut {
|
|||
Description: tr.T("cmd.repo.tree.short"),
|
||||
Flags: []common.Flag{
|
||||
{Name: "path", Short: "p", Usage: tr.T("flag.repo.tree.path")},
|
||||
{Name: "ref", Short: "r", Usage: tr.T("flag.repo.tree.ref"), Default: "master"},
|
||||
{Name: "ref", Short: "r", Usage: tr.T("flag.repo.tree.ref")},
|
||||
},
|
||||
Run: func(ctx *common.RuntimeContext) error {
|
||||
if err := ctx.ResolveOwnerRepo(); err != nil {
|
||||
return err
|
||||
}
|
||||
q := url.Values{}
|
||||
ref := ctx.Arg("ref")
|
||||
if ref == "" {
|
||||
ref = "master"
|
||||
}
|
||||
if path := ctx.Arg("path"); path != "" {
|
||||
q.Set("filepath", path)
|
||||
}
|
||||
q.Set("ref", ref)
|
||||
if ref := ctx.Arg("ref"); ref != "" {
|
||||
q.Set("ref", ref)
|
||||
}
|
||||
env, err := ctx.CallAPIWithQuery("GET", ctx.RepoPath()+"/sub_entries", q)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -161,7 +161,9 @@ func TestRepoTreeListsRootOnDefaultRef(t *testing.T) {
|
|||
if _, ok := r.URL.Query()["filepath"]; ok {
|
||||
t.Fatalf("did not expect filepath query for repository root, got %q", r.URL.Query().Get("filepath"))
|
||||
}
|
||||
assertEqual(t, r.URL.Query().Get("ref"), "master")
|
||||
if _, ok := r.URL.Query()["ref"]; ok {
|
||||
t.Fatalf("did not expect ref query for default ref, got %q", r.URL.Query().Get("ref"))
|
||||
}
|
||||
writeJSON(t, w, map[string]interface{}{
|
||||
"entries": []map[string]interface{}{
|
||||
{"name": "README.md", "type": "file"},
|
||||
|
|
@ -216,7 +218,7 @@ func TestRepoTreeShortcutRegistersHelpFlags(t *testing.T) {
|
|||
if !ok {
|
||||
t.Fatal("tree shortcut missing ref flag")
|
||||
}
|
||||
if refFlag.Short != "r" || refFlag.Default != "master" || refFlag.Usage == "" {
|
||||
if refFlag.Short != "r" || refFlag.Default != "" || refFlag.Usage == "" {
|
||||
t.Fatalf("unexpected ref flag: %+v", refFlag)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue