Skip to content

Commit 331e878

Browse files
authored
Add new event commit status creation and webhook implementation (#27151)
This PR introduces a new event which is similar as Github's. When a new commit status submitted, the event will be trigged. That means, now we can receive all feedback from CI/CD system in webhooks or other notify systems. ref: https://docs.github.com/en/webhooks/webhook-events-and-payloads#status Fix #20749
1 parent 145e266 commit 331e878

File tree

10 files changed

+90
-22
lines changed

10 files changed

+90
-22
lines changed

modules/repository/commits.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ func NewPushCommits() *PushCommits {
4242
return &PushCommits{}
4343
}
4444

45-
// toAPIPayloadCommit converts a single PushCommit to an api.PayloadCommit object.
46-
func (pc *PushCommits) toAPIPayloadCommit(ctx context.Context, emailUsers map[string]*user_model.User, repoPath, repoLink string, commit *PushCommit) (*api.PayloadCommit, error) {
45+
// ToAPIPayloadCommit converts a single PushCommit to an api.PayloadCommit object.
46+
func ToAPIPayloadCommit(ctx context.Context, emailUsers map[string]*user_model.User, repoPath, repoLink string, commit *PushCommit) (*api.PayloadCommit, error) {
4747
var err error
4848
authorUsername := ""
4949
author, ok := emailUsers[commit.AuthorEmail]
@@ -105,7 +105,7 @@ func (pc *PushCommits) ToAPIPayloadCommits(ctx context.Context, repoPath, repoLi
105105
emailUsers := make(map[string]*user_model.User)
106106

107107
for i, commit := range pc.Commits {
108-
apiCommit, err := pc.toAPIPayloadCommit(ctx, emailUsers, repoPath, repoLink, commit)
108+
apiCommit, err := ToAPIPayloadCommit(ctx, emailUsers, repoPath, repoLink, commit)
109109
if err != nil {
110110
return nil, nil, err
111111
}
@@ -117,7 +117,7 @@ func (pc *PushCommits) ToAPIPayloadCommits(ctx context.Context, repoPath, repoLi
117117
}
118118
if pc.HeadCommit != nil && headCommit == nil {
119119
var err error
120-
headCommit, err = pc.toAPIPayloadCommit(ctx, emailUsers, repoPath, repoLink, pc.HeadCommit)
120+
headCommit, err = ToAPIPayloadCommit(ctx, emailUsers, repoPath, repoLink, pc.HeadCommit)
121121
if err != nil {
122122
return nil, nil, err
123123
}

modules/structs/hook.go

+23-7
Original file line numberDiff line numberDiff line change
@@ -262,13 +262,6 @@ func (p *ReleasePayload) JSONPayload() ([]byte, error) {
262262
return json.MarshalIndent(p, "", " ")
263263
}
264264

265-
// __________ .__
266-
// \______ \__ __ _____| |__
267-
// | ___/ | \/ ___/ | \
268-
// | | | | /\___ \| Y \
269-
// |____| |____//____ >___| /
270-
// \/ \/
271-
272265
// PushPayload represents a payload information of push event.
273266
type PushPayload struct {
274267
Ref string `json:"ref"`
@@ -509,3 +502,26 @@ type WorkflowDispatchPayload struct {
509502
func (p *WorkflowDispatchPayload) JSONPayload() ([]byte, error) {
510503
return json.MarshalIndent(p, "", " ")
511504
}
505+
506+
// CommitStatusPayload represents a payload information of commit status event.
507+
type CommitStatusPayload struct {
508+
// TODO: add Branches per https://docs.github.com/en/webhooks/webhook-events-and-payloads#status
509+
Commit *PayloadCommit `json:"commit"`
510+
Context string `json:"context"`
511+
// swagger:strfmt date-time
512+
CreatedAt time.Time `json:"created_at"`
513+
Description string `json:"description"`
514+
ID int64 `json:"id"`
515+
Repo *Repository `json:"repository"`
516+
Sender *User `json:"sender"`
517+
SHA string `json:"sha"`
518+
State string `json:"state"`
519+
TargetURL string `json:"target_url"`
520+
// swagger:strfmt date-time
521+
UpdatedAt *time.Time `json:"updated_at"`
522+
}
523+
524+
// JSONPayload implements Payload
525+
func (p *CommitStatusPayload) JSONPayload() ([]byte, error) {
526+
return json.MarshalIndent(p, "", " ")
527+
}

modules/webhook/type.go

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ const (
3232
HookEventRelease HookEventType = "release"
3333
HookEventPackage HookEventType = "package"
3434
HookEventSchedule HookEventType = "schedule"
35+
HookEventStatus HookEventType = "status"
3536
)
3637

3738
// Event returns the HookEventType as an event string

services/actions/commit_status.go

+2-4
Original file line numberDiff line numberDiff line change
@@ -128,18 +128,16 @@ func createCommitStatus(ctx context.Context, job *actions_model.ActionRunJob) er
128128
if err != nil {
129129
return fmt.Errorf("HashTypeInterfaceFromHashString: %w", err)
130130
}
131-
if err := commitstatus_service.CreateCommitStatus(ctx, repo, creator, commitID.String(), &git_model.CommitStatus{
131+
status := git_model.CommitStatus{
132132
SHA: sha,
133133
TargetURL: fmt.Sprintf("%s/jobs/%d", run.Link(), index),
134134
Description: description,
135135
Context: ctxname,
136136
CreatorID: creator.ID,
137137
State: state,
138-
}); err != nil {
139-
return fmt.Errorf("NewCommitStatus: %w", err)
140138
}
141139

142-
return nil
140+
return commitstatus_service.CreateCommitStatus(ctx, repo, creator, commitID.String(), &status)
143141
}
144142

145143
func toCommitStatus(status actions_model.Status) api.CommitStatusState {

services/automerge/notify.go

+11
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@ package automerge
66
import (
77
"context"
88

9+
git_model "code.gitea.io/gitea/models/git"
910
issues_model "code.gitea.io/gitea/models/issues"
11+
repo_model "code.gitea.io/gitea/models/repo"
1012
user_model "code.gitea.io/gitea/models/user"
1113
"code.gitea.io/gitea/modules/log"
14+
"code.gitea.io/gitea/modules/repository"
1215
notify_service "code.gitea.io/gitea/services/notify"
1316
)
1417

@@ -44,3 +47,11 @@ func (n *automergeNotifier) PullReviewDismiss(ctx context.Context, doer *user_mo
4447
// as reviews could have blocked a pending automerge let's recheck
4548
StartPRCheckAndAutoMerge(ctx, review.Issue.PullRequest)
4649
}
50+
51+
func (n *automergeNotifier) CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, commit *repository.PushCommit, sender *user_model.User, status *git_model.CommitStatus) {
52+
if status.State.IsSuccess() {
53+
if err := StartPRCheckAndAutoMergeBySHA(ctx, commit.Sha1, repo); err != nil {
54+
log.Error("MergeScheduledPullRequest[repo_id: %d, user_id: %d, sha: %s]: %w", repo.ID, sender.ID, commit.Sha1, err)
55+
}
56+
}
57+
}

services/notify/notifier.go

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package notify
66
import (
77
"context"
88

9+
git_model "code.gitea.io/gitea/models/git"
910
issues_model "code.gitea.io/gitea/models/issues"
1011
packages_model "code.gitea.io/gitea/models/packages"
1112
repo_model "code.gitea.io/gitea/models/repo"
@@ -74,4 +75,6 @@ type Notifier interface {
7475
PackageDelete(ctx context.Context, doer *user_model.User, pd *packages_model.PackageDescriptor)
7576

7677
ChangeDefaultBranch(ctx context.Context, repo *repo_model.Repository)
78+
79+
CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, commit *repository.PushCommit, sender *user_model.User, status *git_model.CommitStatus)
7780
}

services/notify/notify.go

+7
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package notify
66
import (
77
"context"
88

9+
git_model "code.gitea.io/gitea/models/git"
910
issues_model "code.gitea.io/gitea/models/issues"
1011
packages_model "code.gitea.io/gitea/models/packages"
1112
repo_model "code.gitea.io/gitea/models/repo"
@@ -367,3 +368,9 @@ func ChangeDefaultBranch(ctx context.Context, repo *repo_model.Repository) {
367368
notifier.ChangeDefaultBranch(ctx, repo)
368369
}
369370
}
371+
372+
func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, commit *repository.PushCommit, sender *user_model.User, status *git_model.CommitStatus) {
373+
for _, notifier := range notifiers {
374+
notifier.CreateCommitStatus(ctx, repo, commit, sender, status)
375+
}
376+
}

services/notify/null.go

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package notify
66
import (
77
"context"
88

9+
git_model "code.gitea.io/gitea/models/git"
910
issues_model "code.gitea.io/gitea/models/issues"
1011
packages_model "code.gitea.io/gitea/models/packages"
1112
repo_model "code.gitea.io/gitea/models/repo"
@@ -208,3 +209,6 @@ func (*NullNotifier) PackageDelete(ctx context.Context, doer *user_model.User, p
208209
// ChangeDefaultBranch places a place holder function
209210
func (*NullNotifier) ChangeDefaultBranch(ctx context.Context, repo *repo_model.Repository) {
210211
}
212+
213+
func (*NullNotifier) CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, commit *repository.PushCommit, sender *user_model.User, status *git_model.CommitStatus) {
214+
}

services/repository/commitstatus/commitstatus.go

+4-7
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@ import (
1818
"code.gitea.io/gitea/modules/gitrepo"
1919
"code.gitea.io/gitea/modules/json"
2020
"code.gitea.io/gitea/modules/log"
21+
repo_module "code.gitea.io/gitea/modules/repository"
2122
api "code.gitea.io/gitea/modules/structs"
22-
"code.gitea.io/gitea/services/automerge"
23+
"code.gitea.io/gitea/services/notify"
2324
)
2425

2526
func getCacheKey(repoID int64, brancheName string) string {
@@ -103,6 +104,8 @@ func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, creato
103104
return err
104105
}
105106

107+
notify.CreateCommitStatus(ctx, repo, repo_module.CommitToPushCommit(commit), creator, status)
108+
106109
defaultBranchCommit, err := gitRepo.GetBranchCommit(repo.DefaultBranch)
107110
if err != nil {
108111
return fmt.Errorf("GetBranchCommit[%s]: %w", repo.DefaultBranch, err)
@@ -114,12 +117,6 @@ func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, creato
114117
}
115118
}
116119

117-
if status.State.IsSuccess() {
118-
if err := automerge.StartPRCheckAndAutoMergeBySHA(ctx, sha, repo); err != nil {
119-
return fmt.Errorf("MergeScheduledPullRequest[repo_id: %d, user_id: %d, sha: %s]: %w", repo.ID, creator.ID, sha, err)
120-
}
121-
}
122-
123120
return nil
124121
}
125122

services/webhook/notifier.go

+31
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package webhook
66
import (
77
"context"
88

9+
git_model "code.gitea.io/gitea/models/git"
910
issues_model "code.gitea.io/gitea/models/issues"
1011
packages_model "code.gitea.io/gitea/models/packages"
1112
"code.gitea.io/gitea/models/perm"
@@ -861,6 +862,36 @@ func (m *webhookNotifier) SyncPushCommits(ctx context.Context, pusher *user_mode
861862
}
862863
}
863864

865+
func (m *webhookNotifier) CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, commit *repository.PushCommit, sender *user_model.User, status *git_model.CommitStatus) {
866+
apiSender := convert.ToUser(ctx, sender, nil)
867+
apiCommit, err := repository.ToAPIPayloadCommit(ctx, map[string]*user_model.User{}, repo.RepoPath(), repo.HTMLURL(), commit)
868+
if err != nil {
869+
log.Error("commits.ToAPIPayloadCommits failed: %v", err)
870+
return
871+
}
872+
873+
payload := api.CommitStatusPayload{
874+
Context: status.Context,
875+
CreatedAt: status.CreatedUnix.AsTime().UTC(),
876+
Description: status.Description,
877+
ID: status.ID,
878+
SHA: commit.Sha1,
879+
State: status.State.String(),
880+
TargetURL: status.TargetURL,
881+
882+
Commit: apiCommit,
883+
Repo: convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm.AccessModeOwner}),
884+
Sender: apiSender,
885+
}
886+
if !status.UpdatedUnix.IsZero() {
887+
t := status.UpdatedUnix.AsTime().UTC()
888+
payload.UpdatedAt = &t
889+
}
890+
if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventStatus, &payload); err != nil {
891+
log.Error("PrepareWebhooks: %v", err)
892+
}
893+
}
894+
864895
func (m *webhookNotifier) SyncCreateRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refFullName git.RefName, refID string) {
865896
m.CreateRef(ctx, pusher, repo, refFullName, refID)
866897
}

0 commit comments

Comments
 (0)