mirror of
https://github.com/go-gitea/gitea.git
synced 2024-12-21 09:23:45 +08:00
331e878e81
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
174 lines
5.0 KiB
Go
174 lines
5.0 KiB
Go
// Copyright 2019 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package repository
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/url"
|
|
"time"
|
|
|
|
"code.gitea.io/gitea/models/avatars"
|
|
user_model "code.gitea.io/gitea/models/user"
|
|
"code.gitea.io/gitea/modules/cache"
|
|
"code.gitea.io/gitea/modules/git"
|
|
"code.gitea.io/gitea/modules/log"
|
|
"code.gitea.io/gitea/modules/setting"
|
|
api "code.gitea.io/gitea/modules/structs"
|
|
)
|
|
|
|
// PushCommit represents a commit in a push operation.
|
|
type PushCommit struct {
|
|
Sha1 string
|
|
Message string
|
|
AuthorEmail string
|
|
AuthorName string
|
|
CommitterEmail string
|
|
CommitterName string
|
|
Timestamp time.Time
|
|
}
|
|
|
|
// PushCommits represents list of commits in a push operation.
|
|
type PushCommits struct {
|
|
Commits []*PushCommit
|
|
HeadCommit *PushCommit
|
|
CompareURL string
|
|
Len int
|
|
}
|
|
|
|
// NewPushCommits creates a new PushCommits object.
|
|
func NewPushCommits() *PushCommits {
|
|
return &PushCommits{}
|
|
}
|
|
|
|
// 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]
|
|
if !ok {
|
|
author, err = user_model.GetUserByEmail(ctx, commit.AuthorEmail)
|
|
if err == nil {
|
|
authorUsername = author.Name
|
|
emailUsers[commit.AuthorEmail] = author
|
|
}
|
|
} else {
|
|
authorUsername = author.Name
|
|
}
|
|
|
|
committerUsername := ""
|
|
committer, ok := emailUsers[commit.CommitterEmail]
|
|
if !ok {
|
|
committer, err = user_model.GetUserByEmail(ctx, commit.CommitterEmail)
|
|
if err == nil {
|
|
// TODO: check errors other than email not found.
|
|
committerUsername = committer.Name
|
|
emailUsers[commit.CommitterEmail] = committer
|
|
}
|
|
} else {
|
|
committerUsername = committer.Name
|
|
}
|
|
|
|
fileStatus, err := git.GetCommitFileStatus(ctx, repoPath, commit.Sha1)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("FileStatus [commit_sha1: %s]: %w", commit.Sha1, err)
|
|
}
|
|
|
|
return &api.PayloadCommit{
|
|
ID: commit.Sha1,
|
|
Message: commit.Message,
|
|
URL: fmt.Sprintf("%s/commit/%s", repoLink, url.PathEscape(commit.Sha1)),
|
|
Author: &api.PayloadUser{
|
|
Name: commit.AuthorName,
|
|
Email: commit.AuthorEmail,
|
|
UserName: authorUsername,
|
|
},
|
|
Committer: &api.PayloadUser{
|
|
Name: commit.CommitterName,
|
|
Email: commit.CommitterEmail,
|
|
UserName: committerUsername,
|
|
},
|
|
Added: fileStatus.Added,
|
|
Removed: fileStatus.Removed,
|
|
Modified: fileStatus.Modified,
|
|
Timestamp: commit.Timestamp,
|
|
}, nil
|
|
}
|
|
|
|
// ToAPIPayloadCommits converts a PushCommits object to api.PayloadCommit format.
|
|
// It returns all converted commits and, if provided, the head commit or an error otherwise.
|
|
func (pc *PushCommits) ToAPIPayloadCommits(ctx context.Context, repoPath, repoLink string) ([]*api.PayloadCommit, *api.PayloadCommit, error) {
|
|
commits := make([]*api.PayloadCommit, len(pc.Commits))
|
|
var headCommit *api.PayloadCommit
|
|
|
|
emailUsers := make(map[string]*user_model.User)
|
|
|
|
for i, commit := range pc.Commits {
|
|
apiCommit, err := ToAPIPayloadCommit(ctx, emailUsers, repoPath, repoLink, commit)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
commits[i] = apiCommit
|
|
if pc.HeadCommit != nil && pc.HeadCommit.Sha1 == commits[i].ID {
|
|
headCommit = apiCommit
|
|
}
|
|
}
|
|
if pc.HeadCommit != nil && headCommit == nil {
|
|
var err error
|
|
headCommit, err = ToAPIPayloadCommit(ctx, emailUsers, repoPath, repoLink, pc.HeadCommit)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
}
|
|
return commits, headCommit, nil
|
|
}
|
|
|
|
// AvatarLink tries to match user in database with e-mail
|
|
// in order to show custom avatar, and falls back to general avatar link.
|
|
func (pc *PushCommits) AvatarLink(ctx context.Context, email string) string {
|
|
size := avatars.DefaultAvatarPixelSize * setting.Avatar.RenderedSizeFactor
|
|
|
|
v, _ := cache.GetWithContextCache(ctx, "push_commits", email, func() (string, error) {
|
|
u, err := user_model.GetUserByEmail(ctx, email)
|
|
if err != nil {
|
|
if !user_model.IsErrUserNotExist(err) {
|
|
log.Error("GetUserByEmail: %v", err)
|
|
return "", err
|
|
}
|
|
return avatars.GenerateEmailAvatarFastLink(ctx, email, size), nil
|
|
}
|
|
return u.AvatarLinkWithSize(ctx, size), nil
|
|
})
|
|
|
|
return v
|
|
}
|
|
|
|
// CommitToPushCommit transforms a git.Commit to PushCommit type.
|
|
func CommitToPushCommit(commit *git.Commit) *PushCommit {
|
|
return &PushCommit{
|
|
Sha1: commit.ID.String(),
|
|
Message: commit.Message(),
|
|
AuthorEmail: commit.Author.Email,
|
|
AuthorName: commit.Author.Name,
|
|
CommitterEmail: commit.Committer.Email,
|
|
CommitterName: commit.Committer.Name,
|
|
Timestamp: commit.Author.When,
|
|
}
|
|
}
|
|
|
|
// GitToPushCommits transforms a list of git.Commits to PushCommits type.
|
|
func GitToPushCommits(gitCommits []*git.Commit) *PushCommits {
|
|
commits := make([]*PushCommit, 0, len(gitCommits))
|
|
for _, commit := range gitCommits {
|
|
commits = append(commits, CommitToPushCommit(commit))
|
|
}
|
|
return &PushCommits{
|
|
Commits: commits,
|
|
HeadCommit: nil,
|
|
CompareURL: "",
|
|
Len: len(commits),
|
|
}
|
|
}
|