aboutsummaryrefslogtreecommitdiff
path: root/internal/db/repo.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/db/repo.go')
-rw-r--r--internal/db/repo.go151
1 files changed, 104 insertions, 47 deletions
diff --git a/internal/db/repo.go b/internal/db/repo.go
index 360e967c..71cd4601 100644
--- a/internal/db/repo.go
+++ b/internal/db/repo.go
@@ -21,6 +21,7 @@ import (
"time"
"github.com/nfnt/resize"
+ "github.com/pkg/errors"
"github.com/unknwon/cae/zip"
"github.com/unknwon/com"
"gopkg.in/ini.v1"
@@ -33,11 +34,12 @@ import (
embedConf "gogs.io/gogs/conf"
"gogs.io/gogs/internal/avatar"
"gogs.io/gogs/internal/conf"
- "gogs.io/gogs/internal/db/errors"
+ dberrors "gogs.io/gogs/internal/db/errors"
"gogs.io/gogs/internal/errutil"
"gogs.io/gogs/internal/markup"
"gogs.io/gogs/internal/osutil"
"gogs.io/gogs/internal/process"
+ "gogs.io/gogs/internal/repoutil"
"gogs.io/gogs/internal/semverutil"
"gogs.io/gogs/internal/sync"
)
@@ -150,15 +152,15 @@ func NewRepoContext() {
// Repository contains information of a repository.
type Repository struct {
- ID int64
- OwnerID int64 `xorm:"UNIQUE(s)" gorm:"UNIQUE_INDEX:s"`
+ ID int64 `gorm:"primaryKey"`
+ OwnerID int64 `xorm:"UNIQUE(s)" gorm:"uniqueIndex:repo_owner_name_unique"`
Owner *User `xorm:"-" gorm:"-" json:"-"`
- LowerName string `xorm:"UNIQUE(s) INDEX NOT NULL" gorm:"UNIQUE_INDEX:s"`
- Name string `xorm:"INDEX NOT NULL" gorm:"NOT NULL"`
- Description string `xorm:"VARCHAR(512)" gorm:"TYPE:VARCHAR(512)"`
+ LowerName string `xorm:"UNIQUE(s) INDEX NOT NULL" gorm:"uniqueIndex:repo_owner_name_unique;index;not null"`
+ Name string `xorm:"INDEX NOT NULL" gorm:"index;not null"`
+ Description string `xorm:"VARCHAR(512)" gorm:"type:VARCHAR(512)"`
Website string
DefaultBranch string
- Size int64 `xorm:"NOT NULL DEFAULT 0" gorm:"NOT NULL;DEFAULT:0"`
+ Size int64 `xorm:"NOT NULL DEFAULT 0" gorm:"not null;default:0"`
UseCustomAvatar bool
// Counters
@@ -171,37 +173,37 @@ type Repository struct {
NumPulls int
NumClosedPulls int
NumOpenPulls int `xorm:"-" gorm:"-" json:"-"`
- NumMilestones int `xorm:"NOT NULL DEFAULT 0" gorm:"NOT NULL;DEFAULT:0"`
- NumClosedMilestones int `xorm:"NOT NULL DEFAULT 0" gorm:"NOT NULL;DEFAULT:0"`
+ NumMilestones int `xorm:"NOT NULL DEFAULT 0" gorm:"not null;default:0"`
+ NumClosedMilestones int `xorm:"NOT NULL DEFAULT 0" gorm:"not null;default:0"`
NumOpenMilestones int `xorm:"-" gorm:"-" json:"-"`
NumTags int `xorm:"-" gorm:"-" json:"-"`
IsPrivate bool
// TODO: When migrate to GORM, make sure to do a loose migration with `HasColumn` and `AddColumn`,
// see docs in https://gorm.io/docs/migration.html.
- IsUnlisted bool `xorm:"NOT NULL DEFAULT false"`
+ IsUnlisted bool `xorm:"NOT NULL DEFAULT false" gorm:"not null;default:FALSE"`
IsBare bool
IsMirror bool
*Mirror `xorm:"-" gorm:"-" json:"-"`
// Advanced settings
- EnableWiki bool `xorm:"NOT NULL DEFAULT true" gorm:"NOT NULL;DEFAULT:TRUE"`
+ EnableWiki bool `xorm:"NOT NULL DEFAULT true" gorm:"not null;default:TRUE"`
AllowPublicWiki bool
EnableExternalWiki bool
ExternalWikiURL string
- EnableIssues bool `xorm:"NOT NULL DEFAULT true" gorm:"NOT NULL;DEFAULT:TRUE"`
+ EnableIssues bool `xorm:"NOT NULL DEFAULT true" gorm:"not null;default:TRUE"`
AllowPublicIssues bool
EnableExternalTracker bool
ExternalTrackerURL string
ExternalTrackerFormat string
ExternalTrackerStyle string
ExternalMetas map[string]string `xorm:"-" gorm:"-" json:"-"`
- EnablePulls bool `xorm:"NOT NULL DEFAULT true" gorm:"NOT NULL;DEFAULT:TRUE"`
- PullsIgnoreWhitespace bool `xorm:"NOT NULL DEFAULT false" gorm:"NOT NULL;DEFAULT:FALSE"`
- PullsAllowRebase bool `xorm:"NOT NULL DEFAULT false" gorm:"NOT NULL;DEFAULT:FALSE"`
+ EnablePulls bool `xorm:"NOT NULL DEFAULT true" gorm:"not null;default:TRUE"`
+ PullsIgnoreWhitespace bool `xorm:"NOT NULL DEFAULT false" gorm:"not null;default:FALSE"`
+ PullsAllowRebase bool `xorm:"NOT NULL DEFAULT false" gorm:"not null;default:FALSE"`
- IsFork bool `xorm:"NOT NULL DEFAULT false" gorm:"NOT NULL;DEFAULT:FALSE"`
+ IsFork bool `xorm:"NOT NULL DEFAULT false" gorm:"not null;default:FALSE"`
ForkID int64
BaseRepo *Repository `xorm:"-" gorm:"-" json:"-"`
@@ -290,6 +292,7 @@ func (repo *Repository) FullName() string {
return repo.MustOwner().Name + "/" + repo.Name
}
+// Deprecated: Use repoutil.HTMLURL instead.
func (repo *Repository) HTMLURL() string {
return conf.Server.ExternalURL + repo.FullName()
}
@@ -356,7 +359,9 @@ func (repo *Repository) DeleteAvatar() error {
// This method assumes following fields have been assigned with valid values:
// Required - BaseRepo (if fork)
// Arguments that are allowed to be nil: permission
-func (repo *Repository) APIFormat(permission *api.Permission, user ...*User) *api.Repository {
+//
+// Deprecated: Use APIFormat instead.
+func (repo *Repository) APIFormatLegacy(permission *api.Permission, user ...*User) *api.Repository {
cloneLink := repo.CloneLink()
apiRepo := &api.Repository{
ID: repo.ID,
@@ -390,7 +395,7 @@ func (repo *Repository) APIFormat(permission *api.Permission, user ...*User) *ap
p.Admin = user[0].IsAdminOfRepo(repo)
p.Push = user[0].IsWriterOfRepo(repo)
}
- apiRepo.Parent = repo.BaseRepo.APIFormat(p)
+ apiRepo.Parent = repo.BaseRepo.APIFormatLegacy(p)
}
return apiRepo
}
@@ -537,6 +542,7 @@ func (repo *Repository) repoPath(e Engine) string {
return RepoPath(repo.mustOwner(e).Name, repo.Name)
}
+// Deprecated: Use repoutil.RepositoryPath instead.
func (repo *Repository) RepoPath() string {
return repo.repoPath(x)
}
@@ -553,6 +559,7 @@ func (repo *Repository) Link() string {
return conf.Server.Subpath + "/" + repo.FullName()
}
+// Deprecated: Use repoutil.ComparePath instead.
func (repo *Repository) ComposeCompareURL(oldCommitID, newCommitID string) string {
return fmt.Sprintf("%s/%s/compare/%s...%s", repo.MustOwner().Name, repo.Name, oldCommitID, newCommitID)
}
@@ -694,37 +701,28 @@ func IsRepositoryExist(u *User, repoName string) (bool, error) {
return isRepositoryExist(x, u, repoName)
}
-// CloneLink represents different types of clone URLs of repository.
-type CloneLink struct {
- SSH string
- HTTPS string
- Git string
-}
-
-// ComposeHTTPSCloneURL returns HTTPS clone URL based on given owner and repository name.
-func ComposeHTTPSCloneURL(owner, repo string) string {
- return fmt.Sprintf("%s%s/%s.git", conf.Server.ExternalURL, owner, repo)
-}
-
-func (repo *Repository) cloneLink(isWiki bool) *CloneLink {
+// Deprecated: Use repoutil.NewCloneLink instead.
+func (repo *Repository) cloneLink(isWiki bool) *repoutil.CloneLink {
repoName := repo.Name
if isWiki {
repoName += ".wiki"
}
repo.Owner = repo.MustOwner()
- cl := new(CloneLink)
+ cl := new(repoutil.CloneLink)
if conf.SSH.Port != 22 {
cl.SSH = fmt.Sprintf("ssh://%s@%s:%d/%s/%s.git", conf.App.RunUser, conf.SSH.Domain, conf.SSH.Port, repo.Owner.Name, repoName)
} else {
cl.SSH = fmt.Sprintf("%s@%s:%s/%s.git", conf.App.RunUser, conf.SSH.Domain, repo.Owner.Name, repoName)
}
- cl.HTTPS = ComposeHTTPSCloneURL(repo.Owner.Name, repoName)
+ cl.HTTPS = repoutil.HTTPSCloneURL(repo.Owner.Name, repoName)
return cl
}
// CloneLink returns clone URLs of repository.
-func (repo *Repository) CloneLink() (cl *CloneLink) {
+//
+// Deprecated: Use repoutil.NewCloneLink instead.
+func (repo *Repository) CloneLink() (cl *repoutil.CloneLink) {
return repo.cloneLink(false)
}
@@ -758,7 +756,7 @@ func wikiRemoteURL(remote string) string {
// MigrateRepository migrates a existing repository from other project hosting.
func MigrateRepository(doer, owner *User, opts MigrateRepoOptions) (*Repository, error) {
- repo, err := CreateRepository(doer, owner, CreateRepoOptions{
+ repo, err := CreateRepository(doer, owner, CreateRepoOptionsLegacy{
Name: opts.Name,
Description: opts.Description,
IsPrivate: opts.IsPrivate,
@@ -930,7 +928,7 @@ func initRepoCommit(tmpPath string, sig *git.Signature) (err error) {
return nil
}
-type CreateRepoOptions struct {
+type CreateRepoOptionsLegacy struct {
Name string
Description string
Gitignores string
@@ -953,7 +951,7 @@ func getRepoInitFile(tp, name string) ([]byte, error) {
return embedConf.Files.ReadFile(relPath)
}
-func prepareRepoCommit(repo *Repository, tmpDir, repoPath string, opts CreateRepoOptions) error {
+func prepareRepoCommit(repo *Repository, tmpDir, repoPath string, opts CreateRepoOptionsLegacy) error {
// Clone to temporary path and do the init commit.
_, stderr, err := process.Exec(
fmt.Sprintf("initRepository(git clone): %s", repoPath), "git", "clone", repoPath, tmpDir)
@@ -1016,7 +1014,7 @@ func prepareRepoCommit(repo *Repository, tmpDir, repoPath string, opts CreateRep
}
// initRepository performs initial commit with chosen setup files on behave of doer.
-func initRepository(e Engine, repoPath string, doer *User, repo *Repository, opts CreateRepoOptions) (err error) {
+func initRepository(e Engine, repoPath string, doer *User, repo *Repository, opts CreateRepoOptionsLegacy) (err error) {
// Somehow the directory could exist.
if com.IsExist(repoPath) {
return fmt.Errorf("initRepository: path already exists: %s", repoPath)
@@ -1116,7 +1114,29 @@ func createRepository(e *xorm.Session, doer, owner *User, repo *Repository) (err
if err = watchRepo(e, owner.ID, repo.ID, true); err != nil {
return fmt.Errorf("watchRepo: %v", err)
- } else if err = newRepoAction(e, doer, owner, repo); err != nil {
+ }
+
+ // FIXME: This is identical to Actions.NewRepo but we are not yet able to wrap
+ // transaction with different ORM objects, should delete this once migrated to
+ // GORM for this part of logic.
+ newRepoAction := func(e Engine, doer *User, repo *Repository) (err error) {
+ opType := ActionCreateRepo
+ if repo.IsFork {
+ opType = ActionForkRepo
+ }
+
+ return notifyWatchers(e, &Action{
+ ActUserID: doer.ID,
+ ActUserName: doer.Name,
+ OpType: opType,
+ RepoID: repo.ID,
+ RepoUserName: repo.Owner.Name,
+ RepoName: repo.Name,
+ IsPrivate: repo.IsPrivate || repo.IsUnlisted,
+ CreatedUnix: time.Now().Unix(),
+ })
+ }
+ if err = newRepoAction(e, doer, repo); err != nil {
return fmt.Errorf("newRepoAction: %v", err)
}
@@ -1137,7 +1157,7 @@ func (err ErrReachLimitOfRepo) Error() string {
}
// CreateRepository creates a repository for given user or organization.
-func CreateRepository(doer, owner *User, opts CreateRepoOptions) (_ *Repository, err error) {
+func CreateRepository(doer, owner *User, opts CreateRepoOptionsLegacy) (_ *Repository, err error) {
if !owner.CanCreateRepo() {
return nil, ErrReachLimitOfRepo{Limit: owner.RepoCreationNum()}
}
@@ -1265,6 +1285,8 @@ func FilterRepositoryWithIssues(repoIDs []int64) ([]int64, error) {
}
// RepoPath returns repository path by given user and repository name.
+//
+// Deprecated: Use repoutil.RepositoryPath instead.
func RepoPath(userName, repoName string) string {
return filepath.Join(UserPath(userName), strings.ToLower(repoName)+".git")
}
@@ -1361,9 +1383,34 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error
return fmt.Errorf("decrease old owner repository count: %v", err)
}
+ // Remove watch for organization.
+ if owner.IsOrganization() {
+ if err = watchRepo(sess, owner.ID, repo.ID, false); err != nil {
+ return errors.Wrap(err, "unwatch repository for the organization owner")
+ }
+ }
+
if err = watchRepo(sess, newOwner.ID, repo.ID, true); err != nil {
return fmt.Errorf("watchRepo: %v", err)
- } else if err = transferRepoAction(sess, doer, owner, repo); err != nil {
+ }
+
+ // FIXME: This is identical to Actions.TransferRepo but we are not yet able to
+ // wrap transaction with different ORM objects, should delete this once migrated
+ // to GORM for this part of logic.
+ transferRepoAction := func(e Engine, doer, oldOwner *User, repo *Repository) error {
+ return notifyWatchers(e, &Action{
+ ActUserID: doer.ID,
+ ActUserName: doer.Name,
+ OpType: ActionTransferRepo,
+ RepoID: repo.ID,
+ RepoUserName: repo.Owner.Name,
+ RepoName: repo.Name,
+ IsPrivate: repo.IsPrivate || repo.IsUnlisted,
+ Content: path.Join(oldOwner.Name, repo.Name),
+ CreatedUnix: time.Now().Unix(),
+ })
+ }
+ if err = transferRepoAction(sess, doer, owner, repo); err != nil {
return fmt.Errorf("transferRepoAction: %v", err)
}
@@ -1651,7 +1698,7 @@ func DeleteRepository(ownerID, repoID int64) error {
func GetRepositoryByRef(ref string) (*Repository, error) {
n := strings.IndexByte(ref, byte('/'))
if n < 2 {
- return nil, errors.InvalidRepoReference{Ref: ref}
+ return nil, dberrors.InvalidRepoReference{Ref: ref}
}
userName, repoName := ref[:n], ref[n+1:]
@@ -2235,9 +2282,9 @@ func (repos MirrorRepositoryList) LoadAttributes() error {
// Watch is connection request for receiving repository notification.
type Watch struct {
- ID int64
- UserID int64 `xorm:"UNIQUE(watch)"`
- RepoID int64 `xorm:"UNIQUE(watch)"`
+ ID int64 `gorm:"primaryKey"`
+ UserID int64 `xorm:"UNIQUE(watch)" gorm:"uniqueIndex:watch_user_repo_unique;not null"`
+ RepoID int64 `xorm:"UNIQUE(watch)" gorm:"uniqueIndex:watch_user_repo_unique;not null"`
}
func isWatching(e Engine, userID, repoID int64) bool {
@@ -2276,12 +2323,15 @@ func WatchRepo(userID, repoID int64, watch bool) (err error) {
return watchRepo(x, userID, repoID, watch)
}
+// Deprecated: Use Repos.ListByRepo instead.
func getWatchers(e Engine, repoID int64) ([]*Watch, error) {
watches := make([]*Watch, 0, 10)
return watches, e.Find(&watches, &Watch{RepoID: repoID})
}
// GetWatchers returns all watchers of given repository.
+//
+// Deprecated: Use Repos.ListByRepo instead.
func GetWatchers(repoID int64) ([]*Watch, error) {
return getWatchers(x, repoID)
}
@@ -2298,7 +2348,12 @@ func (repo *Repository) GetWatchers(page int) ([]*User, error) {
return users, sess.Find(&users)
}
+// Deprecated: Use Actions.notifyWatchers instead.
func notifyWatchers(e Engine, act *Action) error {
+ if act.CreatedUnix <= 0 {
+ act.CreatedUnix = time.Now().Unix()
+ }
+
// Add feeds for user self and all watchers.
watchers, err := getWatchers(e, act.RepoID)
if err != nil {
@@ -2329,6 +2384,8 @@ func notifyWatchers(e Engine, act *Action) error {
}
// NotifyWatchers creates batch of actions for every watcher.
+//
+// Deprecated: Use Actions.notifyWatchers instead.
func NotifyWatchers(act *Action) error {
return notifyWatchers(x, act)
}
@@ -2469,8 +2526,8 @@ func ForkRepository(doer, owner *User, baseRepo *Repository, name, desc string)
log.Error("UpdateSize [repo_id: %d]: %v", repo.ID, err)
}
if err = PrepareWebhooks(baseRepo, HOOK_EVENT_FORK, &api.ForkPayload{
- Forkee: repo.APIFormat(nil),
- Repo: baseRepo.APIFormat(nil),
+ Forkee: repo.APIFormatLegacy(nil),
+ Repo: baseRepo.APIFormatLegacy(nil),
Sender: doer.APIFormat(),
}); err != nil {
log.Error("PrepareWebhooks [repo_id: %d]: %v", baseRepo.ID, err)