mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-12-27 02:34:09 +01:00
commit
1cfbfb3812
2 changed files with 60 additions and 22 deletions
|
@ -24,8 +24,10 @@ import (
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ActionType represents the type of an action.
|
||||||
type ActionType int
|
type ActionType int
|
||||||
|
|
||||||
|
// Possible action types.
|
||||||
const (
|
const (
|
||||||
ActionCreateRepo ActionType = iota + 1 // 1
|
ActionCreateRepo ActionType = iota + 1 // 1
|
||||||
ActionRenameRepo // 2
|
ActionRenameRepo // 2
|
||||||
|
@ -45,12 +47,13 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// Same as Github. See https://help.github.com/articles/closing-issues-via-commit-messages
|
// Same as Github. See
|
||||||
IssueCloseKeywords = []string{"close", "closes", "closed", "fix", "fixes", "fixed", "resolve", "resolves", "resolved"}
|
// https://help.github.com/articles/closing-issues-via-commit-messages
|
||||||
IssueReopenKeywords = []string{"reopen", "reopens", "reopened"}
|
issueCloseKeywords = []string{"close", "closes", "closed", "fix", "fixes", "fixed", "resolve", "resolves", "resolved"}
|
||||||
|
issueReopenKeywords = []string{"reopen", "reopens", "reopened"}
|
||||||
|
|
||||||
IssueCloseKeywordsPat, IssueReopenKeywordsPat *regexp.Regexp
|
issueCloseKeywordsPat, issueReopenKeywordsPat *regexp.Regexp
|
||||||
IssueReferenceKeywordsPat *regexp.Regexp
|
issueReferenceKeywordsPat *regexp.Regexp
|
||||||
)
|
)
|
||||||
|
|
||||||
func assembleKeywordsPattern(words []string) string {
|
func assembleKeywordsPattern(words []string) string {
|
||||||
|
@ -58,13 +61,14 @@ func assembleKeywordsPattern(words []string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
IssueCloseKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(IssueCloseKeywords))
|
issueCloseKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(issueCloseKeywords))
|
||||||
IssueReopenKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(IssueReopenKeywords))
|
issueReopenKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(issueReopenKeywords))
|
||||||
IssueReferenceKeywordsPat = regexp.MustCompile(`(?i)(?:)(^| )\S+`)
|
issueReferenceKeywordsPat = regexp.MustCompile(`(?i)(?:)(^| )\S+`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Action represents user operation type and other information to repository.,
|
// Action represents user operation type and other information to
|
||||||
// it implemented interface base.Actioner so that can be used in template render.
|
// repository. It implemented interface base.Actioner so that can be
|
||||||
|
// used in template render.
|
||||||
type Action struct {
|
type Action struct {
|
||||||
ID int64 `xorm:"pk autoincr"`
|
ID int64 `xorm:"pk autoincr"`
|
||||||
UserID int64 // Receiver user id.
|
UserID int64 // Receiver user id.
|
||||||
|
@ -82,10 +86,13 @@ type Action struct {
|
||||||
CreatedUnix int64
|
CreatedUnix int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BeforeInsert will be invoked by XORM before inserting a record
|
||||||
|
// representing this object.
|
||||||
func (a *Action) BeforeInsert() {
|
func (a *Action) BeforeInsert() {
|
||||||
a.CreatedUnix = time.Now().Unix()
|
a.CreatedUnix = time.Now().Unix()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AfterSet updates the webhook object upon setting a column.
|
||||||
func (a *Action) AfterSet(colName string, _ xorm.Cell) {
|
func (a *Action) AfterSet(colName string, _ xorm.Cell) {
|
||||||
switch colName {
|
switch colName {
|
||||||
case "created_unix":
|
case "created_unix":
|
||||||
|
@ -93,42 +100,57 @@ func (a *Action) AfterSet(colName string, _ xorm.Cell) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetOpType gets the ActionType of this action.
|
||||||
|
// TODO: change return type to ActionType ?
|
||||||
func (a *Action) GetOpType() int {
|
func (a *Action) GetOpType() int {
|
||||||
return int(a.OpType)
|
return int(a.OpType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetActUserName gets the action's user name.
|
||||||
func (a *Action) GetActUserName() string {
|
func (a *Action) GetActUserName() string {
|
||||||
return a.ActUserName
|
return a.ActUserName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ShortActUserName gets the action's user name trimmed to max 20
|
||||||
|
// chars.
|
||||||
func (a *Action) ShortActUserName() string {
|
func (a *Action) ShortActUserName() string {
|
||||||
return base.EllipsisString(a.ActUserName, 20)
|
return base.EllipsisString(a.ActUserName, 20)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRepoUserName returns the name of the action repository owner.
|
||||||
func (a *Action) GetRepoUserName() string {
|
func (a *Action) GetRepoUserName() string {
|
||||||
return a.RepoUserName
|
return a.RepoUserName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ShortRepoUserName returns the name of the action repository owner
|
||||||
|
// trimmed to max 20 chars.
|
||||||
func (a *Action) ShortRepoUserName() string {
|
func (a *Action) ShortRepoUserName() string {
|
||||||
return base.EllipsisString(a.RepoUserName, 20)
|
return base.EllipsisString(a.RepoUserName, 20)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRepoName returns the name of the action repository.
|
||||||
func (a *Action) GetRepoName() string {
|
func (a *Action) GetRepoName() string {
|
||||||
return a.RepoName
|
return a.RepoName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ShortRepoName returns the name of the action repository
|
||||||
|
// trimmed to max 33 chars.
|
||||||
func (a *Action) ShortRepoName() string {
|
func (a *Action) ShortRepoName() string {
|
||||||
return base.EllipsisString(a.RepoName, 33)
|
return base.EllipsisString(a.RepoName, 33)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRepoPath returns the virtual path to the action repository.
|
||||||
func (a *Action) GetRepoPath() string {
|
func (a *Action) GetRepoPath() string {
|
||||||
return path.Join(a.RepoUserName, a.RepoName)
|
return path.Join(a.RepoUserName, a.RepoName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ShortRepoPath returns the virtual path to the action repository
|
||||||
|
// trimed to max 20 + 1 + 33 chars.
|
||||||
func (a *Action) ShortRepoPath() string {
|
func (a *Action) ShortRepoPath() string {
|
||||||
return path.Join(a.ShortRepoUserName(), a.ShortRepoName())
|
return path.Join(a.ShortRepoUserName(), a.ShortRepoName())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRepoLink returns relative link to action repository.
|
||||||
func (a *Action) GetRepoLink() string {
|
func (a *Action) GetRepoLink() string {
|
||||||
if len(setting.AppSubUrl) > 0 {
|
if len(setting.AppSubUrl) > 0 {
|
||||||
return path.Join(setting.AppSubUrl, a.GetRepoPath())
|
return path.Join(setting.AppSubUrl, a.GetRepoPath())
|
||||||
|
@ -136,22 +158,29 @@ func (a *Action) GetRepoLink() string {
|
||||||
return "/" + a.GetRepoPath()
|
return "/" + a.GetRepoPath()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetBranch returns the action's repository branch.
|
||||||
func (a *Action) GetBranch() string {
|
func (a *Action) GetBranch() string {
|
||||||
return a.RefName
|
return a.RefName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetContent returns the action's content.
|
||||||
func (a *Action) GetContent() string {
|
func (a *Action) GetContent() string {
|
||||||
return a.Content
|
return a.Content
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetCreate returns the action creation time.
|
||||||
func (a *Action) GetCreate() time.Time {
|
func (a *Action) GetCreate() time.Time {
|
||||||
return a.Created
|
return a.Created
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetIssueInfos returns a list of issues associated with
|
||||||
|
// the action.
|
||||||
func (a *Action) GetIssueInfos() []string {
|
func (a *Action) GetIssueInfos() []string {
|
||||||
return strings.SplitN(a.Content, "|", 2)
|
return strings.SplitN(a.Content, "|", 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetIssueTitle returns the title of first issue associated
|
||||||
|
// with the action.
|
||||||
func (a *Action) GetIssueTitle() string {
|
func (a *Action) GetIssueTitle() string {
|
||||||
index := com.StrTo(a.GetIssueInfos()[0]).MustInt64()
|
index := com.StrTo(a.GetIssueInfos()[0]).MustInt64()
|
||||||
issue, err := GetIssueByIndex(a.RepoID, index)
|
issue, err := GetIssueByIndex(a.RepoID, index)
|
||||||
|
@ -162,6 +191,8 @@ func (a *Action) GetIssueTitle() string {
|
||||||
return issue.Title
|
return issue.Title
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetIssueContent returns the content of first issue associated with
|
||||||
|
// this action.
|
||||||
func (a *Action) GetIssueContent() string {
|
func (a *Action) GetIssueContent() string {
|
||||||
index := com.StrTo(a.GetIssueInfos()[0]).MustInt64()
|
index := com.StrTo(a.GetIssueInfos()[0]).MustInt64()
|
||||||
issue, err := GetIssueByIndex(a.RepoID, index)
|
issue, err := GetIssueByIndex(a.RepoID, index)
|
||||||
|
@ -221,6 +252,7 @@ func issueIndexTrimRight(c rune) bool {
|
||||||
return !unicode.IsDigit(c)
|
return !unicode.IsDigit(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PushCommit represents a commit in a push operation.
|
||||||
type PushCommit struct {
|
type PushCommit struct {
|
||||||
Sha1 string
|
Sha1 string
|
||||||
Message string
|
Message string
|
||||||
|
@ -231,6 +263,7 @@ type PushCommit struct {
|
||||||
Timestamp time.Time
|
Timestamp time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PushCommits represents list of commits in a push operation.
|
||||||
type PushCommits struct {
|
type PushCommits struct {
|
||||||
Len int
|
Len int
|
||||||
Commits []*PushCommit
|
Commits []*PushCommit
|
||||||
|
@ -239,13 +272,16 @@ type PushCommits struct {
|
||||||
avatars map[string]string
|
avatars map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewPushCommits creates a new PushCommits object.
|
||||||
func NewPushCommits() *PushCommits {
|
func NewPushCommits() *PushCommits {
|
||||||
return &PushCommits{
|
return &PushCommits{
|
||||||
avatars: make(map[string]string),
|
avatars: make(map[string]string),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pc *PushCommits) ToApiPayloadCommits(repoLink string) []*api.PayloadCommit {
|
// ToAPIPayloadCommits converts a PushCommits object to
|
||||||
|
// api.PayloadCommit format.
|
||||||
|
func (pc *PushCommits) ToAPIPayloadCommits(repoLink string) []*api.PayloadCommit {
|
||||||
commits := make([]*api.PayloadCommit, len(pc.Commits))
|
commits := make([]*api.PayloadCommit, len(pc.Commits))
|
||||||
for i, commit := range pc.Commits {
|
for i, commit := range pc.Commits {
|
||||||
authorUsername := ""
|
authorUsername := ""
|
||||||
|
@ -281,21 +317,21 @@ func (pc *PushCommits) ToApiPayloadCommits(repoLink string) []*api.PayloadCommit
|
||||||
|
|
||||||
// AvatarLink tries to match user in database with e-mail
|
// AvatarLink tries to match user in database with e-mail
|
||||||
// in order to show custom avatar, and falls back to general avatar link.
|
// in order to show custom avatar, and falls back to general avatar link.
|
||||||
func (push *PushCommits) AvatarLink(email string) string {
|
func (pc *PushCommits) AvatarLink(email string) string {
|
||||||
_, ok := push.avatars[email]
|
_, ok := pc.avatars[email]
|
||||||
if !ok {
|
if !ok {
|
||||||
u, err := GetUserByEmail(email)
|
u, err := GetUserByEmail(email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
push.avatars[email] = base.AvatarLink(email)
|
pc.avatars[email] = base.AvatarLink(email)
|
||||||
if !IsErrUserNotExist(err) {
|
if !IsErrUserNotExist(err) {
|
||||||
log.Error(4, "GetUserByEmail: %v", err)
|
log.Error(4, "GetUserByEmail: %v", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
push.avatars[email] = u.RelAvatarLink()
|
pc.avatars[email] = u.RelAvatarLink()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return push.avatars[email]
|
return pc.avatars[email]
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateIssuesCommit checks if issues are manipulated by commit message.
|
// UpdateIssuesCommit checks if issues are manipulated by commit message.
|
||||||
|
@ -305,7 +341,7 @@ func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit) err
|
||||||
c := commits[i]
|
c := commits[i]
|
||||||
|
|
||||||
refMarked := make(map[int64]bool)
|
refMarked := make(map[int64]bool)
|
||||||
for _, ref := range IssueReferenceKeywordsPat.FindAllString(c.Message, -1) {
|
for _, ref := range issueReferenceKeywordsPat.FindAllString(c.Message, -1) {
|
||||||
ref = ref[strings.IndexByte(ref, byte(' '))+1:]
|
ref = ref[strings.IndexByte(ref, byte(' '))+1:]
|
||||||
ref = strings.TrimRightFunc(ref, issueIndexTrimRight)
|
ref = strings.TrimRightFunc(ref, issueIndexTrimRight)
|
||||||
|
|
||||||
|
@ -343,7 +379,7 @@ func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit) err
|
||||||
|
|
||||||
refMarked = make(map[int64]bool)
|
refMarked = make(map[int64]bool)
|
||||||
// FIXME: can merge this one and next one to a common function.
|
// FIXME: can merge this one and next one to a common function.
|
||||||
for _, ref := range IssueCloseKeywordsPat.FindAllString(c.Message, -1) {
|
for _, ref := range issueCloseKeywordsPat.FindAllString(c.Message, -1) {
|
||||||
ref = ref[strings.IndexByte(ref, byte(' '))+1:]
|
ref = ref[strings.IndexByte(ref, byte(' '))+1:]
|
||||||
ref = strings.TrimRightFunc(ref, issueIndexTrimRight)
|
ref = strings.TrimRightFunc(ref, issueIndexTrimRight)
|
||||||
|
|
||||||
|
@ -383,7 +419,7 @@ func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit) err
|
||||||
}
|
}
|
||||||
|
|
||||||
// It is conflict to have close and reopen at same time, so refsMarkd doesn't need to reinit here.
|
// It is conflict to have close and reopen at same time, so refsMarkd doesn't need to reinit here.
|
||||||
for _, ref := range IssueReopenKeywordsPat.FindAllString(c.Message, -1) {
|
for _, ref := range issueReopenKeywordsPat.FindAllString(c.Message, -1) {
|
||||||
ref = ref[strings.IndexByte(ref, byte(' '))+1:]
|
ref = ref[strings.IndexByte(ref, byte(' '))+1:]
|
||||||
ref = strings.TrimRightFunc(ref, issueIndexTrimRight)
|
ref = strings.TrimRightFunc(ref, issueIndexTrimRight)
|
||||||
|
|
||||||
|
@ -425,6 +461,7 @@ func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit) err
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CommitRepoActionOptions represent options of a new commit action.
|
||||||
type CommitRepoActionOptions struct {
|
type CommitRepoActionOptions struct {
|
||||||
PusherName string
|
PusherName string
|
||||||
RepoOwnerID int64
|
RepoOwnerID int64
|
||||||
|
@ -435,7 +472,8 @@ type CommitRepoActionOptions struct {
|
||||||
Commits *PushCommits
|
Commits *PushCommits
|
||||||
}
|
}
|
||||||
|
|
||||||
// CommitRepoAction adds new commit actio to the repository, and prepare corresponding webhooks.
|
// CommitRepoAction adds new commit action to the repository, and prepare
|
||||||
|
// corresponding webhooks.
|
||||||
func CommitRepoAction(opts CommitRepoActionOptions) error {
|
func CommitRepoAction(opts CommitRepoActionOptions) error {
|
||||||
pusher, err := GetUserByName(opts.PusherName)
|
pusher, err := GetUserByName(opts.PusherName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -509,7 +547,7 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
|
||||||
Before: opts.OldCommitID,
|
Before: opts.OldCommitID,
|
||||||
After: opts.NewCommitID,
|
After: opts.NewCommitID,
|
||||||
CompareURL: setting.AppUrl + opts.Commits.CompareURL,
|
CompareURL: setting.AppUrl + opts.Commits.CompareURL,
|
||||||
Commits: opts.Commits.ToApiPayloadCommits(repo.HTMLURL()),
|
Commits: opts.Commits.ToAPIPayloadCommits(repo.HTMLURL()),
|
||||||
Repo: apiRepo,
|
Repo: apiRepo,
|
||||||
Pusher: apiPusher,
|
Pusher: apiPusher,
|
||||||
Sender: apiPusher,
|
Sender: apiPusher,
|
||||||
|
|
|
@ -318,7 +318,7 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository) (err error
|
||||||
Before: pr.MergeBase,
|
Before: pr.MergeBase,
|
||||||
After: pr.MergedCommitID,
|
After: pr.MergedCommitID,
|
||||||
CompareURL: setting.AppUrl + pr.BaseRepo.ComposeCompareURL(pr.MergeBase, pr.MergedCommitID),
|
CompareURL: setting.AppUrl + pr.BaseRepo.ComposeCompareURL(pr.MergeBase, pr.MergedCommitID),
|
||||||
Commits: ListToPushCommits(l).ToApiPayloadCommits(pr.BaseRepo.HTMLURL()),
|
Commits: ListToPushCommits(l).ToAPIPayloadCommits(pr.BaseRepo.HTMLURL()),
|
||||||
Repo: pr.BaseRepo.APIFormat(nil),
|
Repo: pr.BaseRepo.APIFormat(nil),
|
||||||
Pusher: pr.HeadRepo.MustOwner().APIFormat(),
|
Pusher: pr.HeadRepo.MustOwner().APIFormat(),
|
||||||
Sender: doer.APIFormat(),
|
Sender: doer.APIFormat(),
|
||||||
|
|
Loading…
Reference in a new issue