Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 59 additions & 21 deletions models/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ import (
"code.gitea.io/gitea/modules/setting"
)

// ActionType represents the type of an action.
type ActionType int

// Possible action types.
const (
ActionCreateRepo ActionType = iota + 1 // 1
ActionRenameRepo // 2
Expand All @@ -45,26 +47,28 @@ const (
)

var (
// Same as Github. See https://help.github.com/articles/closing-issues-via-commit-messages
IssueCloseKeywords = []string{"close", "closes", "closed", "fix", "fixes", "fixed", "resolve", "resolves", "resolved"}
IssueReopenKeywords = []string{"reopen", "reopens", "reopened"}
// Same as Github. See
// https://help.github.com/articles/closing-issues-via-commit-messages
issueCloseKeywords = []string{"close", "closes", "closed", "fix", "fixes", "fixed", "resolve", "resolves", "resolved"}
issueReopenKeywords = []string{"reopen", "reopens", "reopened"}

IssueCloseKeywordsPat, IssueReopenKeywordsPat *regexp.Regexp
IssueReferenceKeywordsPat *regexp.Regexp
issueCloseKeywordsPat, issueReopenKeywordsPat *regexp.Regexp
issueReferenceKeywordsPat *regexp.Regexp
)

func assembleKeywordsPattern(words []string) string {
return fmt.Sprintf(`(?i)(?:%s) \S+`, strings.Join(words, "|"))
}

func init() {
IssueCloseKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(IssueCloseKeywords))
IssueReopenKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(IssueReopenKeywords))
IssueReferenceKeywordsPat = regexp.MustCompile(`(?i)(?:)(^| )\S+`)
issueCloseKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(issueCloseKeywords))
issueReopenKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(issueReopenKeywords))
issueReferenceKeywordsPat = regexp.MustCompile(`(?i)(?:)(^| )\S+`)
}

// Action represents user operation type and other information to repository.,
// it implemented interface base.Actioner so that can be used in template render.
// Action represents user operation type and other information to
// repository. It implemented interface base.Actioner so that can be
// used in template render.
type Action struct {
ID int64 `xorm:"pk autoincr"`
UserID int64 // Receiver user id.
Expand All @@ -82,76 +86,101 @@ type Action struct {
CreatedUnix int64
}

// BeforeInsert will be invoked by XORM before inserting a record
// representing this object.
func (a *Action) BeforeInsert() {
a.CreatedUnix = time.Now().Unix()
}

// AfterSet updates the webhook object upon setting a column.
func (a *Action) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "created_unix":
a.Created = time.Unix(a.CreatedUnix, 0).Local()
}
}

// GetOpType gets the ActionType of this action.
// TODO: change return type to ActionType ?
func (a *Action) GetOpType() int {
return int(a.OpType)
}

// GetActUserName gets the action's user name.
func (a *Action) GetActUserName() string {
return a.ActUserName
}

// ShortActUserName gets the action's user name trimmed to max 20
// chars.
func (a *Action) ShortActUserName() string {
return base.EllipsisString(a.ActUserName, 20)
}

// GetRepoUserName returns the name of the action repository owner.
func (a *Action) GetRepoUserName() string {
return a.RepoUserName
}

// ShortRepoUserName returns the name of the action repository owner
// trimmed to max 20 chars.
func (a *Action) ShortRepoUserName() string {
return base.EllipsisString(a.RepoUserName, 20)
}

// GetRepoName returns the name of the action repository.
func (a *Action) GetRepoName() string {
return a.RepoName
}

// ShortRepoName returns the name of the action repository
// trimmed to max 33 chars.
func (a *Action) ShortRepoName() string {
return base.EllipsisString(a.RepoName, 33)
}

