Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add branch overiew page #2108

Merged
merged 4 commits into from
Oct 26, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions integrations/branches_test.go
Original file line number Diff line number Diff line change
@@ -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
}
107 changes: 107 additions & 0 deletions models/branches.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"

"github.com/Unknwon/com"
Expand Down Expand Up @@ -193,3 +194,109 @@ func (repo *Repository) DeleteProtectedBranch(id int64) (err error) {

return sess.Commit()
}

// DeletedBranch struct
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"`
DeletedBy *User `xorm:"-"`
Deleted time.Time `xorm:"-"`
DeletedUnix int64 `xorm:"INDEX created"`
}

// AfterLoad is invoked from XORM after setting the values of all fields of this object.
func (deletedBranch *DeletedBranch) AfterLoad() {
deletedBranch.Deleted = time.Unix(deletedBranch.DeletedUnix, 0).Local()
}

// AddDeletedBranch adds a deleted branch to the database
func (repo *Repository) AddDeletedBranch(branchName, commit string, deletedByID int64) error {
deletedBranch := &DeletedBranch{
RepoID: repo.ID,
Name: branchName,
Commit: commit,
DeletedByID: deletedByID,
}

sess := x.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
return err
}

if _, err := sess.InsertOne(deletedBranch); err != nil {
return err
}

return sess.Commit()
}

// GetDeletedBranches returns all the deleted branches
func (repo *Repository) GetDeletedBranches() ([]*DeletedBranch, error) {
deletedBranches := make([]*DeletedBranch, 0)
return deletedBranches, x.Where("repo_id = ?", repo.ID).Desc("deleted_unix").Find(&deletedBranches)
}

// GetDeletedBranchByID get a deleted branch by its ID
func (repo *Repository) GetDeletedBranchByID(ID int64) (*DeletedBranch, error) {
deletedBranch := &DeletedBranch{ID: ID}
has, err := x.Get(deletedBranch)
if err != nil {
return nil, err
}
if !has {
return nil, nil
}
return deletedBranch, nil
}

// RemoveDeletedBranch removes a deleted branch from the database
func (repo *Repository) RemoveDeletedBranch(id int64) (err error) {
deletedBranch := &DeletedBranch{
RepoID: repo.ID,
ID: id,
}

sess := x.NewSession()
defer sess.Close()
if err = sess.Begin(); err != nil {
return err
}

if affected, err := sess.Delete(deletedBranch); err != nil {
return err
} else if affected != 1 {
return fmt.Errorf("remove deleted branch ID(%v) failed", id)
}

return sess.Commit()
}

// LoadUser loads the user that deleted the branch
// When there's no user found it returns a NewGhostUser
func (deletedBranch *DeletedBranch) LoadUser() {
user, err := GetUserByID(deletedBranch.DeletedByID)
if err != nil {
user = NewGhostUser()
}
deletedBranch.DeletedBy = user
}

// RemoveOldDeletedBranches removes old deleted branches
func RemoveOldDeletedBranches() {
if !taskStatusTable.StartIfNotRunning(`deleted_branches_cleanup`) {
return
}
defer taskStatusTable.Stop(`deleted_branches_cleanup`)

log.Trace("Doing: DeletedBranchesCleanup")

deleteBefore := time.Now().Add(-setting.Cron.DeletedBranchesCleanup.OlderThan)
_, err := x.Where("deleted_unix < ?", deleteBefore.Unix()).Delete(new(DeletedBranch))
if err != nil {
log.Error(4, "DeletedBranchesCleanup: %v", err)
}
}
89 changes: 89 additions & 0 deletions models/branches_test.go
Original file line number Diff line number Diff line change
@@ -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
}
2 changes: 2 additions & 0 deletions models/migrations/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ var migrations = []Migration{
NewMigration("remove index column from repo_unit table", removeIndexColumnFromRepoUnitTable),
// v46 -> v47
NewMigration("remove organization watch repositories", removeOrganizationWatchRepo),
// v47 -> v48
NewMigration("add deleted branches", addDeletedBranch),
}

// Migrate database to current version
Expand Down
29 changes: 29 additions & 0 deletions models/migrations/v47.go
Original file line number Diff line number Diff line change
@@ -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
}
1 change: 1 addition & 0 deletions models/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ func init() {
new(CommitStatus),
new(Stopwatch),
new(TrackedTime),
new(DeletedBranch),
)

gonicNames := []string{"SSL", "UID"}
Expand Down
11 changes: 11 additions & 0 deletions modules/cron/cron.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,17 @@ func NewContext() {
go models.SyncExternalUsers()
}
}
if setting.Cron.DeletedBranchesCleanup.Enabled {
entry, err = c.AddFunc("Remove old deleted branches", setting.Cron.DeletedBranchesCleanup.Schedule, models.RemoveOldDeletedBranches)
if err != nil {
log.Fatal(4, "Cron[Remove old deleted branches]: %v", err)
}
if setting.Cron.DeletedBranchesCleanup.RunAtStart {
entry.Prev = time.Now()
entry.ExecTimes++
go models.RemoveOldDeletedBranches()
}
}
c.Start()
}

Expand Down
17 changes: 17 additions & 0 deletions modules/setting/setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,12 @@ var (
Schedule string
UpdateExisting bool
} `ini:"cron.sync_external_users"`
DeletedBranchesCleanup struct {
Enabled bool
RunAtStart bool
Schedule string
OlderThan time.Duration
} `ini:"cron.deleted_branches_cleanup"`
}{
UpdateMirror: struct {
Enabled bool
Expand Down Expand Up @@ -419,6 +425,17 @@ var (
Schedule: "@every 24h",
UpdateExisting: true,
},
DeletedBranchesCleanup: struct {
Enabled bool
RunAtStart bool
Schedule string
OlderThan time.Duration
}{
Enabled: true,
RunAtStart: true,
Schedule: "@every 24h",
OlderThan: 24 * time.Hour,
},
}

// Git settings
Expand Down
Loading