Merge pull request '基础设施修复' (#2) from jtx_branch into master
This commit is contained in:
commit
2620a4bf5d
|
|
@ -0,0 +1,41 @@
|
|||
version: 2
|
||||
name: gitlink_cli_ci
|
||||
description: "gitlink-cli 代码提交时自动执行 CI 检查(构建、测试、格式化)"
|
||||
trigger:
|
||||
webhook: gitlink@1.0.0
|
||||
event:
|
||||
- ref: push
|
||||
ruleset-operator: AND
|
||||
global:
|
||||
concurrent: 1
|
||||
workflow:
|
||||
- ref: start
|
||||
name: 开始
|
||||
task: start
|
||||
- ref: git_clone_0
|
||||
name: 拉取代码
|
||||
task: git_clone@1.2.9
|
||||
input:
|
||||
remote_url: '"https://gitlink.org.cn/jiangtx/gitlink-cli.git"'
|
||||
ref: '"refs/heads/jtx_branch"'
|
||||
commit_id: '""'
|
||||
depth: 1
|
||||
needs:
|
||||
- start
|
||||
- ref: ssh_cmd_0
|
||||
name: CI 检查
|
||||
task: ssh_cmd@1.1.1
|
||||
input:
|
||||
ssh_pass: ((gitlink_cli_ci.ssh_pass))
|
||||
ssh_ip: '"121.41.212.97"'
|
||||
ssh_port: '"22"'
|
||||
ssh_user: '"root"'
|
||||
ssh_cmd: >-
|
||||
"cd /root && rm -rf gitlink-cli && git clone --depth=1 -b jtx_branch https://gitlink.org.cn/jiangtx/gitlink-cli.git && cd gitlink-cli && export PATH=$PATH:/usr/local/go/bin && export GOPROXY=https://goproxy.cn,direct && go version && go build ./... && go vet ./... && go test -race ./... && output=$(gofmt -s -l .) && if [ -n \"$output\" ]; then echo '格式化检查失败:' && echo \"$output\" && exit 1; fi && echo '所有 CI 检查通过'"
|
||||
needs:
|
||||
- git_clone_0
|
||||
- ref: end
|
||||
name: 结束
|
||||
task: end
|
||||
needs:
|
||||
- ssh_cmd_0
|
||||
|
|
@ -15,7 +15,7 @@ jobs:
|
|||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.22'
|
||||
go-version: '1.26.1'
|
||||
|
||||
- name: Build
|
||||
run: go build ./...
|
||||
|
|
|
|||
|
|
@ -107,10 +107,21 @@ func (c *Client) Do(method, path string, body interface{}, query url.Values) (*o
|
|||
}
|
||||
}
|
||||
|
||||
// Detect HTML responses (GitLink returns login pages when auth is missing)
|
||||
if detectHTMLResponse(respData) {
|
||||
msg := "服务器返回了 HTML 页面而非 JSON 数据"
|
||||
suggestion := suggestHTMLFix()
|
||||
return output.ErrorEnvelope(resp.StatusCode, msg, suggestion),
|
||||
&APIError{
|
||||
StatusCode: resp.StatusCode,
|
||||
Code: "HTML_RESPONSE",
|
||||
Message: msg + "\n" + suggestion,
|
||||
}
|
||||
}
|
||||
|
||||
// Parse JSON
|
||||
var raw map[string]interface{}
|
||||
if err := json.Unmarshal(respData, &raw); err != nil {
|
||||
// Not JSON, return as-is
|
||||
return output.SuccessEnvelope(string(respData), nil), nil
|
||||
}
|
||||
|
||||
|
|
@ -215,3 +226,26 @@ func suggestFix(code int) string {
|
|||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func detectHTMLResponse(data []byte) bool {
|
||||
trimmed := bytes.TrimSpace(data)
|
||||
if len(trimmed) == 0 {
|
||||
return false
|
||||
}
|
||||
prefixes := []string{"<!DOCTYPE", "<html", "<HTML", "<!doctype"}
|
||||
for _, p := range prefixes {
|
||||
if bytes.HasPrefix(trimmed, []byte(p)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func suggestHTMLFix() string {
|
||||
return "API 返回了 HTML 页面而非 JSON 数据。" +
|
||||
"可能原因:\n" +
|
||||
" 1. 未登录或 Token 已过期 → 运行 gitlink-cli auth login\n" +
|
||||
" 2. Token 权限不足 → 在 GitLink 平台重新生成 Token\n" +
|
||||
" 3. API 端点不存在 → 检查路径是否正确\n" +
|
||||
" 4. 使用 Shortcut 命令替代 Raw API → 运行 gitlink-cli --help 查看可用命令"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
|
@ -525,3 +526,67 @@ func TestShouldAppendJSONSuffixSkipsExistingJSONPath(t *testing.T) {
|
|||
t.Fatal("existing .json path should not get another suffix")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDetectHTMLResponse(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
body string
|
||||
wantHTML bool
|
||||
}{
|
||||
{"正常 JSON", `{"key":"value"}`, false},
|
||||
{"DOCTYPE 开头", `<!DOCTYPE html><html>...</html>`, true},
|
||||
{"html 小写开头", `<html><head>...</head></html>`, true},
|
||||
{"HTML 大写开头", `<HTML><HEAD>...</HEAD></HTML>`, true},
|
||||
{"doctype 小写开头", `<!doctype html><html lang="en">`, true},
|
||||
{"空响应体", "", false},
|
||||
{"纯文本", `just some text`, false},
|
||||
{"空白后 HTML", ` <!DOCTYPE html>`, true},
|
||||
{"JSON 数组", `[1,2,3]`, false},
|
||||
{"HTML 片段(无前缀)", `<body>content</body>`, false},
|
||||
{"XML 声明后跟 HTML", `<?xml version="1.0"?><!DOCTYPE html>`, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := detectHTMLResponse([]byte(tt.body)); got != tt.wantHTML {
|
||||
t.Errorf("detectHTMLResponse(%q) = %v, want %v", tt.body, got, tt.wantHTML)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientDoHTMLResponse(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/html")
|
||||
w.Write([]byte(`<!DOCTYPE html><html><head><title>Sign in</title></head><body>Please log in</body></html>`))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
c := &Client{HTTP: server.Client(), BaseURL: server.URL}
|
||||
env, err := c.Do("GET", "/api/test", nil, nil)
|
||||
if err == nil {
|
||||
t.Fatal("expected error for HTML response")
|
||||
}
|
||||
if env == nil {
|
||||
t.Fatal("expected envelope for HTML response")
|
||||
}
|
||||
if env.OK {
|
||||
t.Fatal("expected OK=false for HTML response")
|
||||
}
|
||||
apiErr, ok := err.(*APIError)
|
||||
if !ok {
|
||||
t.Fatalf("expected *APIError, got %T", err)
|
||||
}
|
||||
if apiErr.Code != "HTML_RESPONSE" {
|
||||
t.Fatalf("Code = %v, want HTML_RESPONSE", apiErr.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSuggestHTMLFix(t *testing.T) {
|
||||
msg := suggestHTMLFix()
|
||||
if msg == "" {
|
||||
t.Fatal("suggestHTMLFix should return a non-empty message")
|
||||
}
|
||||
if !strings.Contains(msg, "gitlink-cli auth login") {
|
||||
t.Fatal("suggestHTMLFix should mention auth login")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue