mirror of
https://github.com/go-gitea/gitea.git
synced 2026-10-03 02:21:17 +02:00
work on PR conversation
This commit is contained in:
1 parent
63fecac537
commit
8c046073a8
20 files changed
+784
-303
No files matched your search
+3
-2
@@ -513,13 +513,14 @@ func runWeb(ctx *cli.Context) {
|
||||
m.Post("/edit/:tagname", bindIgnErr(auth.EditReleaseForm{}), repo.EditReleasePost)
|
||||
}, reqRepoAdmin, middleware.RepoRef())
|
||||
|
||||
m.Combo("/compare/*").Get(repo.CompareAndPullRequest)
|
||||
m.Combo("/compare/*").Get(repo.CompareAndPullRequest).
|
||||
Post(bindIgnErr(auth.CreateIssueForm{}), repo.CompareAndPullRequestPost)
|
||||
}, reqSignIn, middleware.RepoAssignment(true))
|
||||
|
||||
m.Group("/:username/:reponame", func() {
|
||||
m.Get("/releases", middleware.RepoRef(), repo.Releases)
|
||||
m.Get("/issues", repo.RetrieveLabels, repo.Issues)
|
||||
m.Get("/issues/:index", repo.ViewIssue)
|
||||
m.Get("/:type(issues|pulls)/:index", repo.ViewIssue)
|
||||
m.Get("/labels/", repo.RetrieveLabels, repo.Labels)
|
||||
m.Get("/milestones", repo.Milestones)
|
||||
m.Get("/pulls", repo.Pulls)
|
||||
|
||||
@@ -464,6 +464,9 @@ pulls.compare_changes = Compare Changes
|
||||
pulls.compare_changes_desc = Compare two branches and make a pull request for changes.
|
||||
pulls.no_results = No results found.
|
||||
pulls.create = Create Pull Request
|
||||
pulls.tab_conversation = Conversation
|
||||
pulls.tab_commits = Commits
|
||||
pulls.tab_files = Files changed
|
||||
|
||||
milestones.new = New Milestone
|
||||
milestones.open_tab = %d Open
|
||||
|
||||
@@ -281,6 +281,27 @@ func (err ErrIssueNotExist) Error() string {
|
||||
return fmt.Sprintf("issue does not exist [id: %d, repo_id: %d, index: %d]", err.ID, err.RepoID, err.Index)
|
||||
}
|
||||
|
||||
// __________ .__ .__ __________ __
|
||||
// \______ \__ __| | | |\______ \ ____ ________ __ ____ _______/ |_
|
||||
// | ___/ | \ | | | | _// __ \/ ____/ | \_/ __ \ / ___/\ __\
|
||||
// | | | | / |_| |_| | \ ___< <_| | | /\ ___/ \___ \ | |
|
||||
// |____| |____/|____/____/____|_ /\___ >__ |____/ \___ >____ > |__|
|
||||
// \/ \/ |__| \/ \/
|
||||
|
||||
type ErrPullRepoNotExist struct {
|
||||
ID int64
|
||||
PullID int64
|
||||
}
|
||||
|
||||
func IsErrPullRepoNotExist(err error) bool {
|
||||
_, ok := err.(ErrPullRepoNotExist)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrPullRepoNotExist) Error() string {
|
||||
return fmt.Sprintf("pull repo does not exist [id: %d, pull_id: %d]", err.ID, err.PullID)
|
||||
}
|
||||
|
||||
// _________ __
|
||||
// \_ ___ \ ____ _____ _____ ____ _____/ |_
|
||||
// / \ \/ / _ \ / \ / \_/ __ \ / \ __\
|
||||
|
||||
+159
-31
@@ -9,6 +9,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"os"
|
||||
"path"
|
||||
@@ -21,6 +22,7 @@ import (
|
||||
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/process"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
gouuid "github.com/gogits/gogs/modules/uuid"
|
||||
)
|
||||
@@ -44,9 +46,10 @@ type Issue struct {
|
||||
MilestoneID int64
|
||||
Milestone *Milestone `xorm:"-"`
|
||||
AssigneeID int64
|
||||
Assignee *User `xorm:"-"`
|
||||
IsRead bool `xorm:"-"`
|
||||
IsPull bool // Indicates whether is a pull request or not.
|
||||
Assignee *User `xorm:"-"`
|
||||
IsRead bool `xorm:"-"`
|
||||
IsPull bool // Indicates whether is a pull request or not.
|
||||
PullRepo *PullRepo `xorm:"-"`
|
||||
IsClosed bool
|
||||
Content string `xorm:"TEXT"`
|
||||
RenderedContent string `xorm:"-"`
|
||||
@@ -92,6 +95,11 @@ func (i *Issue) AfterSet(colName string, _ xorm.Cell) {
|
||||
if err != nil {
|
||||
log.Error(3, "GetUserByID[%d]: %v", i.ID, err)
|
||||
}
|
||||
case "is_pull":
|
||||
i.PullRepo, err = GetPullRepoByPullID(i.ID)
|
||||
if err != nil {
|
||||
log.Error(3, "GetPullRepoByPullID[%d]: %v", i.ID, err)
|
||||
}
|
||||
case "created":
|
||||
i.Created = regulateTimeZone(i.Created)
|
||||
}
|
||||
@@ -273,30 +281,11 @@ func (i *Issue) ChangeStatus(doer *User, isClosed bool) (err error) {
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
// CreateIssue creates new issue with labels for repository.
|
||||
func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, uuids []string) (err error) {
|
||||
// Check attachments.
|
||||
attachments := make([]*Attachment, 0, len(uuids))
|
||||
for _, uuid := range uuids {
|
||||
attach, err := GetAttachmentByUUID(uuid)
|
||||
if err != nil {
|
||||
if IsErrAttachmentNotExist(err) {
|
||||
continue
|
||||
}
|
||||
return fmt.Errorf("GetAttachmentByUUID[%s]: %v", uuid, err)
|
||||
}
|
||||
attachments = append(attachments, attach)
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
// It's caller's responsibility to create action.
|
||||
func newIssue(e *xorm.Session, repo *Repository, issue *Issue, labelIDs []int64, uuids []string) (err error) {
|
||||
if _, err = e.Insert(issue); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = sess.Insert(issue); err != nil {
|
||||
return err
|
||||
} else if _, err = sess.Exec("UPDATE `repository` SET num_issues=num_issues+1 WHERE id=?", issue.RepoID); err != nil {
|
||||
} else if _, err = e.Exec("UPDATE `repository` SET num_issues=num_issues+1 WHERE id=?", issue.RepoID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -306,34 +295,62 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, uuids []string)
|
||||
continue
|
||||
}
|
||||
|
||||
label, err = getLabelByID(sess, id)
|
||||
label, err = getLabelByID(e, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = issue.addLabel(sess, label); err != nil {
|
||||
if err = issue.addLabel(e, label); err != nil {
|
||||
return fmt.Errorf("addLabel: %v", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if issue.MilestoneID > 0 {
|
||||
if err = changeMilestoneAssign(sess, 0, issue); err != nil {
|
||||
if err = changeMilestoneAssign(e, 0, issue); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err = newIssueUsers(sess, repo, issue); err != nil {
|
||||
if err = newIssueUsers(e, repo, issue); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check attachments.
|
||||
attachments := make([]*Attachment, 0, len(uuids))
|
||||
for _, uuid := range uuids {
|
||||
attach, err := getAttachmentByUUID(e, uuid)
|
||||
if err != nil {
|
||||
if IsErrAttachmentNotExist(err) {
|
||||
continue
|
||||
}
|
||||
return fmt.Errorf("getAttachmentByUUID[%s]: %v", uuid, err)
|
||||
}
|
||||
attachments = append(attachments, attach)
|
||||
}
|
||||
|
||||
for i := range attachments {
|
||||
attachments[i].IssueID = issue.ID
|
||||
// No assign value could be 0, so ignore AllCols().
|
||||
if _, err = sess.Id(attachments[i].ID).Update(attachments[i]); err != nil {
|
||||
if _, err = e.Id(attachments[i].ID).Update(attachments[i]); err != nil {
|
||||
return fmt.Errorf("update attachment[%d]: %v", attachments[i].ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewIssue creates new issue with labels for repository.
|
||||
func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, uuids []string) (err error) {
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = newIssue(sess, repo, issue, labelIDs, uuids); err != nil {
|
||||
return fmt.Errorf("newIssue: %v", err)
|
||||
}
|
||||
|
||||
// Notify watchers.
|
||||
act := &Action{
|
||||
ActUserID: issue.Poster.Id,
|
||||
@@ -813,6 +830,117 @@ func UpdateIssueUsersByMentions(uids []int64, iid int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// __________ .__ .__ __________ __
|
||||
// \______ \__ __| | | |\______ \ ____ ________ __ ____ _______/ |_
|
||||
// | ___/ | \ | | | | _// __ \/ ____/ | \_/ __ \ / ___/\ __\
|
||||
// | | | | / |_| |_| | \ ___< <_| | | /\ ___/ \___ \ | |
|
||||
// |____| |____/|____/____/____|_ /\___ >__ |____/ \___ >____ > |__|
|
||||
// \/ \/ |__| \/ \/
|
||||
|
||||
type PullRequestType int
|
||||
|
||||
const (
|
||||
PULL_REQUEST_GOGS = iota
|
||||
PLLL_ERQUEST_GIT
|
||||
)
|
||||
|
||||
// PullRepo represents relation between pull request and repositories.
|
||||
type PullRepo struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
PullID int64 `xorm:"INDEX"`
|
||||
HeadRepoID int64 `xorm:"UNIQUE(s)"`
|
||||
HeadRepo *Repository `xorm:"-"`
|
||||
BaseRepoID int64 `xorm:"UNIQUE(s)"`
|
||||
HeadBarcnh string `xorm:"UNIQUE(s)"`
|
||||
BaseBranch string `xorm:"UNIQUE(s)"`
|
||||
MergeBase string `xorm:"VARCHAR(40)"`
|
||||
Type PullRequestType
|
||||
CanAutoMerge bool
|
||||
}
|
||||
|
||||
func (pr *PullRepo) AfterSet(colName string, _ xorm.Cell) {
|
||||
var err error
|
||||
switch colName {
|
||||
case "head_repo_id":
|
||||
pr.HeadRepo, err = GetRepositoryByID(pr.HeadRepoID)
|
||||
if err != nil {
|
||||
log.Error(3, "GetRepositoryByID[%d]: %v", pr.ID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NewPullRequest creates new pull request with labels for repository.
|
||||
func NewPullRequest(repo *Repository, pr *Issue, labelIDs []int64, uuids []string, pullRepo *PullRepo, patch []byte) (err error) {
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = newIssue(sess, repo, pr, labelIDs, uuids); err != nil {
|
||||
return fmt.Errorf("newIssue: %v", err)
|
||||
}
|
||||
|
||||
// Notify watchers.
|
||||
act := &Action{
|
||||
ActUserID: pr.Poster.Id,
|
||||
ActUserName: pr.Poster.Name,
|
||||
ActEmail: pr.Poster.Email,
|
||||
OpType: PULL_REQUEST,
|
||||
Content: fmt.Sprintf("%d|%s", pr.Index, pr.Name),
|
||||
RepoID: repo.ID,
|
||||
RepoUserName: repo.Owner.Name,
|
||||
RepoName: repo.Name,
|
||||
IsPrivate: repo.IsPrivate,
|
||||
}
|
||||
if err = notifyWatchers(sess, act); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Test apply patch.
|
||||
repoPath, err := repo.RepoPath()
|
||||
if err != nil {
|
||||
return fmt.Errorf("RepoPath: %v", err)
|
||||
}
|
||||
patchPath := path.Join(repoPath, "pulls", com.ToStr(pr.ID)+".patch")
|
||||
|
||||
os.MkdirAll(path.Dir(patchPath), os.ModePerm)
|
||||
if err = ioutil.WriteFile(patchPath, patch, 0644); err != nil {
|
||||
return fmt.Errorf("save patch: %v", err)
|
||||
}
|
||||
defer os.Remove(patchPath)
|
||||
|
||||
stdout, stderr, err := process.ExecDir(-1, repoPath,
|
||||
fmt.Sprintf("NewPullRequest(git apply --check): %d", repo.ID),
|
||||
"git", "apply", "--check", "-v", patchPath)
|
||||
if err != nil {
|
||||
if strings.Contains(stderr, "fatal:") {
|
||||
return fmt.Errorf("git apply --check: %v - %s", err, stderr)
|
||||
}
|
||||
}
|
||||
pullRepo.CanAutoMerge = !strings.Contains(stdout, "error: patch failed:")
|
||||
|
||||
pullRepo.PullID = pr.ID
|
||||
if _, err = sess.Insert(pullRepo); err != nil {
|
||||
return fmt.Errorf("insert pull repo: %v", err)
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
// GetPullRepoByPullID returns pull repo by given pull ID.
|
||||
func GetPullRepoByPullID(pullID int64) (*PullRepo, error) {
|
||||
pullRepo := new(PullRepo)
|
||||
has, err := x.Where("pull_id=?", pullID).Get(pullRepo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !has {
|
||||
return nil, ErrPullRepoNotExist{0, pullID}
|
||||
}
|
||||
return pullRepo, nil
|
||||
}
|
||||
|
||||
// .____ ___. .__
|
||||
// | | _____ \_ |__ ____ | |
|
||||
// | | \__ \ | __ \_/ __ \| |
|
||||
|
||||
+2
-2
@@ -78,8 +78,8 @@ func init() {
|
||||
tables = append(tables,
|
||||
new(User), new(PublicKey), new(Oauth2), new(AccessToken),
|
||||
new(Repository), new(DeployKey), new(Collaboration), new(Access),
|
||||
new(Watch), new(Star), new(ForkInfo), new(Follow), new(Action),
|
||||
new(Issue), new(Comment), new(Attachment), new(IssueUser),
|
||||
new(Watch), new(Star), new(Follow), new(Action),
|
||||
new(Issue), new(PullRepo), new(Comment), new(Attachment), new(IssueUser),
|
||||
new(Label), new(IssueLabel), new(Milestone),
|
||||
new(Mirror), new(Release), new(LoginSource), new(Webhook),
|
||||
new(UpdateTask), new(HookTask),
|
||||
|
||||
@@ -160,7 +160,6 @@ type Repository struct {
|
||||
IsFork bool `xorm:"NOT NULL DEFAULT false"`
|
||||
ForkID int64
|
||||
BaseRepo *Repository `xorm:"-"`
|
||||
ForkInfo *ForkInfo `xorm:"-"`
|
||||
|
||||
Created time.Time `xorm:"CREATED"`
|
||||
Updated time.Time `xorm:"UPDATED"`
|
||||
@@ -168,15 +167,6 @@ type Repository struct {
|
||||
|
||||
func (repo *Repository) AfterSet(colName string, _ xorm.Cell) {
|
||||
switch colName {
|
||||
case "is_fork":
|
||||
forkInfo := new(ForkInfo)
|
||||
has, err := x.Where("repo_id=?", repo.ID).Get(forkInfo)
|
||||
if err != nil {
|
||||
log.Error(3, "get fork in[%d]: %v", repo.ID, err)
|
||||
return
|
||||
} else if has {
|
||||
repo.ForkInfo = forkInfo
|
||||
}
|
||||
case "updated":
|
||||
repo.Updated = regulateTimeZone(repo.Updated)
|
||||
}
|
||||
@@ -1047,8 +1037,6 @@ func DeleteRepository(uid, repoID int64) error {
|
||||
if repo.IsFork {
|
||||
if _, err = sess.Exec("UPDATE `repository` SET num_forks=num_forks-1 WHERE id=?", repo.ForkID); err != nil {
|
||||
return fmt.Errorf("decrease fork count: %v", err)
|
||||
} else if _, err = sess.Delete(&ForkInfo{RepoID: repo.ID}); err != nil {
|
||||
return fmt.Errorf("delete fork info: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1095,9 +1083,6 @@ func DeleteRepository(uid, repoID int64) error {
|
||||
if _, err = x.Exec("UPDATE `repository` SET fork_id=0,is_fork=? WHERE fork_id=?", false, repo.ID); err != nil {
|
||||
log.Error(4, "reset 'fork_id' and 'is_fork': %v", err)
|
||||
}
|
||||
if _, err = x.Delete(&ForkInfo{ForkID: repo.ID}); err != nil {
|
||||
log.Error(4, "clear fork infos: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1669,13 +1654,6 @@ func IsStaring(uid, repoId int64) bool {
|
||||
// \___ / \____/|__| |__|_ \
|
||||
// \/ \/
|
||||
|
||||
type ForkInfo struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
ForkID int64
|
||||
RepoID int64 `xorm:"UNIQUE"`
|
||||
StartCommitID string `xorm:"VARCHAR(40)"`
|
||||
}
|
||||
|
||||
// HasForkedRepo checks if given user has already forked a repository with given ID.
|
||||
func HasForkedRepo(ownerID, repoID int64) (*Repository, bool) {
|
||||
repo := new(Repository)
|
||||
@@ -1709,13 +1687,6 @@ func ForkRepository(u *User, oldRepo *Repository, name, desc string) (_ *Reposit
|
||||
if _, err = sess.Exec("UPDATE `repository` SET num_forks=num_forks+1 WHERE id=?", oldRepo.ID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// else if _, err = sess.Insert(&ForkInfo{
|
||||
// ForkID: oldRepo.ID,
|
||||
// RepoID: repo.ID,
|
||||
// StartCommitID: "",
|
||||
// }); err != nil {
|
||||
// return nil, fmt.Errorf("insert fork info: %v", err)
|
||||
// }
|
||||
|
||||
oldRepoPath, err := oldRepo.RepoPath()
|
||||
if err != nil {
|
||||
|
||||
@@ -4364,7 +4364,7 @@ func confLocaleLocale_deDeIni() (*asset, error) {
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _confLocaleLocale_enUsIni = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xc4\x7d\xfd\x72\xdc\x48\x8e\xe7\xff\x7c\x0a\xb6\x37\x7c\xee\x8e\x90\xcb\xd1\xdd\x71\x1f\xd1\x61\xbb\x4f\x96\xda\x1f\xb3\x96\xa5\xb5\xe4\x99\x9b\x73\x38\xd8\xac\x22\xab\x8a\xe3\x2a\xb2\x9a\x64\xb9\xac\xd9\xd8\x88\x7b\x8d\x7b\xbd\x7b\x92\x03\x7e\x00\xf2\x83\x64\xc9\xf6\xec\xc6\xdd\x3f\x12\x2b\x13\xf9\x85\x44\x22\x01\x24\x12\x99\xef\x76\x59\x51\x76\x8b\xf4\x49\x7a\x9a\xee\xf2\xaa\xde\x94\x5d\x97\x76\xe5\x66\xf9\x70\xdd\x74\x7d\x59\xa4\x2f\xaa\x9e\x7e\xb7\x9f\xaa\x45\x99\x24\xeb\x66\x5b\x12\xe8\x4b\xfa\x97\x14\x79\xb7\x9e\x37\x79\x5b\x50\xc2\xb9\x7d\x27\xe5\xe7\xdd\xa6\x69\x19\xe8\x37\xf9\x4a\xd6\xe5\x66\xc7\x65\xe8\x5f\xd2\x55\xab\x3a\xab\x6a\xfa\x79\x4d\x5f\xe9\xab\x3a\xe9\x9a\x45\x95\x6f\xb2\x20\x03\x09\x96\xff\x4b\xfa\x53\x5d\xa4\xd7\x7d\xb9\x4b\x1f\x77\xdb\x7c\xb3\x79\x9a\x77\x28\xd2\x97\x69\xbe\x58\x34\xfb\xba\x7f\xfc\x48\x32\xa4\xf2\x66\xdf\x5b\xed\x97\xfb\x5e\xd2\xf6\x3b\x4b\x7a\xb7\x4b\xda\x72\x55\xd1\xc0\x5a\x4a\x7a\xab\x9f\xc9\xa1\x9c\x77\x55\xcf\x9d\xfe\x8b\x7c\x25\x9f\xca\xb6\xab\x1a\xee\xcf\x9f\xe5\x2b\xd9\xe5\x2b\x06\xb8\xa2\x7f\x49\x5f\x6e\x77\x9b\x1c\x05\x6e\xf4\x33\xd9\xe4\xf5\x6a\x2f\x30\xaf\xf5\x33\x59\xb4\x25\x65\x65\x75\x79\xa0\xd4\x33\xfc\x48\xe9\xc7\x6c\x36\x4b\xf6\x84\xd3\x6c\xd7\x36\xcb\x6a\x53\x66\x79\x5d\x64\x5b\xc1\xda\x3b\x4a\x4f\x35\x3d\xa5\xf4\x94\xd3\x31\x8c\xb2\x20\x04\x65\x79\xa7\x63\xa1\xa9\x21\x7c\xe5\x5d\x82\xaa\xea\x7c\x6b\xa5\xf9\x33\x29\xb7\x79\xb5\xe1\x49\x78\xc8\x1f\xd4\xf9\xae\x3b\x34\x98\xaa\x2b\xfd\x24\x44\x64\xfd\xed\xae\x04\x1e\x1e\xde\xd0\x57\xb2\xc8\x77\xfd\x62\x9d\x73\x5f\xe5\x2b\x21\xa0\x5d\x43\x08\x69\xda\x5b\xc0\xd9\x8f\xa4\x69\x57\x79\x5d\xfd\x3d\xef\x05\x49\x97\xc1\xcf\x64\x5b\xb5\x6d\xc3\xf8\xbd\xc0\x47\x42\x23\xce\xb8\x1e\x4a\x79\x43\x98\x08\x6a\xe1\x9c\x6d\xb5\x6a\x05\x95\x9c\x79\x81\x5f\x5c\x0b\xe7\x2d\x9b\xf6\xa3\x66\x3c\xe7\xcf\x41\x51\xea\x84\xe6\xc6\xed\xe7\x35\x21\x5f\x73\x2f\xf0\x23\x02\xe8\x92\xbc\xd8\x12\x2a\x77\x79\x5d\x32\x8e\x4e\xf9\x17\xe1\x85\x7e\x25\x4a\x53\x59\x57\xf6\x7d\x55\xaf\x18\xd9\xa7\x92\x94\x5e\x6b\x52\x12\xe4\xb9\xb4\xdb\x66\xef\xa6\x93\xd2\xff\x4a\x3f\xd3\x2b\xf9\x29\x79\x41\x21\x64\xba\x92\x3c\x92\x2e\x5b\x96\x65\x21\x63\xe9\xd2\xe7\xf4\x9d\xec\xf6\x9b\x0d\x61\xed\x8f\x7d\xd9\xf5\x5c\xe8\x8a\x7e\xd3\xf8\xe5\x77\x52\x75\x1d\x7d\x50\xf2\x2b\x7c\x24\x34\x75\xf5\x02\x83\x39\xc3\x47\x92\xbc\xef\xca\xbc\x5d\xac\x3f\x24\xf2\x1f\x7d\xe5\x0f\xa6\xbd\x63\x93\xca\x84\xa4\x44\x24\x2d\x58\x03\xc9\xa2\x29\xf8\xc7\x19\xfd\xa3\xaa\xab\xba\xeb\x69\xc5\x7d\x48\xf4\x83\xc1\xe4\x4b\x26\xa0\xaf\x7a\x60\x41\x13\xb1\x7c\x3b\x9e\xc1\xf4\x79\xd5\x76\xfd\xc3\xbe\x22\x62\x7d\xbb\xaf\x13\x1e\x1f\xad\xb6\xac\x98\x1b\x13\x7a\xd1\x10\x8a\x90\xdc\xd2\xf8\x2e\x6e\xaf\xff\xe5\xf5\x49\x7a\x45\x9c\x68\xd5\x96\xf4\x9d\x52\x1d\xf4\x8f\xca\xfc\x3c\x4b\xa8\x94\xb5\x74\x9e\xf7\xf9\x3c\xef\x4a\x8f\x56\xce\x14\xea\x76\x79\xa0\x71\xe6\x6a\xe0\x60\x5d\x1f\x8d\x77\x6a\x85\x50\x1d\xba\xae\x5c\x1d\x6f\x78\x71\x51\x3a\x33\x35\x14\xbe\xda\x94\x9c\x4e\x55\xa5\xaf\xde\xbc\xb9\x3c\x7f\x96\x96\xf5\xaa\xaa\xcb\xf4\x50\xf5\xeb\x74\xdf\x2f\xff\x5b\xb6\x2a\xeb\xb2\x25\x1e\xb7\xa8\x52\x5a\x53\x2d\x51\x42\x4a\x84\x2d\x83\x9b\x25\x5d\xb7\xa1\xb5\x0f\xf4\x5e\x5f\xbf\x4e\x2f\x18\xc5\xbb\xbc\x5f\xa3\x23\xfd\x3a\xe9\xfe\xd8\x30\x8a\x5c\x83\x37\xeb\x32\x05\x95\x01\xa8\x59\x1a\x3e\xd2\x42\xfb\x38\x4b\xca\xb6\xcd\x88\x2d\xf5\xb7\x99\x16\xd6\xfa\x86\x90\x52\x05\x91\x4e\xdd\xf4\xe9\xbc\x4c\x51\x66\x96\x24\xd6\x61\xc3\xee\xe9\x6e\xb7\xa9\x16\xb2\xd6\x5f\x48\x9e\x47\x34\xef\x20\x8a\xa5\x10\x0e\x88\xb2\xbc\x00\x5d\xc4\x9e\x79\x3d\xa4\x11\x03\x41\xf9\x75\x49\x0c\x70\xbd\x5f\x09\xdb\xdb\x34\xfb\xe2\x3b\x50\xaa\xf5\xde\x13\x6a\xfa\xb6\xa1\x0e\x03\x3b\x0e\xc0\x37\x71\x4a\x14\xc7\x9b\x56\x5b\x6e\x1b\xe2\x2b\x8e\xd8\x2b\x22\xa8\x43\x45\x99\x34\xd2\x2e\xff\x44\xeb\xad\x6f\xd2\x7e\x5d\x75\x69\x41\xc4\xb6\xe0\x8a\x69\x69\xec\x69\xbb\x10\xb2\x20\x02\x15\xd2\xb0\xb4\x78\x0e\x00\xb5\xdd\x13\x35\xad\xa9\x32\xde\x8c\x78\xe7\xa4\x2a\xa7\xfa\x89\x21\x51\x3d\xa0\x6f\xa2\xdc\x86\xb8\x32\xf3\xcd\x73\x7c\xe8\xef\xb0\x7e\xea\x55\xbe\x5c\x52\xaf\x3a\xa2\x8a\x97\xe9\x62\xd3\x10\x49\xbd\x7b\xfb\xba\x63\x82\x59\x67\xbb\xa6\xc5\x36\x47\x59\x57\xf4\xe9\xd2\x02\x44\x33\x44\xbd\xdf\xce\xe9\xd7\x61\x5d\x11\x07\x00\xda\xb9\x04\xef\xe6\x94\x4a\x4d\xec\x3b\x9a\xc2\x93\x94\x48\x98\x46\x40\x28\x03\x01\xf0\x18\x8a\xaa\xcb\xe7\x34\xf7\x0c\xbe\xa4\x6d\x6b\xdf\x12\x59\xad\xfb\x7e\x67\x2d\xbf\xbc\xb9\xb9\x92\xa6\x5d\xea\x5d\x6d\xe7\x01\x65\x60\x0e\x36\xbc\xf1\xd6\x69\x53\xcf\x40\x24\xfb\x76\x33\xa0\x1f\x1a\xab\xe5\x1c\xc1\x0b\x77\xe1\x11\xff\xb9\xf6\xe8\x01\x9e\x3b\x92\x4e\x0e\xa0\x26\xc2\x71\x89\x0d\x90\x88\xba\xd9\x71\xbd\x01\x55\x5f\x6a\x82\x27\x65\x6c\x9a\x2e\x5f\xb6\x4e\xca\x85\xec\x13\xb0\xff\x2d\x0d\x58\xd9\xc8\xf5\x05\xa1\x01\xbc\x04\xa9\xcb\xb6\xd9\x52\xea\x73\xfa\xe7\x13\x7c\xf7\x2f\xb8\x3e\xc0\xe4\x45\x41\xfc\xad\x3b\x49\xdf\x3e\x3f\x4b\xff\xf3\xcf\x3f\xfd\x34\x4b\x5f\xf5\xbc\x12\x99\x38\xff\xc6\x44\x45\x9f\xb2\x87\x3b\x50\x62\x19\x3d\xd1\xdd\x3Line truncated
|
||||
var _confLocaleLocale_enUsIni = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xc4\x7d\xfd\x72\xdc\x48\x8e\xe7\xff\x7c\x0a\xb6\x37\x7c\xee\x8e\x90\xcb\xd1\xdd\x71\x1f\xd1\x61\xbb\x4f\x96\xda\x1f\xb3\x96\xa5\xb5\xe4\x99\x9b\x73\x38\xd8\xac\x22\xab\x8a\xe3\x2a\xb2\x9a\x64\xb9\xac\xd9\xd8\x88\x7b\x8d\x7b\xbd\x7b\x92\x03\x7e\x00\xf2\x83\x64\xc9\xf6\xec\xc6\xdd\x3f\x12\x2b\x13\xf9\x85\x44\x22\x01\x24\x12\x99\xef\x76\x59\x51\x76\x8b\xf4\x49\x7a\x9a\xee\xf2\xaa\xde\x94\x5d\x97\x76\xe5\x66\xf9\x70\xdd\x74\x7d\x59\xa4\x2f\xaa\x9e\x7e\xb7\x9f\xaa\x45\x99\x24\xeb\x66\x5b\x12\xe8\x4b\xfa\x97\x14\x79\xb7\x9e\x37\x79\x5b\x50\xc2\xb9\x7d\x27\xe5\xe7\xdd\xa6\x69\x19\xe8\x37\xf9\x4a\xd6\xe5\x66\xc7\x65\xe8\x5f\xd2\x55\xab\x3a\xab\x6a\xfa\x79\x4d\x5f\xe9\xab\x3a\xe9\x9a\x45\x95\x6f\xb2\x20\x03\x09\x96\xff\x4b\xfa\x53\x5d\xa4\xd7\x7d\xb9\x4b\x1f\x77\xdb\x7c\xb3\x79\x9a\x77\x28\xd2\x97\x69\xbe\x58\x34\xfb\xba\x7f\xfc\x48\x32\xa4\xf2\x66\xdf\x5b\xed\x97\xfb\x5e\xd2\xf6\x3b\x4b\x7a\xb7\x4b\xda\x72\x55\xd1\xc0\x5a\x4a\x7a\xab\x9f\xc9\xa1\x9c\x77\x55\xcf\x9d\xfe\x8b\x7c\x25\x9f\xca\xb6\xab\x1a\xee\xcf\x9f\xe5\x2b\xd9\xe5\x2b\x06\xb8\xa2\x7f\x49\x5f\x6e\x77\x9b\x1c\x05\x6e\xf4\x33\xd9\xe4\xf5\x6a\x2f\x30\xaf\xf5\x33\x59\xb4\x25\x65\x65\x75\x79\xa0\xd4\x33\xfc\x48\xe9\xc7\x6c\x36\x4b\xf6\x84\xd3\x6c\xd7\x36\xcb\x6a\x53\x66\x79\x5d\x64\x5b\xc1\xda\x3b\x4a\x4f\x35\x3d\xa5\xf4\x94\xd3\x31\x8c\xb2\x20\x04\x65\x79\xa7\x63\xa1\xa9\x21\x7c\xe5\x5d\x82\xaa\xea\x7c\x6b\xa5\xf9\x33\x29\xb7\x79\xb5\xe1\x49\x78\xc8\x1f\xd4\xf9\xae\x3b\x34\x98\xaa\x2b\xfd\x24\x44\x64\xfd\xed\xae\x04\x1e\x1e\xde\xd0\x57\xb2\xc8\x77\xfd\x62\x9d\x73\x5f\xe5\x2b\x21\xa0\x5d\x43\x08\x69\xda\x5b\xc0\xd9\x8f\xa4\x69\x57\x79\x5d\xfd\x3d\xef\x05\x49\x97\xc1\xcf\x64\x5b\xb5\x6d\xc3\xf8\xbd\xc0\x47\x42\x23\xce\xb8\x1e\x4a\x79\x43\x98\x08\x6a\xe1\x9c\x6d\xb5\x6a\x05\x95\x9c\x79\x81\x5f\x5c\x0b\xe7\x2d\x9b\xf6\xa3\x66\x3c\xe7\xcf\x41\x51\xea\x84\xe6\xc6\xed\xe7\x35\x21\x5f\x73\x2f\xf0\x23\x02\xe8\x92\xbc\xd8\x12\x2a\x77\x79\x5d\x32\x8e\x4e\xf9\x17\xe1\x85\x7e\x25\x4a\x53\x59\x57\xf6\x7d\x55\xaf\x18\xd9\xa7\x92\x94\x5e\x6b\x52\x12\xe4\xb9\xb4\xdb\x66\xef\xa6\x93\xd2\xff\x4a\x3f\xd3\x2b\xf9\x29\x79\x41\x21\x64\xba\x92\x3c\x92\x2e\x5b\x96\x65\x21\x63\xe9\xd2\xe7\xf4\x9d\xec\xf6\x9b\x0d\x61\xed\x8f\x7d\xd9\xf5\x5c\xe8\x8a\x7e\xd3\xf8\xe5\x77\x52\x75\x1d\x7d\x50\xf2\x2b\x7c\x24\x34\x75\xf5\x02\x83\x39\xc3\x47\x92\xbc\xef\xca\xbc\x5d\xac\x3f\x24\xf2\x1f\x7d\xe5\x0f\xa6\xbd\x63\x93\xca\x84\xa4\x44\x24\x2d\x58\x03\xc9\xa2\x29\xf8\xc7\x19\xfd\xa3\xaa\xab\xba\xeb\x69\xc5\x7d\x48\xf4\x83\xc1\xe4\x4b\x26\xa0\xaf\x7a\x60\x41\x13\xb1\x7c\x3b\x9e\xc1\xf4\x79\xd5\x76\xfd\xc3\xbe\x22\x62\x7d\xbb\xaf\x13\x1e\x1f\xad\xb6\xac\x98\x1b\x13\x7a\xd1\x10\x8a\x90\xdc\xd2\xf8\x2e\x6e\xaf\xff\xe5\xf5\x49\x7a\x45\x9c\x68\xd5\x96\xf4\x9d\x52\x1d\xf4\x8f\xca\xfc\x3c\x4b\xa8\x94\xb5\x74\x9e\xf7\xf9\x3c\xef\x4a\x8f\x56\xce\x14\xea\x76\x79\xa0\x71\xe6\x6a\xe0\x60\x5d\x1f\x8d\x77\x6a\x85\x50\x1d\xba\xae\x5c\x1d\x6f\x78\x71\x51\x3a\x33\x35\x14\xbe\xda\x94\x9c\x4e\x55\xa5\xaf\xde\xbc\xb9\x3c\x7f\x96\x96\xf5\xaa\xaa\xcb\xf4\x50\xf5\xeb\x74\xdf\x2f\xff\x5b\xb6\x2a\xeb\xb2\x25\x1e\xb7\xa8\x52\x5a\x53\x2d\x51\x42\x4a\x84\x2d\x83\x9b\x25\x5d\xb7\xa1\xb5\x0f\xf4\x5e\x5f\xbf\x4e\x2f\x18\xc5\xbb\xbc\x5f\xa3\x23\xfd\x3a\xe9\xfe\xd8\x30\x8a\x5c\x83\x37\xeb\x32\x05\x95\x01\xa8\x59\x1a\x3e\xd2\x42\xfb\x38\x4b\xca\xb6\xcd\x88\x2d\xf5\xb7\x99\x16\xd6\xfa\x86\x90\x52\x05\x91\x4e\xdd\xf4\xe9\xbc\x4c\x51\x66\x96\x24\xd6\x61\xc3\xee\xe9\x6e\xb7\xa9\x16\xb2\xd6\x5f\x48\x9e\x47\x34\xef\x20\x8a\xa5\x10\x0e\x88\xb2\xbc\x00\x5d\xc4\x9e\x79\x3d\xa4\x11\x03\x41\xf9\x75\x49\x0c\x70\xbd\x5f\x09\xdb\xdb\x34\xfb\xe2\x3b\x50\xaa\xf5\xde\x13\x6a\xfa\xb6\xa1\x0e\x03\x3b\x0e\xc0\x37\x71\x4a\x14\xc7\x9b\x56\x5b\x6e\x1b\xe2\x2b\x8e\xd8\x2b\x22\xa8\x43\x45\x99\x34\xd2\x2e\xff\x44\xeb\xad\x6f\xd2\x7e\x5d\x75\x69\x41\xc4\xb6\xe0\x8a\x69\x69\xec\x69\xbb\x10\xb2\x20\x02\x15\xd2\xb0\xb4\x78\x0e\x00\xb5\xdd\x13\x35\xad\xa9\x32\xde\x8c\x78\xe7\xa4\x2a\xa7\xfa\x89\x21\x51\x3d\xa0\x6f\xa2\xdc\x86\xb8\x32\xf3\xcd\x73\x7c\xe8\xef\xb0\x7e\xea\x55\xbe\x5c\x52\xaf\x3a\xa2\x8a\x97\xe9\x62\xd3\x10\x49\xbd\x7b\xfb\xba\x63\x82\x59\x67\xbb\xa6\xc5\x36\x47\x59\x57\xf4\xe9\xd2\x02\x44\x33\x44\xbd\xdf\xce\xe9\xd7\x61\x5d\x11\x07\x00\xda\xb9\x04\xef\xe6\x94\x4a\x4d\xec\x3b\x9a\xc2\x93\x94\x48\x98\x46\x40\x28\x03\x01\xf0\x18\x8a\xaa\xcb\xe7\x34\xf7\x0c\xbe\xa4\x6d\x6b\xdf\x12\x59\xad\xfb\x7e\x67\x2d\xbf\xbc\xb9\xb9\x92\xa6\x5d\xea\x5d\x6d\xe7\x01\x65\x60\x0e\x36\xbc\xf1\xd6\x69\x53\xcf\x40\x24\xfb\x76\x33\xa0\x1f\x1a\xab\xe5\x1c\xc1\x0b\x77\xe1\x11\xff\xb9\xf6\xe8\x01\x9e\x3b\x92\x4e\x0e\xa0\x26\xc2\x71\x89\x0d\x90\x88\xba\xd9\x71\xbd\x01\x55\x5f\x6a\x82\x27\x65\x6c\x9a\x2e\x5f\xb6\x4e\xca\x85\xec\x13\xb0\xff\x2d\x0d\x58\xd9\xc8\xf5\x05\xa1\x01\xbc\x04\xa9\xcb\xb6\xd9\x52\xea\x73\xfa\xe7\x13\x7c\xf7\x2f\xb8\x3e\xc0\xe4\x45\x41\xfc\xad\x3b\x49\xdf\x3e\x3f\x4b\xff\xf3\xcf\x3f\xfd\x34\x4b\x5f\xf5\xbc\x12\x99\x38\xff\xc6\x44\x45\x9f\xb2\x87\x3b\x50\x62\x19\x3d\xd1\xdd\x3Line truncated
|
||||
|
||||
func confLocaleLocale_enUsIniBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
@@ -4379,7 +4379,7 @@ func confLocaleLocale_enUsIni() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "conf/locale/locale_en-US.ini", size: 40911, mode: os.FileMode(420), modTime: time.Unix(1441119631, 0)}
|
||||
info := bindataFileInfo{name: "conf/locale/locale_en-US.ini", size: 41009, mode: os.FileMode(420), modTime: time.Unix(1441146568, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
// Copyright 2015 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package git
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
)
|
||||
|
||||
type PullRequestInfo struct {
|
||||
MergeBase string
|
||||
Commits *list.List
|
||||
// Diff *Diff
|
||||
NumFiles int
|
||||
}
|
||||
|
||||
// GetPullRequestInfo generates and returns pull request information
|
||||
// between base and head branches of repositories.
|
||||
func (repo *Repository) GetPullRequestInfo(basePath, baseBranch, headBranch string) (*PullRequestInfo, error) {
|
||||
// Add a temporary remote.
|
||||
tmpRemote := com.ToStr(time.Now().UnixNano())
|
||||
_, stderr, err := com.ExecCmdDir(repo.Path, "git", "remote", "add", "-f", tmpRemote, basePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("add base as remote: %v", concatenateError(err, stderr))
|
||||
}
|
||||
defer func() {
|
||||
com.ExecCmdDir(repo.Path, "git", "remote", "remove", tmpRemote)
|
||||
}()
|
||||
|
||||
prInfo := new(PullRequestInfo)
|
||||
|
||||
var stdout string
|
||||
remoteBranch := "remotes/" + tmpRemote + "/" + baseBranch
|
||||
// Get merge base commit.
|
||||
stdout, stderr, err = com.ExecCmdDir(repo.Path, "git", "merge-base", remoteBranch, headBranch)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get merge base: %v", concatenateError(err, stderr))
|
||||
}
|
||||
prInfo.MergeBase = strings.TrimSpace(stdout)
|
||||
|
||||
stdout, stderr, err = com.ExecCmdDir(repo.Path, "git", "log", remoteBranch+"..."+headBranch, prettyLogFormat)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list diff logs: %v", concatenateError(err, stderr))
|
||||
}
|
||||
prInfo.Commits, err = parsePrettyFormatLog(repo, []byte(stdout))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsePrettyFormatLog: %v", err)
|
||||
}
|
||||
|
||||
// Count number of changed files.
|
||||
stdout, stderr, err = com.ExecCmdDir(repo.Path, "git", "diff", "--name-only", remoteBranch+"..."+headBranch)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list changed files: %v", concatenateError(err, stderr))
|
||||
}
|
||||
prInfo.NumFiles = len(strings.Split(stdout, "\n")) - 1
|
||||
|
||||
return prInfo, nil
|
||||
}
|
||||
|
||||
// GetPatch generates and returns patch data between given branches.
|
||||
func (repo *Repository) GetPatch(basePath, baseBranch, headBranch string) ([]byte, error) {
|
||||
// Add a temporary remote.
|
||||
tmpRemote := com.ToStr(time.Now().UnixNano())
|
||||
_, stderr, err := com.ExecCmdDirBytes(repo.Path, "git", "remote", "add", "-f", tmpRemote, basePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("add base as remote: %v", concatenateError(err, string(stderr)))
|
||||
}
|
||||
defer func() {
|
||||
com.ExecCmdDir(repo.Path, "git", "remote", "remove", tmpRemote)
|
||||
}()
|
||||
|
||||
var stdout []byte
|
||||
remoteBranch := "remotes/" + tmpRemote + "/" + baseBranch
|
||||
stdout, stderr, err = com.ExecCmdDirBytes(repo.Path, "git", "diff", "-p", remoteBranch, headBranch)
|
||||
if err != nil {
|
||||
return nil, concatenateError(err, string(stderr))
|
||||
}
|
||||
|
||||
return stdout, nil
|
||||
}
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
@font-face{font-family:octicons;src:url(../fonts/octicons.eot?#iefix&v=396334ee3da78f4302d25c758ae3e3ce5dc3c97d) format('embedded-opentype'),url(../fonts/octicons.woff?v=396334ee3da78f4302d25c758ae3e3ce5dc3c97d) format('woff'),url(../fonts/octicons.ttf?v=396334ee3da78f4302d25c758ae3e3ce5dc3c97d) format('truetype'),url(../fonts/octicons.svg?v=396334ee3da78f4302d25c758ae3e3ce5dc3c97d#octicons) format('svg');font-weight:400;font-style:normal}.mega-octicon,.octicon{font:normal normal normal 16px/1 octicons;display:inline-block;text-decoration:none;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.mega-octicon{font-size:32px}.octicon-alert:before{content:'\f02d'}.octicon-arrow-down:before{content:'\f03f'}.octicon-arrow-left:before{content:'\f040'}.octicon-arrow-right:before{content:'\f03e'}.octicon-arrow-small-down:before{content:'\f0a0'}.octicon-arrow-small-left:before{content:'\f0a1'}.octicon-arrow-small-right:before{content:'\f071'}.octicon-arrow-small-up:before{content:'\f09f'}.octicon-arrow-up:before{content:'\f03d'}.octicon-beaker:before,.octicon-microscope:before{content:'\f0dd'}.octicon-bell:before{content:'\f0de'}.octicon-book:before{content:'\f007'}.octicon-bookmark:before{content:'\f07b'}.octicon-briefcase:before{content:'\f0d3'}.octicon-broadcast:before{content:'\f048'}.octicon-browser:before{content:'\f0c5'}.octicon-bug:before{content:'\f091'}.octicon-calendar:before{content:'\f068'}.octicon-check:before{content:'\f03a'}.octicon-checklist:before{content:'\f076'}.octicon-chevron-down:before{content:'\f0a3'}.octicon-chevron-left:before{content:'\f0a4'}.octicon-chevron-right:before{content:'\f078'}.octicon-chevron-up:before{content:'\f0a2'}.octicon-circle-slash:before{content:'\f084'}.octicon-circuit-board:before{content:'\f0d6'}.octicon-clippy:before{content:'\f035'}.octicon-clock:before{content:'\f046'}.octicon-cloud-download:before{content:'\f00b'}.octicon-cloud-upload:before{content:'\f00c'}.octicon-code:before{content:'\f05f'}.octicon-color-mode:before{content:'\f065'}.octicon-comment-add:before,.octicon-comment:before{content:'\f02b'}.octicon-comment-discussion:before{content:'\f04f'}.octicon-credit-card:before{content:'\f045'}.octicon-dash:before{content:'\f0ca'}.octicon-dashboard:before{content:'\f07d'}.octicon-database:before{content:'\f096'}.octicon-clone:before,.octicon-desktop-download:before{content:'\f0dc'}.octicon-device-camera:before{content:'\f056'}.octicon-device-camera-video:before{content:'\f057'}.octicon-device-desktop:before{content:'\f27c'}.octicon-device-mobile:before{content:'\f038'}.octicon-diff:before{content:'\f04d'}.octicon-diff-added:before{content:'\f06b'}.octicon-diff-ignored:before{content:'\f099'}.octicon-diff-modified:before{content:'\f06d'}.octicon-diff-removed:before{content:'\f06c'}.octicon-diff-renamed:before{content:'\f06e'}.octicon-ellipsis:before{content:'\f09a'}.octicon-eye-unwatch:before,.octicon-eye-watch:before,.octicon-eye:before{content:'\f04e'}.octicon-file-binary:before{content:'\f094'}.octicon-file-code:before{content:'\f010'}.octicon-file-directory:before{content:'\f016'}.octicon-file-media:before{content:'\f012'}.octicon-file-pdf:before{content:'\f014'}.octicon-file-submodule:before{content:'\f017'}.octicon-file-symlink-directory:before{content:'\f0b1'}.octicon-file-symlink-file:before{content:'\f0b0'}.octicon-file-text:before{content:'\f011'}.octicon-file-zip:before{content:'\f013'}.octicon-flame:before{content:'\f0d2'}.octicon-fold:before{content:'\f0cc'}.octicon-gear:before{content:'\f02f'}.octicon-gift:before{content:'\f042'}.octicon-gist:before{content:'\f00e'}.octicon-gist-secret:before{content:'\f08c'}.octicon-git-branch-create:before,.octicon-git-branch-delete:before,.octicon-git-branch:before{content:'\f020'}.octicon-git-commit:before{content:'\f01f'}.octicon-git-compare:before{content:'\f0ac'}.octicon-git-merge:before{content:'\f023'}.octicon-git-pull-request-abandoned:before,.octicon-git-pull-request:before{content:'\f009'}.octicon-globe:before{content:'\f0b6'}.octicon-graph:before{content:'\f043'}.octicon-heart:before{content:'\2665'}.octicon-history:before{content:'\f07e'}.octicon-home:before{content:'\f08d'}.octicon-horizontal-rule:before{content:'\f070'}.octicon-hubot:before{content:'\f09d'}.octicon-inbox:before{content:'\f0cf'}.octicon-info:before{content:'\f059'}.octicon-issue-closed:before{content:'\f028'}.octicon-issue-opened:before{content:'\f026'}.octicon-issue-reopened:before{content:'\f027'}.octicon-jersey:before{content:'\f019'}.octicon-key:before{content:'\f049'}.octicon-keyboard:before{content:'\f00d'}.octicon-law:before{content:'\f0d8'}.octicon-light-bulb:before{content:'\f000'}.octicon-link:before{content:'\f05c'}.octicon-link-external:before{content:'\f07f'}.octicon-list-ordered:before{content:'\f062'}.octicon-list-unordered:before{content:'\f061'}.octicon-location:before{content:'\f060'}.octicon-gLine truncated
|
||||
@font-face{font-family:octicons;src:url(../fonts/octicons.eot?#iefix&v=396334ee3da78f4302d25c758ae3e3ce5dc3c97d) format('embedded-opentype'),url(../fonts/octicons.woff?v=396334ee3da78f4302d25c758ae3e3ce5dc3c97d) format('woff'),url(../fonts/octicons.ttf?v=396334ee3da78f4302d25c758ae3e3ce5dc3c97d) format('truetype'),url(../fonts/octicons.svg?v=396334ee3da78f4302d25c758ae3e3ce5dc3c97d#octicons) format('svg');font-weight:400;font-style:normal}.mega-octicon,.octicon{font:normal normal normal 16px/1 octicons;display:inline-block;text-decoration:none;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.mega-octicon{font-size:32px}.octicon-alert:before{content:'\f02d'}.octicon-arrow-down:before{content:'\f03f'}.octicon-arrow-left:before{content:'\f040'}.octicon-arrow-right:before{content:'\f03e'}.octicon-arrow-small-down:before{content:'\f0a0'}.octicon-arrow-small-left:before{content:'\f0a1'}.octicon-arrow-small-right:before{content:'\f071'}.octicon-arrow-small-up:before{content:'\f09f'}.octicon-arrow-up:before{content:'\f03d'}.octicon-beaker:before,.octicon-microscope:before{content:'\f0dd'}.octicon-bell:before{content:'\f0de'}.octicon-book:before{content:'\f007'}.octicon-bookmark:before{content:'\f07b'}.octicon-briefcase:before{content:'\f0d3'}.octicon-broadcast:before{content:'\f048'}.octicon-browser:before{content:'\f0c5'}.octicon-bug:before{content:'\f091'}.octicon-calendar:before{content:'\f068'}.octicon-check:before{content:'\f03a'}.octicon-checklist:before{content:'\f076'}.octicon-chevron-down:before{content:'\f0a3'}.octicon-chevron-left:before{content:'\f0a4'}.octicon-chevron-right:before{content:'\f078'}.octicon-chevron-up:before{content:'\f0a2'}.octicon-circle-slash:before{content:'\f084'}.octicon-circuit-board:before{content:'\f0d6'}.octicon-clippy:before{content:'\f035'}.octicon-clock:before{content:'\f046'}.octicon-cloud-download:before{content:'\f00b'}.octicon-cloud-upload:before{content:'\f00c'}.octicon-code:before{content:'\f05f'}.octicon-color-mode:before{content:'\f065'}.octicon-comment-add:before,.octicon-comment:before{content:'\f02b'}.octicon-comment-discussion:before{content:'\f04f'}.octicon-credit-card:before{content:'\f045'}.octicon-dash:before{content:'\f0ca'}.octicon-dashboard:before{content:'\f07d'}.octicon-database:before{content:'\f096'}.octicon-clone:before,.octicon-desktop-download:before{content:'\f0dc'}.octicon-device-camera:before{content:'\f056'}.octicon-device-camera-video:before{content:'\f057'}.octicon-device-desktop:before{content:'\f27c'}.octicon-device-mobile:before{content:'\f038'}.octicon-diff:before{content:'\f04d'}.octicon-diff-added:before{content:'\f06b'}.octicon-diff-ignored:before{content:'\f099'}.octicon-diff-modified:before{content:'\f06d'}.octicon-diff-removed:before{content:'\f06c'}.octicon-diff-renamed:before{content:'\f06e'}.octicon-ellipsis:before{content:'\f09a'}.octicon-eye-unwatch:before,.octicon-eye-watch:before,.octicon-eye:before{content:'\f04e'}.octicon-file-binary:before{content:'\f094'}.octicon-file-code:before{content:'\f010'}.octicon-file-directory:before{content:'\f016'}.octicon-file-media:before{content:'\f012'}.octicon-file-pdf:before{content:'\f014'}.octicon-file-submodule:before{content:'\f017'}.octicon-file-symlink-directory:before{content:'\f0b1'}.octicon-file-symlink-file:before{content:'\f0b0'}.octicon-file-text:before{content:'\f011'}.octicon-file-zip:before{content:'\f013'}.octicon-flame:before{content:'\f0d2'}.octicon-fold:before{content:'\f0cc'}.octicon-gear:before{content:'\f02f'}.octicon-gift:before{content:'\f042'}.octicon-gist:before{content:'\f00e'}.octicon-gist-secret:before{content:'\f08c'}.octicon-git-branch-create:before,.octicon-git-branch-delete:before,.octicon-git-branch:before{content:'\f020'}.octicon-git-commit:before{content:'\f01f'}.octicon-git-compare:before{content:'\f0ac'}.octicon-git-merge:before{content:'\f023'}.octicon-git-pull-request-abandoned:before,.octicon-git-pull-request:before{content:'\f009'}.octicon-globe:before{content:'\f0b6'}.octicon-graph:before{content:'\f043'}.octicon-heart:before{content:'\2665'}.octicon-history:before{content:'\f07e'}.octicon-home:before{content:'\f08d'}.octicon-horizontal-rule:before{content:'\f070'}.octicon-hubot:before{content:'\f09d'}.octicon-inbox:before{content:'\f0cf'}.octicon-info:before{content:'\f059'}.octicon-issue-closed:before{content:'\f028'}.octicon-issue-opened:before{content:'\f026'}.octicon-issue-reopened:before{content:'\f027'}.octicon-jersey:before{content:'\f019'}.octicon-key:before{content:'\f049'}.octicon-keyboard:before{content:'\f00d'}.octicon-law:before{content:'\f0d8'}.octicon-light-bulb:before{content:'\f000'}.octicon-link:before{content:'\f05c'}.octicon-link-external:before{content:'\f07f'}.octicon-list-ordered:before{content:'\f062'}.octicon-list-unordered:before{content:'\f061'}.octicon-location:before{content:'\f060'}.octicon-gLine truncated
|
||||
@@ -152,6 +152,22 @@
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
.pull {
|
||||
&.tabular.menu {
|
||||
margin-bottom: 10px;
|
||||
.octicon {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
&.tab.segment {
|
||||
border: none;
|
||||
padding: 0;
|
||||
padding-top: 10px;
|
||||
box-shadow: none;
|
||||
background-color: inherit;
|
||||
}
|
||||
}
|
||||
.comment-list {
|
||||
&:before {
|
||||
display: block;
|
||||
|
||||
@@ -297,6 +297,7 @@ func CompareDiff(ctx *middleware.Context) {
|
||||
}
|
||||
commits = models.ValidateCommitsWithEmails(commits)
|
||||
|
||||
ctx.Data["CommitRepoLink"] = ctx.Repo.RepoLink
|
||||
ctx.Data["Commits"] = commits
|
||||
ctx.Data["CommitCount"] = commits.Len()
|
||||
ctx.Data["BeforeCommitID"] = beforeCommitID
|
||||
|
||||
+119
-77
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/auth"
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/git"
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/mailer"
|
||||
"github.com/gogits/gogs/modules/middleware"
|
||||
@@ -185,11 +186,32 @@ func Issues(ctx *middleware.Context) {
|
||||
}
|
||||
|
||||
func renderAttachmentSettings(ctx *middleware.Context) {
|
||||
ctx.Data["RequireDropzone"] = true
|
||||
ctx.Data["IsAttachmentEnabled"] = setting.AttachmentEnabled
|
||||
ctx.Data["AttachmentAllowedTypes"] = setting.AttachmentAllowedTypes
|
||||
ctx.Data["AttachmentMaxFiles"] = setting.AttachmentMaxFiles
|
||||
}
|
||||
|
||||
func RetrieveRepoMilestonesAndAssignees(ctx *middleware.Context, repo *models.Repository) {
|
||||
var err error
|
||||
ctx.Data["OpenMilestones"], err = models.GetMilestones(repo.ID, -1, false)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "GetMilestones: %v", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["ClosedMilestones"], err = models.GetMilestones(repo.ID, -1, true)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "GetMilestones: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["Assignees"], err = repo.GetAssignees()
|
||||
if err != nil {
|
||||
ctx.Handle(500, "GetAssignees: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func RetrieveRepoMetas(ctx *middleware.Context, repo *models.Repository) []*models.Label {
|
||||
if !ctx.Repo.IsAdmin() {
|
||||
return nil
|
||||
@@ -202,29 +224,17 @@ func RetrieveRepoMetas(ctx *middleware.Context, repo *models.Repository) []*mode
|
||||
}
|
||||
ctx.Data["Labels"] = labels
|
||||
|
||||
ctx.Data["OpenMilestones"], err = models.GetMilestones(repo.ID, -1, false)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "GetMilestones: %v", err)
|
||||
return nil
|
||||
}
|
||||
ctx.Data["ClosedMilestones"], err = models.GetMilestones(repo.ID, -1, true)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "GetMilestones: %v", err)
|
||||
RetrieveRepoMilestonesAndAssignees(ctx, repo)
|
||||
if ctx.Written() {
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx.Data["Assignees"], err = repo.GetAssignees()
|
||||
if err != nil {
|
||||
ctx.Handle(500, "GetAssignees: %v", err)
|
||||
return nil
|
||||
}
|
||||
return labels
|
||||
}
|
||||
|
||||
func NewIssue(ctx *middleware.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("repo.issues.new")
|
||||
ctx.Data["PageIsIssueList"] = true
|
||||
ctx.Data["RequireDropzone"] = true
|
||||
renderAttachmentSettings(ctx)
|
||||
|
||||
RetrieveRepoMetas(ctx, ctx.Repo.Repository)
|
||||
@@ -235,62 +245,73 @@ func NewIssue(ctx *middleware.Context) {
|
||||
ctx.HTML(200, ISSUE_NEW)
|
||||
}
|
||||
|
||||
func ValidateRepoMetas(ctx *middleware.Context, form auth.CreateIssueForm) ([]int64, int64, int64) {
|
||||
var (
|
||||
repo = ctx.Repo.Repository
|
||||
err error
|
||||
)
|
||||
|
||||
labels := RetrieveRepoMetas(ctx, ctx.Repo.Repository)
|
||||
if ctx.Written() {
|
||||
return nil, 0, 0
|
||||
}
|
||||
|
||||
if !ctx.Repo.IsAdmin() {
|
||||
return nil, 0, 0
|
||||
}
|
||||
|
||||
// Check labels.
|
||||
labelIDs := base.StringsToInt64s(strings.Split(form.LabelIDs, ","))
|
||||
labelIDMark := base.Int64sToMap(labelIDs)
|
||||
hasSelected := false
|
||||
for i := range labels {
|
||||
if labelIDMark[labels[i].ID] {
|
||||
labels[i].IsChecked = true
|
||||
hasSelected = true
|
||||
}
|
||||
}
|
||||
ctx.Data["HasSelectedLabel"] = hasSelected
|
||||
ctx.Data["label_ids"] = form.LabelIDs
|
||||
ctx.Data["Labels"] = labels
|
||||
|
||||
// Check milestone.
|
||||
milestoneID := form.MilestoneID
|
||||
if milestoneID > 0 {
|
||||
ctx.Data["Milestone"], err = repo.GetMilestoneByID(milestoneID)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "GetMilestoneByID: %v", err)
|
||||
return nil, 0, 0
|
||||
}
|
||||
ctx.Data["milestone_id"] = milestoneID
|
||||
}
|
||||
|
||||
// Check assignee.
|
||||
assigneeID := form.AssigneeID
|
||||
if assigneeID > 0 {
|
||||
ctx.Data["Assignee"], err = repo.GetAssigneeByID(assigneeID)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "GetAssigneeByID: %v", err)
|
||||
return nil, 0, 0
|
||||
}
|
||||
ctx.Data["assignee_id"] = assigneeID
|
||||
}
|
||||
|
||||
return labelIDs, milestoneID, assigneeID
|
||||
}
|
||||
|
||||
func NewIssuePost(ctx *middleware.Context, form auth.CreateIssueForm) {
|
||||
ctx.Data["Title"] = ctx.Tr("repo.issues.new")
|
||||
ctx.Data["PageIsIssueList"] = true
|
||||
ctx.Data["RequireDropzone"] = true
|
||||
renderAttachmentSettings(ctx)
|
||||
|
||||
var (
|
||||
repo = ctx.Repo.Repository
|
||||
labelIDs []int64
|
||||
milestoneID int64
|
||||
assigneeID int64
|
||||
attachments []string
|
||||
err error
|
||||
)
|
||||
|
||||
if ctx.Repo.IsAdmin() {
|
||||
labels := RetrieveRepoMetas(ctx, repo)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
// Check labels.
|
||||
labelIDs = base.StringsToInt64s(strings.Split(form.LabelIDs, ","))
|
||||
labelIDMark := base.Int64sToMap(labelIDs)
|
||||
hasSelected := false
|
||||
for i := range labels {
|
||||
if labelIDMark[labels[i].ID] {
|
||||
labels[i].IsChecked = true
|
||||
hasSelected = true
|
||||
}
|
||||
}
|
||||
ctx.Data["HasSelectedLabel"] = hasSelected
|
||||
ctx.Data["label_ids"] = form.LabelIDs
|
||||
ctx.Data["Labels"] = labels
|
||||
|
||||
// Check milestone.
|
||||
milestoneID = form.MilestoneID
|
||||
if milestoneID > 0 {
|
||||
ctx.Data["Milestone"], err = repo.GetMilestoneByID(milestoneID)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "GetMilestoneByID: %v", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["milestone_id"] = milestoneID
|
||||
}
|
||||
|
||||
// Check assignee.
|
||||
assigneeID = form.AssigneeID
|
||||
if assigneeID > 0 {
|
||||
ctx.Data["Assignee"], err = repo.GetAssigneeByID(assigneeID)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "GetAssigneeByID: %v", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["assignee_id"] = assigneeID
|
||||
}
|
||||
labelIDs, milestoneID, assigneeID := ValidateRepoMetas(ctx, form)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
if setting.AttachmentEnabled {
|
||||
@@ -332,7 +353,7 @@ func NewIssuePost(ctx *middleware.Context, form auth.CreateIssueForm) {
|
||||
|
||||
// Mail watchers and mentions.
|
||||
if setting.Service.EnableNotifyMail {
|
||||
tos, err := mailer.SendIssueNotifyMail(ctx.User, ctx.Repo.Owner, ctx.Repo.Repository, issue)
|
||||
tos, err := mailer.SendIssueNotifyMail(ctx.User, ctx.Repo.Owner, repo, issue)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "SendIssueNotifyMail", err)
|
||||
return
|
||||
@@ -348,13 +369,13 @@ func NewIssuePost(ctx *middleware.Context, form auth.CreateIssueForm) {
|
||||
newTos = append(newTos, m)
|
||||
}
|
||||
if err = mailer.SendIssueMentionMail(ctx.Render, ctx.User, ctx.Repo.Owner,
|
||||
ctx.Repo.Repository, issue, models.GetUserEmailsByNames(newTos)); err != nil {
|
||||
repo, issue, models.GetUserEmailsByNames(newTos)); err != nil {
|
||||
ctx.Handle(500, "SendIssueMentionMail", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
log.Trace("Issue created: %d/%d", ctx.Repo.Repository.ID, issue.ID)
|
||||
log.Trace("Issue created: %d/%d", repo.ID, issue.ID)
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/issues/" + com.ToStr(issue.Index))
|
||||
}
|
||||
|
||||
@@ -421,6 +442,15 @@ func ViewIssue(ctx *middleware.Context) {
|
||||
}
|
||||
ctx.Data["Title"] = issue.Name
|
||||
|
||||
// Make sure type and URL matches.
|
||||
if ctx.Params(":type") == "issues" && issue.IsPull {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(issue.Index))
|
||||
return
|
||||
} else if ctx.Params(":type") == "pulls" && !issue.IsPull {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/issues/" + com.ToStr(issue.Index))
|
||||
return
|
||||
}
|
||||
|
||||
if err = issue.GetPoster(); err != nil {
|
||||
ctx.Handle(500, "GetPoster", err)
|
||||
return
|
||||
@@ -429,6 +459,30 @@ func ViewIssue(ctx *middleware.Context) {
|
||||
|
||||
repo := ctx.Repo.Repository
|
||||
|
||||
// Get more information if it's a pull request.
|
||||
if issue.IsPull {
|
||||
headRepoPath, err := issue.PullRepo.HeadRepo.RepoPath()
|
||||
if err != nil {
|
||||
ctx.Handle(500, "PullRepo.HeadRepo.RepoPath", err)
|
||||
return
|
||||
}
|
||||
|
||||
headGitRepo, err := git.OpenRepository(headRepoPath)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "OpenRepository", err)
|
||||
return
|
||||
}
|
||||
|
||||
prInfo, err := headGitRepo.GetPullRequestInfo(models.RepoPath(repo.Owner.Name, repo.Name),
|
||||
issue.PullRepo.BaseBranch, issue.PullRepo.HeadBarcnh)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "GetPullRequestInfo", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["NumCommits"] = prInfo.Commits.Len()
|
||||
ctx.Data["NumFiles"] = prInfo.NumFiles
|
||||
}
|
||||
|
||||
// Metas.
|
||||
// Check labels.
|
||||
if err = issue.GetLabels(); err != nil {
|
||||
@@ -456,20 +510,8 @@ func ViewIssue(ctx *middleware.Context) {
|
||||
|
||||
// Check milestone and assignee.
|
||||
if ctx.Repo.IsAdmin() {
|
||||
ctx.Data["OpenMilestones"], err = models.GetMilestones(repo.ID, -1, false)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "GetMilestones: %v", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["ClosedMilestones"], err = models.GetMilestones(repo.ID, -1, true)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "GetMilestones: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["Assignees"], err = repo.GetAssignees()
|
||||
if err != nil {
|
||||
ctx.Handle(500, "GetAssignees: %v", err)
|
||||
RetrieveRepoMilestonesAndAssignees(ctx, repo)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
+203
-25
@@ -5,9 +5,11 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/auth"
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
@@ -124,17 +126,19 @@ func ForkPost(ctx *middleware.Context, form auth.CreateRepoForm) {
|
||||
ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + repo.Name)
|
||||
}
|
||||
|
||||
func CompareAndPullRequest(ctx *middleware.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("repo.pulls.compare_changes")
|
||||
ctx.Data["PageIsComparePull"] = true
|
||||
func Pulls(ctx *middleware.Context) {
|
||||
ctx.Data["IsRepoToolbarPulls"] = true
|
||||
ctx.HTML(200, PULLS)
|
||||
}
|
||||
|
||||
repo := ctx.Repo.Repository
|
||||
// func ViewPull
|
||||
|
||||
func ParseCompareInfo(ctx *middleware.Context) (*models.User, *models.Repository, *git.Repository, *git.PullRequestInfo, string, string) {
|
||||
// Get compare branch information.
|
||||
infos := strings.Split(ctx.Params("*"), "...")
|
||||
if len(infos) != 2 {
|
||||
ctx.Handle(404, "CompareAndPullRequest", nil)
|
||||
return
|
||||
return nil, nil, nil, nil, "", ""
|
||||
}
|
||||
|
||||
baseBranch := infos[0]
|
||||
@@ -143,47 +147,221 @@ func CompareAndPullRequest(ctx *middleware.Context) {
|
||||
headInfos := strings.Split(infos[1], ":")
|
||||
if len(headInfos) != 2 {
|
||||
ctx.Handle(404, "CompareAndPullRequest", nil)
|
||||
return
|
||||
return nil, nil, nil, nil, "", ""
|
||||
}
|
||||
headUser := headInfos[0]
|
||||
headUsername := headInfos[0]
|
||||
headBranch := headInfos[1]
|
||||
ctx.Data["HeadBranch"] = headBranch
|
||||
|
||||
// TODO: check if branches are valid.
|
||||
fmt.Println(baseBranch, headUser, headBranch)
|
||||
|
||||
// TODO: add organization support
|
||||
// Check if current user has fork of repository.
|
||||
headRepo, has := models.HasForkedRepo(ctx.User.Id, repo.ID)
|
||||
if !has {
|
||||
ctx.Handle(404, "HasForkedRepo", nil)
|
||||
return
|
||||
headUser, err := models.GetUserByName(headUsername)
|
||||
if err != nil {
|
||||
if models.IsErrUserNotExist(err) {
|
||||
ctx.Handle(404, "GetUserByName", nil)
|
||||
} else {
|
||||
ctx.Handle(500, "GetUserByName", err)
|
||||
}
|
||||
return nil, nil, nil, nil, "", ""
|
||||
}
|
||||
|
||||
headGitRepo, err := git.OpenRepository(models.RepoPath(ctx.User.Name, headRepo.Name))
|
||||
repo := ctx.Repo.Repository
|
||||
|
||||
// Check if base branch is valid.
|
||||
if !ctx.Repo.GitRepo.IsBranchExist(baseBranch) {
|
||||
ctx.Handle(404, "IsBranchExist", nil)
|
||||
return nil, nil, nil, nil, "", ""
|
||||
}
|
||||
|
||||
// Check if current user has fork of repository.
|
||||
headRepo, has := models.HasForkedRepo(headUser.Id, repo.ID)
|
||||
if !has || !ctx.User.IsAdminOfRepo(headRepo) {
|
||||
ctx.Handle(404, "HasForkedRepo", nil)
|
||||
return nil, nil, nil, nil, "", ""
|
||||
}
|
||||
|
||||
headGitRepo, err := git.OpenRepository(models.RepoPath(headUser.Name, headRepo.Name))
|
||||
if err != nil {
|
||||
ctx.Handle(500, "OpenRepository", err)
|
||||
return
|
||||
return nil, nil, nil, nil, "", ""
|
||||
}
|
||||
|
||||
// Check if head branch is valid.
|
||||
if !headGitRepo.IsBranchExist(headBranch) {
|
||||
ctx.Handle(404, "IsBranchExist", nil)
|
||||
return nil, nil, nil, nil, "", ""
|
||||
}
|
||||
|
||||
headBranches, err := headGitRepo.GetBranches()
|
||||
if err != nil {
|
||||
ctx.Handle(500, "GetBranches", err)
|
||||
return
|
||||
return nil, nil, nil, nil, "", ""
|
||||
}
|
||||
ctx.Data["HeadBranches"] = headBranches
|
||||
|
||||
prInfo, err := headGitRepo.GetPullRequestInfo(models.RepoPath(repo.Owner.Name, repo.Name), baseBranch, headBranch)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "GetPullRequestInfo", err)
|
||||
return nil, nil, nil, nil, "", ""
|
||||
}
|
||||
ctx.Data["BeforeCommitID"] = prInfo.MergeBase
|
||||
|
||||
return headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch
|
||||
}
|
||||
|
||||
func PrepareCompareDiff(
|
||||
ctx *middleware.Context,
|
||||
headUser *models.User,
|
||||
headRepo *models.Repository,
|
||||
headGitRepo *git.Repository,
|
||||
prInfo *git.PullRequestInfo,
|
||||
baseBranch, headBranch string) {
|
||||
|
||||
var (
|
||||
repo = ctx.Repo.Repository
|
||||
err error
|
||||
)
|
||||
|
||||
// Get diff information.
|
||||
ctx.Data["CommitRepoLink"], err = headRepo.RepoLink()
|
||||
if err != nil {
|
||||
ctx.Handle(500, "RepoLink", err)
|
||||
return
|
||||
}
|
||||
|
||||
headCommitID, err := headGitRepo.GetCommitIdOfBranch(headBranch)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "GetCommitIdOfBranch", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["AfterCommitID"] = headCommitID
|
||||
|
||||
diff, err := models.GetDiffRange(models.RepoPath(headUser.Name, headRepo.Name),
|
||||
prInfo.MergeBase, headCommitID, setting.Git.MaxGitDiffLines)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "GetDiffRange", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["Diff"] = diff
|
||||
ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0
|
||||
|
||||
headCommit, err := headGitRepo.GetCommit(headCommitID)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "GetCommit", err)
|
||||
return
|
||||
}
|
||||
isImageFile := func(name string) bool {
|
||||
blob, err := headCommit.GetBlobByPath(name)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
dataRc, err := blob.Data()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
buf := make([]byte, 1024)
|
||||
n, _ := dataRc.Read(buf)
|
||||
if n > 0 {
|
||||
buf = buf[:n]
|
||||
}
|
||||
_, isImage := base.IsImageFile(buf)
|
||||
return isImage
|
||||
}
|
||||
|
||||
prInfo.Commits = models.ValidateCommitsWithEmails(prInfo.Commits)
|
||||
ctx.Data["Commits"] = prInfo.Commits
|
||||
ctx.Data["CommitCount"] = prInfo.Commits.Len()
|
||||
ctx.Data["Username"] = headUser.Name
|
||||
ctx.Data["Reponame"] = headRepo.Name
|
||||
ctx.Data["IsImageFile"] = isImageFile
|
||||
ctx.Data["SourcePath"] = setting.AppSubUrl + "/" + path.Join(headUser.Name, repo.Name, "src", headCommitID)
|
||||
ctx.Data["BeforeSourcePath"] = setting.AppSubUrl + "/" + path.Join(headUser.Name, repo.Name, "src", prInfo.MergeBase)
|
||||
ctx.Data["RawPath"] = setting.AppSubUrl + "/" + path.Join(headUser.Name, repo.Name, "raw", headCommitID)
|
||||
}
|
||||
|
||||
func CompareAndPullRequest(ctx *middleware.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("repo.pulls.compare_changes")
|
||||
ctx.Data["PageIsComparePull"] = true
|
||||
ctx.Data["IsDiffCompare"] = true
|
||||
renderAttachmentSettings(ctx)
|
||||
|
||||
headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch := ParseCompareInfo(ctx)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
PrepareCompareDiff(ctx, headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
// Setup information for new form.
|
||||
RetrieveRepoMetas(ctx, ctx.Repo.Repository)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
// Get diff information.
|
||||
|
||||
ctx.HTML(200, COMPARE_PULL)
|
||||
}
|
||||
|
||||
func Pulls(ctx *middleware.Context) {
|
||||
ctx.Data["IsRepoToolbarPulls"] = true
|
||||
ctx.HTML(200, PULLS)
|
||||
func CompareAndPullRequestPost(ctx *middleware.Context, form auth.CreateIssueForm) {
|
||||
ctx.Data["Title"] = ctx.Tr("repo.pulls.compare_changes")
|
||||
ctx.Data["PageIsComparePull"] = true
|
||||
ctx.Data["IsDiffCompare"] = true
|
||||
renderAttachmentSettings(ctx)
|
||||
|
||||
var (
|
||||
repo = ctx.Repo.Repository
|
||||
attachments []string
|
||||
)
|
||||
|
||||
_, headRepo, headGitRepo, prInfo, baseBranch, headBranch := ParseCompareInfo(ctx)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
patch, err := headGitRepo.GetPatch(models.RepoPath(repo.Owner.Name, repo.Name), baseBranch, headBranch)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "GetPatch", err)
|
||||
return
|
||||
}
|
||||
|
||||
labelIDs, milestoneID, assigneeID := ValidateRepoMetas(ctx, form)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
if setting.AttachmentEnabled {
|
||||
attachments = form.Attachments
|
||||
}
|
||||
|
||||
if ctx.HasError() {
|
||||
ctx.HTML(200, COMPARE_PULL)
|
||||
return
|
||||
}
|
||||
|
||||
pr := &models.Issue{
|
||||
RepoID: repo.ID,
|
||||
Index: int64(repo.NumIssues) + 1,
|
||||
Name: form.Title,
|
||||
PosterID: ctx.User.Id,
|
||||
Poster: ctx.User,
|
||||
MilestoneID: milestoneID,
|
||||
AssigneeID: assigneeID,
|
||||
IsPull: true,
|
||||
Content: form.Content,
|
||||
}
|
||||
if err := models.NewPullRequest(repo, pr, labelIDs, attachments, &models.PullRepo{
|
||||
HeadRepoID: headRepo.ID,
|
||||
BaseRepoID: repo.ID,
|
||||
HeadBarcnh: headBranch,
|
||||
BaseBranch: baseBranch,
|
||||
MergeBase: prInfo.MergeBase,
|
||||
Type: models.PULL_REQUEST_GOGS,
|
||||
}, patch); err != nil {
|
||||
ctx.Handle(500, "NewPullRequest", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Trace("Pull request created: %d/%d", repo.ID, pr.ID)
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(pr.Index))
|
||||
}
|
||||
@@ -10,9 +10,11 @@
|
||||
</form>
|
||||
</div>
|
||||
{{else if .IsDiffCompare}}
|
||||
<a href="{{$.RepoLink}}/commit/{{.BeforeCommitID}}" class="ui green sha label">{{ShortSha .BeforeCommitID}}</a> ... <a href="{{$.RepoLink}}/commit/{{.AfterCommitID}}" class="ui green sha label">{{ShortSha .AfterCommitID}}</a>
|
||||
<a href="{{$.CommitRepoLink}}/commit/{{.BeforeCommitID}}" class="ui green sha label">{{ShortSha .BeforeCommitID}}</a> ... <a href="{{$.CommitRepoLink}}/commit/{{.AfterCommitID}}" class="ui green sha label">{{ShortSha .AfterCommitID}}</a>
|
||||
{{end}}
|
||||
</h4>
|
||||
|
||||
{{if .Commits}}
|
||||
<div class="ui attached table segment">
|
||||
<table class="ui very basic striped commits table">
|
||||
<thead>
|
||||
@@ -24,9 +26,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{ $username := .Username}}
|
||||
{{ $reponame := .Reponame}}
|
||||
{{ $r:= List .Commits}}
|
||||
{{ $r:= List .Commits}}
|
||||
{{range $r}}
|
||||
<tr>
|
||||
<td class="author">
|
||||
@@ -36,7 +36,7 @@
|
||||
<img class="ui avatar image" src="{{AvatarLink .Author.Email}}" alt=""/> {{.Author.Name}}
|
||||
{{end}}
|
||||
</td>
|
||||
<td class="sha"><a rel="nofollow" class="ui green sha label" href="{{AppSubUrl}}/{{$username}}/{{$reponame}}/commit/{{.Id}} ">{{SubStr .Id.String 0 10}} </a></td>
|
||||
<td class="sha"><a rel="nofollow" class="ui green sha label" href="{{AppSubUrl}}/{{$.Username}}/{{$.Reponame}}/commit/{{.Id}} ">{{SubStr .Id.String 0 10}} </a></td>
|
||||
<td class="message"><span class="text truncate">{{RenderCommitMessage .Summary $.RepoLink}}</span></td>
|
||||
<td class="date">{{TimeSince .Author.When $.Lang}}</td>
|
||||
</tr>
|
||||
@@ -44,6 +44,7 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{with .Page}}
|
||||
{{if gt .TotalPages 1}}
|
||||
|
||||
@@ -41,98 +41,7 @@
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{if .DiffNotAvailable}}
|
||||
<h4>{{.i18n.Tr "repo.diff.data_not_available"}}</h4>
|
||||
{{else}}
|
||||
<div class="diff-detail-box diff-box">
|
||||
<div>
|
||||
<i class="fa fa-retweet"></i>
|
||||
{{.i18n.Tr "repo.diff.stats_desc" .Diff.NumFiles .Diff.TotalAddition .Diff.TotalDeletion | Str2html}}
|
||||
<div class="ui right">
|
||||
<a class="ui tiny basic black toggle button" data-target="#diff-files">{{.i18n.Tr "repo.diff.show_diff_stats"}}</a>
|
||||
</div>
|
||||
</div>
|
||||
<ol class="detail-files hide" id="diff-files">
|
||||
{{range .Diff.Files}}
|
||||
<li>
|
||||
<div class="diff-counter count pull-right">
|
||||
{{if not .IsBin}}
|
||||
<span class="add" data-line="{{.Addition}}">{{.Addition}}</span>
|
||||
<span class="bar">
|
||||
<span class="pull-left add"></span>
|
||||
<span class="pull-left del"></span>
|
||||
</span>
|
||||
<span class="del" data-line="{{.Deletion}}">{{.Deletion}}</span>
|
||||
{{else}}
|
||||
<span>{{$.i18n.Tr "repo.diff.bin"}}</span>
|
||||
{{end}}
|
||||
</div>
|
||||
<!-- todo finish all file status, now modify, add, delete and rename -->
|
||||
<span class="status {{DiffTypeToStr .Type}} poping up" data-content="{{DiffTypeToStr .Type}}" data-variation="inverted tiny" data-position="right center"> </span>
|
||||
<a class="file" href="#diff-{{.Index}}">{{.Name}}</a>
|
||||
</li>
|
||||
{{end}}
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
{{range $i, $file := .Diff.Files}}
|
||||
<div class="diff-file-box diff-box file-content" id="diff-{{.Index}}">
|
||||
<h4 class="ui top attached normal header">
|
||||
<div class="diff-counter count ui left">
|
||||
{{if not $file.IsBin}}
|
||||
<span class="add" data-line="{{.Addition}}">+ {{.Addition}}</span>
|
||||
<span class="bar">
|
||||
<span class="pull-left add"></span>
|
||||
<span class="pull-left del"></span>
|
||||
</span>
|
||||
<span class="del" data-line="{{.Deletion}}">- {{.Deletion}}</span>
|
||||
{{else}}
|
||||
{{$.i18n.Tr "repo.diff.bin"}}
|
||||
{{end}}
|
||||
</div>
|
||||
<span class="file">{{$file.Name}}</span>
|
||||
<div class="ui right">
|
||||
{{if $file.IsDeleted}}
|
||||
<a class="ui basic tiny button" rel="nofollow" href="{{EscapePound $.BeforeSourcePath}}/{{EscapePound .Name}}">{{$.i18n.Tr "repo.diff.view_file"}}</a>
|
||||
{{else}}
|
||||
<a class="ui basic tiny button" rel="nofollow" href="{{EscapePound $.SourcePath}}/{{EscapePound .Name}}">{{$.i18n.Tr "repo.diff.view_file"}}</a>
|
||||
{{end}}
|
||||
</div>
|
||||
</h4>
|
||||
<div class="ui attached table segment">
|
||||
{{$isImage := (call $.IsImageFile $file.Name)}}
|
||||
{{if $isImage}}
|
||||
<div class="center">
|
||||
<img src="{{$.RawPath}}/{{EscapePound .Name}}">
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="file-body file-code code-view code-diff">
|
||||
<table>
|
||||
<tbody>
|
||||
{{range .Sections}}
|
||||
{{range $k, $line := .Lines}}
|
||||
<tr class="{{DiffLineTypeToStr .Type}}-code nl-{{$k}} ol-{{$k}}">
|
||||
<td class="lines-num lines-num-old">
|
||||
<span rel="{{if $line.LeftIdx}}diff-{{Sha1 $file.Name}}L{{$line.LeftIdx}}{{end}}">{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}</span>
|
||||
</td>
|
||||
<td class="lines-num lines-num-new">
|
||||
<span rel="{{if $line.RightIdx}}diff-{{Sha1 $file.Name}}R{{$line.RightIdx}}{{end}}">{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}</span>
|
||||
</td>
|
||||
<td class="lines-code">
|
||||
<pre>{{$line.Content}}</pre>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{template "repo/diff_box" .}}
|
||||
</div>
|
||||
</div>
|
||||
{{template "base/footer" .}}
|
||||
@@ -0,0 +1,92 @@
|
||||
{{if .DiffNotAvailable}}
|
||||
<h4>{{.i18n.Tr "repo.diff.data_not_available"}}</h4>
|
||||
{{else}}
|
||||
<div class="diff-detail-box diff-box">
|
||||
<div>
|
||||
<i class="fa fa-retweet"></i>
|
||||
{{.i18n.Tr "repo.diff.stats_desc" .Diff.NumFiles .Diff.TotalAddition .Diff.TotalDeletion | Str2html}}
|
||||
<div class="ui right">
|
||||
<a class="ui tiny basic black toggle button" data-target="#diff-files">{{.i18n.Tr "repo.diff.show_diff_stats"}}</a>
|
||||
</div>
|
||||
</div>
|
||||
<ol class="detail-files hide" id="diff-files">
|
||||
{{range .Diff.Files}}
|
||||
<li>
|
||||
<div class="diff-counter count pull-right">
|
||||
{{if not .IsBin}}
|
||||
<span class="add" data-line="{{.Addition}}">{{.Addition}}</span>
|
||||
<span class="bar">
|
||||
<span class="pull-left add"></span>
|
||||
<span class="pull-left del"></span>
|
||||
</span>
|
||||
<span class="del" data-line="{{.Deletion}}">{{.Deletion}}</span>
|
||||
{{else}}
|
||||
<span>{{$.i18n.Tr "repo.diff.bin"}}</span>
|
||||
{{end}}
|
||||
</div>
|
||||
<!-- todo finish all file status, now modify, add, delete and rename -->
|
||||
<span class="status {{DiffTypeToStr .Type}} poping up" data-content="{{DiffTypeToStr .Type}}" data-variation="inverted tiny" data-position="right center"> </span>
|
||||
<a class="file" href="#diff-{{.Index}}">{{.Name}}</a>
|
||||
</li>
|
||||
{{end}}
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
{{range $i, $file := .Diff.Files}}
|
||||
<div class="diff-file-box diff-box file-content" id="diff-{{.Index}}">
|
||||
<h4 class="ui top attached normal header">
|
||||
<div class="diff-counter count ui left">
|
||||
{{if not $file.IsBin}}
|
||||
<span class="add" data-line="{{.Addition}}">+ {{.Addition}}</span>
|
||||
<span class="bar">
|
||||
<span class="pull-left add"></span>
|
||||
<span class="pull-left del"></span>
|
||||
</span>
|
||||
<span class="del" data-line="{{.Deletion}}">- {{.Deletion}}</span>
|
||||
{{else}}
|
||||
{{$.i18n.Tr "repo.diff.bin"}}
|
||||
{{end}}
|
||||
</div>
|
||||
<span class="file">{{$file.Name}}</span>
|
||||
<div class="ui right">
|
||||
{{if $file.IsDeleted}}
|
||||
<a class="ui basic tiny button" rel="nofollow" href="{{EscapePound $.BeforeSourcePath}}/{{EscapePound .Name}}">{{$.i18n.Tr "repo.diff.view_file"}}</a>
|
||||
{{else}}
|
||||
<a class="ui basic tiny button" rel="nofollow" href="{{EscapePound $.SourcePath}}/{{EscapePound .Name}}">{{$.i18n.Tr "repo.diff.view_file"}}</a>
|
||||
{{end}}
|
||||
</div>
|
||||
</h4>
|
||||
<div class="ui attached table segment">
|
||||
{{$isImage := (call $.IsImageFile $file.Name)}}
|
||||
{{if $isImage}}
|
||||
<div class="center">
|
||||
<img src="{{$.RawPath}}/{{EscapePound .Name}}">
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="file-body file-code code-view code-diff">
|
||||
<table>
|
||||
<tbody>
|
||||
{{range .Sections}}
|
||||
{{range $k, $line := .Lines}}
|
||||
<tr class="{{DiffLineTypeToStr .Type}}-code nl-{{$k}} ol-{{$k}}">
|
||||
<td class="lines-num lines-num-old">
|
||||
<span rel="{{if $line.LeftIdx}}diff-{{Sha1 $file.Name}}L{{$line.LeftIdx}}{{end}}">{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}</span>
|
||||
</td>
|
||||
<td class="lines-num lines-num-new">
|
||||
<span rel="{{if $line.RightIdx}}diff-{{Sha1 $file.Name}}R{{$line.RightIdx}}{{end}}">{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}</span>
|
||||
</td>
|
||||
<td class="lines-code">
|
||||
<pre>{{$line.Content}}</pre>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
{{end}}
|
||||
{{end}}
|
||||
@@ -9,7 +9,31 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui divider"></div>
|
||||
{{if .Issue.IsPull}}
|
||||
{{template "repo/issue/view_title" .}}
|
||||
<div class="ui top attached pull tabular menu">
|
||||
<a class="item active" href="{{.RepoLink}}/pulls/{{.Issue.Index}}">
|
||||
<span class="octicon octicon-comment-discussion"></span>
|
||||
{{$.i18n.Tr "repo.pulls.tab_conversation"}}
|
||||
<span class="ui label">{{.Issue.NumComments}}</span>
|
||||
</a>
|
||||
<a class="item" href="{{.RepoLink}}/pulls/{{.Issue.Index}}/commits">
|
||||
<span class="octicon octicon-git-commit"></span>
|
||||
{{$.i18n.Tr "repo.pulls.tab_commits"}}
|
||||
<span class="ui label">{{.NumCommits}}</span>
|
||||
</a>
|
||||
<a class="item" href="{{.RepoLink}}/pulls/{{.Issue.Index}}/files">
|
||||
<span class="octicon octicon-diff"></span>
|
||||
{{$.i18n.Tr "repo.pulls.tab_files"}}
|
||||
<span class="ui label">{{.NumFiles}}</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="ui bottom attached tab pull segment active" data-tab="request-{{.ID}}">
|
||||
{{template "repo/issue/view_content" .}}
|
||||
</div>
|
||||
{{else}}
|
||||
{{template "repo/issue/view_content" .}}
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{template "base/footer" .}}
|
||||
@@ -4,41 +4,11 @@
|
||||
{{template "base/alert" .}}
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="sixteen wide column title">
|
||||
<div class="ui grid">
|
||||
<h1 class="twelve wide column">
|
||||
<span class="index">#{{.Issue.Index}}</span> <span id="issue-title">{{.Issue.Name}}</span>
|
||||
<div id="edit-title-input" class="ui input" style="display: none">
|
||||
<input value="{{.Issue.Name}}">
|
||||
</div>
|
||||
</h1>
|
||||
{{if .IsIssueOwner}}
|
||||
<div class="four wide column">
|
||||
<div class="edit-zone text right">
|
||||
<div id="edit-title" class="ui basic green not-in-edit button">{{.i18n.Tr "repo.issues.edit"}}</div>
|
||||
<div id="cancel-edit-title" class="ui basic blue in-edit button" style="display: none">{{.i18n.Tr "repo.issues.cancel"}}</div>
|
||||
<div id="save-edit-title" class="ui green in-edit button" style="display: none" data-update-url="{{.Link}}/title">{{.i18n.Tr "repo.issues.save"}}</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{if .Issue.IsClosed}}
|
||||
<div class="ui red large label"><i class="octicon octicon-issue-closed"></i> {{.i18n.Tr "repo.issues.closed_title"}}</div>
|
||||
{{else}}
|
||||
<div class="ui green large label"><i class="octicon octicon-issue-opened"></i> {{.i18n.Tr "repo.issues.open_title"}}</div>
|
||||
{{end}}
|
||||
{{ $createdStr:= TimeSince .Issue.Created $.Lang }}
|
||||
<span class="time-desc">
|
||||
{{if gt .Issue.Poster.Id 0}}
|
||||
{{$.i18n.Tr "repo.issues.opened_by" $createdStr .Issue.Poster.HomeLink .Issue.Poster.Name | Safe}}
|
||||
{{else}}
|
||||
{{$.i18n.Tr "repo.issues.opened_by_fake" $createdStr .Issue.Poster.Name | Safe}}
|
||||
{{end}}
|
||||
·
|
||||
{{$.i18n.Tr "repo.issues.num_comments" .Issue.NumComments}}
|
||||
</span>
|
||||
<div class="ui divider"></div>
|
||||
</div>
|
||||
{{if not .Issue.IsPull}}
|
||||
{{template "repo/issue/view_title" .}}
|
||||
{{end}}
|
||||
|
||||
{{ $createdStr:= TimeSince .Issue.Created $.Lang }}
|
||||
<div class="twelve wide column comment-list">
|
||||
<ui class="ui comments">
|
||||
<div class="comment">
|
||||
@@ -63,7 +33,7 @@
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="raw-content hide">{{.Issue.Content}}</div>
|
||||
<div class="edit-content-zone hide" data-write="issue-{{.Issue.ID}}-write" data-preview="issue-{{.Issue.ID}}-preview" data-update-url="{{.Link}}/content" data-context="{{.RepoLink}}"></div>
|
||||
<div class="edit-content-zone hide" data-write="issue-{{.Issue.ID}}-write" data-preview="issue-{{.Issue.ID}}-preview" data-update-url="{{$.RepoLink}}/issues/{{.Issue.Index}}/content" data-context="{{.RepoLink}}"></div>
|
||||
</div>
|
||||
{{if .Issue.Attachments}}
|
||||
<div class="ui bottom attached segment">
|
||||
@@ -167,7 +137,7 @@
|
||||
<img src="{{.SignedUser.AvatarLink}}">
|
||||
</a>
|
||||
<div class="content">
|
||||
<form class="ui segment form" id="comment-form" action="{{.Link}}/comments" method="post">
|
||||
<form class="ui segment form" id="comment-form" action="{{$.RepoLink}}/issues/{{.Issue.Index}}/comments" method="post">
|
||||
{{template "repo/issue/comment_tab" .}}
|
||||
{{.CsrfTokenHtml}}
|
||||
<input id="status" name="status" type="hidden">
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
<div class="sixteen wide column title">
|
||||
<div class="ui grid">
|
||||
<h1 class="twelve wide column">
|
||||
<span class="index">#{{.Issue.Index}}</span> <span id="issue-title">{{.Issue.Name}}</span>
|
||||
<div id="edit-title-input" class="ui input" style="display: none">
|
||||
<input value="{{.Issue.Name}}">
|
||||
</div>
|
||||
</h1>
|
||||
{{if .IsIssueOwner}}
|
||||
<div class="four wide column">
|
||||
<div class="edit-zone text right">
|
||||
<div id="edit-title" class="ui basic green not-in-edit button">{{.i18n.Tr "repo.issues.edit"}}</div>
|
||||
<div id="cancel-edit-title" class="ui basic blue in-edit button" style="display: none">{{.i18n.Tr "repo.issues.cancel"}}</div>
|
||||
<div id="save-edit-title" class="ui green in-edit button" style="display: none" data-update-url="{{$.RepoLink}}/issues/{{.Issue.Index}}/title">{{.i18n.Tr "repo.issues.save"}}</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{if .Issue.IsClosed}}
|
||||
<div class="ui red large label"><i class="octicon octicon-issue-closed"></i> {{.i18n.Tr "repo.issues.closed_title"}}</div>
|
||||
{{else}}
|
||||
<div class="ui green large label"><i class="octicon octicon-issue-opened"></i> {{.i18n.Tr "repo.issues.open_title"}}</div>
|
||||
{{end}}
|
||||
{{ $createdStr:= TimeSince .Issue.Created $.Lang }}
|
||||
<span class="time-desc">
|
||||
{{if gt .Issue.Poster.Id 0}}
|
||||
{{$.i18n.Tr "repo.issues.opened_by" $createdStr .Issue.Poster.HomeLink .Issue.Poster.Name | Safe}}
|
||||
{{else}}
|
||||
{{$.i18n.Tr "repo.issues.opened_by_fake" $createdStr .Issue.Poster.Name | Safe}}
|
||||
{{end}}
|
||||
·
|
||||
{{$.i18n.Tr "repo.issues.num_comments" .Issue.NumComments}}
|
||||
</span>
|
||||
<div class="ui divider"></div>
|
||||
</div>
|
||||
@@ -46,6 +46,9 @@
|
||||
</div>
|
||||
</div>
|
||||
{{template "repo/issue/new_form" .}}
|
||||
|
||||
{{template "repo/commits_table" .}}
|
||||
{{template "repo/diff_box" .}}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user