✨ feat(spx): 按 git origin 支持 GitHub 仓库,state 评论改成隐藏注释格式,新增 issue view / pr view / pr create
This commit is contained in:
1 parent
64d5961b62
commit
c90d84d7f2
17 files changed
+2683
-400
No files matched your search
@@ -0,0 +1,131 @@
|
||||
package forge
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNextLink(t *testing.T) {
|
||||
cases := map[string]string{
|
||||
``: ``,
|
||||
`<https://api.github.com/repositories/1/issues?page=2>; rel="next", <https://api.github.com/repositories/1/issues?page=9>; rel="last"`: `https://api.github.com/repositories/1/issues?page=2`,
|
||||
`<https://x/a?page=1>; rel="prev", <https://x/a?page=3>; rel="next"`: `https://x/a?page=3`,
|
||||
`<https://x/a?page=1>; rel="first", <https://x/a?page=1>; rel="prev"`: ``,
|
||||
`<https://x/a?labels=a,b&page=2>; rel=next`: `https://x/a?labels=a,b&page=2`,
|
||||
`<http://localhost/api/v1/repos/search?limit=1&page=2>; rel="next",<http://localhost/api/v1/repos/search?limit=1&page=5252>; rel="last"`: `http://localhost/api/v1/repos/search?limit=1&page=2`,
|
||||
}
|
||||
for header, want := range cases {
|
||||
if got := nextLink(header); got != want {
|
||||
t.Errorf("nextLink(%q) = %q, want %q", header, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pagedServer serves `total` comments `size` at a time at any path, linking each page to the next one under `nextPath`.
|
||||
func pagedServer(t *testing.T, total, size int, nextPath string, check func(r *http.Request)) (*httptest.Server, *int32) {
|
||||
t.Helper()
|
||||
var calls int32
|
||||
var srv *httptest.Server
|
||||
srv = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
atomic.AddInt32(&calls, 1)
|
||||
check(r)
|
||||
page := 1
|
||||
fmt.Sscan(r.URL.Query().Get("page"), &page)
|
||||
start := (page - 1) * size
|
||||
end := min(start+size, total)
|
||||
if end < total {
|
||||
w.Header().Set("Link", fmt.Sprintf(`<%s%s?page=%d>; rel="next"`, srv.URL, nextPath, page+1))
|
||||
}
|
||||
out := []map[string]any{}
|
||||
for i := start; i < end; i++ {
|
||||
out = append(out, map[string]any{"id": i + 1, "body": fmt.Sprintf("c%d", i+1), "user": map[string]any{"login": "bob"}})
|
||||
}
|
||||
_ = json.NewEncoder(w).Encode(out)
|
||||
}))
|
||||
t.Cleanup(srv.Close)
|
||||
return srv, &calls
|
||||
}
|
||||
|
||||
func TestGitHubPaginationFollowsLinkToOtherPath(t *testing.T) {
|
||||
srv, calls := pagedServer(t, 230, 100, "/repositories/42/issues/7/comments", func(r *http.Request) {
|
||||
if r.Header.Get("Authorization") != "Bearer tok" ||
|
||||
r.Header.Get("Accept") != "application/vnd.github+json" ||
|
||||
r.Header.Get("X-GitHub-Api-Version") != "2022-11-28" {
|
||||
t.Errorf("GitHub 请求头不对: %v", r.Header)
|
||||
}
|
||||
if r.URL.Query().Get("page") == "" {
|
||||
if r.URL.Path != "/repos/o/r/issues/7/comments" || r.URL.Query().Get("per_page") != "100" {
|
||||
t.Errorf("第一页请求不对: %s", r.URL.RequestURI())
|
||||
}
|
||||
} else if r.URL.Path != "/repositories/42/issues/7/comments" {
|
||||
t.Errorf("后续页应照 Link 走: %s", r.URL.RequestURI())
|
||||
}
|
||||
})
|
||||
list, err := NewGitHub(srv.URL, "tok", "o", "r").ListIssueComments(7)
|
||||
if err != nil {
|
||||
t.Fatalf("ListIssueComments 出错: %v", err)
|
||||
}
|
||||
if len(list) != 230 || list[229].Body != "c230" || *calls != 3 {
|
||||
t.Fatalf("应 3 次请求取全 230 条,得到 %d 条 / %d 次", len(list), *calls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGiteaPaginationFollowsLinkWithLimit(t *testing.T) {
|
||||
srv, calls := pagedServer(t, 120, 50, "/api/v1/repos/o/r/issues/7/comments", func(r *http.Request) {
|
||||
if r.Header.Get("Authorization") != "token tok" {
|
||||
t.Errorf("Gitea 认证头不对: %q", r.Header.Get("Authorization"))
|
||||
}
|
||||
if !strings.HasPrefix(r.URL.Path, "/api/v1/") {
|
||||
t.Errorf("Gitea 请求应在 /api/v1 下: %s", r.URL.Path)
|
||||
}
|
||||
if r.URL.Query().Get("page") == "" {
|
||||
if r.URL.Query().Get("limit") != "50" {
|
||||
t.Errorf("第一页应带 limit=50: %s", r.URL.RequestURI())
|
||||
}
|
||||
}
|
||||
})
|
||||
list, err := NewGitea(srv.URL, "tok", "o", "r").ListIssueComments(7)
|
||||
if err != nil {
|
||||
t.Fatalf("ListIssueComments 出错: %v", err)
|
||||
}
|
||||
if len(list) != 120 || *calls != 3 {
|
||||
t.Fatalf("应 3 次请求取全 120 条,得到 %d 条 / %d 次", len(list), *calls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPaginationStopsWithoutLinkHeader(t *testing.T) {
|
||||
srv, calls := pagedServer(t, 120, 1000, "", func(*http.Request) {})
|
||||
list, err := NewGitea(srv.URL, "tok", "o", "r").ListIssueComments(7)
|
||||
if err != nil {
|
||||
t.Fatalf("ListIssueComments 出错: %v", err)
|
||||
}
|
||||
if len(list) != 120 || *calls != 1 {
|
||||
t.Fatalf("没有 Link 头时应一次取完,得到 %d 条 / %d 次", len(list), *calls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPaginationRefusesLinkToAnotherHost(t *testing.T) {
|
||||
var foreignCalls int32
|
||||
foreign := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
atomic.AddInt32(&foreignCalls, 1)
|
||||
_, _ = w.Write([]byte("[]"))
|
||||
}))
|
||||
t.Cleanup(foreign.Close)
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Link", fmt.Sprintf(`<%s/steal?page=2>; rel="next"`, foreign.URL))
|
||||
_, _ = w.Write([]byte(`[{"id":1,"body":"x","user":{"login":"bob"}}]`))
|
||||
}))
|
||||
t.Cleanup(srv.Close)
|
||||
_, err := NewGitHub(srv.URL, "tok", "o", "r").ListIssueComments(7)
|
||||
if err == nil {
|
||||
t.Fatal("Link 指向别的主机时应报错")
|
||||
}
|
||||
if foreignCalls != 0 {
|
||||
t.Fatalf("不应带 token 请求别的主机,实际请求了 %d 次", foreignCalls)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user