2020-01-12 15:11:17 +03:00
// Copyright 2019 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 repository
import (
"fmt"
"strings"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
2020-08-11 23:05:34 +03:00
"code.gitea.io/gitea/modules/util"
2020-01-12 15:11:17 +03:00
)
// CreateRepository creates a repository for the user/organization.
2020-09-25 07:09:23 +03:00
func CreateRepository ( doer , u * models . User , opts models . CreateRepoOptions ) ( * models . Repository , error ) {
2020-01-12 15:11:17 +03:00
if ! doer . IsAdmin && ! u . CanCreateRepo ( ) {
return nil , models . ErrReachLimitOfRepo {
Limit : u . MaxRepoCreation ,
}
}
2020-09-06 23:58:54 +03:00
if len ( opts . DefaultBranch ) == 0 {
opts . DefaultBranch = setting . Repository . DefaultBranch
}
2021-01-18 23:00:50 +03:00
// Check if label template exist
if len ( opts . IssueLabels ) > 0 {
if _ , err := models . GetLabelTemplateFile ( opts . IssueLabels ) ; err != nil {
return nil , err
}
}
2020-01-12 15:11:17 +03:00
repo := & models . Repository {
OwnerID : u . ID ,
Owner : u ,
OwnerName : u . Name ,
Name : opts . Name ,
LowerName : strings . ToLower ( opts . Name ) ,
Description : opts . Description ,
OriginalURL : opts . OriginalURL ,
OriginalServiceType : opts . GitServiceType ,
IsPrivate : opts . IsPrivate ,
IsFsckEnabled : ! opts . IsMirror ,
2020-09-25 08:18:37 +03:00
IsTemplate : opts . IsTemplate ,
2020-01-12 15:11:17 +03:00
CloseIssuesViaCommitInAnyBranch : setting . Repository . DefaultCloseIssuesViaCommitsInAnyBranch ,
Status : opts . Status ,
IsEmpty : ! opts . AutoInit ,
2020-09-19 19:44:55 +03:00
TrustModel : opts . TrustModel ,
2020-01-12 15:11:17 +03:00
}
2021-01-18 23:00:50 +03:00
var rollbackRepo * models . Repository
2020-09-25 07:09:23 +03:00
if err := models . WithTx ( func ( ctx models . DBContext ) error {
if err := models . CreateRepository ( ctx , doer , u , repo , false ) ; err != nil {
2020-01-12 15:11:17 +03:00
return err
}
// No need for init mirror.
2020-09-25 07:09:23 +03:00
if opts . IsMirror {
return nil
}
repoPath := models . RepoPath ( u . Name , repo . Name )
2020-11-28 05:42:08 +03:00
isExist , err := util . IsExist ( repoPath )
if err != nil {
log . Error ( "Unable to check if %s exists. Error: %v" , repoPath , err )
return err
}
if isExist {
2020-09-25 07:09:23 +03:00
// repo already exists - We have two or three options.
// 1. We fail stating that the directory exists
// 2. We create the db repository to go with this data and adopt the git repo
// 3. We delete it and start afresh
//
// Previously Gitea would just delete and start afresh - this was naughty.
// So we will now fail and delegate to other functionality to adopt or delete
log . Error ( "Files already exist in %s and we are not going to adopt or delete." , repoPath )
return models . ErrRepoFilesAlreadyExist {
Uname : u . Name ,
Name : repo . Name ,
}
}
2021-01-18 23:00:50 +03:00
if err = initRepository ( ctx , repoPath , doer , repo , opts ) ; err != nil {
2020-09-25 07:09:23 +03:00
if err2 := util . RemoveAll ( repoPath ) ; err2 != nil {
log . Error ( "initRepository: %v" , err )
return fmt . Errorf (
"delete repo directory %s/%s failed(2): %v" , u . Name , repo . Name , err2 )
2020-01-12 15:11:17 +03:00
}
2020-09-25 07:09:23 +03:00
return fmt . Errorf ( "initRepository: %v" , err )
}
2020-01-12 15:11:17 +03:00
2020-09-25 07:09:23 +03:00
// Initialize Issue Labels if selected
if len ( opts . IssueLabels ) > 0 {
2021-01-18 23:00:50 +03:00
if err = models . InitializeLabels ( ctx , repo . ID , opts . IssueLabels , false ) ; err != nil {
rollbackRepo = repo
rollbackRepo . OwnerID = u . ID
2020-09-25 07:09:23 +03:00
return fmt . Errorf ( "InitializeLabels: %v" , err )
2020-01-12 15:11:17 +03:00
}
2020-09-25 07:09:23 +03:00
}
2020-01-12 15:11:17 +03:00
2020-09-25 07:09:23 +03:00
if stdout , err := git . NewCommand ( "update-server-info" ) .
SetDescription ( fmt . Sprintf ( "CreateRepository(git update-server-info): %s" , repoPath ) ) .
RunInDir ( repoPath ) ; err != nil {
log . Error ( "CreateRepository(git update-server-info) in %v: Stdout: %s\nError: %v" , repo , stdout , err )
2021-01-18 23:00:50 +03:00
rollbackRepo = repo
rollbackRepo . OwnerID = u . ID
2020-09-25 07:09:23 +03:00
return fmt . Errorf ( "CreateRepository(git update-server-info): %v" , err )
2020-01-12 15:11:17 +03:00
}
return nil
2020-09-25 07:09:23 +03:00
} ) ; err != nil {
2021-01-18 23:00:50 +03:00
if rollbackRepo != nil {
if errDelete := models . DeleteRepository ( doer , rollbackRepo . OwnerID , rollbackRepo . ID ) ; errDelete != nil {
log . Error ( "Rollback deleteRepository: %v" , errDelete )
}
}
2020-09-25 07:09:23 +03:00
return nil , err
}
2020-01-12 15:11:17 +03:00
2020-09-25 07:09:23 +03:00
return repo , nil
2020-01-12 15:11:17 +03:00
}