From e9c9e87306e266bd3004643ca28aa817e862ae24 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 20 Sep 2023 21:20:11 +0800 Subject: [PATCH] Add new event commit status creation and webhook implementation --- modules/repository/commits.go | 8 ++++---- modules/structs/hook.go | 29 +++++++++++++++++++------- services/notify/notifier.go | 3 +++ services/notify/notify.go | 7 +++++++ services/notify/null.go | 4 ++++ services/repository/files/commit.go | 7 ++++++- services/webhook/notifier.go | 32 +++++++++++++++++++++++++++++ 7 files changed, 78 insertions(+), 12 deletions(-) diff --git a/modules/repository/commits.go b/modules/repository/commits.go index ede60429a1..6e4b75d5ca 100644 --- a/modules/repository/commits.go +++ b/modules/repository/commits.go @@ -42,8 +42,8 @@ func NewPushCommits() *PushCommits { return &PushCommits{} } -// toAPIPayloadCommit converts a single PushCommit to an api.PayloadCommit object. -func (pc *PushCommits) toAPIPayloadCommit(ctx context.Context, emailUsers map[string]*user_model.User, repoPath, repoLink string, commit *PushCommit) (*api.PayloadCommit, error) { +// ToAPIPayloadCommit converts a single PushCommit to an api.PayloadCommit object. +func ToAPIPayloadCommit(ctx context.Context, emailUsers map[string]*user_model.User, repoPath, repoLink string, commit *PushCommit) (*api.PayloadCommit, error) { var err error authorUsername := "" author, ok := emailUsers[commit.AuthorEmail] @@ -105,7 +105,7 @@ func (pc *PushCommits) ToAPIPayloadCommits(ctx context.Context, repoPath, repoLi emailUsers := make(map[string]*user_model.User) for i, commit := range pc.Commits { - apiCommit, err := pc.toAPIPayloadCommit(ctx, emailUsers, repoPath, repoLink, commit) + apiCommit, err := ToAPIPayloadCommit(ctx, emailUsers, repoPath, repoLink, commit) if err != nil { return nil, nil, err } @@ -117,7 +117,7 @@ func (pc *PushCommits) ToAPIPayloadCommits(ctx context.Context, repoPath, repoLi } if pc.HeadCommit != nil && headCommit == nil { var err error - headCommit, err = pc.toAPIPayloadCommit(ctx, emailUsers, repoPath, repoLink, pc.HeadCommit) + headCommit, err = ToAPIPayloadCommit(ctx, emailUsers, repoPath, repoLink, pc.HeadCommit) if err != nil { return nil, nil, err } diff --git a/modules/structs/hook.go b/modules/structs/hook.go index 0babe84410..1a5c4761c0 100644 --- a/modules/structs/hook.go +++ b/modules/structs/hook.go @@ -261,13 +261,6 @@ func (p *ReleasePayload) JSONPayload() ([]byte, error) { return json.MarshalIndent(p, "", " ") } -// __________ .__ -// \______ \__ __ _____| |__ -// | ___/ | \/ ___/ | \ -// | | | | /\___ \| Y \ -// |____| |____//____ >___| / -// \/ \/ - // PushPayload represents a payload information of push event. type PushPayload struct { Ref string `json:"ref"` @@ -494,3 +487,25 @@ type PackagePayload struct { func (p *PackagePayload) JSONPayload() ([]byte, error) { return json.MarshalIndent(p, "", " ") } + +// CommitStatusPayload represents a payload information of commit status event. +type CommitStatusPayload struct { + // TODO: add Branches + Commit *PayloadCommit `json:"commit"` + Context string `json:"context"` + CreatedAt time.Time `json:"created_at"` + Description string `json:"description"` + ID int64 `json:"id"` + // Name string `json:"name"` + Repo *Repository `json:"repository"` + Sender *User `json:"sender"` + SHA string `json:"sha"` + State string `json:"state"` + TargetURL string `json:"target_url"` + UpdatedAt *time.Time `json:"updated_at"` +} + +// JSONPayload FIXME +func (p *CommitStatusPayload) JSONPayload() ([]byte, error) { + return json.MarshalIndent(p, "", " ") +} diff --git a/services/notify/notifier.go b/services/notify/notifier.go index ed053a812a..29bbb5702b 100644 --- a/services/notify/notifier.go +++ b/services/notify/notifier.go @@ -6,6 +6,7 @@ package notify import ( "context" + git_model "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" packages_model "code.gitea.io/gitea/models/packages" repo_model "code.gitea.io/gitea/models/repo" @@ -74,4 +75,6 @@ type Notifier interface { PackageDelete(ctx context.Context, doer *user_model.User, pd *packages_model.PackageDescriptor) ChangeDefaultBranch(ctx context.Context, repo *repo_model.Repository) + + CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, commit *repository.PushCommit, sender *user_model.User, status *git_model.CommitStatus) } diff --git a/services/notify/notify.go b/services/notify/notify.go index 16fbb6325d..44a31d243b 100644 --- a/services/notify/notify.go +++ b/services/notify/notify.go @@ -6,6 +6,7 @@ package notify import ( "context" + git_model "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" packages_model "code.gitea.io/gitea/models/packages" repo_model "code.gitea.io/gitea/models/repo" @@ -367,3 +368,9 @@ func ChangeDefaultBranch(ctx context.Context, repo *repo_model.Repository) { notifier.ChangeDefaultBranch(ctx, repo) } } + +func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, commit *repository.PushCommit, sender *user_model.User, status *git_model.CommitStatus) { + for _, notifier := range notifiers { + notifier.CreateCommitStatus(ctx, repo, commit, sender, status) + } +} diff --git a/services/notify/null.go b/services/notify/null.go index dddd421bef..7354efd701 100644 --- a/services/notify/null.go +++ b/services/notify/null.go @@ -6,6 +6,7 @@ package notify import ( "context" + git_model "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" packages_model "code.gitea.io/gitea/models/packages" repo_model "code.gitea.io/gitea/models/repo" @@ -208,3 +209,6 @@ func (*NullNotifier) PackageDelete(ctx context.Context, doer *user_model.User, p // ChangeDefaultBranch places a place holder function func (*NullNotifier) ChangeDefaultBranch(ctx context.Context, repo *repo_model.Repository) { } + +func (*NullNotifier) CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, commit *repository.PushCommit, sender *user_model.User, status *git_model.CommitStatus) { +} diff --git a/services/repository/files/commit.go b/services/repository/files/commit.go index 3e4627487b..dc2c0eea1b 100644 --- a/services/repository/files/commit.go +++ b/services/repository/files/commit.go @@ -12,8 +12,10 @@ import ( repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/git" + repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/services/automerge" + "code.gitea.io/gitea/services/notify" ) // CreateCommitStatus creates a new CommitStatus given a bunch of parameters @@ -29,7 +31,8 @@ func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, creato } defer closer.Close() - if commit, err := gitRepo.GetCommit(sha); err != nil { + commit, err := gitRepo.GetCommit(sha) + if err != nil { gitRepo.Close() return fmt.Errorf("GetCommit[%s]: %w", sha, err) } else if len(sha) != git.SHAFullLength { @@ -47,6 +50,8 @@ func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, creato return fmt.Errorf("NewCommitStatus[repo_id: %d, user_id: %d, sha: %s]: %w", repo.ID, creator.ID, sha, err) } + notify.CreateCommitStatus(ctx, repo, repo_module.CommitToPushCommit(commit), creator, status) + if status.State.IsSuccess() { if err := automerge.MergeScheduledPullRequest(ctx, sha, repo); err != nil { return fmt.Errorf("MergeScheduledPullRequest[repo_id: %d, user_id: %d, sha: %s]: %w", repo.ID, creator.ID, sha, err) diff --git a/services/webhook/notifier.go b/services/webhook/notifier.go index 1ab14fd6a7..a5b174b294 100644 --- a/services/webhook/notifier.go +++ b/services/webhook/notifier.go @@ -6,6 +6,7 @@ package webhook import ( "context" + git_model "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" packages_model "code.gitea.io/gitea/models/packages" "code.gitea.io/gitea/models/perm" @@ -15,6 +16,7 @@ import ( "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/repository" + repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" webhook_module "code.gitea.io/gitea/modules/webhook" @@ -851,6 +853,36 @@ func (m *webhookNotifier) SyncPushCommits(ctx context.Context, pusher *user_mode } } +func (m *webhookNotifier) CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, commit *repository.PushCommit, sender *user_model.User, status *git_model.CommitStatus) { + apiSender := convert.ToUser(ctx, sender, nil) + apiCommit, err := repo_module.ToAPIPayloadCommit(ctx, map[string]*user_model.User{}, repo.RepoPath(), repo.HTMLURL(), commit) + if err != nil { + log.Error("commits.ToAPIPayloadCommits failed: %v", err) + return + } + + payload := api.CommitStatusPayload{ + Context: status.Context, + CreatedAt: status.CreatedUnix.AsTime().UTC(), + Description: status.Description, + ID: status.ID, + SHA: commit.Sha1, + State: status.State.String(), + TargetURL: status.TargetURL, + + Commit: apiCommit, + Repo: convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm.AccessModeOwner}), + Sender: apiSender, + } + if !status.UpdatedUnix.IsZero() { + t := status.UpdatedUnix.AsTime().UTC() + payload.UpdatedAt = &t + } + if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventPush, &payload); err != nil { + log.Error("PrepareWebhooks: %v", err) + } +} + func (m *webhookNotifier) SyncCreateRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refFullName git.RefName, refID string) { m.CreateRef(ctx, pusher, repo, refFullName, refID) }