2016-01-28 22:49:05 +03:00
// Copyright 2016 The Gogs Authors. All rights reserved.
2019-04-19 15:17:27 +03:00
// Copyright 2019 The Gitea Authors. All rights reserved.
2016-01-28 22:49:05 +03:00
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
2016-01-15 21:24:03 +03:00
package models
import (
2017-10-15 22:59:24 +03:00
"fmt"
2019-03-27 12:33:00 +03:00
"code.gitea.io/gitea/modules/git"
2019-05-11 18:29:17 +03:00
"code.gitea.io/gitea/modules/log"
2016-01-15 21:24:03 +03:00
)
2017-10-15 22:59:24 +03:00
// CanCreateBranch returns true if repository meets the requirements for creating new branches.
func ( repo * Repository ) CanCreateBranch ( ) bool {
return ! repo . IsMirror
}
2019-04-19 15:17:27 +03:00
// GetBranch returns a branch by its name
func ( repo * Repository ) GetBranch ( branch string ) ( * git . Branch , error ) {
gitRepo , err := git . OpenRepository ( repo . RepoPath ( ) )
if err != nil {
return nil , err
2016-02-03 01:07:40 +03:00
}
2019-04-19 15:17:27 +03:00
return gitRepo . GetBranch ( branch )
2016-02-03 01:07:40 +03:00
}
2016-11-26 03:40:35 +03:00
// GetBranches returns all the branches of a repository
2019-04-19 15:17:27 +03:00
func ( repo * Repository ) GetBranches ( ) ( [ ] * git . Branch , error ) {
return git . GetBranchesByPath ( repo . RepoPath ( ) )
2016-01-15 21:24:03 +03:00
}
2017-10-15 22:59:24 +03:00
// CheckBranchName validates branch name with existing repository branches
func ( repo * Repository ) CheckBranchName ( name string ) error {
gitRepo , err := git . OpenRepository ( repo . RepoPath ( ) )
if err != nil {
return err
}
branches , err := repo . GetBranches ( )
if err != nil {
return err
}
for _ , branch := range branches {
if branch . Name == name {
return ErrBranchAlreadyExists { branch . Name }
} else if ( len ( branch . Name ) < len ( name ) && branch . Name + "/" == name [ 0 : len ( branch . Name ) + 1 ] ) ||
( len ( branch . Name ) > len ( name ) && name + "/" == branch . Name [ 0 : len ( name ) + 1 ] ) {
return ErrBranchNameConflict { branch . Name }
}
}
2019-03-11 06:44:58 +03:00
if _ , err := gitRepo . GetTag ( name ) ; err == nil {
return ErrTagAlreadyExists { name }
}
2017-10-15 22:59:24 +03:00
return nil
}
// CreateNewBranch creates a new repository branch
func ( repo * Repository ) CreateNewBranch ( doer * User , oldBranchName , branchName string ) ( err error ) {
// Check if branch name can be used
if err := repo . CheckBranchName ( branchName ) ; err != nil {
return err
}
2019-05-11 18:29:17 +03:00
if ! git . IsBranchExist ( repo . RepoPath ( ) , oldBranchName ) {
return fmt . Errorf ( "OldBranch: %s does not exist. Cannot create new branch from this" , oldBranchName )
2017-10-15 22:59:24 +03:00
}
2019-05-11 18:29:17 +03:00
basePath , err := CreateTemporaryPath ( "branch-maker" )
if err != nil {
return err
2017-10-15 22:59:24 +03:00
}
2019-06-12 22:41:28 +03:00
defer func ( ) {
if err := RemoveTemporaryPath ( basePath ) ; err != nil {
log . Error ( "CreateNewBranch: RemoveTemporaryPath: %s" , err )
}
} ( )
2017-10-15 22:59:24 +03:00
2019-05-11 18:29:17 +03:00
if err := git . Clone ( repo . RepoPath ( ) , basePath , git . CloneRepoOptions {
Bare : true ,
Shared : true ,
2017-10-15 22:59:24 +03:00
} ) ; err != nil {
2019-05-11 18:29:17 +03:00
log . Error ( "Failed to clone repository: %s (%v)" , repo . FullName ( ) , err )
return fmt . Errorf ( "Failed to clone repository: %s (%v)" , repo . FullName ( ) , err )
2017-10-15 22:59:24 +03:00
}
2019-05-11 18:29:17 +03:00
gitRepo , err := git . OpenRepository ( basePath )
if err != nil {
log . Error ( "Unable to open temporary repository: %s (%v)" , basePath , err )
return fmt . Errorf ( "Failed to open new temporary repository in: %s %v" , basePath , err )
}
2017-10-15 22:59:24 +03:00
2019-05-11 18:29:17 +03:00
if err = gitRepo . CreateBranch ( branchName , oldBranchName ) ; err != nil {
log . Error ( "Unable to create branch: %s from %s. (%v)" , branchName , oldBranchName , err )
return fmt . Errorf ( "Unable to create branch: %s from %s. (%v)" , branchName , oldBranchName , err )
2017-10-15 22:59:24 +03:00
}
2019-05-11 18:29:17 +03:00
if err = git . Push ( basePath , git . PushOptions {
Remote : "origin" ,
Branch : branchName ,
Env : PushingEnvironment ( doer , repo ) ,
2017-10-15 22:59:24 +03:00
} ) ; err != nil {
2019-05-11 18:29:17 +03:00
return fmt . Errorf ( "Push: %v" , err )
2017-10-15 22:59:24 +03:00
}
2019-05-11 18:29:17 +03:00
return nil
2017-10-15 22:59:24 +03:00
}
// CreateNewBranchFromCommit creates a new repository branch
func ( repo * Repository ) CreateNewBranchFromCommit ( doer * User , commit , branchName string ) ( err error ) {
// Check if branch name can be used
if err := repo . CheckBranchName ( branchName ) ; err != nil {
return err
}
2019-05-11 18:29:17 +03:00
basePath , err := CreateTemporaryPath ( "branch-maker" )
if err != nil {
return err
}
2019-06-12 22:41:28 +03:00
defer func ( ) {
if err := RemoveTemporaryPath ( basePath ) ; err != nil {
log . Error ( "CreateNewBranchFromCommit: RemoveTemporaryPath: %s" , err )
}
} ( )
2017-10-15 22:59:24 +03:00
2019-05-11 18:29:17 +03:00
if err := git . Clone ( repo . RepoPath ( ) , basePath , git . CloneRepoOptions {
Bare : true ,
Shared : true ,
} ) ; err != nil {
log . Error ( "Failed to clone repository: %s (%v)" , repo . FullName ( ) , err )
return fmt . Errorf ( "Failed to clone repository: %s (%v)" , repo . FullName ( ) , err )
}
2017-10-15 22:59:24 +03:00
2019-05-11 18:29:17 +03:00
gitRepo , err := git . OpenRepository ( basePath )
if err != nil {
log . Error ( "Unable to open temporary repository: %s (%v)" , basePath , err )
return fmt . Errorf ( "Failed to open new temporary repository in: %s %v" , basePath , err )
2017-10-15 22:59:24 +03:00
}
2019-05-11 18:29:17 +03:00
if err = gitRepo . CreateBranch ( branchName , commit ) ; err != nil {
log . Error ( "Unable to create branch: %s from %s. (%v)" , branchName , commit , err )
return fmt . Errorf ( "Unable to create branch: %s from %s. (%v)" , branchName , commit , err )
2017-10-15 22:59:24 +03:00
}
2019-05-11 18:29:17 +03:00
if err = git . Push ( basePath , git . PushOptions {
2017-10-15 22:59:24 +03:00
Remote : "origin" ,
Branch : branchName ,
2019-05-11 18:29:17 +03:00
Env : PushingEnvironment ( doer , repo ) ,
2017-10-15 22:59:24 +03:00
} ) ; err != nil {
return fmt . Errorf ( "Push: %v" , err )
}
return nil
}