From dc9cd9e168ad55b1134731a00aa206daaad5024a Mon Sep 17 00:00:00 2001 From: yystopf Date: Tue, 28 Feb 2023 10:48:49 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9A=E8=B4=A1?= =?UTF-8?q?=E7=8C=AE=E8=80=85=E6=96=B0=E6=96=B9=E6=A1=88=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E6=95=88=E7=8E=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/git/repo_contributors.go | 88 ++++++++++++++++++++++++++++++++ routers/hat/repo/repo.go | 5 +- 2 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 modules/git/repo_contributors.go diff --git a/modules/git/repo_contributors.go b/modules/git/repo_contributors.go new file mode 100644 index 0000000..f7646cc --- /dev/null +++ b/modules/git/repo_contributors.go @@ -0,0 +1,88 @@ +package git + +import ( + "bufio" + "context" + "os" + "strconv" + "strings" + + gitea_git "code.gitea.io/gitea/modules/git" +) + +type RepoContributor struct { + Name string `json:"name"` + Email string `json:"email"` + Commits int `json:"commits"` +} + +func GetRepoContributors(repo *gitea_git.Repository, page, pageSize int) (int, []*RepoContributor, error) { + var total, skip int + var contributors []*RepoContributor + + skip = (page - 1) * pageSize + + stdoutReader, stdoutWriter, err := os.Pipe() + if err != nil { + return total, nil, err + } + defer func() { + _ = stdoutReader.Close() + _ = stdoutWriter.Close() + }() + cmd := gitea_git.NewCommand(repo.Ctx, "shortlog", "-sne", "HEAD") + + stderr := new(strings.Builder) + err = cmd.Run(&gitea_git.RunOpts{ + Env: []string{}, + Dir: repo.Path, + Stdout: stdoutWriter, + Stderr: stderr, + PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error { + _ = stdoutWriter.Close() + scanner := bufio.NewScanner(stdoutReader) + scanner.Split(bufio.ScanLines) + var ca int + for scanner.Scan() { + total++ + if skip > 0 { + skip-- + } else { + if ca < pageSize { + l := strings.TrimSpace(scanner.Text()) + commits := l[0:strings.Index(l, "\t")] + commitsInt, err := strconv.Atoi(commits) + if err != nil { + return err + } + name := l[strings.Index(l, "\t")+1 : strings.Index(l, " <")] + email := l[strings.Index(l, "<")+1 : strings.Index(l, ">")] + contributors = append(contributors, &RepoContributor{ + Commits: commitsInt, + Name: name, + Email: email, + }) + ca++ + } + } + } + + _ = stdoutReader.Close() + return nil + }, + }) + + // skip := (page - 1) * pageSize + // for _, con := range contributorsArr { + // if skip > 0 { + // contributors = append(contributors, &RepoContributor{ + // Commits: con, + // }) + // skip-- + + // } + + // } + + return total, contributors, nil +} diff --git a/routers/hat/repo/repo.go b/routers/hat/repo/repo.go index a92c2c0..8e206ba 100644 --- a/routers/hat/repo/repo.go +++ b/routers/hat/repo/repo.go @@ -483,11 +483,10 @@ func SetDiffViewStyle(ctx *context.Context) { func GetContributors(ctx *context.APIContext) { listOptions := utils.GetListOptions(ctx) - branch := ctx.FormString("branch") - total, list, err := hat_git.GetPaginateCodeAuthorsWithoutSince(ctx.Repo.GitRepo, branch, listOptions.Page, listOptions.PageSize) + total, list, err := hat_git.GetRepoContributors(ctx.Repo.GitRepo, listOptions.Page, listOptions.PageSize) if err != nil { - ctx.Error(http.StatusInternalServerError, "GetContributors", err) + ctx.Error(http.StatusInternalServerError, "GetRepoContributors", err) return } -- 2.34.1 From 3cbba6e36fa972413f730ba46cf1f870e7e2ff67 Mon Sep 17 00:00:00 2001 From: yystopf Date: Tue, 28 Feb 2023 14:16:46 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9Awebhook=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E6=94=AF=E6=8C=81http=5Fmethod?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/git/repo_contributors.go | 12 ---- modules/structs/hook.go | 7 ++ routers/hat/hat.go | 1 + routers/hat/repo/hook.go | 119 +++++++++++++++++++++++++++++++ 4 files changed, 127 insertions(+), 12 deletions(-) diff --git a/modules/git/repo_contributors.go b/modules/git/repo_contributors.go index f7646cc..683157f 100644 --- a/modules/git/repo_contributors.go +++ b/modules/git/repo_contributors.go @@ -72,17 +72,5 @@ func GetRepoContributors(repo *gitea_git.Repository, page, pageSize int) (int, [ }, }) - // skip := (page - 1) * pageSize - // for _, con := range contributorsArr { - // if skip > 0 { - // contributors = append(contributors, &RepoContributor{ - // Commits: con, - // }) - // skip-- - - // } - - // } - return total, contributors, nil } diff --git a/modules/structs/hook.go b/modules/structs/hook.go index 4311606..df79c41 100644 --- a/modules/structs/hook.go +++ b/modules/structs/hook.go @@ -16,6 +16,13 @@ type CreateHookOption struct { Active bool `json:"active"` } +type EditHookOption struct { + Config map[string]string `json:"config"` + Events []string `json:"events"` + BranchFilter string `json:"branch_filter" binding:"GlobPattern"` + Active *bool `json:"active"` +} + type HookTask struct { ID int64 `json:"id"` UUID string `json:"uuid"` diff --git a/routers/hat/hat.go b/routers/hat/hat.go index 31cc2ae..b5f1096 100644 --- a/routers/hat/hat.go +++ b/routers/hat/hat.go @@ -128,6 +128,7 @@ func Routers(ctx gocontext.Context) *web.Route { m.Group("/hooks", func() { m.Combo("").Post(bind(hat_api.CreateHookOption{}), repo.CreateHook) m.Group("/{id}", func() { + m.Combo("").Patch(bind(hat_api.EditHookOption{}), repo.EditHook) m.Get("/hooktasks", repo.ListHookTask) }) }, reqToken(), reqAdmin(), reqWebhooksEnabled()) diff --git a/routers/hat/repo/hook.go b/routers/hat/repo/hook.go index 52264ec..f338cf7 100644 --- a/routers/hat/repo/hook.go +++ b/routers/hat/repo/hook.go @@ -16,8 +16,127 @@ import ( hat_webhook "code.gitlink.org.cn/Gitlink/gitea_hat.git/models/webhook" hat_convert "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/convert" hat_api "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/structs" + jsoniter "github.com/json-iterator/go" ) +func EditHook(ctx *context.APIContext) { + form := web.GetForm(ctx).(*hat_api.EditHookOption) + hookID := ctx.ParamsInt64(":id") + editRepoHook(ctx, form, hookID) +} + +func editRepoHook(ctx *context.APIContext, form *hat_api.EditHookOption, hookID int64) { + repo := ctx.Repo + hook, err := utils.GetRepoHook(ctx, repo.Repository.ID, hookID) + if err != nil { + return + } + + if !editHook(ctx, form, hook) { + return + } + + updated, err := utils.GetRepoHook(ctx, repo.Repository.ID, hookID) + if err != nil { + return + } + + ctx.JSON(http.StatusOK, convert.ToHook(repo.RepoLink, updated)) +} + +func editHook(ctx *context.APIContext, form *hat_api.EditHookOption, w *webhook.Webhook) bool { + if form.Config != nil { + if url, ok := form.Config["url"]; ok { + w.URL = url + } + if secret, ok := form.Config["secret"]; ok { + w.Secret = secret + } + + if ct, ok := form.Config["content_type"]; ok { + if !webhook.IsValidHookContentType(ct) { + ctx.Error(http.StatusUnprocessableEntity, "", "Invalid content type") + return false + } + w.ContentType = webhook.ToHookContentType(ct) + } + + if hw, ok := form.Config["http_method"]; ok { + if !isValidHookHttpMethod(hw) { + ctx.Error(http.StatusUnprocessableEntity, "", "Invalid http method") + return false + } + w.HTTPMethod = hw + } + + if w.Type == webhook.SLACK { + if channel, ok := form.Config["channel"]; ok { + json := jsoniter.ConfigCompatibleWithStandardLibrary + meta, err := json.Marshal(&webhook_service.SlackMeta{ + Channel: channel, + Username: form.Config["username"], + IconURL: form.Config["icon_url"], + Color: form.Config["color"], + }) + if err != nil { + ctx.Error(http.StatusInternalServerError, "slack: JSON marshal failed", err) + return false + } + w.Meta = string(meta) + } + } + } + + // Update events + if len(form.Events) == 0 { + form.Events = []string{"push"} + } + w.PushOnly = false + w.SendEverything = false + w.ChooseEvents = true + w.Create = util.IsStringInSlice(string(webhook.HookEventCreate), form.Events, true) + w.Push = util.IsStringInSlice(string(webhook.HookEventPush), form.Events, true) + w.PullRequest = util.IsStringInSlice(string(webhook.HookEventPullRequest), form.Events, true) + // w.Create = util.IsStringInSlice(string(webhook.HookEventCreate), form.Events, true) + w.Delete = util.IsStringInSlice(string(webhook.HookEventDelete), form.Events, true) + w.Fork = util.IsStringInSlice(string(webhook.HookEventFork), form.Events, true) + w.Issues = util.IsStringInSlice(string(webhook.HookEventIssues), form.Events, true) + w.Issues = issuesHook(form.Events, "issues_only") + w.IssueAssign = issuesHook(form.Events, string(webhook.HookEventIssueAssign)) + w.IssueLabel = issuesHook(form.Events, string(webhook.HookEventIssueLabel)) + w.IssueMilestone = issuesHook(form.Events, string(webhook.HookEventIssueMilestone)) + w.IssueComment = issuesHook(form.Events, string(webhook.HookEventIssueComment)) + // w.IssueComment = util.IsStringInSlice(string(webhook.HookEventIssueComment), form.Events, true) + w.Push = util.IsStringInSlice(string(webhook.HookEventPush), form.Events, true) + // w.PullRequest = util.IsStringInSlice(string(webhook.HookEventPullRequest), form.Events, true) + w.PullRequest = pullHook(form.Events, "pull_request_only") + w.PullRequestAssign = pullHook(form.Events, string(webhook.HookEventPullRequestAssign)) + w.PullRequestLabel = pullHook(form.Events, string(webhook.HookEventPullRequestLabel)) + w.PullRequestMilestone = pullHook(form.Events, string(webhook.HookEventPullRequestMilestone)) + w.PullRequestComment = pullHook(form.Events, string(webhook.HookEventPullRequestComment)) + w.PullRequestReview = pullHook(form.Events, "pull_request_review") + w.PullRequestSync = pullHook(form.Events, string(webhook.HookEventPullRequestSync)) + w.Repository = util.IsStringInSlice(string(webhook.HookEventRepository), form.Events, true) + w.Release = util.IsStringInSlice(string(webhook.HookEventRelease), form.Events, true) + w.BranchFilter = form.BranchFilter + w.HookEvent.BranchFilter = form.BranchFilter + + if err := w.UpdateEvent(); err != nil { + ctx.Error(http.StatusInternalServerError, "UpdateEvent", err) + return false + } + + if form.Active != nil { + w.IsActive = *form.Active + } + + if err := webhook.UpdateWebhook(w); err != nil { + ctx.Error(http.StatusInternalServerError, "UpdateWebhook", err) + return false + } + return true +} + func CreateHook(ctx *context.APIContext) { form := web.GetForm(ctx).(*hat_api.CreateHookOption) if !checkCreateHookOption(ctx, form) { -- 2.34.1