Add branch overiew page (#2108)
* Add branch overiew page * fix changed method name on sub menu * remove unused codetokarchuk/v1.17
parent
e86a0bf3fe
commit
3ab580c8d6
@ -0,0 +1,79 @@ |
|||||||
|
// Copyright 2017 The Gitea 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 integrations |
||||||
|
|
||||||
|
import ( |
||||||
|
"net/http" |
||||||
|
"net/url" |
||||||
|
"testing" |
||||||
|
|
||||||
|
"github.com/PuerkitoBio/goquery" |
||||||
|
"github.com/Unknwon/i18n" |
||||||
|
"github.com/stretchr/testify/assert" |
||||||
|
) |
||||||
|
|
||||||
|
func TestViewBranches(t *testing.T) { |
||||||
|
prepareTestEnv(t) |
||||||
|
|
||||||
|
req := NewRequest(t, "GET", "/user2/repo1/branches") |
||||||
|
resp := MakeRequest(t, req, http.StatusOK) |
||||||
|
|
||||||
|
htmlDoc := NewHTMLParser(t, resp.Body) |
||||||
|
_, exists := htmlDoc.doc.Find(".delete-branch-button").Attr("data-url") |
||||||
|
assert.False(t, exists, "The template has changed") |
||||||
|
} |
||||||
|
|
||||||
|
func TestDeleteBranch(t *testing.T) { |
||||||
|
prepareTestEnv(t) |
||||||
|
|
||||||
|
deleteBranch(t) |
||||||
|
} |
||||||
|
|
||||||
|
func TestUndoDeleteBranch(t *testing.T) { |
||||||
|
prepareTestEnv(t) |
||||||
|
|
||||||
|
deleteBranch(t) |
||||||
|
htmlDoc, name := branchAction(t, ".undo-button") |
||||||
|
assert.Contains(t, |
||||||
|
htmlDoc.doc.Find(".ui.positive.message").Text(), |
||||||
|
i18n.Tr("en", "repo.branch.restore_success", name), |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
func deleteBranch(t *testing.T) { |
||||||
|
htmlDoc, name := branchAction(t, ".delete-branch-button") |
||||||
|
assert.Contains(t, |
||||||
|
htmlDoc.doc.Find(".ui.positive.message").Text(), |
||||||
|
i18n.Tr("en", "repo.branch.deletion_success", name), |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
func branchAction(t *testing.T, button string) (*HTMLDoc, string) { |
||||||
|
session := loginUser(t, "user2") |
||||||
|
req := NewRequest(t, "GET", "/user2/repo1/branches") |
||||||
|
resp := session.MakeRequest(t, req, http.StatusOK) |
||||||
|
|
||||||
|
htmlDoc := NewHTMLParser(t, resp.Body) |
||||||
|
link, exists := htmlDoc.doc.Find(button).Attr("data-url") |
||||||
|
assert.True(t, exists, "The template has changed") |
||||||
|
|
||||||
|
htmlDoc = NewHTMLParser(t, resp.Body) |
||||||
|
req = NewRequestWithValues(t, "POST", link, map[string]string{ |
||||||
|
"_csrf": getCsrf(htmlDoc.doc), |
||||||
|
}) |
||||||
|
resp = session.MakeRequest(t, req, http.StatusOK) |
||||||
|
|
||||||
|
url, err := url.Parse(link) |
||||||
|
assert.NoError(t, err) |
||||||
|
req = NewRequest(t, "GET", "/user2/repo1/branches") |
||||||
|
resp = session.MakeRequest(t, req, http.StatusOK) |
||||||
|
|
||||||
|
return NewHTMLParser(t, resp.Body), url.Query()["name"][0] |
||||||
|
} |
||||||
|
|
||||||
|
func getCsrf(doc *goquery.Document) string { |
||||||
|
csrf, _ := doc.Find("meta[name=\"_csrf\"]").Attr("content") |
||||||
|
return csrf |
||||||
|
} |
@ -0,0 +1,89 @@ |
|||||||
|
// Copyright 2017 The Gitea 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 models |
||||||
|
|
||||||
|
import ( |
||||||
|
"testing" |
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert" |
||||||
|
) |
||||||
|
|
||||||
|
var firstBranch = DeletedBranch{ |
||||||
|
ID: 1, |
||||||
|
Name: "foo", |
||||||
|
Commit: "1213212312313213213132131", |
||||||
|
DeletedByID: int64(1), |
||||||
|
} |
||||||
|
|
||||||
|
var secondBranch = DeletedBranch{ |
||||||
|
ID: 2, |
||||||
|
Name: "bar", |
||||||
|
Commit: "5655464564554545466464655", |
||||||
|
DeletedByID: int64(99), |
||||||
|
} |
||||||
|
|
||||||
|
func TestAddDeletedBranch(t *testing.T) { |
||||||
|
assert.NoError(t, PrepareTestDatabase()) |
||||||
|
repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) |
||||||
|
assert.NoError(t, repo.AddDeletedBranch(firstBranch.Name, firstBranch.Commit, firstBranch.DeletedByID)) |
||||||
|
assert.Error(t, repo.AddDeletedBranch(firstBranch.Name, firstBranch.Commit, firstBranch.DeletedByID)) |
||||||
|
assert.NoError(t, repo.AddDeletedBranch(secondBranch.Name, secondBranch.Commit, secondBranch.DeletedByID)) |
||||||
|
} |
||||||
|
func TestGetDeletedBranches(t *testing.T) { |
||||||
|
assert.NoError(t, PrepareTestDatabase()) |
||||||
|
AssertExistsAndLoadBean(t, &DeletedBranch{ID: 1}) |
||||||
|
repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) |
||||||
|
|
||||||
|
branches, err := repo.GetDeletedBranches() |
||||||
|
assert.NoError(t, err) |
||||||
|
assert.Len(t, branches, 2) |
||||||
|
} |
||||||
|
|
||||||
|
func TestGetDeletedBranch(t *testing.T) { |
||||||
|
assert.NoError(t, PrepareTestDatabase()) |
||||||
|
assert.NotNil(t, getDeletedBranch(t, firstBranch)) |
||||||
|
} |
||||||
|
|
||||||
|
func TestDeletedBranchLoadUser(t *testing.T) { |
||||||
|
assert.NoError(t, PrepareTestDatabase()) |
||||||
|
branch := getDeletedBranch(t, firstBranch) |
||||||
|
assert.Nil(t, branch.DeletedBy) |
||||||
|
branch.LoadUser() |
||||||
|
assert.NotNil(t, branch.DeletedBy) |
||||||
|
assert.Equal(t, "user1", branch.DeletedBy.Name) |
||||||
|
|
||||||
|
branch = getDeletedBranch(t, secondBranch) |
||||||
|
assert.Nil(t, branch.DeletedBy) |
||||||
|
branch.LoadUser() |
||||||
|
assert.NotNil(t, branch.DeletedBy) |
||||||
|
assert.Equal(t, "Ghost", branch.DeletedBy.Name) |
||||||
|
} |
||||||
|
|
||||||
|
func TestRemoveDeletedBranch(t *testing.T) { |
||||||
|
assert.NoError(t, PrepareTestDatabase()) |
||||||
|
|
||||||
|
branch := DeletedBranch{ID: 1} |
||||||
|
AssertExistsAndLoadBean(t, &branch) |
||||||
|
repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) |
||||||
|
|
||||||
|
err := repo.RemoveDeletedBranch(1) |
||||||
|
assert.NoError(t, err) |
||||||
|
AssertNotExistsBean(t, &branch) |
||||||
|
AssertExistsAndLoadBean(t, &DeletedBranch{ID: 2}) |
||||||
|
} |
||||||
|
|
||||||
|
func getDeletedBranch(t *testing.T, branch DeletedBranch) *DeletedBranch { |
||||||
|
AssertExistsAndLoadBean(t, &DeletedBranch{ID: 1}) |
||||||
|
repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) |
||||||
|
|
||||||
|
deletedBranch, err := repo.GetDeletedBranchByID(branch.ID) |
||||||
|
assert.NoError(t, err) |
||||||
|
assert.Equal(t, branch.ID, deletedBranch.ID) |
||||||
|
assert.Equal(t, branch.Name, deletedBranch.Name) |
||||||
|
assert.Equal(t, branch.Commit, deletedBranch.Commit) |
||||||
|
assert.Equal(t, branch.DeletedByID, deletedBranch.DeletedByID) |
||||||
|
|
||||||
|
return deletedBranch |
||||||
|
} |
@ -0,0 +1,29 @@ |
|||||||
|
// Copyright 2017 The Gitea 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 migrations |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
|
||||||
|
"github.com/go-xorm/xorm" |
||||||
|
) |
||||||
|
|
||||||
|
func addDeletedBranch(x *xorm.Engine) (err error) { |
||||||
|
// DeletedBranch contains the deleted branch information
|
||||||
|
type DeletedBranch struct { |
||||||
|
ID int64 `xorm:"pk autoincr"` |
||||||
|
RepoID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"` |
||||||
|
Name string `xorm:"UNIQUE(s) NOT NULL"` |
||||||
|
Commit string `xorm:"UNIQUE(s) NOT NULL"` |
||||||
|
DeletedByID int64 `xorm:"INDEX NOT NULL"` |
||||||
|
DeletedUnix int64 `xorm:"INDEX"` |
||||||
|
} |
||||||
|
|
||||||
|
if err = x.Sync2(new(DeletedBranch)); err != nil { |
||||||
|
return fmt.Errorf("Sync2: %v", err) |
||||||
|
} |
||||||
|
|
||||||
|
return nil |
||||||
|
} |
File diff suppressed because one or more lines are too long
@ -0,0 +1,81 @@ |
|||||||
|
{{template "base/head" .}} |
||||||
|
<div class="ui repository branches"> |
||||||
|
{{template "repo/header" .}} |
||||||
|
<div class="ui container"> |
||||||
|
{{template "base/alert" .}} |
||||||
|
{{template "repo/sub_menu" .}} |
||||||
|
<h4 class="ui top attached header"> |
||||||
|
{{.i18n.Tr "repo.default_branch"}} |
||||||
|
</h4> |
||||||
|
|
||||||
|
<div class="ui attached table segment"> |
||||||
|
<table class="ui very basic striped fixed table single line"> |
||||||
|
<tbody> |
||||||
|
<tr> |
||||||
|
<td>{{.DefaultBranch}}</td> |
||||||
|
</tr> |
||||||
|
</tbody> |
||||||
|
</table> |
||||||
|
</div> |
||||||
|
|
||||||
|
{{if gt (len .Branches) 1}} |
||||||
|
<h4 class="ui top attached header"> |
||||||
|
{{.i18n.Tr "repo.branches"}} |
||||||
|
</h4> |
||||||
|
<div class="ui attached table segment"> |
||||||
|
<table class="ui very basic striped fixed table single line"> |
||||||
|
<thead> |
||||||
|
<tr> |
||||||
|
<th class="nine wide">{{.i18n.Tr "repo.branch.name"}}</th> |
||||||
|
{{if and $.IsWriter (not $.IsMirror)}} |
||||||
|
<th class="one wide right aligned">{{.i18n.Tr "repo.branch.delete_head"}}</th> |
||||||
|
{{end}} |
||||||
|
</tr> |
||||||
|
</thead> |
||||||
|
<tbody> |
||||||
|
{{range $branch := .Branches}} |
||||||
|
{{if ne .Name $.DefaultBranch}} |
||||||
|
<tr> |
||||||
|
<td> |
||||||
|
{{if .IsDeleted}} |
||||||
|
<s>{{.Name}}</s> |
||||||
|
<p class="time">{{$.i18n.Tr "repo.branch.deleted_by" .DeletedBranch.DeletedBy.Name}} {{TimeSince .DeletedBranch.Deleted $.i18n.Lang}}</p> |
||||||
|
{{else}} |
||||||
|
{{.Name}} |
||||||
|
<p class="time">{{$.i18n.Tr "org.repo_updated"}} {{TimeSince .Commit.Committer.When $.i18n.Lang}}</p> |
||||||
|
</td> |
||||||
|
{{end}} |
||||||
|
{{if and $.IsWriter (not $.IsMirror)}} |
||||||
|
<td class="right aligned"> |
||||||
|
{{if .IsProtected}} |
||||||
|
<i class="octicon octicon-shield"></i> |
||||||
|
{{else if .IsDeleted}} |
||||||
|
<a class="undo-button" href data-url="{{$.Link}}/restore?branch_id={{.DeletedBranch.ID | urlquery}}&name={{.DeletedBranch.Name | urlquery}}"><i class="octicon octicon-reply"></i></a> |
||||||
|
{{else}} |
||||||
|
<a class="delete-branch-button" href data-url="{{$.Link}}/delete?name={{.Name | urlquery}}" data-val="{{.Name}}"><i class="trash icon text red"></i></a> |
||||||
|
{{end}} |
||||||
|
</td> |
||||||
|
{{end}} |
||||||
|
</tr> |
||||||
|
{{end}} |
||||||
|
{{end}} |
||||||
|
</tbody> |
||||||
|
</table> |
||||||
|
</div> |
||||||
|
{{end}} |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="ui small basic delete modal"> |
||||||
|
<div class="ui icon header"> |
||||||
|
<i class="trash icon"></i> |
||||||
|
{{.i18n.Tr "repo.branch.delete_html"| Safe}} <span class="branch-name"></span> |
||||||
|
</div> |
||||||
|
<div class="content"> |
||||||
|
<p>{{.i18n.Tr "repo.branch.delete_desc" | Safe}}</p> |
||||||
|
{{.i18n.Tr "repo.branch.delete_notices_1" | Safe}}<br> |
||||||
|
{{.i18n.Tr "repo.branch.delete_notices_html" | Safe}} <span class="branch-name"></span><br> |
||||||
|
</div> |
||||||
|
{{template "base/delete_modal_actions" .}} |
||||||
|
</div> |
||||||
|
{{template "base/footer" .}} |
@ -0,0 +1,14 @@ |
|||||||
|
<div class="ui segment sub-menu"> |
||||||
|
<div class="ui two horizontal center link list"> |
||||||
|
{{if and (.Repository.UnitEnabled $.UnitTypeCode) (not .IsBareRepo)}} |
||||||
|
<div class="item{{if .PageIsCommits}} active{{end}}"> |
||||||
|
<a href="{{.RepoLink}}/commits/{{EscapePound .BranchName}}"><i class="octicon octicon-history"></i> <b>{{.CommitsCount}}</b> {{.i18n.Tr "repo.commits"}}</a> |
||||||
|
</div> |
||||||
|
{{end}} |
||||||
|
{{if and (.Repository.UnitEnabled $.UnitTypeCode) (not .IsBareRepo) }} |
||||||
|
<div class="item{{if .PageIsBranches}} active{{end}}"> |
||||||
|
<a href="{{.RepoLink}}/branches/"><i class="octicon octicon-git-branch"></i> <b>{{.BrancheCount}}</b> {{.i18n.Tr "repo.branches"}}</a> |
||||||
|
</div> |
||||||
|
{{end}} |
||||||
|
</div> |
||||||
|
</div> |
Loading…
Reference in new issue