// GetRepoPath returns the virtual path to the action repository.
func (a *Action) GetRepoPath() string {
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 {
return path.Join(a.ShortRepoUserName(), a.ShortRepoName())
}

// GetRepoLink returns relative link to action repository.
func (a *Action) GetRepoLink() string {
if len(setting.AppSubUrl) > 0 {
return path.Join(setting.AppSubUrl, a.GetRepoPath())
}
return "/" + a.GetRepoPath()
}

// GetBranch returns the action's repository branch.
func (a *Action) GetBranch() string {
return a.RefName
}

// GetContent returns the action's content.
func (a *Action) GetContent() string {
return a.Content
}

// GetCreate returns the action creation time.
func (a *Action) GetCreate() time.Time {
return a.Created
}

// GetIssueInfos returns a list of issues associated with
// the action.
func (a *Action) GetIssueInfos() []string {
return strings.SplitN(a.Content, "|", 2)
}

// GetIssueTitle returns the title of first issue associated
// with the action.
func (a *Action) GetIssueTitle() string {
index := com.StrTo(a.GetIssueInfos()[0]).MustInt64()
issue, err := GetIssueByIndex(a.RepoID, index)
Expand All @@ -162,6 +191,8 @@ func (a *Action) GetIssueTitle() string {
return issue.Title
}

// GetIssueContent returns the content of first issue associated with
// this action.
func (a *Action) GetIssueContent() string {
index := com.StrTo(a.GetIssueInfos()[0]).MustInt64()
issue, err := GetIssueByIndex(a.RepoID, index)
Expand Down Expand Up @@ -221,6 +252,7 @@ func issueIndexTrimRight(c rune) bool {
return !unicode.IsDigit(c)
}

// PushCommit represents a commit in a push operation.
type PushCommit struct {
Sha1 string
Message string
Expand All @@ -231,6 +263,7 @@ type PushCommit struct {
Timestamp time.Time
}

// PushCommits represents list of commits in a push operation.
type PushCommits struct {
Len int
Commits []*PushCommit
Expand All @@ -239,13 +272,16 @@ type PushCommits struct {
avatars map[string]string
}

// NewPushCommits creates a new PushCommits object.
func NewPushCommits() *PushCommits {
return &PushCommits{
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))
for i, commit := range pc.Commits {
authorUsername := ""
Expand Down Expand Up @@ -281,21 +317,21 @@ func (pc *PushCommits) ToApiPayloadCommits(repoLink string) []*api.PayloadCommit

// AvatarLink tries to match user in database with e-mail
// in order to show custom avatar, and falls back to general avatar link.
func (push *PushCommits) AvatarLink(email string) string {
_, ok := push.avatars[email]
func (pc *PushCommits) AvatarLink(email string) string {
_, ok := pc.avatars[email]
if !ok {
u, err := GetUserByEmail(email)
if err != nil {
push.avatars[email] = base.AvatarLink(email)
pc.avatars[email] = base.AvatarLink(email)
if !IsErrUserNotExist(err) {
log.Error(4, "GetUserByEmail: %v", err)
}
} 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.
Expand All @@ -305,7 +341,7 @@ func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit) err
c := commits[i]

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 = strings.TrimRightFunc(ref, issueIndexTrimRight)

Expand Down Expand Up @@ -343,7 +379,7 @@ func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit) err

refMarked = make(map[int64]bool)
// 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 = strings.TrimRightFunc(ref, issueIndexTrimRight)

Expand Down Expand Up @@ -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.
for _, ref := range IssueReopenKeywordsPat.FindAllString(c.Message, -1) {
for _, ref := range issueReopenKeywordsPat.FindAllString(c.Message, -1) {
ref = ref[strings.IndexByte(ref, byte(' '))+1:]
ref = strings.TrimRightFunc(ref, issueIndexTrimRight)

Expand Down Expand Up @@ -425,6 +461,7 @@ func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit) err
return nil
}

// CommitRepoActionOptions represent options of a new commit action.
type CommitRepoActionOptions struct {
PusherName string
RepoOwnerID int64
Expand All @@ -435,7 +472,8 @@ type CommitRepoActionOptions struct {
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 {
pusher, err := GetUserByName(opts.PusherName)
if err != nil {
Expand Down Expand Up @@ -509,7 +547,7 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
Before: opts.OldCommitID,
After: opts.NewCommitID,
CompareURL: setting.AppUrl + opts.Commits.CompareURL,
Commits: opts.Commits.ToApiPayloadCommits(repo.HTMLURL()),
Commits: opts.Commits.ToAPIPayloadCommits(repo.HTMLURL()),
Repo: apiRepo,
Pusher: apiPusher,
Sender: apiPusher,
Expand Down
2 changes: 1 addition & 1 deletion models/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository) (err error
Before: pr.MergeBase,
After: 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),
Pusher: pr.HeadRepo.MustOwner().APIFormat(),
Sender: doer.APIFormat(),
Expand Down