forked from Gitlink/gitlink-cli
Merge pull request '修改webhook功能中的相关代码,完善其功能' (#7) from zzx_branch into master
This commit is contained in:
commit
297a2ccbbe
|
|
@ -44,19 +44,25 @@ func newLoginCmd() *cobra.Command {
|
|||
}
|
||||
|
||||
func loginWithPassword() error {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
// Check for credentials from environment variables for non-interactive login
|
||||
username := os.Getenv("GITLINK_USERNAME")
|
||||
password := os.Getenv("GITLINK_PASSWORD")
|
||||
|
||||
fmt.Print("Username/Email/Phone: ")
|
||||
username, _ := reader.ReadString('\n')
|
||||
username = strings.TrimSpace(username)
|
||||
if username == "" || password == "" {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
|
||||
fmt.Print("Password: ")
|
||||
passwordBytes, err := term.ReadPassword(int(syscall.Stdin))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read password: %w", err)
|
||||
fmt.Print("Username/Email/Phone: ")
|
||||
usernameInput, _ := reader.ReadString('\n')
|
||||
username = strings.TrimSpace(usernameInput)
|
||||
|
||||
fmt.Print("Password: ")
|
||||
passwordBytes, err := term.ReadPassword(int(syscall.Stdin))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read password: %w", err)
|
||||
}
|
||||
fmt.Println()
|
||||
password = string(passwordBytes)
|
||||
}
|
||||
fmt.Println()
|
||||
password := string(passwordBytes)
|
||||
|
||||
result, err := internalAuth.Login(username, password)
|
||||
if err != nil {
|
||||
|
|
|
|||
BIN
gitlink-cli.exe
BIN
gitlink-cli.exe
Binary file not shown.
|
|
@ -71,7 +71,7 @@ func Login(username, password string) (*LoginResult, error) {
|
|||
// Collect auth cookies from response (GitLink uses autologin_trustie for session persistence)
|
||||
var authCookies []string
|
||||
for _, cookie := range resp.Cookies() {
|
||||
if cookie.Name == "autologin_trustie" || cookie.Name == "_educoder_session" {
|
||||
if cookie.Name == "Authorization" || cookie.Name == "autologin_trustie" || cookie.Name == "_educoder_session" || cookie.Name == "autologin" || cookie.Name == "login" {
|
||||
authCookies = append(authCookies, cookie.Name+"="+cookie.Value)
|
||||
}
|
||||
}
|
||||
|
|
@ -79,7 +79,7 @@ func Login(username, password string) (*LoginResult, error) {
|
|||
if len(authCookies) == 0 {
|
||||
if u, err := url.Parse(loginURL); err == nil {
|
||||
for _, cookie := range jar.Cookies(u) {
|
||||
if cookie.Name == "autologin_trustie" || cookie.Name == "_educoder_session" {
|
||||
if cookie.Name == "Authorization" || cookie.Name == "autologin_trustie" || cookie.Name == "_educoder_session" || cookie.Name == "autologin" || cookie.Name == "login" {
|
||||
authCookies = append(authCookies, cookie.Name+"="+cookie.Value)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,11 +59,33 @@ func parseRemoteURL(remote string) (string, string, error) {
|
|||
}
|
||||
|
||||
func parsePathSegments(path string) (string, string, error) {
|
||||
path = strings.TrimPrefix(path, "/")
|
||||
// 处理URL路径格式:可能包含域名前缀
|
||||
// 例如://www.gitlink.org.cn/zzx-coder/gitlink-cli 或 /zzx-coder/gitlink-cli
|
||||
|
||||
// 先去掉域名部分(如果存在)
|
||||
if strings.HasPrefix(path, "//www.gitlink.org.cn/") {
|
||||
path = strings.TrimPrefix(path, "//www.gitlink.org.cn/")
|
||||
} else if strings.HasPrefix(path, "//") {
|
||||
// 处理其他可能的域名格式:找到第二个斜杠后的内容
|
||||
if idx := strings.Index(path[2:], "/"); idx != -1 {
|
||||
path = path[2+idx+1:]
|
||||
} else {
|
||||
path = path[2:]
|
||||
}
|
||||
} else if strings.HasPrefix(path, "/") {
|
||||
// 去掉单个前导斜杠
|
||||
path = strings.TrimPrefix(path, "/")
|
||||
}
|
||||
|
||||
// 去掉.git后缀
|
||||
path = strings.TrimSuffix(path, ".git")
|
||||
parts := strings.SplitN(path, "/", 3)
|
||||
|
||||
// 现在应该得到 "zzx-coder/gitlink-cli" 格式
|
||||
parts := strings.Split(path, "/")
|
||||
if len(parts) < 2 {
|
||||
return "", "", fmt.Errorf("cannot extract owner/repo from path: %s", path)
|
||||
}
|
||||
|
||||
// 第一个部分是owner,第二个是repo(可能还有更多部分但忽略)
|
||||
return parts[0], parts[1], nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"name": "gitlink-cli",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {}
|
||||
}
|
||||
|
|
@ -48,6 +48,12 @@ func parseEvents(eventsStr string) []string {
|
|||
return validEvents
|
||||
}
|
||||
|
||||
// webhookRepoPath returns the webhook API path prefix: /v1/{owner}/{repo}
|
||||
// Note: BaseURL already includes /api prefix
|
||||
func webhookRepoPath(ctx *common.RuntimeContext) string {
|
||||
return fmt.Sprintf("/v1/%s/%s", ctx.Owner, ctx.Repo)
|
||||
}
|
||||
|
||||
func Shortcuts() []*common.Shortcut {
|
||||
return []*common.Shortcut{
|
||||
{
|
||||
|
|
@ -64,7 +70,7 @@ func Shortcuts() []*common.Shortcut {
|
|||
q := url.Values{}
|
||||
q.Set("page", ctx.Arg("page"))
|
||||
q.Set("limit", ctx.Arg("limit"))
|
||||
env, err := ctx.CallAPIWithQuery("GET", ctx.RepoPath()+"/hooks", q)
|
||||
env, err := ctx.CallAPIWithQuery("GET", webhookRepoPath(ctx)+"/webhooks", q)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -78,7 +84,6 @@ func Shortcuts() []*common.Shortcut {
|
|||
{Name: "url", Short: "u", Usage: "Webhook callback URL", Required: true},
|
||||
{Name: "events", Short: "e", Usage: "Trigger events (comma-separated), e.g., push,pull_request,issue", Default: "push"},
|
||||
{Name: "active", Usage: "Webhook active status (true/false)", Default: "true"},
|
||||
{Name: "content_type", Usage: "Content type (json/form)", Default: "json"},
|
||||
{Name: "secret", Usage: "Webhook secret for HMAC verification"},
|
||||
{Name: "description", Short: "d", Usage: "Webhook description"},
|
||||
},
|
||||
|
|
@ -98,10 +103,16 @@ func Shortcuts() []*common.Shortcut {
|
|||
}
|
||||
|
||||
payload := map[string]interface{}{
|
||||
"hook_url": webhookURL,
|
||||
"events": events,
|
||||
"is_active": ctx.Arg("active") == "true",
|
||||
"content_type": ctx.Arg("content_type"),
|
||||
"url": webhookURL,
|
||||
"http_method": "POST",
|
||||
"active": true,
|
||||
"content_type": "json",
|
||||
}
|
||||
|
||||
if len(events) > 0 {
|
||||
payload["events"] = events
|
||||
} else {
|
||||
payload["events"] = []string{"push"}
|
||||
}
|
||||
|
||||
if secret := ctx.Arg("secret"); secret != "" {
|
||||
|
|
@ -112,7 +123,7 @@ func Shortcuts() []*common.Shortcut {
|
|||
payload["description"] = description
|
||||
}
|
||||
|
||||
env, err := ctx.CallAPI("POST", ctx.RepoPath()+"/hooks", payload)
|
||||
env, err := ctx.CallAPI("POST", webhookRepoPath(ctx)+"/webhooks", payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -141,12 +152,31 @@ func Shortcuts() []*common.Shortcut {
|
|||
return err
|
||||
}
|
||||
|
||||
payload := map[string]interface{}{}
|
||||
|
||||
if webhookURL := ctx.Arg("url"); webhookURL != "" {
|
||||
payload["hook_url"] = webhookURL
|
||||
payload := map[string]interface{}{
|
||||
"http_method": "POST",
|
||||
"active": true,
|
||||
"content_type": "json",
|
||||
}
|
||||
|
||||
// 如果用户没有提供URL,获取当前webhook的URL
|
||||
webhookURL := ctx.Arg("url")
|
||||
if webhookURL == "" {
|
||||
getEnv, err := ctx.CallAPI("GET", fmt.Sprintf("%s/webhooks/%s", webhookRepoPath(ctx), webhookID), nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get current webhook info: %w", err)
|
||||
}
|
||||
webhookData, ok := getEnv.Data.(map[string]interface{})
|
||||
if !ok {
|
||||
return fmt.Errorf("failed to parse webhook data")
|
||||
}
|
||||
currentURL, ok := webhookData["url"].(string)
|
||||
if !ok || currentURL == "" {
|
||||
return fmt.Errorf("failed to get current webhook URL")
|
||||
}
|
||||
webhookURL = currentURL
|
||||
}
|
||||
payload["url"] = webhookURL
|
||||
|
||||
if events := ctx.Arg("events"); events != "" {
|
||||
validEvents := parseEvents(events)
|
||||
if len(validEvents) == 0 {
|
||||
|
|
@ -155,9 +185,6 @@ func Shortcuts() []*common.Shortcut {
|
|||
payload["events"] = validEvents
|
||||
}
|
||||
|
||||
if active := ctx.Arg("active"); active != "" {
|
||||
payload["is_active"] = active == "true"
|
||||
}
|
||||
|
||||
if contentType := ctx.Arg("content_type"); contentType != "" {
|
||||
payload["content_type"] = contentType
|
||||
|
|
@ -171,11 +198,8 @@ func Shortcuts() []*common.Shortcut {
|
|||
payload["description"] = description
|
||||
}
|
||||
|
||||
if len(payload) == 0 {
|
||||
return fmt.Errorf("no fields specified for update")
|
||||
}
|
||||
|
||||
env, err := ctx.CallAPI("PUT", fmt.Sprintf("%s/hooks/%s", ctx.RepoPath(), webhookID), payload)
|
||||
env, err := ctx.CallAPI("PUT", fmt.Sprintf("%s/webhooks/%s", webhookRepoPath(ctx), webhookID), payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -198,10 +222,10 @@ func Shortcuts() []*common.Shortcut {
|
|||
return err
|
||||
}
|
||||
|
||||
_, delErr := ctx.CallAPI("DELETE", fmt.Sprintf("%s/hooks/%s", ctx.RepoPath(), webhookID), nil)
|
||||
_, delErr := ctx.CallAPI("DELETE", fmt.Sprintf("%s/webhooks/%s", webhookRepoPath(ctx), webhookID), nil)
|
||||
if delErr != nil {
|
||||
// 验证是否真的删除成功(类似release的处理)
|
||||
_, viewErr := ctx.CallAPI("GET", fmt.Sprintf("%s/hooks/%s", ctx.RepoPath(), webhookID), nil)
|
||||
_, viewErr := ctx.CallAPI("GET", fmt.Sprintf("%s/webhooks/%s", webhookRepoPath(ctx), webhookID), nil)
|
||||
if viewErr != nil {
|
||||
// Webhook不存在了,说明删除成功
|
||||
return ctx.Output(output.SuccessEnvelope(map[string]interface{}{
|
||||
|
|
@ -237,11 +261,7 @@ func Shortcuts() []*common.Shortcut {
|
|||
return fmt.Errorf("unsupported event type: %s. Supported events: %s", eventType, strings.Join(supportedEvents, ", "))
|
||||
}
|
||||
|
||||
payload := map[string]interface{}{
|
||||
"event_type": eventType,
|
||||
}
|
||||
|
||||
env, err := ctx.CallAPI("POST", fmt.Sprintf("%s/hooks/%s/test", ctx.RepoPath(), webhookID), payload)
|
||||
env, err := ctx.CallAPI("POST", fmt.Sprintf("%s/webhooks/%s/tests", webhookRepoPath(ctx), webhookID), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -264,7 +284,7 @@ func Shortcuts() []*common.Shortcut {
|
|||
return err
|
||||
}
|
||||
|
||||
env, err := ctx.CallAPI("GET", fmt.Sprintf("%s/hooks/%s", ctx.RepoPath(), webhookID), nil)
|
||||
env, err := ctx.CallAPI("GET", fmt.Sprintf("%s/webhooks/%s", webhookRepoPath(ctx), webhookID), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue