Add push commits history comment on PR time-line (#11167)
* Add push commits history comment on PR time-line * Add notify by email and ui of this comment type also Signed-off-by: a1012112796 <1012112796@qq.com> * Add migrations for IsForcePush * fix wrong force-push judgement * Apply suggestions from code review * Remove commit number check * add own notify fun * fix some typo Co-authored-by: guillep2k <18600385+guillep2k@users.noreply.github.com> * fix lint * fix style again, I forgot something before * Change email notify way * fix api * add number check if It's force-push * Add repo commit link fuction remove unnecessary check skip show push commits comment which not have commits alive * Update issue_comment.go * Apply suggestions from code review Co-authored-by: mrsdizzie <info@mrsdizzie.com> * Apply suggestions from code review * fix ui view Co-authored-by: silverwind <me@silverwind.io> * fix height * remove unnecessary style define * simplify GetBranchName * Apply suggestions from code review * save commit ids and isForce push by json * simplify GetBranchName * fix bug Co-authored-by: guillep2k <18600385+guillep2k@users.noreply.github.com> Co-authored-by: mrsdizzie <info@mrsdizzie.com> Co-authored-by: Lauris BH <lauris@nix.lv> Co-authored-by: silverwind <me@silverwind.io>
This commit is contained in:
parent
9e0e2a9fcf
commit
0903b1ac8c
18 changed files with 478 additions and 6 deletions
|
@ -7,6 +7,8 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"container/list"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -90,6 +92,8 @@ const (
|
||||||
CommentTypeReviewRequest
|
CommentTypeReviewRequest
|
||||||
// merge pull request
|
// merge pull request
|
||||||
CommentTypeMergePull
|
CommentTypeMergePull
|
||||||
|
// push to PR head branch
|
||||||
|
CommentTypePullPush
|
||||||
)
|
)
|
||||||
|
|
||||||
// CommentTag defines comment tag type
|
// CommentTag defines comment tag type
|
||||||
|
@ -167,6 +171,18 @@ type Comment struct {
|
||||||
RefRepo *Repository `xorm:"-"`
|
RefRepo *Repository `xorm:"-"`
|
||||||
RefIssue *Issue `xorm:"-"`
|
RefIssue *Issue `xorm:"-"`
|
||||||
RefComment *Comment `xorm:"-"`
|
RefComment *Comment `xorm:"-"`
|
||||||
|
|
||||||
|
Commits *list.List `xorm:"-"`
|
||||||
|
OldCommit string `xorm:"-"`
|
||||||
|
NewCommit string `xorm:"-"`
|
||||||
|
CommitsNum int64 `xorm:"-"`
|
||||||
|
IsForcePush bool `xorm:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PushActionContent is content of push pull comment
|
||||||
|
type PushActionContent struct {
|
||||||
|
IsForcePush bool `json:"is_force_push"`
|
||||||
|
CommitIDs []string `json:"commit_ids"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadIssue loads issue from database
|
// LoadIssue loads issue from database
|
||||||
|
@ -543,6 +559,47 @@ func (c *Comment) CodeCommentURL() string {
|
||||||
return fmt.Sprintf("%s/files#%s", c.Issue.HTMLURL(), c.HashTag())
|
return fmt.Sprintf("%s/files#%s", c.Issue.HTMLURL(), c.HashTag())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadPushCommits Load push commits
|
||||||
|
func (c *Comment) LoadPushCommits() (err error) {
|
||||||
|
if c.Content == "" || c.Commits != nil || c.Type != CommentTypePullPush {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var data PushActionContent
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(c.Content), &data)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.IsForcePush = data.IsForcePush
|
||||||
|
|
||||||
|
if c.IsForcePush {
|
||||||
|
if len(data.CommitIDs) != 2 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
c.OldCommit = data.CommitIDs[0]
|
||||||
|
c.NewCommit = data.CommitIDs[1]
|
||||||
|
} else {
|
||||||
|
repoPath := c.Issue.Repo.RepoPath()
|
||||||
|
gitRepo, err := git.OpenRepository(repoPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer gitRepo.Close()
|
||||||
|
|
||||||
|
c.Commits = gitRepo.GetCommitsFromIDs(data.CommitIDs)
|
||||||
|
c.CommitsNum = int64(c.Commits.Len())
|
||||||
|
if c.CommitsNum > 0 {
|
||||||
|
c.Commits = ValidateCommitsWithEmails(c.Commits)
|
||||||
|
c.Commits = ParseCommitsWithSignature(c.Commits, c.Issue.Repo)
|
||||||
|
c.Commits = ParseCommitsWithStatus(c.Commits, c.Issue.Repo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err error) {
|
func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err error) {
|
||||||
var LabelID int64
|
var LabelID int64
|
||||||
if opts.Label != nil {
|
if opts.Label != nil {
|
||||||
|
@ -576,6 +633,7 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err
|
||||||
RefCommentID: opts.RefCommentID,
|
RefCommentID: opts.RefCommentID,
|
||||||
RefAction: opts.RefAction,
|
RefAction: opts.RefAction,
|
||||||
RefIsPull: opts.RefIsPull,
|
RefIsPull: opts.RefIsPull,
|
||||||
|
IsForcePush: opts.IsForcePush,
|
||||||
}
|
}
|
||||||
if _, err = e.Insert(comment); err != nil {
|
if _, err = e.Insert(comment); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -738,6 +796,7 @@ type CreateCommentOptions struct {
|
||||||
RefCommentID int64
|
RefCommentID int64
|
||||||
RefAction references.XRefAction
|
RefAction references.XRefAction
|
||||||
RefIsPull bool
|
RefIsPull bool
|
||||||
|
IsForcePush bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateComment creates comment of issue or commit.
|
// CreateComment creates comment of issue or commit.
|
||||||
|
@ -1016,3 +1075,92 @@ func UpdateCommentsMigrationsByType(tp structs.GitServiceType, originalAuthorID
|
||||||
})
|
})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreatePushPullComment create push code to pull base commend
|
||||||
|
func CreatePushPullComment(pusher *User, pr *PullRequest, oldCommitID, newCommitID string) (comment *Comment, err error) {
|
||||||
|
if pr.HasMerged || oldCommitID == "" || newCommitID == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ops := &CreateCommentOptions{
|
||||||
|
Type: CommentTypePullPush,
|
||||||
|
Doer: pusher,
|
||||||
|
Repo: pr.BaseRepo,
|
||||||
|
}
|
||||||
|
|
||||||
|
var data PushActionContent
|
||||||
|
|
||||||
|
data.CommitIDs, data.IsForcePush, err = getCommitIDsFromRepo(pr.BaseRepo, oldCommitID, newCommitID, pr.BaseBranch)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ops.Issue = pr.Issue
|
||||||
|
dataJSON, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ops.Content = string(dataJSON)
|
||||||
|
|
||||||
|
comment, err = CreateComment(ops)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// getCommitsFromRepo get commit IDs from repo in betwern oldCommitID and newCommitID
|
||||||
|
// isForcePush will be true if oldCommit isn't on the branch
|
||||||
|
// Commit on baseBranch will skip
|
||||||
|
func getCommitIDsFromRepo(repo *Repository, oldCommitID, newCommitID, baseBranch string) (commitIDs []string, isForcePush bool, err error) {
|
||||||
|
repoPath := repo.RepoPath()
|
||||||
|
gitRepo, err := git.OpenRepository(repoPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
defer gitRepo.Close()
|
||||||
|
|
||||||
|
oldCommit, err := gitRepo.GetCommit(oldCommitID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
oldCommitBranch, err := oldCommit.GetBranchName()
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if oldCommitBranch == "undefined" {
|
||||||
|
commitIDs = make([]string, 2)
|
||||||
|
commitIDs[0] = oldCommitID
|
||||||
|
commitIDs[1] = newCommitID
|
||||||
|
|
||||||
|
return commitIDs, true, err
|
||||||
|
}
|
||||||
|
|
||||||
|
newCommit, err := gitRepo.GetCommit(newCommitID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var commits *list.List
|
||||||
|
commits, err = newCommit.CommitsBeforeUntil(oldCommitID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
commitIDs = make([]string, 0, commits.Len())
|
||||||
|
|
||||||
|
for e := commits.Back(); e != nil; e = e.Prev() {
|
||||||
|
commit := e.Value.(*git.Commit)
|
||||||
|
commitBranch, err := commit.GetBranchName()
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if commitBranch != baseBranch {
|
||||||
|
commitIDs = append(commitIDs, commit.ID.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
|
@ -264,6 +264,17 @@ func (repo *Repository) HTMLURL() string {
|
||||||
return setting.AppURL + repo.FullName()
|
return setting.AppURL + repo.FullName()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CommitLink make link to by commit full ID
|
||||||
|
// note: won't check whether it's an right id
|
||||||
|
func (repo *Repository) CommitLink(commitID string) (result string) {
|
||||||
|
if commitID == "" || commitID == "0000000000000000000000000000000000000000" {
|
||||||
|
result = ""
|
||||||
|
} else {
|
||||||
|
result = repo.HTMLURL() + "/commit/" + commitID
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// APIURL returns the repository API URL
|
// APIURL returns the repository API URL
|
||||||
func (repo *Repository) APIURL() string {
|
func (repo *Repository) APIURL() string {
|
||||||
return setting.AppURL + path.Join("api/v1/repos", repo.FullName())
|
return setting.AppURL + path.Join("api/v1/repos", repo.FullName())
|
||||||
|
|
|
@ -466,15 +466,15 @@ func (c *Commit) GetSubModule(entryname string) (*SubModule, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBranchName gets the closes branch name (as returned by 'git name-rev')
|
// GetBranchName gets the closes branch name (as returned by 'git name-rev --name-only')
|
||||||
func (c *Commit) GetBranchName() (string, error) {
|
func (c *Commit) GetBranchName() (string, error) {
|
||||||
data, err := NewCommand("name-rev", c.ID.String()).RunInDirBytes(c.repo.Path)
|
data, err := NewCommand("name-rev", "--name-only", c.ID.String()).RunInDir(c.repo.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// name-rev commitID output will be "COMMIT_ID master" or "COMMIT_ID master~12"
|
// name-rev commitID output will be "master" or "master~12"
|
||||||
return strings.Split(strings.Split(string(data), " ")[1], "~")[0], nil
|
return strings.SplitN(strings.TrimSpace(data), "~", 2)[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CommitFileStatus represents status of files in a commit.
|
// CommitFileStatus represents status of files in a commit.
|
||||||
|
|
|
@ -454,3 +454,21 @@ func (repo *Repository) getBranches(commit *Commit, limit int) ([]string, error)
|
||||||
}
|
}
|
||||||
return branches, nil
|
return branches, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetCommitsFromIDs get commits from commit IDs
|
||||||
|
func (repo *Repository) GetCommitsFromIDs(commitIDs []string) (commits *list.List) {
|
||||||
|
if len(commitIDs) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
commits = list.New()
|
||||||
|
|
||||||
|
for _, commitID := range commitIDs {
|
||||||
|
commit, err := repo.GetCommit(commitID)
|
||||||
|
if err == nil && commit != nil {
|
||||||
|
commits.PushBack(commit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return commits
|
||||||
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ type Notifier interface {
|
||||||
NotifyPullRequestSynchronized(doer *models.User, pr *models.PullRequest)
|
NotifyPullRequestSynchronized(doer *models.User, pr *models.PullRequest)
|
||||||
NotifyPullRequestReview(*models.PullRequest, *models.Review, *models.Comment)
|
NotifyPullRequestReview(*models.PullRequest, *models.Review, *models.Comment)
|
||||||
NotifyPullRequestChangeTargetBranch(doer *models.User, pr *models.PullRequest, oldBranch string)
|
NotifyPullRequestChangeTargetBranch(doer *models.User, pr *models.PullRequest, oldBranch string)
|
||||||
|
NotifyPullRequestPushCommits(doer *models.User, pr *models.PullRequest, comment *models.Comment)
|
||||||
|
|
||||||
NotifyCreateIssueComment(*models.User, *models.Repository,
|
NotifyCreateIssueComment(*models.User, *models.Repository,
|
||||||
*models.Issue, *models.Comment)
|
*models.Issue, *models.Comment)
|
||||||
|
|
|
@ -54,6 +54,10 @@ func (*NullNotifier) NotifyPullRequestSynchronized(doer *models.User, pr *models
|
||||||
func (*NullNotifier) NotifyPullRequestChangeTargetBranch(doer *models.User, pr *models.PullRequest, oldBranch string) {
|
func (*NullNotifier) NotifyPullRequestChangeTargetBranch(doer *models.User, pr *models.PullRequest, oldBranch string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NotifyPullRequestPushCommits notifies when push commits to pull request's head branch
|
||||||
|
func (*NullNotifier) NotifyPullRequestPushCommits(doer *models.User, pr *models.PullRequest, comment *models.Comment) {
|
||||||
|
}
|
||||||
|
|
||||||
// NotifyUpdateComment places a place holder function
|
// NotifyUpdateComment places a place holder function
|
||||||
func (*NullNotifier) NotifyUpdateComment(doer *models.User, c *models.Comment, oldContent string) {
|
func (*NullNotifier) NotifyUpdateComment(doer *models.User, c *models.Comment, oldContent string) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,8 @@ func (m *mailNotifier) NotifyCreateIssueComment(doer *models.User, repo *models.
|
||||||
act = models.ActionCommentIssue
|
act = models.ActionCommentIssue
|
||||||
} else if comment.Type == models.CommentTypeCode {
|
} else if comment.Type == models.CommentTypeCode {
|
||||||
act = models.ActionCommentIssue
|
act = models.ActionCommentIssue
|
||||||
|
} else if comment.Type == models.CommentTypePullPush {
|
||||||
|
act = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := mailer.MailParticipantsComment(comment, act, issue); err != nil {
|
if err := mailer.MailParticipantsComment(comment, act, issue); err != nil {
|
||||||
|
@ -117,3 +119,29 @@ func (m *mailNotifier) NotifyMergePullRequest(pr *models.PullRequest, doer *mode
|
||||||
log.Error("MailParticipants: %v", err)
|
log.Error("MailParticipants: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *mailNotifier) NotifyPullRequestPushCommits(doer *models.User, pr *models.PullRequest, comment *models.Comment) {
|
||||||
|
var err error
|
||||||
|
if err = comment.LoadIssue(); err != nil {
|
||||||
|
log.Error("comment.LoadIssue: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = comment.Issue.LoadRepo(); err != nil {
|
||||||
|
log.Error("comment.Issue.LoadRepo: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = comment.Issue.LoadPullRequest(); err != nil {
|
||||||
|
log.Error("comment.Issue.LoadPullRequest: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = comment.Issue.PullRequest.LoadBaseRepo(); err != nil {
|
||||||
|
log.Error("comment.Issue.PullRequest.LoadBaseRepo: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := comment.LoadPushCommits(); err != nil {
|
||||||
|
log.Error("comment.LoadPushCommits: %v", err)
|
||||||
|
}
|
||||||
|
comment.Content = ""
|
||||||
|
|
||||||
|
m.NotifyCreateIssueComment(doer, comment.Issue.Repo, comment.Issue, comment)
|
||||||
|
}
|
||||||
|
|
|
@ -94,6 +94,13 @@ func NotifyPullRequestChangeTargetBranch(doer *models.User, pr *models.PullReque
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NotifyPullRequestPushCommits notifies when push commits to pull request's head branch
|
||||||
|
func NotifyPullRequestPushCommits(doer *models.User, pr *models.PullRequest, comment *models.Comment) {
|
||||||
|
for _, notifier := range notifiers {
|
||||||
|
notifier.NotifyPullRequestPushCommits(doer, pr, comment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NotifyUpdateComment notifies update comment to notifiers
|
// NotifyUpdateComment notifies update comment to notifiers
|
||||||
func NotifyUpdateComment(doer *models.User, c *models.Comment, oldContent string) {
|
func NotifyUpdateComment(doer *models.User, c *models.Comment, oldContent string) {
|
||||||
for _, notifier := range notifiers {
|
for _, notifier := range notifiers {
|
||||||
|
|
|
@ -105,6 +105,15 @@ func (ns *notificationService) NotifyPullRequestReview(pr *models.PullRequest, r
|
||||||
_ = ns.issueQueue.Push(opts)
|
_ = ns.issueQueue.Push(opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ns *notificationService) NotifyPullRequestPushCommits(doer *models.User, pr *models.PullRequest, comment *models.Comment) {
|
||||||
|
var opts = issueNotificationOpts{
|
||||||
|
IssueID: pr.IssueID,
|
||||||
|
NotificationAuthorID: doer.ID,
|
||||||
|
CommentID: comment.ID,
|
||||||
|
}
|
||||||
|
_ = ns.issueQueue.Push(opts)
|
||||||
|
}
|
||||||
|
|
||||||
func (ns *notificationService) NotifyIssueChangeAssignee(doer *models.User, issue *models.Issue, assignee *models.User, removed bool, comment *models.Comment) {
|
func (ns *notificationService) NotifyIssueChangeAssignee(doer *models.User, issue *models.Issue, assignee *models.User, removed bool, comment *models.Comment) {
|
||||||
if !removed {
|
if !removed {
|
||||||
var opts = issueNotificationOpts{
|
var opts = issueNotificationOpts{
|
||||||
|
|
|
@ -1029,6 +1029,9 @@ issues.due_date = Due Date
|
||||||
issues.invalid_due_date_format = "Due date format must be 'yyyy-mm-dd'."
|
issues.invalid_due_date_format = "Due date format must be 'yyyy-mm-dd'."
|
||||||
issues.error_modifying_due_date = "Failed to modify the due date."
|
issues.error_modifying_due_date = "Failed to modify the due date."
|
||||||
issues.error_removing_due_date = "Failed to remove the due date."
|
issues.error_removing_due_date = "Failed to remove the due date."
|
||||||
|
issues.push_commit_1 = "added %d commit %s"
|
||||||
|
issues.push_commits_n = "added %d commits %s"
|
||||||
|
issues.force_push_codes = `force-pushed the %[1]s branch from <a href="%[3]s">%[2]s</a> to <a href="%[5]s">%[4]s</a>. %[6]s`
|
||||||
issues.due_date_form = "yyyy-mm-dd"
|
issues.due_date_form = "yyyy-mm-dd"
|
||||||
issues.due_date_form_add = "Add due date"
|
issues.due_date_form_add = "Add due date"
|
||||||
issues.due_date_form_edit = "Edit"
|
issues.due_date_form_edit = "Edit"
|
||||||
|
|
|
@ -999,6 +999,12 @@ func ViewIssue(ctx *context.Context) {
|
||||||
ctx.ServerError("LoadResolveDoer", err)
|
ctx.ServerError("LoadResolveDoer", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
} else if comment.Type == models.CommentTypePullPush {
|
||||||
|
participants = addParticipant(comment.Poster, participants)
|
||||||
|
if err = comment.LoadPushCommits(); err != nil {
|
||||||
|
ctx.ServerError("LoadPushCommits", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -319,6 +319,8 @@ func actionToTemplate(issue *models.Issue, actionType models.ActionType,
|
||||||
name = "code"
|
name = "code"
|
||||||
case models.CommentTypeAssignees:
|
case models.CommentTypeAssignees:
|
||||||
name = "assigned"
|
name = "assigned"
|
||||||
|
case models.CommentTypePullPush:
|
||||||
|
name = "push"
|
||||||
default:
|
default:
|
||||||
name = "default"
|
name = "default"
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
@ -57,6 +58,43 @@ func NewPullRequest(repo *models.Repository, pull *models.Issue, labelIDs []int6
|
||||||
|
|
||||||
notification.NotifyNewPullRequest(pr)
|
notification.NotifyNewPullRequest(pr)
|
||||||
|
|
||||||
|
// add first push codes comment
|
||||||
|
baseGitRepo, err := git.OpenRepository(pr.BaseRepo.RepoPath())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer baseGitRepo.Close()
|
||||||
|
|
||||||
|
compareInfo, err := baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(),
|
||||||
|
pr.BaseBranch, pr.GetGitRefName())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if compareInfo.Commits.Len() > 0 {
|
||||||
|
data := models.PushActionContent{IsForcePush: false}
|
||||||
|
data.CommitIDs = make([]string, 0, compareInfo.Commits.Len())
|
||||||
|
for e := compareInfo.Commits.Back(); e != nil; e = e.Prev() {
|
||||||
|
data.CommitIDs = append(data.CommitIDs, e.Value.(*git.Commit).ID.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
dataJSON, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ops := &models.CreateCommentOptions{
|
||||||
|
Type: models.CommentTypePullPush,
|
||||||
|
Doer: pull.Poster,
|
||||||
|
Repo: repo,
|
||||||
|
Issue: pr.Issue,
|
||||||
|
IsForcePush: false,
|
||||||
|
Content: string(dataJSON),
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _ = models.CreateComment(ops)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,6 +275,12 @@ func AddTestPullRequestTask(doer *models.User, repoID int64, branch string, isSy
|
||||||
}
|
}
|
||||||
|
|
||||||
addHeadRepoTasks(prs)
|
addHeadRepoTasks(prs)
|
||||||
|
for _, pr := range prs {
|
||||||
|
comment, err := models.CreatePushPullComment(doer, pr, oldCommitID, newCommitID)
|
||||||
|
if err == nil && comment != nil {
|
||||||
|
notification.NotifyPullRequestPushCommits(doer, pr, comment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
log.Trace("AddTestPullRequestTask [base_repo_id: %d, base_branch: %s]: finding pull requests", repoID, branch)
|
log.Trace("AddTestPullRequestTask [base_repo_id: %d, base_branch: %s]: finding pull requests", repoID, branch)
|
||||||
prs, err = models.GetUnmergedPullRequestsByBaseInfo(repoID, branch)
|
prs, err = models.GetUnmergedPullRequestsByBaseInfo(repoID, branch)
|
||||||
|
|
|
@ -17,6 +17,25 @@
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
{{if .IsMention}}<p><b>@{{.Doer.Name}}</b> mentioned you:</p>{{end}}
|
{{if .IsMention}}<p><b>@{{.Doer.Name}}</b> mentioned you:</p>{{end}}
|
||||||
|
{{if eq .Comment.Type 29}}
|
||||||
|
<p>
|
||||||
|
<b>{{.Doer.Name}}</b>
|
||||||
|
{{if .Comment.IsForcePush}}
|
||||||
|
{{ $oldCommitLink:= printf "%s%s/%s/commit/%s" AppUrl .Comment.Issue.PullRequest.BaseRepo.OwnerName .Comment.Issue.PullRequest.BaseRepo.Name .Comment.OldCommit}}
|
||||||
|
{{ $newCommitLink:= printf "%s%s/%s/commit/%s" AppUrl .Comment.Issue.PullRequest.BaseRepo.OwnerName .Comment.Issue.PullRequest.BaseRepo.Name .Comment.NewCommit}}
|
||||||
|
force-pushed the <b>{{.Comment.Issue.PullRequest.HeadBranch}}</b> from
|
||||||
|
<a href="{{$oldCommitLink}}"><b>{{ShortSha .Comment.OldCommit}}</b></a>
|
||||||
|
to
|
||||||
|
<a href="{{$newCommitLink}}"><b>{{ShortSha .Comment.NewCommit}}</b></a>.
|
||||||
|
{{else}}
|
||||||
|
{{if eq .Comment.Commits.Len 1}}
|
||||||
|
{{printf "pushed 1 commit to %s:" .Comment.Issue.PullRequest.HeadBranch}}
|
||||||
|
{{else}}
|
||||||
|
{{printf "pushed %d commits to %s:" .Comment.Commits.Len .Comment.Issue.PullRequest.HeadBranch}}
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
</p>
|
||||||
|
{{end}}
|
||||||
<p>
|
<p>
|
||||||
{{if eq .ActionName "close"}}
|
{{if eq .ActionName "close"}}
|
||||||
Closed #{{.Issue.Index}}.
|
Closed #{{.Issue.Index}}.
|
||||||
|
@ -46,7 +65,19 @@
|
||||||
<pre>{{.Patch}}</pre>
|
<pre>{{.Patch}}</pre>
|
||||||
<div>{{.RenderedContent | Safe}}</div>
|
<div>{{.RenderedContent | Safe}}</div>
|
||||||
</div>
|
</div>
|
||||||
{{end -}}
|
{{end -}}
|
||||||
|
{{if eq .Comment.Type 29}}
|
||||||
|
{{ $r:= List .Comment.Commits}}
|
||||||
|
<ul>
|
||||||
|
{{range $r}}
|
||||||
|
<li>
|
||||||
|
<a href="{{AppUrl}}{{$.Comment.Issue.PullRequest.BaseRepo.OwnerName}}/{{$.Comment.Issue.PullRequest.BaseRepo.Name}}/commit/{{.ID}}">
|
||||||
|
{{ShortSha .ID.String}}
|
||||||
|
</a> - {{.Summary}}
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
{{end}}
|
||||||
</p>
|
</p>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
<p>
|
<p>
|
||||||
|
|
57
templates/repo/commits_list_small.tmpl
Normal file
57
templates/repo/commits_list_small.tmpl
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
{{ $r:= List .Commits}}
|
||||||
|
{{ $index := 0}}
|
||||||
|
{{range $r}}
|
||||||
|
{{ $tag := printf "%s-%d" $.HashTag $index }}
|
||||||
|
{{ $index = Add $index 1}}
|
||||||
|
<div class="timeline-item event small-line-spacing" id="{{$tag}}">
|
||||||
|
<span class="badge badge-commit">{{svg "octicon-git-commit" 16}}</span>
|
||||||
|
{{if .User}}
|
||||||
|
<a class="ui avatar image" href="{{AppSubUrl}}/{{.User.Name}}"><img src="{{.User.RelAvatarLink}}" alt=""/></a>
|
||||||
|
{{else}}
|
||||||
|
<img class="ui avatar image" src="{{AvatarLink .Author.Email}}" alt=""/>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
<span class="ui float right shabox">
|
||||||
|
{{$class := "ui sha label"}}
|
||||||
|
{{if .Signature}}
|
||||||
|
{{$class = (printf "%s%s" $class " isSigned")}}
|
||||||
|
{{if .Verification.Verified}}
|
||||||
|
{{if eq .Verification.TrustStatus "trusted"}}
|
||||||
|
{{$class = (printf "%s%s" $class " isVerified")}}
|
||||||
|
{{else if eq .Verification.TrustStatus "untrusted"}}
|
||||||
|
{{$class = (printf "%s%s" $class " isVerifiedUntrusted")}}
|
||||||
|
{{else}}
|
||||||
|
{{$class = (printf "%s%s" $class " isVerifiedUnmatched")}}
|
||||||
|
{{end}}
|
||||||
|
{{else if .Verification.Warning}}
|
||||||
|
{{$class = (printf "%s%s" $class " isWarning")}}
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
{{if $.Issue.PullRequest.BaseRepo.Name}}
|
||||||
|
<a href="{{AppSubUrl}}/{{$.Issue.PullRequest.BaseRepo.OwnerName}}/{{$.Issue.PullRequest.BaseRepo.Name}}/commit/{{.ID}}" rel="nofollow" class="{{$class}}">
|
||||||
|
{{else}}
|
||||||
|
<span class="{{$class}}">
|
||||||
|
{{end}}
|
||||||
|
<span class="shortsha">{{ShortSha .ID.String}}</span>
|
||||||
|
{{if $.Issue.PullRequest.BaseRepo.Name}}
|
||||||
|
</a>
|
||||||
|
{{else}}
|
||||||
|
</span>
|
||||||
|
{{end}}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="message-wrapper">
|
||||||
|
{{ $commitLink:= printf "%s/%s/%s/commit/%s" AppSubUrl $.Issue.PullRequest.BaseRepo.OwnerName $.Issue.PullRequest.BaseRepo.Name .ID }}
|
||||||
|
<span class="commit-summary has-emoji{{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{RenderCommitMessageLinkSubject .Message ($.Issue.PullRequest.BaseRepo.Link|Escape) $commitLink $.Issue.PullRequest.BaseRepo.ComposeMetas}}</span>
|
||||||
|
</span>
|
||||||
|
{{if IsMultilineCommitMessage .Message}}
|
||||||
|
<button class="basic compact mini ui icon button commit-button"><i class="ellipsis horizontal icon"></i></button>
|
||||||
|
{{end}}
|
||||||
|
{{if eq (CommitType .) "SignCommitWithStatuses"}}
|
||||||
|
{{template "repo/commit_status" .Status}}
|
||||||
|
{{end}}
|
||||||
|
{{if IsMultilineCommitMessage .Message}}
|
||||||
|
<pre class="commit-body" style="display: none;">{{RenderCommitBody .Message ($.Issue.PullRequest.BaseRepo.Link|Escape) $.Issue.PullRequest.BaseRepo.ComposeMetas}}</pre>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
|
@ -7,7 +7,8 @@
|
||||||
13 = STOP_TRACKING, 14 = ADD_TIME_MANUAL, 16 = ADDED_DEADLINE, 17 = MODIFIED_DEADLINE,
|
13 = STOP_TRACKING, 14 = ADD_TIME_MANUAL, 16 = ADDED_DEADLINE, 17 = MODIFIED_DEADLINE,
|
||||||
18 = REMOVED_DEADLINE, 19 = ADD_DEPENDENCY, 20 = REMOVE_DEPENDENCY, 21 = CODE,
|
18 = REMOVED_DEADLINE, 19 = ADD_DEPENDENCY, 20 = REMOVE_DEPENDENCY, 21 = CODE,
|
||||||
22 = REVIEW, 23 = ISSUE_LOCKED, 24 = ISSUE_UNLOCKED, 25 = TARGET_BRANCH_CHANGED,
|
22 = REVIEW, 23 = ISSUE_LOCKED, 24 = ISSUE_UNLOCKED, 25 = TARGET_BRANCH_CHANGED,
|
||||||
26 = DELETE_TIME_MANUAL, 27 = REVIEW_REQUEST, 28 = MERGE_PULL_REQUEST -->
|
26 = DELETE_TIME_MANUAL, 27 = REVIEW_REQUEST, 28 = MERGE_PULL_REQUEST,
|
||||||
|
29 = PULL_PUSH_EVENT -->
|
||||||
{{if eq .Type 0}}
|
{{if eq .Type 0}}
|
||||||
<div class="timeline-item comment" id="{{.HashTag}}">
|
<div class="timeline-item comment" id="{{.HashTag}}">
|
||||||
{{if .OriginalAuthor }}
|
{{if .OriginalAuthor }}
|
||||||
|
@ -594,5 +595,23 @@
|
||||||
{{end}}
|
{{end}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
{{else if and (eq .Type 29) (or (gt .CommitsNum 0) .IsForcePush)}}
|
||||||
|
<div class="timeline-item event" id="{{.HashTag}}">
|
||||||
|
<span class="badge">{{svg "octicon-repo-force-push" 16}}</span>
|
||||||
|
<a class="ui avatar image" href="{{.Poster.HomeLink}}">
|
||||||
|
<img src="{{.Poster.RelAvatarLink}}">
|
||||||
|
</a>
|
||||||
|
<span class="text grey">
|
||||||
|
<a href="{{.Poster.HomeLink}}">{{.Poster.GetDisplayName}}</a>
|
||||||
|
{{ if .IsForcePush }}
|
||||||
|
{{$.i18n.Tr "repo.issues.force_push_codes" $.Issue.PullRequest.HeadBranch (ShortSha .OldCommit) ($.Issue.Repo.CommitLink .OldCommit) (ShortSha .NewCommit) ($.Issue.Repo.CommitLink .NewCommit) $createdStr | Safe}}
|
||||||
|
{{else}}
|
||||||
|
{{$.i18n.Tr (TrN $.i18n.Lang .Commits.Len "repo.issues.push_commit_1" "repo.issues.push_commits_n") .Commits.Len $createdStr | Safe}}
|
||||||
|
{{end}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{{if not .IsForcePush}}
|
||||||
|
{{template "repo/commits_list_small" .}}
|
||||||
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -762,6 +762,12 @@
|
||||||
padding-bottom: 0 !important;
|
padding-bottom: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.badge.badge-commit {
|
||||||
|
border-color: transparent;
|
||||||
|
background: radial-gradient(white 60%, transparent 60%) no-repeat;
|
||||||
|
height: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
.badge {
|
.badge {
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
|
@ -804,6 +810,16 @@
|
||||||
line-height: 30px;
|
line-height: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.event.small-line-spacing {
|
||||||
|
padding: 2px 0 0 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.event > .commit-status-link {
|
||||||
|
float: right;
|
||||||
|
margin-right: 8px;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.author {
|
.author {
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
@ -1040,6 +1056,69 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
& > .shabox {
|
||||||
|
.sha.label {
|
||||||
|
margin: 0;
|
||||||
|
border: 1px solid #bbbbbb;
|
||||||
|
|
||||||
|
&.isSigned.isWarning {
|
||||||
|
border: 1px solid #db2828;
|
||||||
|
background: fade(#db2828, 10%);
|
||||||
|
|
||||||
|
.shortsha {
|
||||||
|
display: inline-block;
|
||||||
|
padding-top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: fade(#db2828, 30%) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.isSigned.isVerified {
|
||||||
|
border: 1px solid #21ba45;
|
||||||
|
background: fade(#21ba45, 10%);
|
||||||
|
|
||||||
|
.shortsha {
|
||||||
|
display: inline-block;
|
||||||
|
padding-top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: fade(#21ba45, 30%) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.isSigned.isVerifiedUntrusted {
|
||||||
|
border: 1px solid #fbbd08;
|
||||||
|
background: fade(#fbbd08, 10%);
|
||||||
|
|
||||||
|
.shortsha {
|
||||||
|
display: inline-block;
|
||||||
|
padding-top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: fade(#fbbd08, 30%) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.isSigned.isVerifiedUnmatched {
|
||||||
|
border: 1px solid #f2711c;
|
||||||
|
background: fade(#f2711c, 10%);
|
||||||
|
|
||||||
|
.shortsha {
|
||||||
|
display: inline-block;
|
||||||
|
padding-top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: fade(#f2711c, 30%) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.detail {
|
.detail {
|
||||||
font-size: .9rem;
|
font-size: .9rem;
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
|
|
|
@ -704,6 +704,11 @@ a.ui.basic.green.label:hover {
|
||||||
color: #9e9e9e;
|
color: #9e9e9e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.repository.view.issue .comment-list .timeline-item .badge.badge-commit {
|
||||||
|
background: radial-gradient(#383c4a 60%, transparent 60%) no-repeat;
|
||||||
|
height: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
.repository .comment.form .content .form:after {
|
.repository .comment.form .content .form:after {
|
||||||
border-right-color: #313c47;
|
border-right-color: #313c47;
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue