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 units concept for modulable functions of a repository #742

Merged
merged 7 commits into from
Feb 4, 2017
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 4 additions & 4 deletions cmd/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ func runWeb(ctx *cli.Context) error {

}, func(ctx *context.Context) {
ctx.Data["PageIsSettings"] = true
})
}, context.UnitTypes())
}, reqSignIn, context.RepoAssignment(), reqRepoAdmin, context.RepoRef())

m.Get("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), repo.Action)
Expand Down Expand Up @@ -529,7 +529,7 @@ func runWeb(ctx *cli.Context) error {
return
}
})
}, reqSignIn, context.RepoAssignment(), repo.MustBeNotBare)
}, reqSignIn, context.RepoAssignment(), repo.MustBeNotBare, context.UnitTypes())

m.Group("/:username/:reponame", func() {
m.Group("", func() {
Expand Down Expand Up @@ -575,7 +575,7 @@ func runWeb(ctx *cli.Context) error {
m.Get("/commit/:sha([a-f0-9]{7,40})\\.:ext(patch|diff)", repo.RawDiff)

m.Get("/compare/:before([a-z0-9]{40})\\.\\.\\.:after([a-z0-9]{40})", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.CompareDiff)
}, ignSignIn, context.RepoAssignment(), repo.MustBeNotBare)
}, ignSignIn, context.RepoAssignment(), repo.MustBeNotBare, context.UnitTypes())
m.Group("/:username/:reponame", func() {
m.Get("/stars", repo.Stars)
m.Get("/watchers", repo.Watchers)
Expand All @@ -585,7 +585,7 @@ func runWeb(ctx *cli.Context) error {
m.Group("/:reponame", func() {
m.Get("", repo.SetEditorconfigIfExists, repo.Home)
m.Get("\\.git$", repo.SetEditorconfigIfExists, repo.Home)
}, ignSignIn, context.RepoAssignment(true), context.RepoRef())
}, ignSignIn, context.RepoAssignment(true), context.RepoRef(), context.UnitTypes())

m.Group("/:reponame", func() {
m.Group("/info/lfs", func() {
Expand Down
2 changes: 2 additions & 0 deletions models/migrations/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ var migrations = []Migration{
NewMigration("create user column diff view style", createUserColumnDiffViewStyle),
// v15
NewMigration("create user column allow create organization", createAllowCreateOrganizationColumn),
// V16
NewMigration("create repo unit table and add units for all repos", addUnitsToTables),
}

// Migrate database to current version
Expand Down
117 changes: 117 additions & 0 deletions models/migrations/v16.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package migrations

import (
"fmt"
"time"

"code.gitea.io/gitea/modules/markdown"

"github.com/go-xorm/xorm"
)

// RepoUnit describes all units of a repository
type RepoUnit struct {
ID int64
RepoID int64 `xorm:"INDEX(s)"`
Type int `xorm:"INDEX(s)"`
Index int
Config map[string]string `xorm:"JSON"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be better to have the keys of RepoUnit.Config be an enum type instead of string literals? I see two advantages to using an enum:

  1. We don't need to have "magic" string literals in our code. It is easy to accidentally mistype something like "ExternalTrackerFormat", and the compiler won't tell you if you do.
  2. When the RepoUnit.Config field is converted to JSON to store in the database, the generated JSON object will have shorter fields, and thus will use up less disk space.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

CreatedUnix int64 `xorm:"INDEX CREATED"`
Created time.Time `xorm:"-"`
}

// Enumerate all the unit types
const (
UnitTypeCode = iota + 1 // 1 code
UnitTypeIssues // 2 issues
UnitTypePRs // 3 PRs
UnitTypeCommits // 4 Commits
UnitTypeReleases // 5 Releases
UnitTypeWiki // 6 Wiki
UnitTypeSettings // 7 Settings
UnitTypeExternalWiki // 8 ExternalWiki
UnitTypeExternalTracker // 9 ExternalTracker
)

// Repo describes a repository
type Repo struct {
ID int64
EnableWiki, EnableExternalWiki, EnableIssues, EnableExternalTracker, EnablePulls bool
ExternalWikiURL, ExternalTrackerURL, ExternalTrackerFormat, ExternalTrackerStyle string
}

func addUnitsToTables(x *xorm.Engine) error {
var repos []Repo
err := x.Table("repository").Find(&repos)
if err != nil {
return fmt.Errorf("Query repositories: %v", err)
}

sess := x.NewSession()
defer sess.Close()

if err := sess.Begin(); err != nil {
return err
}

var repoUnit RepoUnit
if err := sess.CreateTable(&repoUnit); err != nil {
return fmt.Errorf("CreateTable RepoUnit: %v", err)
}

if err := sess.CreateUniques(&repoUnit); err != nil {
return fmt.Errorf("CreateUniques RepoUnit: %v", err)
}

if err := sess.CreateIndexes(&repoUnit); err != nil {
return fmt.Errorf("CreateIndexes RepoUnit: %v", err)
}

for _, repo := range repos {
for i := 1; i <= 9; i++ {
if (i == UnitTypeWiki || i == UnitTypeExternalWiki) && !repo.EnableWiki {
continue
}
if i == UnitTypeExternalWiki && !repo.EnableExternalWiki {
continue
}
if i == UnitTypePRs && !repo.EnablePulls {
continue
}
if (i == UnitTypeIssues || i == UnitTypeExternalTracker) && !repo.EnableIssues {
continue
}
if i == UnitTypeExternalTracker && !repo.EnableExternalTracker {
continue
}

var config = make(map[string]string)
switch i {
case UnitTypeExternalTracker:
config["ExternalTrackerURL"] = repo.ExternalTrackerURL
config["ExternalTrackerFormat"] = repo.ExternalTrackerFormat
if len(repo.ExternalTrackerStyle) == 0 {
repo.ExternalTrackerStyle = markdown.IssueNameStyleNumeric
}
config["ExternalTrackerStyle"] = repo.ExternalTrackerStyle
case UnitTypeExternalWiki:
config["ExternalWikiURL"] = repo.ExternalWikiURL
}

if _, err = sess.Insert(&RepoUnit{
RepoID: repo.ID,
Type: i,
Index: i,
Config: config,
}); err != nil {
return fmt.Errorf("Insert repo unit: %v", err)
}
}
}

if err := sess.Commit(); err != nil {
return err
}

return nil
}
1 change: 1 addition & 0 deletions models/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ func init() {
new(IssueUser),
new(LFSMetaObject),
new(TwoFactor),
new(RepoUnit),
)

gonicNames := []string{"SSL", "UID"}
Expand Down
139 changes: 111 additions & 28 deletions models/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,17 +200,8 @@ type Repository struct {
IsMirror bool `xorm:"INDEX"`
*Mirror `xorm:"-"`

// Advanced settings
EnableWiki bool `xorm:"NOT NULL DEFAULT true"`
EnableExternalWiki bool
ExternalWikiURL string
EnableIssues bool `xorm:"NOT NULL DEFAULT true"`
EnableExternalTracker bool
ExternalTrackerURL string
ExternalTrackerFormat string
ExternalTrackerStyle string
ExternalMetas map[string]string `xorm:"-"`
EnablePulls bool `xorm:"NOT NULL DEFAULT true"`
ExternalMetas map[string]string `xorm:"-"`
Units []*RepoUnit `xorm:"-"`

IsFork bool `xorm:"INDEX NOT NULL DEFAULT false"`
ForkID int64 `xorm:"INDEX"`
Expand Down Expand Up @@ -247,10 +238,6 @@ func (repo *Repository) AfterSet(colName string, _ xorm.Cell) {
repo.NumOpenPulls = repo.NumPulls - repo.NumClosedPulls
case "num_closed_milestones":
repo.NumOpenMilestones = repo.NumMilestones - repo.NumClosedMilestones
case "external_tracker_style":
if len(repo.ExternalTrackerStyle) == 0 {
repo.ExternalTrackerStyle = markdown.IssueNameStyleNumeric
}
case "created_unix":
repo.Created = time.Unix(repo.CreatedUnix, 0).Local()
case "updated_unix":
Expand Down Expand Up @@ -307,6 +294,60 @@ func (repo *Repository) APIFormat(mode AccessMode) *api.Repository {
}
}

func (repo *Repository) getUnits(e Engine) (err error) {
if repo.Units != nil {
return nil
}

repo.Units, err = getUnitsByRepoID(e, repo.ID)
return err
}

func getUnitsByRepoID(e Engine, repoID int64) (units []*RepoUnit, err error) {
return units, e.Where("repo_id = ?", repoID).Find(&units)
}

// EnableUnit if this repository enabled some unit
func (repo *Repository) EnableUnit(tp UnitType) bool {
repo.getUnits(x)
for _, unit := range repo.Units {
if unit.Type == tp {
return true
}
}
return false
}

var (
// ErrUnitNotExist organization does not exist
ErrUnitNotExist = errors.New("Unit does not exist")
)

// MustGetUnit always returns a RepoUnit object
func (repo *Repository) MustGetUnit(tp UnitType) *RepoUnit {
ru, err := repo.GetUnit(tp)
if err == nil {
return ru
}
return &RepoUnit{
Type: tp,
Config: make(map[string]string),
}
}

// GetUnit returns a RepoUnit object
func (repo *Repository) GetUnit(tp UnitType) (*RepoUnit, error) {
if err := repo.getUnits(x); err != nil {
return nil, err
}
for _, unit := range repo.Units {
if unit.Type == tp {
return unit, nil
}
}
return nil, ErrUnitNotExist
}

func (repo *Repository) getOwner(e Engine) (err error) {
if repo.Owner != nil {
return nil
Expand Down Expand Up @@ -334,15 +375,18 @@ func (repo *Repository) mustOwner(e Engine) *User {

// ComposeMetas composes a map of metas for rendering external issue tracker URL.
func (repo *Repository) ComposeMetas() map[string]string {
if !repo.EnableExternalTracker {
externalTracker, err := repo.GetUnit(UnitTypeExternalTracker)
if err != nil {
return nil
} else if repo.ExternalMetas == nil {
}

if repo.ExternalMetas == nil {
repo.ExternalMetas = map[string]string{
"format": repo.ExternalTrackerFormat,
"format": externalTracker.Config["ExternalTrackerFormat"],
"user": repo.MustOwner().Name,
"repo": repo.Name,
}
switch repo.ExternalTrackerStyle {
switch externalTracker.Config["ExternalTrackerStyle"] {
case markdown.IssueNameStyleAlphanumeric:
repo.ExternalMetas["style"] = markdown.IssueNameStyleAlphanumeric
default:
Expand All @@ -359,6 +403,8 @@ func (repo *Repository) DeleteWiki() {
for _, wikiPath := range wikiPaths {
RemoveAllWithNotice("Delete repository wiki", wikiPath)
}

x.Where("repo_id = ?", repo.ID).And("type = ?", UnitTypeWiki).Delete(new(RepoUnit))
}

func (repo *Repository) getAssignees(e Engine) (_ []*User, err error) {
Expand Down Expand Up @@ -482,7 +528,7 @@ func (repo *Repository) CanEnablePulls() bool {

// AllowsPulls returns true if repository meets the requirements of accepting pulls and has them enabled.
func (repo *Repository) AllowsPulls() bool {
return repo.CanEnablePulls() && repo.EnablePulls
return repo.CanEnablePulls() && repo.EnableUnit(UnitTypePullRequests)
}

// CanEnableEditor returns true if repository meets the requirements of web editor.
Expand Down Expand Up @@ -997,6 +1043,20 @@ func createRepository(e *xorm.Session, u *User, repo *Repository) (err error) {
return err
}

// insert units for repo
var units = make([]RepoUnit, 0, len(defaultRepoUnits))
for i, tp := range defaultRepoUnits {
units = append(units, RepoUnit{
RepoID: repo.ID,
Type: tp,
Index: i,
})
}

if _, err = e.Insert(&units); err != nil {
return err
}

u.NumRepos++
// Remember visibility preference.
u.LastRepoVisibility = repo.IsPrivate
Expand Down Expand Up @@ -1035,15 +1095,15 @@ func CreateRepository(u *User, opts CreateRepoOptions) (_ *Repository, err error
}

repo := &Repository{
OwnerID: u.ID,
Owner: u,
Name: opts.Name,
LowerName: strings.ToLower(opts.Name),
Description: opts.Description,
IsPrivate: opts.IsPrivate,
EnableWiki: true,
OwnerID: u.ID,
Owner: u,
Name: opts.Name,
LowerName: strings.ToLower(opts.Name),
Description: opts.Description,
IsPrivate: opts.IsPrivate,
/*EnableWiki: true,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why keep commented code? Git can handle it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

EnableIssues: true,
EnablePulls: true,
EnablePulls: true,*/
}

sess := x.NewSession()
Expand Down Expand Up @@ -1380,6 +1440,25 @@ func UpdateRepository(repo *Repository, visibilityChanged bool) (err error) {
return sess.Commit()
}

// UpdateRepositoryUnits updates a repository's units
func UpdateRepositoryUnits(repo *Repository, units []RepoUnit) (err error) {
sess := x.NewSession()
defer sess.Close()
if err = sess.Begin(); err != nil {
return err
}

if _, err = sess.Where("repo_id = ?", repo.ID).Delete(new(RepoUnit)); err != nil {
return err
}

if _, err = sess.Insert(units); err != nil {
return err
}

return sess.Commit()
}

// DeleteRepository deletes a repository for a user or organization.
func DeleteRepository(uid, repoID int64) error {
repo := &Repository{ID: repoID, OwnerID: uid}
Expand Down Expand Up @@ -1465,6 +1544,10 @@ func DeleteRepository(uid, repoID int64) error {
return err
}

if _, err = sess.Where("repo_id = ?", repoID).Delete(new(RepoUnit)); err != nil {
return err
}

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)
Expand Down