Protected branches system (#339)

* Protected branches system

* Moved default branch to branches section (`:org/:reponame/settings/branches`).
* Initial support Protected Branch.
  - Admin does not restrict
  - Owner not to limit
  - To write permission restrictions

* reformat tmpl

* finished the UI and add/delete protected branch response

* remove unused comment

* indent all the template files and remove ru translations since we use crowdin

* fix the push bug
This commit is contained in:
Denis Denisov 2017-02-21 17:02:10 +02:00 committed by Lunny Xiao
parent fe5ff8e4b2
commit fd941db246
17 changed files with 606 additions and 49 deletions

161
models/branches.go Normal file
View file

@ -0,0 +1,161 @@
// Copyright 2016 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 (
"fmt"
"strings"
"time"
)
// Protected metadata
const (
// Protected User ID
ProtectedBranchUserID = "GITEA_USER_ID"
// Protected Repo ID
ProtectedBranchRepoID = "GITEA_REPO_ID"
// Protected access mode
ProtectedBranchAccessMode = "GITEA_ACCESS_MODE"
)
// ProtectedBranch struct
type ProtectedBranch struct {
ID int64 `xorm:"pk autoincr"`
RepoID int64 `xorm:"UNIQUE(s)"`
BranchName string `xorm:"UNIQUE(s)"`
CanPush bool
Created time.Time `xorm:"-"`
CreatedUnix int64
Updated time.Time `xorm:"-"`
UpdatedUnix int64
}
// BeforeInsert before protected branch insert create and update time
func (protectBranch *ProtectedBranch) BeforeInsert() {
protectBranch.CreatedUnix = time.Now().Unix()
protectBranch.UpdatedUnix = protectBranch.CreatedUnix
}
// BeforeUpdate before protected branch update time
func (protectBranch *ProtectedBranch) BeforeUpdate() {
protectBranch.UpdatedUnix = time.Now().Unix()
}
// GetProtectedBranchByRepoID getting protected branch by repo ID
func GetProtectedBranchByRepoID(RepoID int64) ([]*ProtectedBranch, error) {
protectedBranches := make([]*ProtectedBranch, 0)
return protectedBranches, x.Where("repo_id = ?", RepoID).Desc("updated_unix").Find(&protectedBranches)
}
// GetProtectedBranchBy getting protected branch by ID/Name
func GetProtectedBranchBy(repoID int64, BranchName string) (*ProtectedBranch, error) {
rel := &ProtectedBranch{RepoID: repoID, BranchName: strings.ToLower(BranchName)}
has, err := x.Get(rel)
if err != nil {
return nil, err
}
if !has {
return nil, nil
}
return rel, nil
}
// GetProtectedBranches get all protected btanches
func (repo *Repository) GetProtectedBranches() ([]*ProtectedBranch, error) {
protectedBranches := make([]*ProtectedBranch, 0)
return protectedBranches, x.Find(&protectedBranches, &ProtectedBranch{RepoID: repo.ID})
}
// AddProtectedBranch add protection to branch
func (repo *Repository) AddProtectedBranch(branchName string, canPush bool) error {
protectedBranch := &ProtectedBranch{
RepoID: repo.ID,
BranchName: branchName,
}
has, err := x.Get(protectedBranch)
if err != nil {
return err
} else if has {
return nil
}
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
protectedBranch.CanPush = canPush
if _, err = sess.InsertOne(protectedBranch); err != nil {
return err
}
return sess.Commit()
}
// ChangeProtectedBranch access mode sets new access mode for the ProtectedBranch.
func (repo *Repository) ChangeProtectedBranch(id int64, canPush bool) error {
ProtectedBranch := &ProtectedBranch{
RepoID: repo.ID,
ID: id,
}
has, err := x.Get(ProtectedBranch)
if err != nil {
return fmt.Errorf("get ProtectedBranch: %v", err)
} else if !has {
return nil
}
if ProtectedBranch.CanPush == canPush {
return nil
}
ProtectedBranch.CanPush = canPush
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
if _, err = sess.Id(ProtectedBranch.ID).AllCols().Update(ProtectedBranch); err != nil {
return fmt.Errorf("update ProtectedBranch: %v", err)
}
return sess.Commit()
}
// DeleteProtectedBranch removes ProtectedBranch relation between the user and repository.
func (repo *Repository) DeleteProtectedBranch(id int64) (err error) {
protectedBranch := &ProtectedBranch{
RepoID: repo.ID,
ID: id,
}
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
if affected, err := sess.Delete(protectedBranch); err != nil {
return err
} else if affected != 1 {
return fmt.Errorf("delete protected branch ID(%v) failed", id)
}
return sess.Commit()
}
// newProtectedBranch insert one queue
func newProtectedBranch(protectedBranch *ProtectedBranch) error {
_, err := x.InsertOne(protectedBranch)
return err
}
// UpdateProtectedBranch update queue
func UpdateProtectedBranch(protectedBranch *ProtectedBranch) error {
_, err := x.Update(protectedBranch)
return err
}

View file

@ -82,6 +82,8 @@ var migrations = []Migration{
NewMigration("create user column allow create organization", createAllowCreateOrganizationColumn),
// V16 -> v17
NewMigration("create repo unit table and add units for all repos", addUnitsToTables),
// v17 -> v18
NewMigration("set protect branches updated with created", setProtectedBranchUpdatedWithCreated),
}
// Migrate database to current version

29
models/migrations/v17.go Normal file
View file

@ -0,0 +1,29 @@
// Copyright 2016 Gitea. 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"
"time"
"github.com/go-xorm/xorm"
)
func setProtectedBranchUpdatedWithCreated(x *xorm.Engine) (err error) {
type ProtectedBranch struct {
ID int64 `xorm:"pk autoincr"`
RepoID int64 `xorm:"UNIQUE(s)"`
BranchName string `xorm:"UNIQUE(s)"`
CanPush bool
Created time.Time `xorm:"-"`
CreatedUnix int64
Updated time.Time `xorm:"-"`
UpdatedUnix int64
}
if err = x.Sync2(new(ProtectedBranch)); err != nil {
return fmt.Errorf("Sync2: %v", err)
}
return nil
}

View file

@ -524,6 +524,12 @@ func (repo *Repository) HasAccess(u *User) bool {
return has
}
// UpdateDefaultBranch updates the default branch
func (repo *Repository) UpdateDefaultBranch() error {
_, err := x.ID(repo.ID).Cols("default_branch").Update(repo)
return err
}
// IsOwnedBy returns true when user owns this repository
func (repo *Repository) IsOwnedBy(userID int64) bool {
return repo.OwnerID == userID